diff --git a/src/aabb.h b/src/aabb.h index 0bdd8bd..292b57e 100644 --- a/src/aabb.h +++ b/src/aabb.h @@ -12,5 +12,16 @@ struct Aabb { if(min.y > p.y) min.y = p.y; if(min.z > p.z) min.z = p.z; } + template + bool IsIn(const vector3 p) const { + return ((p.x >= min.x) && (p.x <= max.x) && + (p.y >= min.y) && (p.y <= max.y) && + (p.z >= min.z) && (p.z <= max.z)); + } + bool Intersects(const Aabb& o) const { + return (min.x < o.max.x) && (max.x > o.min.x) && + (min.y < o.max.y) && (max.y > o.min.y) && + (min.z < o.max.z) && (max.z > o.min.z); + } }; diff --git a/src/collider/collision_space.cpp b/src/collider/collision_space.cpp index a23623b..7377489 100644 --- a/src/collider/collision_space.cpp +++ b/src/collider/collision_space.cpp @@ -28,17 +28,33 @@ void CollisionSpace::TraceRay(const vector3d& start, const vector3d& dir, isect_ } } -void CollisionSpace::CollideGeoms(Geom* a, Geom* b, void (*callback)(CollisionContact*)) { - a->Collide(b, callback); - b->Collide(a, callback); +void CollisionSpace::CollideGeoms(Geom* a, void (*callback)(CollisionContact*)) { + /* Our big Aabb. */ + vector3d pos = a->GetPosition(); + Aabb bigAabb; + bigAabb = a->GetGeomTree()->GetMaxAabb(); + bigAabb.min += pos; + bigAabb.max += pos; + + for(std::list::iterator i = m_geoms.begin(); i != m_geoms.end(); ++i) { + if((*i) != a) { + Aabb bigAabb2; + bigAabb2 = (*i)->GetGeomTree()->GetMaxAabb(); + vector3d pos2 = (*i)->GetPosition(); + bigAabb2.min += pos2; + bigAabb2.max += pos2; + if(bigAabb.Intersects(bigAabb2)) { + a->Collide(*i, callback); + if(!(*i)->HasMoved()) (*i)->Collide(a, callback); + } + } + } } void CollisionSpace::Collide(void (*callback)(CollisionContact*)) { /* For now, do a totally stupid intersection of every body on every other. */ for(std::list::iterator i = m_geoms.begin(); i != m_geoms.end(); ++i) { - for(std::list::iterator j = m_geoms.begin(); j != m_geoms.end(); ++j) { - if((*i) != (*j))CollideGeoms(*i, *j, callback); - } + if((*i)->HasMoved()) CollideGeoms(*i, callback); } } diff --git a/src/collider/collision_space.h b/src/collider/collision_space.h index 75b0075..33216db 100644 --- a/src/collider/collision_space.h +++ b/src/collider/collision_space.h @@ -14,7 +14,7 @@ public: void TraceRay(const vector3d& start, const vector3d& dir, isect_t* isect); void Collide(void (*callback)(CollisionContact*)); private: - void CollideGeoms(Geom* a, Geom* b, void (*callback)(CollisionContact*)); + void CollideGeoms(Geom* a, void (*callback)(CollisionContact*)); std::list m_geoms; }; diff --git a/src/collider/geom.cpp b/src/collider/geom.cpp index b6f8615..9a59778 100644 --- a/src/collider/geom.cpp +++ b/src/collider/geom.cpp @@ -10,6 +10,7 @@ Geom::Geom(GeomTree* geomtree) { m_invOrient = matrix4x4d::Identity(); m_orientIdx = 0; m_active = true; + m_moved = false; m_data = 0; } @@ -17,6 +18,7 @@ void Geom::MoveTo(const matrix4x4d& m) { m_orientIdx = !m_orientIdx; m_orient[m_orientIdx] = m; m_invOrient = m.InverseOf(); + m_moved = true; } void Geom::MoveTo(const matrix4x4d& m, const vector3d pos) { @@ -28,7 +30,14 @@ void Geom::MoveTo(const matrix4x4d& m, const vector3d pos) { m_invOrient = m_orient[m_orientIdx].InverseOf(); } +vector3d Geom::GetPosition(void) const { + return vector3d(m_orient[m_orientIdx][12], + m_orient[m_orientIdx][13], + m_orient[m_orientIdx][14]); +} + void Geom::Collide(Geom* b, void(*callback)(CollisionContact*)) { + m_moved = false; for(int i = 0; i < m_geomtree->m_numVertices; i++) { vector3d v(&m_geomtree->m_vertices[3*i]); vector3d from = m_orient[!m_orientIdx] * v; diff --git a/src/collider/geom.h b/src/collider/geom.h index 64b27d8..36b0767 100644 --- a/src/collider/geom.h +++ b/src/collider/geom.h @@ -13,9 +13,11 @@ public: void MoveTo(const matrix4x4d& m, const vector3d pos); const matrix4x4d& GetInvTransform(void) { return m_invOrient; } const matrix4x4d& GetTransform(void) { return m_orient[m_orientIdx]; } + vector3d GetPosition(void) const; void Enable(void) { m_active = true; } void Disable(void) {m_active = false; } bool IsEnabled(void) { return m_active; } + bool HasMoved(void) { return m_moved; } GeomTree* GetGeomTree(void) { return m_geomtree; } void Collide(Geom* b, void(*callback)(CollisionContact*)); void SetUserData(void* d) { m_data = d; } @@ -25,6 +27,7 @@ private: matrix4x4d m_orient[2], m_invOrient; int m_orientIdx; bool m_active; + bool m_moved; GeomTree* m_geomtree; void* m_data; }; diff --git a/src/collider/geom_tree.cpp b/src/collider/geom_tree.cpp index c0e7886..3350eb1 100644 --- a/src/collider/geom_tree.cpp +++ b/src/collider/geom_tree.cpp @@ -80,9 +80,11 @@ GeomTree::~GeomTree(void) { delete [] m_triAlloc; } -GeomTree::GeomTree(int numVerts, int numTris, float* vertices, int* indices) : m_numVertices(numVerts) { +GeomTree::GeomTree(int numVerts, int numTris, float* vertices, int* indices, + int* triflags) : m_numVertices(numVerts) { m_vertices = vertices; m_indices = indices; + m_triFlags = triflags; m_aabb.min = vector3d(FLT_MAX, FLT_MAX, FLT_MAX); m_aabb.max = vector3d(FLT_MAX, FLT_MAX, FLT_MAX); @@ -94,6 +96,15 @@ GeomTree::GeomTree(int numVerts, int numTris, float* vertices, int* indices) : m } m_triAlloc[numTris-1].next = 0; + /* Make big rotation aabb. */ + { + vector3d cent = 0.5*(m_aabb.min+m_aabb.max); + double mdim = (cent - m_aabb.min).Length(); + mdim = MAX(mdim,(m_aabb.max - cent).Length()); + m_maxAabb.min = vector3d(cent.x - mdim, cent.y - mdim, cent.z - mdim); + m_maxAabb.max = vector3d(cent.x + mdim, cent.y + mdim, cent.z + mdim); + } + printf("Building BIHTree of %d triangles\n", numTris); printf("Aabb: %f,%f,%f -> %f,%f,%f\n", m_aabb.min.x, @@ -102,6 +113,13 @@ GeomTree::GeomTree(int numVerts, int numTris, float* vertices, int* indices) : m m_aabb.max.x, m_aabb.max.y, m_aabb.max.z); + printf("MaxAabb: %f,%f,%f -> %f,%f,%f\n", + m_maxAabb.min.x, + m_maxAabb.min.y, + m_maxAabb.min.z, + m_maxAabb.max.x, + m_maxAabb.max.y, + m_maxAabb.max.z); m_nodes = new BIHNode[numTris*4]; m_nodesAllocSize = numTris*4; m_nodesAllocPos = 0; @@ -183,7 +201,6 @@ void GeomTree::BihTreeGhBuild(BIHNode* a_node, Aabb& a_box, Aabb& a_splitBox, in //if(axis != -1) printf("Best is axis %d on %s (cost %f%%)\n", axis, (isTop ? "top" : "botton"), bestCost*100); /* Cut off whitespace. */ if((bestCost > MIN_SPACE_CUTOFF) && (bestCost < 1.0f)) { - printf("Clicing off %f%%\n", bestCost*100); a_node->SetLeaf(false); a_node->SetAxis(axis); @@ -465,21 +482,22 @@ void GeomTree::RayTriIntersect(const vector3f& origin, const vector3f& dir, int const float v1d = vector3f::Dot(v1_cross,dir); const float v2d = vector3f::Dot(v2_cross,dir); - if((v0d > 0) && (v1d > 0) && (v2d > 0)) { + if(((v0d > 0) && (v1d > 0) && (v2d > 0)) || + ((v0d < 0) && (v1d < 0) && (v2d < 0))) { const vector3f n = vector3f::Cross(c-a, b-a); const float nominator = vector3f::Dot(n, (a-origin)); const float dist = nominator / vector3f::Dot(dir, n); if((dist > EPSILON) && (dist < isect->dist)) { isect->dist = dist; - isect->triIdx = triIdx; + isect->triIdx = triIdx/3; } } } vector3f GeomTree::GetTriNormal(int triIdx) const { - const vector3f a(&m_vertices[3*m_indices[triIdx]]); - const vector3f b(&m_vertices[3*m_indices[triIdx+1]]); - const vector3f c(&m_vertices[3*m_indices[triIdx+2]]); + const vector3f a(&m_vertices[3*m_indices[3*triIdx]]); + const vector3f b(&m_vertices[3*m_indices[3*triIdx+1]]); + const vector3f c(&m_vertices[3*m_indices[3*triIdx+2]]); return vector3f::Normalize(vector3f::Cross(b-a, c-a)); } diff --git a/src/collider/geom_tree.h b/src/collider/geom_tree.h index 8c87d6d..40ab24a 100644 --- a/src/collider/geom_tree.h +++ b/src/collider/geom_tree.h @@ -12,9 +12,10 @@ struct isect_t { class GeomTree { public: - GeomTree(int numVerts, int numTris, float* vertices, int* indices); + GeomTree(int numVerts, int numTris, float* vertices, int* indices, int* triflags); ~GeomTree(void); - Aabb GetAabb(void) { return m_aabb; } + const Aabb& GetAabb(void) { return m_aabb; } + const Aabb& GetMaxAabb(void) { return m_maxAabb; } /* * dir should be unit length, * isect.dist should be ray length. @@ -22,6 +23,7 @@ public: */ void TraceRay(const vector3f& start, const vector3f& dir, isect_t* isect); vector3f GetTriNormal(int triIdx) const; + int GetTriFlag(int triIdx) const { return m_triFlags[triIdx]; } const int m_numVertices; const float* m_vertices; @@ -34,6 +36,7 @@ private: void BihTreeGhBuild(BIHNode* a_node, Aabb& a_box, Aabb& a_splitBox, int a_depth, int a_prims); Aabb m_aabb; + Aabb m_maxAabb; /* An aabb that still contains the object regardless of rotation. */ BIHNode* m_nodes; int m_nodesAllocPos; int m_nodesAllocSize; @@ -42,5 +45,6 @@ private: int m_triAllocSize; const int* m_indices; + const int* m_triFlags; }; diff --git a/src/main.cpp b/src/main.cpp index a19497b..90880dc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -168,18 +168,17 @@ void L3D::HandleEvents(void) { #ifdef DEBUG if(event.key.keysym.sym == SDLK_F12) { /* Add test object. */ - Ship* body = new Ship(ShipType::LADYBIRD); + /*Ship* body = new Ship(ShipType::LADYBIRD); body->SetLabel("A friend"); body->SetFrame(L3D::player->GetFrame()); body->SetPosition(L3D::player->GetPosition()+vector3d(0,0,-1000)); - Space::AddBody(body); -#if 0 + Space::AddBody(body);*/ SpaceStation* station = new SpaceStation(SpaceStation::JJHOOP); station->SetLabel("Poemi-chan's Folly"); station->SetFrame(L3D::player->GetFrame()); - station->SetPosition(L3D::player->GetPosition()+vector3d(0,0,-1000)); + station->SetRotMatrix(matrix4x4d::RotateZMatrix(M_PI)); + station->SetPosition(L3D::player->GetPosition() + vector3d(0, 0, -5000)); Space::AddBody(station); -#endif } #endif if(event.key.keysym.sym == SDLK_F11) SDL_WM_ToggleFullScreen(L3D::scrSurface); @@ -394,12 +393,14 @@ void L3D::MainLoop(void) { time_before_frame = SDL_GetTicks(); /* Fixed 62.5hz physics. */ + int num_steps = 0; while(time_before_frame - last_phys_update > 16) { last_phys_update += 16; const float step = L3D::GetTimeStep(); if(step) Space::TimeStep(step); gameTime += step; phys_stat++; + if(++num_steps > 3) break; } currentView->Update(); diff --git a/src/model_body.cpp b/src/model_body.cpp index 9ee869e..75f01af 100644 --- a/src/model_body.cpp +++ b/src/model_body.cpp @@ -60,6 +60,7 @@ void ModelBody::SetModel(int sbreModel) { CollMeshSet* mset = GetModelCollMeshSet(sbreModel); m_geom = new Geom(mset->m_geomTree); + m_geom->SetUserData((void*)this); geomColl.resize(mset->numMeshParts); geoms.resize(mset->numMeshParts); @@ -77,6 +78,7 @@ void ModelBody::SetPosition(vector3d p) { matrix4x4d m; GetRotMatrix(m); m_geom->MoveTo(m, p); + m_geom->MoveTo(m, p); for(unsigned int i = 0; i < geoms.size(); i++) { dGeomSetPosition(geoms[i], p.x, p.y, p.z); @@ -120,6 +122,9 @@ void ModelBody::SetRotMatrix(const matrix4x4d& r) { for(unsigned int i = 0; i < geoms.size(); i++) { dGeomSetRotation(geoms[i], _m); } + vector3d pos = m_geom->GetPosition(); + m_geom->MoveTo(r, pos); + m_geom->MoveTo(r, pos); } void ModelBody::GetRotMatrix(matrix4x4d& m) const { @@ -172,7 +177,6 @@ void ModelBody::TriMeshUpdateLastPos(void) { matrix4x4d wtf; memcpy(&wtf[0], t, 16*sizeof(double)); m_geom->MoveTo(wtf); - m_geom->SetUserData(dGeomGetBody(geoms[0])); m_triMeshLastMatrixIndex = !m_triMeshLastMatrixIndex; for(unsigned int i = 0; i < geoms.size(); i++) { diff --git a/src/model_coll_mesh_data.cpp b/src/model_coll_mesh_data.cpp index e7c4b5e..5ee61b2 100644 --- a/src/model_coll_mesh_data.cpp +++ b/src/model_coll_mesh_data.cpp @@ -82,7 +82,8 @@ CollMeshSet::CollMeshSet(int sbreModel) { aabb.max[a] = sbreCollMesh->pVertex[i+a]; } } - m_geomTree = new GeomTree(sbreCollMesh->nv, sbreCollMesh->ni/3, sbreCollMesh->pVertex, sbreCollMesh->pIndex); + m_geomTree = new GeomTree(sbreCollMesh->nv, sbreCollMesh->ni/3, + sbreCollMesh->pVertex, sbreCollMesh->pIndex, sbreCollMesh->pFlag); triIndices = new coltri_t[sbreCollMesh->ni/3]; int tidx = 0; diff --git a/src/sbre_viewer.cpp b/src/sbre_viewer.cpp index 656c37e..783880f 100644 --- a/src/sbre_viewer.cpp +++ b/src/sbre_viewer.cpp @@ -159,6 +159,7 @@ static void render_coll_mesh(const CollMesh* m) { float foo[TEXSIZE][TEXSIZE]; float aspectRatio = 1.0; float camera_zoom = 1.0; +float distance = 100; static void raytraceCollMesh(vector3d camPos, vector3d camera_up, vector3d camera_forward, CollisionSpace* space) { memset(foo, 0, sizeof(float)*TEXSIZE*TEXSIZE); @@ -191,7 +192,7 @@ static void raytraceCollMesh(vector3d camPos, vector3d camera_up, vector3d camer space->TraceRay(camPos, toPoint, &isect); if(isect.triIdx != -1) { - foo[x][y] = 10.0/isect.dist; + foo[x][y] = distance/(10*isect.dist); } else { foo[x][y] = 0; } @@ -238,7 +239,6 @@ static void onCollision(CollisionContact* c) { void Viewer::MainLoop(void) { matrix4x4d rot = matrix4x4d::Identity(); - float distance = 100; Uint32 lastFoo = SDL_GetTicks(); CollMesh* cmesh = (CollMesh*)calloc(1, sizeof(CollMesh)); @@ -251,15 +251,16 @@ void Viewer::MainLoop(void) { } Uint32 t= SDL_GetTicks(); - GeomTree* geomtree = new GeomTree(cmesh->nv, cmesh->ni/3, cmesh->pVertex, cmesh->pIndex); + GeomTree* geomtree = new GeomTree(cmesh->nv, cmesh->ni/3, cmesh->pVertex, + cmesh->pIndex, cmesh->pFlag); printf("Geom tree build in $dms\n", SDL_GetTicks() -t); Geom* geom = new Geom(geomtree); - Geom* geom2 = new Geom(geomtree); + //Geom* geom2 = new Geom(geomtree); CollisionSpace* space = new CollisionSpace(); - space->AddGeom(geom2); + //space->AddGeom(geom2); space->AddGeom(geom); - geom2->MoveTo(rot, vector3d(80,0,0)); - geom2->MoveTo(rot, vector3d(80,0,0)); + //geom2->MoveTo(rot, vector3d(80,0,0)); + //geom2->MoveTo(rot, vector3d(80,0,0)); for(;;) { PollEvents(); diff --git a/src/space.cpp b/src/space.cpp index 6564098..2320ad1 100644 --- a/src/space.cpp +++ b/src/space.cpp @@ -324,6 +324,24 @@ static void dump_contact(const dContact* c) { printf("fdir1 %f,%f,%f\n", c->fdir1[0], c->fdir1[1], c->fdir1[2]); } +static bool _OnCollision2(Object* o1, Object* o2, CollisionContact* c) { + Body* pb1, *pb2; + int flags = c->g2->GetGeomTree()->GetTriFlag(c->triIdx); + //printf("Collision flags %x (triIdx %d)\n", flags, c->triIdx); + /* Geom bodies point to their parents. */ + if(o1->IsType(Object::GEOM)) { + pb1 = static_cast(o1)->parent; + flags |= static_cast(o1)->flags; + } else pb1 = static_cast(o1); + if(o2->IsType(Object::GEOM)) { + pb2 = static_cast(o2)->parent; + flags |= static_cast(o2)->flags; + } else pb2 = static_cast(o2); + + if((pb1 && !pb1->OnCollision(pb2, flags)) || (pb2 && !pb2->OnCollision(pb1, flags))) return false; + return true; +} + #define MAX_CONTACTS 10 static int contact_num; static void hitCallback(CollisionContact* c) {