summaryrefslogtreecommitdiffhomepage
path: root/Stars45/Solid.cpp
diff options
context:
space:
mode:
authorAki <please@ignore.pl>2022-04-01 21:23:39 +0200
committerAki <please@ignore.pl>2022-04-01 21:23:39 +0200
commit3c487c5cd69c53d6fea948643c0a76df03516605 (patch)
tree72730c7b8b26a5ef8fc9a987ec4c16129efd5aac /Stars45/Solid.cpp
parent8f353abd0bfe18baddd8a8250ab7c4f2d1c83a6e (diff)
downloadstarshatter-3c487c5cd69c53d6fea948643c0a76df03516605.zip
starshatter-3c487c5cd69c53d6fea948643c0a76df03516605.tar.gz
starshatter-3c487c5cd69c53d6fea948643c0a76df03516605.tar.bz2
Moved Stars45 to StarsEx
Diffstat (limited to 'Stars45/Solid.cpp')
-rw-r--r--Stars45/Solid.cpp2476
1 files changed, 0 insertions, 2476 deletions
diff --git a/Stars45/Solid.cpp b/Stars45/Solid.cpp
deleted file mode 100644
index ff4f610..0000000
--- a/Stars45/Solid.cpp
+++ /dev/null
@@ -1,2476 +0,0 @@
-/* Starshatter: The Open Source Project
- Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors
- Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors
- Copyright (c) 1997-2006, Destroyer Studios LLC.
-
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Classes for rendering solid meshes of polygons
-*/
-
-#include "Solid.h"
-#include "Scene.h"
-#include "Bitmap.h"
-#include "DataLoader.h"
-#include "Light.h"
-#include "Shadow.h"
-#include "Projector.h"
-#include "Opcode.h"
-#include "Utils.h"
-
-#ifdef for
-#undef for
-#endif
-
-// +--------------------------------------------------------------------+
-
-static bool use_collision_detection = true;
-
-bool Solid::IsCollisionEnabled() { return use_collision_detection; }
-void Solid::EnableCollision(bool e) { use_collision_detection = e; }
-
-// +--------------------------------------------------------------------+
-
-Opcode::AABBTreeCollider opcode_collider;
-
-class OPCODE_data
-{
-public:
- OPCODE_data(Surface* s) {
- bool status = false;
-
- if (s) {
- using namespace Opcode;
- opcode_collider.SetFirstContact(true);
-
- npolys = s->NumPolys();
- nverts = s->NumVerts();
- ntris = s->NumIndices() / 3;
-
- locs = new IcePoint[nverts];
- tris = new IndexedTriangle[ntris];
-
- if (locs && tris) {
- int i, n = 0;
-
- for (i = 0; i < nverts; i++) {
- IcePoint* p = locs + i;
- Vec3* v = s->GetVertexSet()->loc + i;
-
- p->Set(v->x, v->y, v->z);
- }
-
- for (i = 0; i < npolys; i++) {
- Poly* p = s->GetPolys() + i;
-
- if (p->nverts == 3) {
- IndexedTriangle& t = tris[n++];
-
- t.mVRef[0] = p->verts[0];
- t.mVRef[1] = p->verts[2];
- t.mVRef[2] = p->verts[1];
- }
- else {
- IndexedTriangle& t1 = tris[n++];
- IndexedTriangle& t2 = tris[n++];
-
- t1.mVRef[0] = p->verts[0];
- t1.mVRef[1] = p->verts[2];
- t1.mVRef[2] = p->verts[1];
-
- t2.mVRef[0] = p->verts[0];
- t2.mVRef[1] = p->verts[3];
- t2.mVRef[2] = p->verts[2];
- }
- }
-
- mesh.SetNbVertices(nverts);
- mesh.SetNbTriangles(ntris);
- mesh.SetPointers(tris, locs);
-
- OPCODECREATE creator;
- creator.mIMesh = &mesh;
- status = model.Build(creator);
- }
- }
- else {
- tris = 0;
- locs = 0;
- npolys = 0;
- nverts = 0;
- ntris = 0;
- }
- }
-
- ~OPCODE_data() {
- delete [] tris;
- delete [] locs;
- }
-
- Opcode::Model model;
- Opcode::MeshInterface mesh;
- IndexedTriangle* tris;
- IcePoint* locs;
- int npolys;
- int nverts;
- int ntris;
-};
-
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-
-Solid::Solid()
- : model(0), own_model(1), roll(0.0f), pitch(0.0f), yaw(0.0f), intersection_poly(0)
-{
- shadow = true;
- sprintf_s(name, "Solid %d", id);
-}
-
-// +--------------------------------------------------------------------+
-
-Solid::~Solid()
-{
- if (own_model)
- delete model;
-
- shadows.destroy();
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Solid::Update()
-{
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Solid::SetOrientation(const Matrix& o)
-{
- orientation = o;
-}
-
-void
-Solid::SetLuminous(bool l)
-{
- luminous = l;
-
- if (model && luminous) {
- model->luminous = luminous;
-
- ListIter<Material> iter = model->GetMaterials();
-
- while (++iter) {
- Material* mtl = iter.value();
-
- mtl->Ka = Color::Black;
- mtl->Kd = Color::Black;
- mtl->Ks = Color::Black;
- mtl->Ke = Color::White;
-
- if (mtl->tex_diffuse && !mtl->tex_emissive)
- mtl->tex_emissive = mtl->tex_diffuse;
- }
-
- ListIter<Surface> s_iter = model->GetSurfaces();
- while (++s_iter) {
- Surface* surface = s_iter.value();
- VertexSet* vset = surface->GetVertexSet();
-
- for (int i = 0; i < vset->nverts; i++) {
- vset->diffuse[i] = Color::White.Value();
- vset->specular[i] = Color::Black.Value();
- }
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Solid::SetOrientation(const Solid& match)
-{
- if (!model || infinite)
- return;
-
- // copy the orientation matrix from the solid we are matching:
- orientation = match.Orientation();
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Solid::Render(Video* video, DWORD flags)
-{
- if (flags & RENDER_ADDITIVE)
- return;
-
- if (video && model && model->NumPolys()) {
- DWORD blend_modes = Video::BLEND_SOLID;
-
- if (flags == RENDER_ALPHA)
- blend_modes = Video::BLEND_ALPHA | Video::BLEND_ADDITIVE;
-
- video->DrawSolid(this, blend_modes);
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Solid::SelectDetail(Projector* p)
-{
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Solid::ProjectScreenRect(Projector* p)
-{
- if (model && p) {
- Point tmp = loc;
- p->Transform(tmp);
-
- if (tmp.z > 1) {
- int l = 2000;
- int r = -2000;
- int t = 2000;
- int b = -2000;
-
- for (int i = 0; i < 6; i++) {
- Point extent;
-
- if (i < 2)
- extent.x = model->extents[i];
-
- else if (i < 4)
- extent.y = model->extents[i];
-
- else
- extent.z = model->extents[i];
-
- extent = extent * orientation + loc;
-
- p->Transform(extent);
- p->Project(extent);
-
- if (extent.x < l) l = (int) extent.x;
- if (extent.x > r) r = (int) extent.x;
- if (extent.y < t) t = (int) extent.y;
- if (extent.y > b) b = (int) extent.y;
- }
-
- screen_rect.x = l;
- screen_rect.y = t;
- screen_rect.w = r-l;
- screen_rect.h = b-t;
- return;
- }
- }
-
- screen_rect.x = 2000;
- screen_rect.y = 2000;
- screen_rect.w = 0;
- screen_rect.h = 0;
-}
-
-// +--------------------------------------------------------------------+
-// Polygon Interference Detection:
-
-int
-Solid::CollidesWith(Graphic& o)
-{
- Vec3 delta_loc = Location() - o.Location();
-
- // bounding spheres test:
- if (delta_loc.length() > Radius() + o.Radius())
- return 0;
-
- // possible collision, but no further refinement can be done:
- if (!o.IsSolid())
- return 1;
-
- Solid& s = (Solid&) o;
-
- // use the OPCODE library to check for polygon interference:
- if (model && s.model) {
- using namespace Opcode;
-
- bool contact = false;
-
- // first, reverse the orientation matrices for OPCODE:
- Matrix m1 = orientation;
- Matrix m2 = s.orientation;
-
- Matrix4x4 world0;
- Matrix4x4 world1;
-
- world0.m[0][0] = (float) m1.elem[0][0];
- world0.m[0][1] = (float) m1.elem[0][1];
- world0.m[0][2] = (float) m1.elem[0][2];
- world0.m[0][3] = 0.0f;
-
- world0.m[1][0] = (float) m1.elem[1][0];
- world0.m[1][1] = (float) m1.elem[1][1];
- world0.m[1][2] = (float) m1.elem[1][2];
- world0.m[1][3] = 0.0f;
-
- world0.m[2][0] = (float) m1.elem[2][0];
- world0.m[2][1] = (float) m1.elem[2][1];
- world0.m[2][2] = (float) m1.elem[2][2];
- world0.m[2][3] = 0.0f;
-
- world0.m[3][0] = (float) Location().x;
- world0.m[3][1] = (float) Location().y;
- world0.m[3][2] = (float) Location().z;
- world0.m[3][3] = 1.0f;
-
- world1.m[0][0] = (float) m2.elem[0][0];
- world1.m[0][1] = (float) m2.elem[1][0];
- world1.m[0][2] = (float) m2.elem[2][0];
- world1.m[0][3] = 0.0f;
-
- world1.m[1][0] = (float) m2.elem[0][1];
- world1.m[1][1] = (float) m2.elem[1][1];
- world1.m[1][2] = (float) m2.elem[2][1];
- world1.m[1][3] = 0.0f;
-
- world1.m[2][0] = (float) m2.elem[0][2];
- world1.m[2][1] = (float) m2.elem[1][2];
- world1.m[2][2] = (float) m2.elem[2][2];
- world1.m[2][3] = 0.0f;
-
- world1.m[3][0] = (float) s.Location().x;
- world1.m[3][1] = (float) s.Location().y;
- world1.m[3][2] = (float) s.Location().z;
- world1.m[3][3] = 1.0f;
-
- ListIter<Surface> s1_iter = model->surfaces;
- while (++s1_iter && !contact) {
- Surface* s1 = s1_iter.value();
-
- ListIter<Surface> s2_iter = s.model->surfaces;
- while (++s2_iter && !contact) {
- Surface* s2 = s2_iter.value();
-
- if (s1->opcode && s2->opcode) {
- BVTCache bvt;
- bvt.Model0 = &s1->opcode->model;
- bvt.Model1 = &s2->opcode->model;
-
- if (opcode_collider.Collide(bvt, &world0, &world1))
- if (opcode_collider.GetContactStatus() != 0)
- contact = true;
- }
- }
- }
-
- return contact;
- }
-
-
- return 1;
-}
-
-// +--------------------------------------------------------------------+
-// Find the intersection of the ray (Q + w*len) with the solid.
-// If the ray intersects a polygon of the solid, place the intersection
-// point in ipt, and return 1. Otherwise, return 0.
-
-int
-Solid::CheckRayIntersection(Point Q, Point w, double len, Point& ipt,
-bool treat_translucent_polys_as_solid)
-{
- int impact = 0;
-
- if (!model || model->npolys < 1)
- return impact;
-
- // check right angle spherical distance:
- Point d0 = loc - Q;
- Point d1 = d0.cross(w);
- double dlen = d1.length(); // distance of point from line
-
- if (dlen > radius) // clean miss
- return 0; // (no impact)
-
- // possible collision course...
-
- /**********************************
-
-
- /--- + leading_edge = Q + w * len
- / / \
- delta2 / delta 0
- / / \
- / *........x <- solid location
- / /
- / / delta1
-/--- Q * = closest point
-
-
-************************************/
-
- // find the point on the ray that is closest
- // to the solid's location:
- Point closest = Q + w * (d0 * w);
-
- // find the leading edge, and it's distance from the location:
- Point leading_edge = Q + w*len;
- Point leading_delta = leading_edge - loc;
- double leading_dist = leading_delta.length();
-
- // if the leading edge is not within the bounding sphere,
- if (leading_dist > radius) {
- // check to see if the closest point is between the
- // ray's endpoints:
- Point delta1 = closest - Q;
- Point delta2 = leading_edge - Q; // this is w*len
-
- // if the closest point is not between the leading edge
- // and the origin, this ray does not intersect:
- if (delta1 * delta2 < 0 || delta1.length() > len) {
- return 0;
- }
- }
-
- // probable hit at this point...
-
- // if not active, that's good enough:
- if (GetScene() == 0) {
- ipt = closest;
- return 1;
- }
-
- // transform ray into object space:
- Matrix xform(Orientation());
-
- Vec3 tmp = w;
-
- w.x = tmp * Vec3(xform(0,0), xform(0,1), xform(0,2));
- w.y = tmp * Vec3(xform(1,0), xform(1,1), xform(1,2));
- w.z = tmp * Vec3(xform(2,0), xform(2,1), xform(2,2));
-
- tmp = Q-loc;
-
- Q.x = tmp * Vec3(xform(0,0), xform(0,1), xform(0,2));
- Q.y = tmp * Vec3(xform(1,0), xform(1,1), xform(1,2));
- Q.z = tmp * Vec3(xform(2,0), xform(2,1), xform(2,2));
-
- double min = len;
- intersection_poly = 0;
-
- // check each polygon:
- ListIter<Surface> iter = model->surfaces;
- while (++iter) {
- Surface* s = iter.value();
- Poly* p = s->GetPolys();
-
- for (int i = 0; i < s->NumPolys(); i++) {
- if (!treat_translucent_polys_as_solid && p->material && !p->material->IsSolid()) {
- p++;
- continue;
- }
-
- Point v = p->plane.normal;
- double d = p->plane.distance;
-
- double denom = w*v;
-
- if (denom < -1.0e-5) {
- Point P = v * d;
- double ilen = ((P-Q)*v)/denom;
-
- if (ilen > 0 && ilen < min) {
- Point intersect = Q + w * ilen;
-
- if (p->Contains(intersect)) {
- intersection_poly = p;
- ipt = intersect;
- min = ilen;
- impact = 1;
- }
- }
- }
-
- p++;
- }
- }
-
- // xform impact point back into world coordinates:
-
- if (impact) {
- ipt = (ipt * Orientation()) + loc;
- }
-
- return impact;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Solid::ClearModel()
-{
- if (own_model && model) {
- delete model;
- model = 0;
- }
-
- radius = 0.0f;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Solid::UseModel(Model* m)
-{
- // get rid of the existing model:
- ClearModel();
-
- // point to the new model:
- own_model = 0;
- model = m;
- radius = m->radius;
-}
-
-// +--------------------------------------------------------------------+
-
-bool
-Solid::Load(const char* mag_file, double scale)
-{
- // get ready to load, delete existing model:
- ClearModel();
-
- // loading our own copy, so we own the model:
- model = new Model;
- own_model = 1;
-
- // now load the model:
- if (model->Load(mag_file, scale)) {
- radius = model->radius;
- strncpy_s(name, model->name, sizeof(name));
- return true;
- }
-
- // load failed:
- ClearModel();
- return false;
-}
-
-bool
-Solid::Load(ModelFile* mod_file, double scale)
-{
- // get ready to load, delete existing model:
- ClearModel();
-
- // loading our own copy, so we own the model:
- model = new Model;
- own_model = 1;
-
- // now load the model:
- if (model->Load(mod_file, scale)) {
- radius = model->radius;
- return true;
- }
-
- // load failed:
- ClearModel();
- return false;
-}
-
-bool
-Solid::Rescale(double scale)
-{
- if (!own_model || !model)
- return false;
-
- radius = 0;
-
- ListIter<Surface> iter = model->GetSurfaces();
- while (++iter) {
- Surface* s = iter.value();
-
- for (int v = 0; v < s->NumVerts(); v++) {
- s->vertex_set->loc[v] *= (float) scale;
- s->vloc[v] *= (float) scale;
-
- float lvi = s->vloc[v].length();
- if (lvi > radius)
- radius = lvi;
- }
- }
-
- model->radius = radius;
-
- InvalidateSurfaceData();
-
- return true;
-}
-
-void
-Solid::CreateShadows(int nlights)
-{
- while (shadows.size() < nlights) {
- shadows.append(new Shadow(this));
- }
-}
-
-void
-Solid::UpdateShadows(List<Light>& lights)
-{
- List<Light> active_lights;
- ListIter<Light> iter = lights;
-
- while (++iter) {
- Light* light = iter.value();
-
- if (light->IsActive() && light->CastsShadow()) {
- double distance = Point(Location() - light->Location()).length();
- double intensity = light->Intensity();
-
- if (light->Type() == Light::LIGHT_POINT) {
- if (intensity / distance > 1)
- active_lights.append(light);
- }
-
- else if (light->Type() == Light::LIGHT_DIRECTIONAL) {
- if (intensity > 0.65)
- active_lights.insert(light);
- }
- }
- }
-
- iter.attach(active_lights);
-
- while (++iter) {
- Light* light = iter.value();
- int index = iter.index();
-
- if (index < shadows.size()) {
- shadows[index]->Update(light);
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Solid::DeletePrivateData()
-{
- if (model)
- model->DeletePrivateData();
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Solid::InvalidateSurfaceData()
-{
- if (!model)
- return;
-
- bool invalidate = model->IsDynamic();
-
- ListIter<Surface> iter = model->GetSurfaces();
- while (++iter) {
- Surface* s = iter.value();
- VideoPrivateData* vpd = s->GetVideoPrivateData();
-
- if (vpd) {
- if (invalidate) {
- vpd->Invalidate();
- }
- else {
- delete vpd;
- s->SetVideoPrivateData(0);
- }
- }
- }
-}
-
-void
-Solid::InvalidateSegmentData()
-{
- if (!model)
- return;
-
- bool invalidate = model->IsDynamic();
-
- ListIter<Surface> iter = model->GetSurfaces();
- while (++iter) {
- Surface* s = iter.value();
-
- ListIter<Segment> seg_iter = s->GetSegments();
- while (++seg_iter) {
- Segment* segment = seg_iter.value();
- VideoPrivateData* vpd = segment->GetVideoPrivateData();
-
- if (vpd) {
- if (invalidate) {
- vpd->Invalidate();
- }
- else {
- delete vpd;
- segment->SetVideoPrivateData(0);
- }
- }
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-bool
-Solid::IsDynamic() const
-{
- if (model)
- return model->IsDynamic();
-
- return false;
-}
-
-void
-Solid::SetDynamic(bool d)
-{
- if (model && own_model)
- model->SetDynamic(d);
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Solid::GetAllTextures(List<Bitmap>& textures)
-{
- if (model)
- model->GetAllTextures(textures);
-}
-
-void
-Model::GetAllTextures(List<Bitmap>& textures)
-{
- ListIter<Material> m_iter = materials;
- while (++m_iter) {
- Material* m = m_iter.value();
-
- if (m->tex_diffuse && !textures.contains(m->tex_diffuse))
- textures.append(m->tex_diffuse);
-
- if (m->tex_specular && !textures.contains(m->tex_specular))
- textures.append(m->tex_specular);
-
- if (m->tex_emissive && !textures.contains(m->tex_emissive))
- textures.append(m->tex_emissive);
-
- if (m->tex_bumpmap && !textures.contains(m->tex_bumpmap))
- textures.append(m->tex_bumpmap);
-
- if (m->tex_detail && !textures.contains(m->tex_detail))
- textures.append(m->tex_detail);
- }
-}
-
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-
-Model::Model()
- : nverts(0), npolys(0), radius(0), luminous(false), dynamic(false)
-{
- ZeroMemory(name, sizeof(name));
-}
-
-Model::Model(const Model& m)
- : nverts(0), npolys(0), radius(0), luminous(false), dynamic(false)
-{
- operator=(m);
-}
-
-// +--------------------------------------------------------------------+
-
-Model::~Model()
-{
- surfaces.destroy();
- materials.destroy();
-}
-
-Model&
-Model::operator = (const Model& m)
-{
- if (this != &m) {
- surfaces.destroy();
- materials.destroy();
-
- CopyMemory(name, m.name, Solid::NAMELEN);
-
- nverts = m.nverts;
- npolys = m.npolys;
- radius = m.radius;
- luminous = m.luminous;
- dynamic = m.dynamic;
-
- Model* pmod = (Model*) &m;
-
- ListIter<Material> m_iter = pmod->materials;
- while (++m_iter) {
- Material* matl1 = m_iter.value();
- Material* matl2 = new Material;
-
- CopyMemory(matl2, matl1, sizeof(Material));
- matl2->thumbnail = 0;
-
- materials.append(matl2);
- }
-
- ListIter<Surface> s_iter = pmod->surfaces;
- while (++s_iter) {
- Surface* surf1 = s_iter.value();
- Surface* surf2 = new Surface;
-
- surf2->Copy(*surf1, this);
- surfaces.append(surf2);
- }
- }
-
- return *this;
-}
-
-// +--------------------------------------------------------------------+
-
-int
-Model::NumSegments() const
-{
- int nsegments = 0;
-
- for (int i = 0; i < surfaces.size(); i++) {
- const Surface* s = surfaces[i];
- nsegments += s->NumSegments();
- }
-
- return nsegments;
-}
-
-// +--------------------------------------------------------------------+
-
-inline bool Collinear(const double* a, const double* b, const double* c)
-{
- Point ab(b[0]-a[0], b[1]-a[1], b[2]-a[2]);
- Point ac(c[0]-a[0], c[1]-a[1], c[2]-a[2]);
- Point cross = ab.cross(ac);
- return (cross.length() == 0);
-}
-
-struct HomogenousPlane
-{
- double distance;
- double normal_x;
- double normal_y;
- double normal_z;
- double normal_w;
-};
-
-static void LoadPlane(Plane& p, DataLoader* l, BYTE*& fp)
-{
- HomogenousPlane tmp;
- l->fread(&tmp, sizeof(HomogenousPlane), 1, fp);
-}
-
-static void LoadFlags(LPDWORD flags, DataLoader* l, BYTE*& fp)
-{
- DWORD magic_flags;
- l->fread(&magic_flags, sizeof(DWORD), 1, fp);
-
- /** OLD MAGIC FLAGS
-enum { FLAT_SHADED = 1,
- LUMINOUS = 2,
- TRANSLUCENT = 4, \\ must swap
- CHROMAKEY = 8, // these two
- FOREGROUND = 16, -- not used
- WIREFRAME = 32, -- not used
- SPECULAR1 = 64,
- SPECULAR2 = 128 };
-***/
-
- const DWORD magic_mask = 0x0fc3;
-
- *flags = magic_flags & magic_mask;
-}
-
-// +--------------------------------------------------------------------+
-
-bool
-Model::Load(const char* mag_file, double scale)
-{
- BYTE* block;
- DataLoader* loader = DataLoader::GetLoader();
- bool result = false;
-
- radius = 0.0f;
- extents[0] = 0.0f;
- extents[1] = 0.0f;
- extents[2] = 0.0f;
- extents[3] = 0.0f;
- extents[4] = 0.0f;
- extents[5] = 0.0f;
-
- if (!loader) {
- Print("MAG Open Failed: no data loader for file '%s'\n", mag_file);
- return result;
- }
-
- int size = loader->LoadBuffer(mag_file, block);
- BYTE* fp = block;
-
- // check MAG file:
- if (!size) {
- Print("MAG Open Failed: could not open file '%s'\n", mag_file);
- return result;
- }
-
- strncpy_s(name, mag_file, 31);
- name[31] = 0;
-
- char file_id[5];
- CopyMemory(file_id, block, 4);
- file_id[4] = '\0';
- int version = 1;
-
- if (!strcmp(file_id, "MAG6")) {
- version = 6;
- }
- else if (!strcmp(file_id, "MAG5")) {
- version = 5;
- }
- else if (!strcmp(file_id, "MAG4")) {
- version = 4;
- }
- else {
- Print("MAG Open Failed: File '%s' Invalid file type '%s'\n", mag_file, file_id);
- loader->ReleaseBuffer(block);
- return result;
- }
-
- // get ready to load, delete existing model:
- surfaces.destroy();
- materials.destroy();
- nverts = 0;
- npolys = 0;
-
- // now load the model:
- switch (version) {
- case 4:
- case 5:
- result = LoadMag5(block, size, scale);
- break;
-
- case 6:
- result = LoadMag6(block, size, scale);
- break;
-
- default:
- break;
- }
-
- loader->ReleaseBuffer(block);
- return result;
-}
-
-// +--------------------------------------------------------------------+
-
-bool
-Model::Load(ModelFile* mod_file, double scale)
-{
- if (mod_file) {
- return mod_file->Load(this, scale);
- }
-
- return false;
-}
-
-// +--------------------------------------------------------------------+
-
-static int mcomp(const void* a, const void* b)
-{
- Poly* pa = (Poly*) a;
- Poly* pb = (Poly*) b;
-
- if (pa->sortval == pb->sortval)
- return 0;
-
- if (pa->sortval < pb->sortval)
- return 1;
-
- return -1;
-}
-
-bool
-Model::LoadMag5(BYTE* block, int len, double scale)
-{
- bool result = false;
-
- DataLoader* loader = DataLoader::GetLoader();
- BYTE* fp = block + 4;
- int ntex = 0;
- int nsurfs = 0;
-
- loader->fread(&ntex, sizeof(ntex), 1, fp);
- loader->fread(&nsurfs, sizeof(nsurfs), 1, fp);
-
- // create a default gray material:
- Material* mtl = new Material;
-
- if (mtl) {
- mtl->Ka = Color::LightGray;
- mtl->Kd = Color::LightGray;
- mtl->Ks = ColorValue(0.2f,0.2f,0.2f);
- mtl->power = 20.0f;
-
- mtl->ambient_value = 1.0f;
- mtl->ambient_color = Color::LightGray;
- mtl->diffuse_value = 1.0f;
- mtl->diffuse_color = Color::LightGray;
- mtl->specular_value = 0.2f;
- mtl->specular_color = Color::White;
- strcpy_s(mtl->name, "(default)");
-
- materials.append(mtl);
- }
-
- // read texture list:
- for (int i = 0; i < ntex; i++) {
- mtl = new Material;
- char tname[32];
-
- if (mtl) {
- mtl->Ka = ColorValue(0.5f,0.5f,0.5f);
- mtl->Kd = ColorValue(1.0f,1.0f,1.0f);
- mtl->Ks = ColorValue(0.2f,0.2f,0.2f);
- mtl->power = 20.0f;
-
- mtl->ambient_value = 1.0f;
- mtl->ambient_color = Color::Gray;
- mtl->diffuse_value = 1.0f;
- mtl->diffuse_color = Color::White;
- mtl->specular_value = 0.2f;
- mtl->specular_color = Color::White;
-
- loader->fread(tname, 32, 1, fp);
- loader->LoadTexture(tname, mtl->tex_diffuse, Bitmap::BMP_SOLID, true);
- strcpy_s(mtl->name, tname);
-
- char* dot = strrchr(mtl->name, '.');
- if (dot)
- *dot = 0;
-
- char* plus = strrchr(mtl->name, '+');
- if (plus)
- *plus = 0;
-
- materials.append(mtl);
- }
- }
-
-
- loader->fread(&nverts, 4, 1, fp);
- loader->fread(&npolys, 4, 1, fp);
-
- // plan on creating four verts per poly:
- int mag_nverts = nverts;
- int next_vert = nverts;
-
- nverts = npolys * 4;
-
- Surface* s = new Surface;
- VertexSet* vset = 0;
-
- if (s) {
- strcpy_s(s->name, "default");
-
- s->model = this;
- s->vertex_set = new VertexSet(nverts);
- s->vloc = new Vec3[nverts];
-
- ZeroMemory(s->vertex_set->loc, nverts * sizeof(Vec3));
- ZeroMemory(s->vertex_set->diffuse, nverts * sizeof(DWORD));
- ZeroMemory(s->vertex_set->specular, nverts * sizeof(DWORD));
- ZeroMemory(s->vertex_set->tu, nverts * sizeof(float));
- ZeroMemory(s->vertex_set->tv, nverts * sizeof(float));
- ZeroMemory(s->vertex_set->rw, nverts * sizeof(float));
- ZeroMemory(s->vloc, nverts * sizeof(Vec3));
-
- s->npolys = npolys;
- s->polys = new Poly[npolys];
-
- ZeroMemory(s->polys, sizeof(Poly) * npolys);
- surfaces.append(s);
-
- vset = s->vertex_set;
-
- int v;
- // read vertex set:
- for (v = 0; v < mag_nverts; v++) {
- Vec3 vert, norm;
- DWORD vstate;
-
- loader->fread(&vert, sizeof(Vec3), 1, fp);
- loader->fread(&norm, sizeof(Vec3), 1, fp);
- loader->fread(&vstate, sizeof(DWORD), 1, fp);
-
- vert.SwapYZ();
- vert *= (float) scale;
-
- vset->loc[v] = vert;
- vset->nrm[v] = norm;
-
- double d = vert.length();
- if (d > radius)
- radius = (float) d;
-
- if (vert.x > extents[0]) extents[0] = vert.x;
- if (vert.x < extents[1]) extents[1] = vert.x;
- if (vert.y > extents[2]) extents[2] = vert.y;
- if (vert.y < extents[3]) extents[3] = vert.y;
- if (vert.z > extents[4]) extents[4] = vert.z;
- if (vert.z < extents[5]) extents[5] = vert.z;
- }
-
- while (v < nverts)
- vset->nrm[v++] = Vec3(1,0,0);
-
- // read polys:
- Vec3 dummy_center;
- DWORD dummy_flags;
- DWORD dummy_color;
- Plane dummy_plane;
- int texture_num;
- int poly_nverts;
- int vert_index_buffer[32];
- float texture_index_buffer[32];
-
- for (int n = 0; n < npolys; n++) {
- Poly& poly = s->polys[n];
- poly.vertex_set = vset;
-
- loader->fread(&dummy_flags, sizeof(DWORD), 1, fp);
- loader->fread(&dummy_center, sizeof(Vec3), 1, fp);
-
- LoadPlane(dummy_plane, loader, fp);
-
- loader->fread(&dummy_color, sizeof(DWORD), 1, fp);
- loader->fread(&texture_num, sizeof(int), 1, fp);
-
- if (texture_num >= 0 && texture_num < ntex) {
- int mtl_num = texture_num + 1;
- poly.material = materials[mtl_num];
- poly.sortval = texture_num;
-
- bool flag_translucent = (dummy_flags & 0x04) ? true : false;
- bool flag_transparent = (dummy_flags & 0x08) ? true : false;
-
- // luminous
- if (dummy_flags & 2) {
- mtl = materials[mtl_num];
-
- mtl->Ka = ColorValue(0,0,0,0);
- mtl->Kd = ColorValue(0,0,0,0);
- mtl->Ks = ColorValue(0,0,0,0);
- mtl->Ke = ColorValue(1,1,1,1);
-
- mtl->tex_emissive = mtl->tex_diffuse;
- }
-
- // glowing (additive)
- if (flag_translucent && flag_transparent)
- materials[mtl_num]->blend = Material::MTL_ADDITIVE;
-
- // translucent (alpha)
- else if (flag_translucent)
- materials[mtl_num]->blend = Material::MTL_TRANSLUCENT;
-
- // transparent (just use alpha for this)
- else if (flag_transparent)
- materials[mtl_num]->blend = Material::MTL_TRANSLUCENT;
- }
- else {
- poly.material = materials.first();
- poly.sortval = 1000;
- }
-
- // hack: store flat shaded flag in unused visible byte
- poly.visible = (BYTE) (dummy_flags & 1);
-
- loader->fread(&poly_nverts, sizeof(int), 1, fp);
- loader->fread(vert_index_buffer, sizeof(int), poly_nverts, fp);
-
- if (poly_nverts == 3)
- s->nindices += 3;
-
- else if (poly_nverts == 4)
- s->nindices += 6;
-
- poly.nverts = poly_nverts;
- for (int vi = 0; vi < poly_nverts; vi++) {
- v = vert_index_buffer[vi];
-
- if (vset->rw[v] > 0) {
- vset->CopyVertex(next_vert, v);
- v = next_vert++;
- }
-
- vset->rw[v] = 1;
- poly.verts[vi] = v;
- }
-
- loader->fread(texture_index_buffer, sizeof(float), poly_nverts, fp); // tu's
- for (int vi = 0; vi < poly_nverts; vi++) {
- v = poly.verts[vi];
- vset->tu[v] = texture_index_buffer[vi];
- }
-
- loader->fread(texture_index_buffer, sizeof(float), poly_nverts, fp); // tv's
- for (int vi = 0; vi < poly_nverts; vi++) {
- v = poly.verts[vi];
- vset->tv[v] = texture_index_buffer[vi];
- }
-
- fp += 16;
- }
-
- // pass 2 (adjust vertex normals for flat polys):
- for (int n = 0; n < npolys; n++) {
- Poly& poly = s->polys[n];
- poly.plane = Plane(vset->loc[poly.verts[0]],
- vset->loc[poly.verts[2]],
- vset->loc[poly.verts[1]]);
-
- // hack: retrieve flat shaded flag from unused visible byte
- if (poly.visible) {
- poly_nverts = poly.nverts;
-
- for (int vi = 0; vi < poly_nverts; vi++) {
- v = poly.verts[vi];
- vset->nrm[v] = poly.plane.normal;
- }
- }
- }
-
- // sort the polys by material index:
- qsort((void*) s->polys, s->npolys, sizeof(Poly), mcomp);
-
- // then assign them to cohesive segments:
- Segment* segment = 0;
-
- for (int n = 0; n < npolys; n++) {
- if (segment && segment->material == s->polys[n].material) {
- segment->npolys++;
- }
- else {
- segment = 0;
- }
-
- if (!segment) {
- segment = new Segment;
-
- segment->npolys = 1;
- segment->polys = &s->polys[n];
- segment->material = segment->polys->material;
- segment->model = this;
-
- s->segments.append(segment);
- }
- }
-
- s->BuildHull();
-
- result = nverts && npolys;
- }
-
- return result;
-}
-
-// +--------------------------------------------------------------------+
-
-struct MaterialMag6 {
- char name[Material::NAMELEN];
- char shader[Material::NAMELEN];
- float power; // highlight sharpness (big=shiny)
- float brilliance; // diffuse power function
- float bump; // bump level (0=none)
- DWORD blend; // alpha blend type
- bool shadow; // material casts shadow
- bool luminous; // verts have their own lighting
-
- Color ambient_color;
- Color diffuse_color;
- Color specular_color;
- Color emissive_color;
-
- float ambient_value;
- float diffuse_value;
- float specular_value;
- float emissive_value;
-
- BYTE tex_diffuse;
- BYTE tex_specular;
- BYTE tex_bumpmap;
- BYTE tex_emissive;
-};
-
-// +--------------------------------------------------------------------+
-
-bool
-Model::LoadMag6(BYTE* block, int len, double scale)
-{
- bool result = false;
-
- DataLoader* loader = DataLoader::GetLoader();
- BYTE* fp = block + 4;
- int ntex = 0;
- int nmtls = 0;
- int nsurfs = 0;
- List<Bitmap> textures;
-
- loader->fread(&ntex, sizeof(ntex), 1, fp); // size of texture block
- loader->fread(&nmtls, sizeof(nmtls), 1, fp); // number of materials
- loader->fread(&nsurfs, sizeof(nsurfs), 1, fp); // number of surfaces
-
- // read texture list:
- if (ntex) {
- char* buffer = new char[ntex];
- char* p = buffer;
- Bitmap* bmp = 0;
-
- loader->fread(buffer, ntex, 1, fp);
-
- while (p < buffer + ntex) {
- loader->LoadTexture(p, bmp, Bitmap::BMP_SOLID, true);
- textures.append(bmp);
-
- p += strlen(p) + 1;
- }
-
- delete [] buffer;
- }
-
- for (int i = 0; i < nmtls; i++) {
- MaterialMag6 m6;
- Material* mtl = new Material;
-
- loader->fread(&m6, sizeof(m6), 1, fp);
-
- if (mtl) {
- CopyMemory(mtl->name, m6.name, Material::NAMELEN);
- CopyMemory(mtl->shader, m6.shader, Material::NAMELEN);
-
- mtl->ambient_value = m6.ambient_value;
- mtl->ambient_color = m6.ambient_color;
- mtl->diffuse_value = m6.diffuse_value;
- mtl->diffuse_color = m6.diffuse_color;
- mtl->specular_value = m6.specular_value;
- mtl->specular_color = m6.specular_color;
- mtl->emissive_value = m6.emissive_value;
- mtl->emissive_color = m6.emissive_color;
-
- mtl->Ka = ColorValue(mtl->ambient_color) * mtl->ambient_value;
- mtl->Kd = ColorValue(mtl->diffuse_color) * mtl->diffuse_value;
- mtl->Ks = ColorValue(mtl->specular_color) * mtl->specular_value;
- mtl->Ke = ColorValue(mtl->emissive_color) * mtl->emissive_value;
-
- mtl->power = m6.power;
- mtl->brilliance = m6.brilliance;
- mtl->bump = m6.bump;
- mtl->blend = m6.blend;
- mtl->shadow = m6.shadow;
- mtl->luminous = m6.luminous;
-
- if (m6.tex_diffuse && m6.tex_diffuse <= textures.size())
- mtl->tex_diffuse = textures[m6.tex_diffuse - 1];
-
- if (m6.tex_specular && m6.tex_specular <= textures.size())
- mtl->tex_specular = textures[m6.tex_specular - 1];
-
- if (m6.tex_emissive && m6.tex_emissive <= textures.size())
- mtl->tex_emissive = textures[m6.tex_emissive - 1];
-
- if (m6.tex_bumpmap && m6.tex_bumpmap <= textures.size())
- mtl->tex_bumpmap = textures[m6.tex_bumpmap - 1];
-
- materials.append(mtl);
- }
- }
-
- for (int i = 0; i < nsurfs; i++) {
- int nverts = 0;
- int npolys = 0;
- BYTE namelen = 0;
- char name[128];
-
- loader->fread(&nverts, 4, 1, fp);
- loader->fread(&npolys, 4, 1, fp);
- loader->fread(&namelen, 1, 1, fp);
- loader->fread(name, 1, namelen, fp);
-
- Surface* surface = new Surface;
- surface->model = this;
- surface->SetName(name);
- surface->CreateVerts(nverts);
- surface->CreatePolys(npolys);
-
- VertexSet* vset = surface->GetVertexSet();
- Poly* polys = surface->GetPolys();
-
- ZeroMemory(polys, sizeof(Poly) * npolys);
-
- // read vertex set:
- for (int v = 0; v < nverts; v++) {
- loader->fread(&vset->loc[v], sizeof(float), 3, fp);
- loader->fread(&vset->nrm[v], sizeof(float), 3, fp);
- loader->fread(&vset->tu[v], sizeof(float), 1, fp);
- loader->fread(&vset->tv[v], sizeof(float), 1, fp);
-
- vset->loc[v] *= (float) scale;
-
- Vec3 vert = vset->loc[v];
-
- double d = vert.length();
- if (d > radius)
- radius = (float) d;
-
- if (vert.x > extents[0]) extents[0] = vert.x;
- if (vert.x < extents[1]) extents[1] = vert.x;
- if (vert.y > extents[2]) extents[2] = vert.y;
- if (vert.y < extents[3]) extents[3] = vert.y;
- if (vert.z > extents[4]) extents[4] = vert.z;
- if (vert.z < extents[5]) extents[5] = vert.z;
- }
-
- // read polys:
- for (int n = 0; n < npolys; n++) {
- Poly& poly = polys[n];
- BYTE poly_nverts = 0;
- BYTE material_index = 0;
- WORD poly_verts[8];
-
- loader->fread(&poly_nverts, sizeof(BYTE), 1, fp);
- loader->fread(&material_index, sizeof(BYTE), 1, fp);
- loader->fread(&poly_verts[0], sizeof(WORD), poly_nverts, fp);
-
- if (poly_nverts >= 3) {
- poly.nverts = poly_nverts;
-
- for (int i = 0; i < poly_nverts; i++) {
- poly.verts[i] = poly_verts[i];
- }
- }
- else {
- poly.sortval = 666;
- }
-
- if (material_index > 0) {
- poly.material = materials[material_index-1];
- poly.sortval = material_index;
- }
- else if (materials.size()) {
- poly.material = materials.first();
- poly.sortval = 1;
- }
- else {
- poly.sortval = 1000;
- }
-
- if (poly.nverts == 3)
- surface->AddIndices(3);
-
- else if (poly.nverts == 4)
- surface->AddIndices(6);
-
- poly.vertex_set = vset;
- poly.plane = Plane(vset->loc[poly.verts[0]],
- vset->loc[poly.verts[2]],
- vset->loc[poly.verts[1]]);
- }
-
- // sort the polys by material index:
- qsort((void*) polys, npolys, sizeof(Poly), mcomp);
-
- // then assign them to cohesive segments:
- Segment* segment = 0;
-
- for (int n = 0; n < npolys; n++) {
- if (segment && segment->material == polys[n].material) {
- segment->npolys++;
- }
- else {
- segment = 0;
- }
-
- if (!segment) {
- segment = new Segment;
-
- segment->npolys = 1;
- segment->polys = &polys[n];
- segment->material = segment->polys->material;
- segment->model = this;
-
- surface->GetSegments().append(segment);
- }
- }
-
- surface->BuildHull();
- surfaces.append(surface);
-
- this->nverts += nverts;
- this->npolys += npolys;
- }
-
-
- result = nverts && npolys;
- return result;
-}
-
-void
-Model::AddSurface(Surface* surface)
-{
- if (surface) {
- surface->model = this;
-
- ListIter<Segment> iter = surface->segments;
- while (++iter) {
- Segment* segment = iter.value();
- segment->model = this;
- }
-
- surface->BuildHull();
- surfaces.append(surface);
-
- nverts += surface->NumVerts();
- npolys += surface->NumPolys();
- }
-}
-
-
-// +--------------------------------------------------------------------+
-
-const Material*
-Model::FindMaterial(const char* mtl_name) const
-{
- if (mtl_name && *mtl_name) {
- Model* pThis = (Model*) this;
-
- ListIter<Material> iter = pThis->materials;
- while (++iter) {
- Material* mtl = iter.value();
-
- if (!strcmp(mtl->name, mtl_name))
- return mtl;
- }
- }
-
- return 0;
-}
-
-const Material*
-Model::ReplaceMaterial(const Material* mtl)
-{
- const Material* mtl_orig = 0;
-
- if (mtl) {
- mtl_orig = FindMaterial(mtl->name);
-
- if (mtl_orig) {
- int n = materials.index(mtl_orig);
- materials[n] = (Material*) mtl;
-
- ListIter<Surface> surf_iter = surfaces;
- while (++surf_iter) {
- Surface* surf = surf_iter.value();
-
- ListIter<Segment> seg_iter = surf->GetSegments();
- while (++seg_iter) {
- Segment* segment = seg_iter.value();
-
- if (segment->material == mtl_orig)
- segment->material = (Material*) mtl;
- }
- }
- }
- }
-
- return mtl_orig;
-}
-
-// +--------------------------------------------------------------------+
-
-Poly*
-Model::AddPolys(int nsurf, int np, int nv)
-{
- if (nsurf >= 0 && nsurf < surfaces.size())
- return surfaces[nsurf]->AddPolys(np, nv);
-
- ::Print("WARNING: AddPolys(%d,%d,%d) invalid surface\n", nsurf, np, nv);
- return 0;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Model::ExplodeMesh()
-{
- ListIter<Surface> iter = surfaces;
-
- int nv = 0;
- int np = 0;
-
- while (++iter) {
- Surface* s = iter.value();
- s->ExplodeMesh();
-
- nv += s->NumVerts();
- np += s->NumPolys();
- }
-
- nverts = nv;
- npolys = np;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Model::OptimizeMesh()
-{
- ListIter<Surface> iter = surfaces;
-
- int nv = 0;
- int np = 0;
-
- while (++iter) {
- Surface* s = iter.value();
- s->OptimizeMesh();
-
- nv += s->NumVerts();
- np += s->NumPolys();
- }
-
- nverts = nv;
- npolys = np;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Model::OptimizeMaterials()
-{
- for (int i = 0; i < materials.size(); i++) {
- Material* m1 = materials[i];
-
- for (int n = i; n < materials.size(); n++) {
- Material* m2 = materials[n];
-
- // if they match, merge them:
- if (*m1 == *m2) {
- List<Poly> polys;
- SelectPolys(polys, m2);
-
- ListIter<Poly> iter = polys;
- while (++iter) {
- Poly* p = iter.value();
- p->material = m1;
- }
-
- // and discard the duplicate:
- materials.remove(m2);
- delete m2;
- }
- }
- }
-}
-
-void
-Model::ScaleBy(double factor)
-{
- ListIter<Surface> iter = surfaces;
-
- while (++iter) {
- Surface* s = iter.value();
- s->ScaleBy(factor);
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Model::Normalize()
-{
- ListIter<Surface> iter = surfaces;
-
- while (++iter) {
- Surface* s = iter.value();
- s->Normalize();
- }
-}
-
-void
-Model::SelectPolys(List<Poly>& polys, Vec3 loc)
-{
- ListIter<Surface> iter = surfaces;
-
- while (++iter) {
- Surface* s = iter.value();
- s->SelectPolys(polys, loc);
- }
-}
-
-void
-Model::SelectPolys(List<Poly>& polys, Material* m)
-{
- ListIter<Surface> iter = surfaces;
-
- while (++iter) {
- Surface* s = iter.value();
- s->SelectPolys(polys, m);
- }
-}
-
-void
-Model::ComputeTangents()
-{
- ListIter<Surface> iter = surfaces;
-
- while (++iter) {
- Surface* s = iter.value();
- s->ComputeTangents();
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Model::DeletePrivateData()
-{
- ListIter<Surface> iter = surfaces;
- while (++iter) {
- Surface* s = iter.value();
- VideoPrivateData* vpd = s->GetVideoPrivateData();
-
- if (vpd) {
- delete vpd;
- s->SetVideoPrivateData(0);
- }
-
- ListIter<Segment> seg_iter = s->GetSegments();
- while (++seg_iter) {
- Segment* segment = seg_iter.value();
- VideoPrivateData* vpdp = segment->video_data;
-
- if (vpdp) {
- delete vpdp;
- segment->video_data = 0;
- }
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-
-Surface::Surface()
- : model(0), vertex_set(0), vloc(0), nhull(0), npolys(0), nindices(0),
- polys(0), state(0), video_data(0), opcode(0)
-{
- ZeroMemory(name, sizeof(name));
-}
-
-Surface::~Surface()
-{
- segments.destroy();
-
- delete opcode;
- delete vertex_set;
- delete [] vloc;
- delete [] polys;
- delete video_data;
-
- model = 0;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Surface::Copy(Surface& s, Model* m)
-{
- segments.destroy();
-
- delete opcode;
- delete vertex_set;
- delete [] vloc;
- delete [] polys;
- delete video_data;
-
- CopyMemory(name, s.name, Solid::NAMELEN);
-
- model = m;
- radius = s.radius;
- nhull = s.nhull;
- npolys = s.npolys;
- nindices = s.nindices;
- state = s.state;
- offset = s.offset;
- orientation = s.orientation;
- opcode = 0;
- video_data = 0;
-
- vertex_set = s.vertex_set->Clone();
-
- if (nhull > 0) {
- vloc = new Vec3[nhull];
- CopyMemory(vloc, s.vloc, nhull * sizeof(Vec3));
- }
- else {
- vloc = 0;
- }
-
- polys = new Poly[npolys];
- CopyMemory(polys, s.polys, npolys * sizeof(Poly));
-
- for (int i = 0; i < npolys; i++) {
- polys[i].vertex_set = vertex_set;
-
- if (s.polys[i].material)
- polys[i].material = (Material*) model->FindMaterial(s.polys[i].material->name);
- }
-
- ListIter<Segment> iter = s.segments;
- while (++iter) {
- Segment* seg1 = iter.value();
- Segment* seg2 = new Segment;
-
- seg2->npolys = seg1->npolys;
- seg2->polys = polys + (seg1->polys - s.polys);
-
- if (seg2->polys[0].material)
- seg2->material = seg2->polys[0].material;
-
- seg2->model = model;
- seg2->video_data = 0;
-
- segments.append(seg2);
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Surface::SetName(const char* n)
-{
- int len = sizeof(name);
-
- ZeroMemory(name, len);
- strncpy_s(name, n, len-1);
-}
-
-void
-Surface::SetHidden(bool b)
-{
- if (b)
- state = state | HIDDEN;
-
- else
- state = state & ~HIDDEN;
-}
-
-void
-Surface::SetLocked(bool b)
-{
- if (b)
- state = state | LOCKED;
-
- else
- state = state & ~LOCKED;
-}
-
-void
-Surface::SetSimplified(bool b)
-{
- if (b)
- state = state | SIMPLE;
-
- else
- state = state & ~SIMPLE;
-}
-
-void
-Surface::CreateVerts(int nverts)
-{
- if (!vertex_set && !vloc) {
- vertex_set = new VertexSet(nverts);
- vloc = new Vec3[nverts];
- }
-}
-
-void
-Surface::CreatePolys(int np)
-{
- if (!polys && !npolys) {
- npolys = np;
- polys = new Poly[npolys];
-
- ZeroMemory(polys, npolys * sizeof(Poly));
- }
-}
-
-// +--------------------------------------------------------------------+
-
-Poly*
-Surface::AddPolys(int np, int nv)
-{
- if ( polys && vertex_set &&
- np > 0 && np + npolys < MAX_POLYS &&
- nv > 0 && nv + vertex_set->nverts < MAX_VERTS)
- {
- int newverts = nv + vertex_set->nverts;
- int newpolys = np + npolys;
-
- vertex_set->Resize(newverts, true);
-
- Poly* pset = new Poly[newpolys];
- Poly* pnew = pset + npolys;
-
- CopyMemory(pset, polys, npolys * sizeof(Poly));
- ZeroMemory(pnew, np * sizeof(Poly));
-
- if (segments.size() > 0) {
- Segment* seg = segments.last();
- Material* mtl = seg->material;
-
- for (int i = 0; i < np; i++) {
- Poly* p = pnew + i;
- p->material = mtl;
- }
-
- seg->npolys += np;
- }
- }
-
- return 0;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Surface::ExplodeMesh()
-{
- if (!vertex_set || vertex_set->nverts < 3)
- return;
-
- int i, j, v;
- int nverts = 0;
-
- // count max verts:
- for (i = 0; i < npolys; i++) {
- Poly* p = polys + i;
- nverts += p->nverts;
- }
-
- // create target vertex set:
- VertexSet* vset = new VertexSet(nverts);
- v = 0;
-
- // explode verts:
- for (i = 0; i < npolys; i++) {
- Poly* p = polys + i;
- p->vertex_set = vset;
-
- for (j = 0; j < p->nverts; j++) {
- int vsrc = p->verts[j];
-
- vset->loc[v] = vertex_set->loc[vsrc];
- vset->nrm[v] = vertex_set->nrm[vsrc];
- vset->tu[v] = vertex_set->tu[vsrc];
- vset->tv[v] = vertex_set->tv[vsrc];
- vset->rw[v] = vertex_set->rw[vsrc];
- vset->diffuse[v] = vertex_set->diffuse[vsrc];
- vset->specular[v] = vertex_set->specular[vsrc];
-
- p->verts[j] = v++;
- }
- }
-
- // finalize:
- if (vset) {
- delete vertex_set;
- vertex_set = vset;
- }
-
- if (vloc)
- delete [] vloc;
-
- vloc = new Vec3[nverts];
-
- ComputeTangents();
- BuildHull();
-}
-
-// +--------------------------------------------------------------------+
-
-const double SELECT_EPSILON = 0.05;
-const double SELECT_TEXTURE = 0.0001;
-
-static bool MatchVerts(VertexSet* vset, int i, int j)
-{
- double d = 0;
- const Vec3& vl1 = vset->loc[i];
- const Vec3& vn1 = vset->nrm[i];
- float tu1 = vset->tu[i];
- float tv1 = vset->tv[i];
- const Vec3& vl2 = vset->loc[j];
- const Vec3& vn2 = vset->nrm[j];
- float tu2 = vset->tu[j];
- float tv2 = vset->tv[j];
-
- d = fabs(vl1.x - vl2.x);
- if (d > SELECT_EPSILON)
- return false;
-
- d = fabs(vl1.y - vl2.y);
- if (d > SELECT_EPSILON)
- return false;
-
- d = fabs(vl1.z - vl2.z);
- if (d > SELECT_EPSILON)
- return false;
-
- d = fabs(vn1.x - vn2.x);
- if (d > SELECT_EPSILON)
- return false;
-
- d = fabs(vn1.y - vn2.y);
- if (d > SELECT_EPSILON)
- return false;
-
- d = fabs(vn1.z - vn2.z);
- if (d > SELECT_EPSILON)
- return false;
-
- d = fabs(tu1 - tu2);
- if (d > SELECT_TEXTURE)
- return false;
-
- d = fabs(tv1 - tv2);
- if (d > SELECT_TEXTURE)
- return false;
-
- return true;
-}
-
-void
-Surface::OptimizeMesh()
-{
- if (!vertex_set || vertex_set->nverts < 3)
- return;
-
- int nverts = vertex_set->nverts;
- int used = 0;
- int final = 0;
- int nmatch = 0;
-
- // create vertex maps:
- BYTE* vert_map = new BYTE[nverts];
- WORD* vert_dst = new WORD[nverts];
- ZeroMemory(vert_map, nverts * sizeof(BYTE));
- ZeroMemory(vert_dst, nverts * sizeof(WORD));
-
- // count used verts:
- for (int i = 0; i < npolys; i++) {
- Poly* p = polys + i;
-
- for (int j = 0; j < p->nverts; j++) {
- WORD vert = p->verts[j];
-
- if (vert < nverts) {
- vert_map[vert]++;
- used++;
- }
- }
- }
-
- // create target vertex set:
- VertexSet* vset = new VertexSet(used);
- int v = 0;
-
- // compress verts:
- for (int i = 0; i < nverts; i++) {
- if (vert_map[i] == 0) continue;
-
- vert_dst[i] = v;
- vset->loc[v] = vertex_set->loc[i];
- vset->nrm[v] = vertex_set->nrm[i];
- vset->tu[v] = vertex_set->tu[i];
- vset->tv[v] = vertex_set->tv[i];
- vset->rw[v] = vertex_set->rw[i];
- vset->diffuse[v] = vertex_set->diffuse[i];
- vset->specular[v] = vertex_set->specular[i];
-
- for (int j = i+1; j < nverts; j++) {
- if (vert_map[j] == 0) continue;
-
- if (MatchVerts(vertex_set, i, j)) {
- vert_map[j] = 0;
- vert_dst[j] = v;
- nmatch++;
- }
- }
-
- v++;
- }
-
- final = v;
-
- // remap polys:
- for (int n = 0; n < npolys; n++) {
- Poly* p = polys + n;
- p->vertex_set = vset;
- for (int v = 0; v < p->nverts; v++) {
- p->verts[v] = vert_dst[ p->verts[v] ];
- }
- }
-
- // finalize:
- if (vset && final < nverts) {
- delete vertex_set;
- vertex_set = vset;
- vset->Resize(final, true);
- nverts = final;
- }
-
- // clean up and rebuild hull:
- delete [] vert_map;
-
- if (vloc)
- delete [] vloc;
-
- vloc = new Vec3[nverts];
-
- ComputeTangents();
- BuildHull();
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Surface::ScaleBy(double factor)
-{
- offset *= factor;
-
- if (vertex_set && vertex_set->nverts) {
- for (int i = 0; i < vertex_set->nverts; i++) {
- vertex_set->loc[i] *= (float) factor;
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Surface::BuildHull()
-{
- if (npolys < 1 || !vertex_set || vertex_set->nverts < 1)
- return;
-
- nhull = 0;
-
- for (int i = 0; i < npolys; i++) {
- Poly* p = polys + i;
-
- for (int n = 0; n < p->nverts; n++) {
- WORD v = p->verts[n];
- WORD h;
-
- for (h = 0; h < nhull; h++) {
- Vec3& vl = vertex_set->loc[v];
- Vec3& loc = vloc[h];
-
- double d = vl.x - loc.x;
-
- if (d < -SELECT_EPSILON || d > SELECT_EPSILON)
- continue;
-
- d = vl.y - loc.y;
-
- if (d < -SELECT_EPSILON || d > SELECT_EPSILON)
- continue;
-
- d = vl.z - loc.z;
-
- if (d < -SELECT_EPSILON || d > SELECT_EPSILON)
- continue;
-
- // found a match:
- break;
- }
-
- // didn't find a match:
- if (h >= nhull) {
- vloc[h] = vertex_set->loc[v];
- nhull = h+1;
- }
-
- p->vlocs[n] = h;
- }
- }
-
- if (use_collision_detection)
- InitializeCollisionHull();
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Surface::Normalize()
-{
- if (npolys < 1 || !vertex_set || vertex_set->nverts < 1)
- return;
-
- // STEP ONE: initialize poly planes
-
- for (int i = 0; i < npolys; i++) {
- Poly* p = polys + i;
-
- p->plane = Plane( vertex_set->loc[ p->verts[0] ],
- vertex_set->loc[ p->verts[2] ],
- vertex_set->loc[ p->verts[1] ] );
- }
-
- // STEP TWO: compute vertex normals by averaging adjecent poly planes
-
- List<Poly> faces;
- for (int v = 0; v < vertex_set->nverts; v++) {
- faces.clear();
- SelectPolys(faces, vertex_set->loc[v]);
-
- if (faces.size()) {
- vertex_set->nrm[v] = Vec3(0.0f, 0.0f, 0.0f);
-
- for (int i = 0; i < faces.size(); i++) {
- vertex_set->nrm[v] += faces[i]->plane.normal;
- }
-
- vertex_set->nrm[v].Normalize();
- }
-
- else if (vertex_set->loc[v].length() > 0) {
- vertex_set->nrm[v] = vertex_set->loc[v];
- vertex_set->nrm[v].Normalize();
- }
-
- else {
- vertex_set->nrm[v] = Vec3(0.0f, 1.0f, 0.0f);
- }
- }
-
- // STEP THREE: adjust vertex normals for poly flatness
-
- for (int i = 0; i < npolys; i++) {
- Poly* p = polys + i;
-
- for (int n = 0; n < p->nverts; n++) {
- int v = p->verts[n];
-
- vertex_set->nrm[v] = vertex_set->nrm[v] * (1.0f - p->flatness) +
- p->plane.normal * ( p->flatness);
- }
- }
-}
-
-void
-Surface::SelectPolys(List<Poly>& selection, Vec3 loc)
-{
- const double SELECT_EPSILON = 0.05;
-
- for (int i = 0; i < npolys; i++) {
- Poly* p = polys + i;
-
- for (int n = 0; n < p->nverts; n++) {
- int v = p->verts[n];
- Vec3& vl = vertex_set->loc[v];
- double d = vl.x - loc.x;
-
- if (d < -SELECT_EPSILON || d > SELECT_EPSILON)
- continue;
-
- d = vl.y - loc.y;
-
- if (d < -SELECT_EPSILON || d > SELECT_EPSILON)
- continue;
-
- d = vl.z - loc.z;
-
- if (d < -SELECT_EPSILON || d > SELECT_EPSILON)
- continue;
-
- selection.append(p);
- break;
- }
- }
-}
-
-void
-Surface::SelectPolys(List<Poly>& selection, Material* m)
-{
- for (int i = 0; i < npolys; i++) {
- Poly* p = polys + i;
-
- if (p->material == m)
- selection.append(p);
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Surface::ComputeTangents()
-{
- Vec3 tangent;
- Vec3 binormal;
-
- if (!vertex_set || !vertex_set->nverts)
- return;
-
- if (vertex_set->tangent)
- return;
-
- vertex_set->CreateTangents();
-
- for (int i = 0; i < npolys; i++) {
- Poly* p = polys + i;
-
- CalcGradients(*p, tangent, binormal);
-
- for (int n = 0; n < p->nverts; n++) {
- vertex_set->tangent[p->verts[n]] = tangent;
- vertex_set->binormal[p->verts[n]] = binormal;
- }
- }
-}
-
-void
-Surface::CalcGradients(Poly& p, Vec3& tangent, Vec3& binormal)
-{
- // using Eric Lengyel's approach with a few modifications
- // from Mathematics for 3D Game Programmming and Computer Graphics
- // want to be able to trasform a vector in Object Space to Tangent Space
- // such that the x-axis cooresponds to the 's' direction and the
- // y-axis corresponds to the 't' direction, and the z-axis corresponds
- // to <0,0,1>, straight up out of the texture map
-
- VertexSet* vset = p.vertex_set;
-
- Vec3 P = vset->loc[p.verts[1]] - vset->loc[p.verts[0]];
- Vec3 Q = vset->loc[p.verts[2]] - vset->loc[p.verts[0]];
-
- float s1 = vset->tu[p.verts[1]] - vset->tu[p.verts[0]];
- float t1 = vset->tv[p.verts[1]] - vset->tv[p.verts[0]];
- float s2 = vset->tu[p.verts[2]] - vset->tu[p.verts[0]];
- float t2 = vset->tv[p.verts[2]] - vset->tv[p.verts[0]];
-
- float tmp = 1.0f;
- float denom = s1*t2 - s2*t1;
-
- if (fabsf(denom) > 0.0001f)
- tmp = 1.0f/(denom);
-
- tangent.x = (t2*P.x - t1*Q.x) * tmp;
- tangent.y = (t2*P.y - t1*Q.y) * tmp;
- tangent.z = (t2*P.z - t1*Q.z) * tmp;
-
- tangent.Normalize();
-
- binormal.x = (s1*Q.x - s2*P.x) * tmp;
- binormal.y = (s1*Q.y - s2*P.y) * tmp;
- binormal.z = (s1*Q.z - s2*P.z) * tmp;
-
- binormal.Normalize();
-}
-
-void
-Surface::InitializeCollisionHull()
-{
- opcode = new OPCODE_data(this);
-}
-
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-
-Segment::Segment()
-{
- ZeroMemory(this, sizeof(Segment));
-}
-
-Segment::Segment(int n, Poly* p, Material* mtl, Model* mod)
- : npolys(n), polys(p), material(mtl), model(mod), video_data(0)
-{
-}
-
-Segment::~Segment()
-{
- delete video_data;
-
- ZeroMemory(this, sizeof(Segment));
-}
-
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-
-ModelFile::ModelFile(const char* fname)
- : model(0), pname(0), pnverts(0), pnpolys(0), pradius(0)
-{
- int len = sizeof(filename);
- ZeroMemory(filename, len);
- strncpy_s(filename, fname, len);
- filename[len-1] = 0;
-}
-
-ModelFile::~ModelFile()
-{
-}
-
-bool
-ModelFile::Load(Model* m, double scale)
-{
- model = m;
-
- // expose model innards for child classes:
-
- if (model) {
- pname = model->name;
- pnverts = &model->nverts;
- pnpolys = &model->npolys;
- pradius = &model->radius;
- }
-
- return false;
-}
-
-bool
-ModelFile::Save(Model* m)
-{
- model = m;
-
- // expose model innards for child classes:
-
- if (model) {
- pname = model->name;
- pnverts = &model->nverts;
- pnpolys = &model->npolys;
- pradius = &model->radius;
- }
-
- return false;
-}
-