diff --git a/CMakeLists.txt b/CMakeLists.txt index eeeb3ee..af00fd4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,11 +9,10 @@ IF (NOT OPENGL_FOUND) MESSAGE(FATAL_ERROR "Could not find OpenGL") ENDIF (NOT OPENGL_FOUND) -find_package(X11 REQUIRED) find_package(GLEW REQUIRED) find_package(GLPng REQUIRED) find_package(LibXml2 REQUIRED) -include_directories(${Boost_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR} ${GLEW_INCLUDE_DIR} ${GLPNG_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR} ${X11_X11_INCLUDE_PATH} ${X11_Xi_INCLUDE_PATH}) +include_directories(${Boost_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR} ${GLEW_INCLUDE_DIR} ${GLPNG_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR}) add_subdirectory(src) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d5fefb2..8718ba7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,4 +14,4 @@ add_executable(zoom TriangleRecord.h zoom.cpp ) -target_link_libraries(zoom ${Boost_LIBRARIES} ${OPENGL_gl_LIBRARY} ${GLEW_LIBRARY} ${GLPNG_LIBRARY} ${LIBXML2_LIBRARIES} ${X11_LIBRARIES} ${X11_Xi_LIB}) +target_link_libraries(zoom ${Boost_LIBRARIES} ${OPENGL_gl_LIBRARY} ${GLEW_LIBRARY} ${GLPNG_LIBRARY} ${LIBXML2_LIBRARIES}) diff --git a/src/Collision.cpp b/src/Collision.cpp index 81bc89d..7c72922 100644 --- a/src/Collision.cpp +++ b/src/Collision.cpp @@ -18,11 +18,36 @@ */ #include "Collision.h" -#include -#include namespace Zoom { +vmml::vec3f Collision::projectToEdge(const vmml::vec3f& p, const vmml::vec3f& v1, const vmml::vec3f& v2) { + vmml::vec3f pVec = p - v1; + vmml::vec3f edge = v2 - v1; + + float lengthSq = edge.squared_length(); + float edgeProj = vmml::dot(edge, pVec); + + if(edgeProj < 0) return v1; + if(edgeProj > lengthSq) return v2; + + return v1 + (edgeProj/lengthSq)*edge; +} + +vmml::vec3f Collision::projectToNearestEdge(const vmml::vec3f& p, const Triangle &t) { + vmml::vec3f p1 = projectToEdge(p, t.getVertex(0), t.getVertex(1)); + vmml::vec3f p2 = projectToEdge(p, t.getVertex(1), t.getVertex(2)); + vmml::vec3f p3 = projectToEdge(p, t.getVertex(2), t.getVertex(0)); + + if(p.squared_distance(p1) < p.squared_distance(p2) && p.squared_distance(p1) < p.squared_distance(p3)) + return p1; + else if(p.squared_distance(p2) < p.squared_distance(p3)) + return p2; + else + return p3; +} + + bool Collision::test(const Triangle &t, const MathUtil::Ray &ray, float *distance) { vmml::vec3f edge1 = t.getVertex(1) - t.getVertex(0); vmml::vec3f edge2 = t.getVertex(2) - t.getVertex(0); @@ -50,157 +75,23 @@ bool Collision::test(const Triangle &t, const MathUtil::Ray &ray, float *distanc return true; } -vmml::vec3f Collision::projectToEdge(const vmml::vec3f& p, const vmml::vec3f& v1, const vmml::vec3f& v2) { - vmml::vec3f pVec = p - v1; - vmml::vec3f edge = v2 - v1; - - float lengthSq = edge.squared_length(); - float edgeProj = vmml::dot(edge, pVec); - - if(edgeProj < 0) return v1; - if(edgeProj > lengthSq) return v2; - - return v1 + (edgeProj/lengthSq)*edge; -} - - -bool Collision::testEdge(const vmml::vec3f &v1, const vmml::vec3f &v2, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance) { - vmml::vec3f edge = v2 - v1; - - vmml::vec3f avec = vmml::dot(edge, move)*edge / edge.squared_length() - move; - vmml::vec3f cvec = v1 + vmml::dot(edge, m-v1)*edge / edge.squared_length() - m; - - float a = avec.squared_length(); - float b_2 = vmml::dot(avec, cvec); - float c = cvec.squared_length() - r*r; - - float rootSq = b_2*b_2 - a*c; - if(rootSq < 0) - return false; - - float minRoot = -a - b_2; - float maxRoot = a*MathUtil::EPSILON - b_2; - - if(minRoot < 0) - minRoot = 0; - if(maxRoot < 0) - return false; - - if(rootSq < minRoot*minRoot || rootSq >= maxRoot*maxRoot) - return false; - - minRoot = a*(edge.dot(m - v1) - edge.squared_length())/edge.dot(move) - b_2; - maxRoot = a*edge.dot(m - v1)/edge.dot(move) - b_2; - - if(minRoot < 0) - minRoot = 0; - if(maxRoot < 0) - return false; - - if(rootSq < minRoot*minRoot || rootSq > maxRoot*maxRoot) - return false; - - *distance = -(b_2 + std::sqrt(rootSq))/a; - - return true; -} - -bool Collision::testVertex(const vmml::vec3f &v, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance) { - float a = move.squared_length(); - float b_2 = vmml::dot(m-v, move); - float c = (m-v).squared_length() - r*r; - - float rootSq = b_2*b_2 - a*c; - if(rootSq < 0) - return false; - - float minRoot = -a - b_2; - float maxRoot = a*MathUtil::EPSILON - b_2; - - if(minRoot < 0) - minRoot = 0; - if(maxRoot < 0) - return false; - - if(rootSq <= minRoot*minRoot || rootSq >= maxRoot*maxRoot) - return false; - - *distance = -(b_2 + std::sqrt(rootSq))/a; - - return true; -} - -bool Collision::test(const Triangle &t, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance, vmml::vec3f *normal) { - if(move.squared_length() == 0) - return false; - - float d; - - vmml::vec3f triangleNormal = t.getNormal(); - if(test(t, MathUtil::Ray(m - r*triangleNormal, move), &d) && d > -MathUtil::EPSILON) { - if(d < 1) { - if(distance) - *distance = d; - if(normal) - *normal = triangleNormal; +bool Collision::test(const Triangle &t, const vmml::vec3f &m, float r, const vmml::vec3f &move) { + float distance; + if(test(t, MathUtil::Ray(m - r*t.computeNormal(), move), &distance) && distance > -MathUtil::EPSILON) { + if(distance < 1) return true; - } - else { + else return false; - } } - bool collision = false; - float minDistance; - - for(int i = 0; i < 3; ++i) { - if(testEdge(t.getVertex(i), t.getVertex((i+1)%3), m, r, move, &d)) { - if(!collision || d < minDistance) { - collision = true; - minDistance = d; - - if(normal) { - vmml::vec3f p = m + move*d; - - *normal = (p - projectToEdge(p, t.getVertex(i), t.getVertex((i+1)%3)))/r; - } - } - } - } - - if(collision) { - if(distance) - *distance = minDistance; + vmml::vec3f collisionPoint = projectToNearestEdge(m, t); + vmml::vec3f movedPoint = projectToEdge(m, collisionPoint, collisionPoint - move); + if(m.squared_distance(movedPoint) < r*r) return true; - } - - collision = false; - for(int i = 0; i < 3; ++i) { - if(testVertex(t.getVertex(i), m, r, move, &d)) { - if(!collision || d < minDistance) { - collision = true; - minDistance = d; - } - - if(normal) { - vmml::vec3f p = m + move*d; - - *normal = (p - t.getVertex(i))/r; - } - } - } - - if(collision) { - if(distance) - *distance = minDistance; - - return true; - } - else { + else return false; - } } } diff --git a/src/Collision.h b/src/Collision.h index 2688435..635a7d3 100644 --- a/src/Collision.h +++ b/src/Collision.h @@ -27,15 +27,13 @@ namespace Zoom { class Collision { public: static bool test(const Triangle &t, const MathUtil::Ray &ray, float *distance = 0); - static bool test(const Triangle &t, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance = 0, vmml::vec3f *normal = 0); + static bool test(const Triangle &t, const vmml::vec3f &m, float r, const vmml::vec3f &move); private: Collision(); static vmml::vec3f projectToEdge(const vmml::vec3f& p, const vmml::vec3f& v1, const vmml::vec3f& v2); - - static bool testEdge(const vmml::vec3f &v1, const vmml::vec3f &v2, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance); - static bool testVertex(const vmml::vec3f &v, const vmml::vec3f &m, float r, const vmml::vec3f &move, float *distance); + static vmml::vec3f projectToNearestEdge(const vmml::vec3f& p, const Triangle &t); }; } diff --git a/src/Game.cpp b/src/Game.cpp index d13a262..5b61da7 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -30,7 +30,7 @@ namespace Zoom { -const float Game::PLAYER_SPEED = 3; +const float Game::PLAYER_SPEED = 10; const float Game::PLAYER_RADIUS = 0.3; Game::Game() : playerPos(vmml::vec3f::ZERO), playerRotY(vmml::mat4f::IDENTITY), playerRotX(0), @@ -131,37 +131,36 @@ void Game::run(int delta) { vmml::vec3f origMove = playerMove; - bool collision = true; + bool ok = false; - while(collision) { - collision = false; + while(!ok) { + ok = true; - float nearestDistance; - vmml::vec3f nearestNormal; + MathUtil::Plane nearestPlane; for(std::vector::iterator t = triangles.begin(); t != triangles.end(); ++t) { - float distance; - vmml::vec3f normal; + if(Collision::test(t->getTriangle(), playerPos, PLAYER_RADIUS, playerMove)) { + vmml::vec3f normal = t->getTriangle().computeNormal(); + MathUtil::Plane p(normal, vmml::dot(normal, t->getTriangle().getVertex(0)+PLAYER_RADIUS*normal)); + if(p.isInFront(playerPos) || p.contains(playerPos)) { + if(ok || p.distance(playerPos) < nearestPlane.distance(playerPos)) { + ok = false; - if(Collision::test(t->getTriangle(), playerPos, PLAYER_RADIUS, playerMove, &distance, &normal)) { - normal.y() = 0; - - if(normal.dot(playerMove) >= 0) - continue; - - if(!collision || distance < nearestDistance) { - collision = true; - - nearestDistance = distance; - nearestNormal = normal; + nearestPlane = p; + } } } } - if(collision) { - vmml::vec3f move = playerMove*nearestDistance; + if(!ok) { + vmml::vec3f move; - if(move.dot(origMove) <= 0 && move.squared_length() > 0) { + if(playerMove.dot(nearestPlane.getNormal()) == 0) + move = playerMove; + else + move = nearestPlane.intersection(MathUtil::Ray(playerPos, playerMove)) - playerPos; + + if(move.dot(origMove) <= 0 && move.squared_length() > MathUtil::EPSILON) { return; } @@ -171,8 +170,7 @@ void Game::run(int delta) { playerPos += move; vmml::vec3f restMove = playerMove - move; - - playerMove = restMove - nearestNormal * (nearestNormal.dot(restMove)); + playerMove = restMove - nearestPlane.getNormal() * (nearestPlane.getNormal().dot(restMove)); } } diff --git a/src/Level.cpp b/src/Level.cpp index c6ba915..9b2aa78 100644 --- a/src/Level.cpp +++ b/src/Level.cpp @@ -172,13 +172,13 @@ TriangleRecord Level::loadWall(xmlNodePtr wallNode) { if(++vertexNum > 2) break; - wall.getTriangle().setVertex(vertexNum, loadVector(node), false); + wall.getTriangle().setVertex(vertexNum, loadVector(node)); } else if(!xmlStrcmp(node->name, (xmlChar*)"normal")) { if(vertexNum < 0) continue; - wall.getTriangle().setVertexNormal(vertexNum, loadVector(node)); + wall.getTriangle().setNormal(vertexNum, loadVector(node)); } else if(!xmlStrcmp(node->name, (xmlChar*)"texcoords")) { if(vertexNum < 0) continue; @@ -197,14 +197,18 @@ TriangleRecord Level::loadWall(xmlNodePtr wallNode) { } } - wall.getTriangle().updateNormal(); - vmml::vec3f normal = wall.getTriangle().getNormal(); + vmml::vec3f normal = wall.getTriangle().computeNormal(); - for(int i = 0; i < 3; ++i) { - if(wall.getTriangle().getVertexNormal(i).squared_length() == 0) - wall.getTriangle().setVertexNormal(i, normal); + if(normal.squared_length() > 0) { + normal.normalize(); + + for(int i = 0; i < 3; ++i) { + if(wall.getTriangle().getNormal(i).squared_length() == 0) + wall.getTriangle().setNormal(i, normal); + } } + return wall; } diff --git a/src/MathUtil.h b/src/MathUtil.h index 639336a..3f7ba90 100644 --- a/src/MathUtil.h +++ b/src/MathUtil.h @@ -51,7 +51,7 @@ class MathUtil { class Plane { public: Plane(const vmml::vec3f &n = vmml::vec3f::ZERO, float d0 = 0) : normal(n), d(d0) {} - Plane(const Triangle &t) : normal(t.getNormal()), d(t.getVertex(0).dot(normal)) {} + Plane(const Triangle &t) : normal(t.computeNormal()), d(t.getVertex(0).dot(normal)) {} bool contains(const vmml::vec3f &v) const { return (fabsf(normal.dot(v) - d) < EPSILON); diff --git a/src/Renderer.cpp b/src/Renderer.cpp index 512883d..5d86565 100644 --- a/src/Renderer.cpp +++ b/src/Renderer.cpp @@ -53,7 +53,7 @@ void Renderer::renderTriangle(const Triangle &t) { for(int i = 0; i < 3; ++i) { glTexCoord2fv(t.getTexCoords(i).array); - glNormal3fv(t.getVertexNormal(i).array); + glNormal3fv(t.getNormal(i).array); glVertex3fv(t.getVertex(i).array); } } diff --git a/src/Triangle.h b/src/Triangle.h index e13574c..2b34c3f 100644 --- a/src/Triangle.h +++ b/src/Triangle.h @@ -30,44 +30,30 @@ class Triangle { Triangle() : color(vmml::vec4f::ONE), texture(0) { vertices[0] = vertices[1] = vertices[2] = vmml::vec3f::ZERO; normals[0] = normals[1] = normals[2] = vmml::vec3f::ZERO; - normal = vmml::vec3f::ZERO; texcoords[0] = texcoords[1] = texcoords[2] = vmml::vec2f::ZERO; } - Triangle(const vmml::vec3f &v1, const vmml::vec3f &v2, const vmml::vec3f &v3, const vmml::vec4f &color0, bool update = true) : color(color0), texture(0) { + Triangle(const vmml::vec3f &v1, const vmml::vec3f &v2, const vmml::vec3f &v3, const vmml::vec4f &color0) : color(color0), texture(0) { vertices[0] = v1; vertices[1] = v2; vertices[2] = v3; normals[0] = normals[1] = normals[2] = vmml::vec3f::ZERO; texcoords[0] = texcoords[1] = texcoords[2] = vmml::vec2f::ZERO; - - if(update) - updateNormal(); - else - normal = vmml::vec3f::ZERO; } const vmml::vec3f& getVertex(int i) const {return vertices[i];} - void setVertex(int i, vmml::vec3f v, bool update = true) { + vmml::vec3f& getVertex(int i) {return vertices[i];} + void setVertex(int i, vmml::vec3f v) { vertices[i] = v; - - if(update) - updateNormal(); } - void updateNormal() { - normal = vertices[0].compute_normal(vertices[1], vertices[2]); - } - - const vmml::vec3f& getVertexNormal(int i) const {return normals[i];} - vmml::vec3f& getVertexNormal(int i) {return normals[i];} - void setVertexNormal(int i, vmml::vec3f n) { + const vmml::vec3f& getNormal(int i) const {return normals[i];} + vmml::vec3f& getNormal(int i) {return normals[i];} + void setNormal(int i, vmml::vec3f n) { normals[i] = n; } - const vmml::vec3f& getNormal() const {return normal;} - const vmml::vec2f& getTexCoords(int i) const {return texcoords[i];} vmml::vec2f& getTexCoords(int i) {return texcoords[i];} void setTexCoords(int i, vmml::vec2f t) { @@ -87,8 +73,12 @@ class Triangle { color = c; } + vmml::vec3f computeNormal() const { + return vertices[0].compute_normal(vertices[1], vertices[2]); + } + bool isDegenerate() const { - return (normal.squared_length() == 0); + return (computeNormal().squared_length() == 0); } void transform(const vmml::mat4f &matrix) { @@ -104,7 +94,6 @@ class Triangle { private: vmml::vec3f vertices[3]; vmml::vec3f normals[3]; - vmml::vec3f normal; vmml::vec2f texcoords[3]; vmml::vec4f color; unsigned texture; diff --git a/src/zoom.cpp b/src/zoom.cpp index 78e5389..aa085bf 100644 --- a/src/zoom.cpp +++ b/src/zoom.cpp @@ -26,7 +26,6 @@ #else #include #include -#include #include #include #include @@ -234,10 +233,6 @@ bool XIInit(Display *disp, int *opcode) { return true; } -static Bool WaitForMapNotify(Display*, XEvent *event, XPointer arg) { - return (event->type == MapNotify && event->xmap.window == (Window)arg); -} - bool GLXinit(Display *disp, Atom windele, Window *wnd, GLXContext *gc, int *xi_opcode, int *pointer) { static const int msAttributeList[] = {GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, @@ -310,9 +305,7 @@ bool GLXinit(Display *disp, Atom windele, Window *wnd, GLXContext *gc, int *xi_o XFreePixmap(disp, pixmap); XMapWindow(disp, *wnd); - - XEvent event; - XIfEvent(disp, &event, WaitForMapNotify, (XPointer)*wnd); + XSync(disp, False); XIGetClientPointer(disp, *wnd, pointer); @@ -391,7 +384,7 @@ int main() { break; case KeyPress: - switch(XkbKeycodeToKeysym(disp, event.xkey.keycode, 0, 0)) { + switch(XKeycodeToKeysym(disp, event.xkey.keycode, 0)) { case XK_Up: case XK_w: input |= Zoom::Game::FORWARD; break; case XK_Down: case XK_s: input |= Zoom::Game::BACKWARD; break; case XK_Left: case XK_a: input |= Zoom::Game::LEFT; break; @@ -401,7 +394,7 @@ int main() { break; case KeyRelease: - switch(XkbKeycodeToKeysym(disp, event.xkey.keycode, 0, 0)) { + switch(XKeycodeToKeysym(disp, event.xkey.keycode, 0)) { case XK_Up: case XK_w: input &= ~Zoom::Game::FORWARD; break; case XK_Down: case XK_s: input &= ~Zoom::Game::BACKWARD; break; case XK_Left: case XK_a: input &= ~Zoom::Game::LEFT; break;