From 2d77fb5fb3480f522658f30af6addd5146530517 Mon Sep 17 00:00:00 2001 From: Charles McGarvey Date: Tue, 8 Dec 2009 00:48:59 -0700 Subject: [PATCH] experimental shapes hierarchy and raycasting --- Makefile.am | 8 +- data/scenes/Classic.lua | 4 +- data/textures/BackgroundFar.png | Bin 12399 -> 7707 bytes data/textures/BackgroundNear.png | Bin 15736 -> 18076 bytes doc/yoink.6.in | 2 +- src/Character.cc | 18 +-- src/Character.hh | 2 +- src/GameLayer.cc | 53 ++++++++- src/GameLayer.hh | 11 ++ src/Hud.cc | 52 ++++----- src/MainLayer.cc | 6 +- src/Makefile.am | 8 +- src/Moof/Aabb.cc | 69 +----------- src/Moof/Aabb.hh | 101 ++++++++++++++--- src/Moof/Dispatch.cc | 2 - src/Moof/Dispatch.hh | 1 - src/Moof/Engine.cc | 2 + src/Moof/Entity.hh | 8 +- src/Moof/Frustum.cc | 4 +- src/Moof/Frustum.hh | 8 +- src/Moof/Line.hh | 131 ++++++++++++++++++++++ src/Moof/Math.hh | 21 +++- src/Moof/Octree.hh | 10 +- src/Moof/OpenGL.hh | 183 +++++++++++++------------------ src/Moof/Plane.cc | 4 +- src/Moof/Plane.hh | 48 ++++++-- src/Moof/Ray.hh | 89 +++++++++++++++ src/Moof/Shape.hh | 80 ++++++++++++++ src/Moof/Sphere.cc | 3 +- src/Moof/Sphere.hh | 120 ++++++++++++++++++-- src/Moof/Transition.hh | 10 +- src/Scene.cc | 18 ++- src/version.c | 40 +++++++ src/version.h | 4 + 34 files changed, 835 insertions(+), 285 deletions(-) create mode 100644 src/Moof/Line.hh create mode 100644 src/Moof/Ray.hh create mode 100644 src/Moof/Shape.hh create mode 100644 src/version.c diff --git a/Makefile.am b/Makefile.am index 009c2dc..bb29cd0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,7 +3,10 @@ ACLOCAL_AMFLAGS = -I m4 SUBDIRS = data doc src -EXTRA_DIST = extra +EXTRA_DIST = autogen.sh extra + + +.PHONY: run debug docs package run: all @cd src && $(MAKE) run @@ -11,9 +14,6 @@ run: all debug: all @cd src && $(MAKE) debug - -.PHONY: docs package - docs: $(DOXYGEN) diff --git a/data/scenes/Classic.lua b/data/scenes/Classic.lua index 963db84..68b7b66 100644 --- a/data/scenes/Classic.lua +++ b/data/scenes/Classic.lua @@ -751,8 +751,8 @@ DrawTilemap({ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ResetTransform() -Translate(-0.3, -0.17, -28) -Scale(100, 50, 1) +Translate(-0.32, -0.28, -24) +Scale(105, 52, 1) SetTexture("BackgroundFar") DrawTile() diff --git a/data/textures/BackgroundFar.png b/data/textures/BackgroundFar.png index 39c9c21b3c5f3b3db2767b61c45b4f814fe688a4..df103342ad4081078b8f0759ada535e19cb21d98 100644 GIT binary patch delta 6354 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 U|1twqg#Z8m07*qoM6N<$f_p9NMgRZ+ delta 11118 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 B87Tk& diff --git a/data/textures/BackgroundNear.png b/data/textures/BackgroundNear.png index 762f97d4c8bbe16a61a5ecadf10d91db2fe136f1..fd30b7f7a9ef352b9a9c0a1ad14bd1c72bba411e 100644 GIT binary patch delta 12528 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 JA#sP`{{qK(fs+6L delta 10170 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 k0uWJNL9W+AqOV^Mrg%S2Vw5xee@-T|Vu;tm& aabb) const { int octantNum = -1; diff --git a/src/Character.hh b/src/Character.hh index 28e588b..2173422 100644 --- a/src/Character.hh +++ b/src/Character.hh @@ -68,7 +68,7 @@ public: void addForce(Mf::Vector2 force); void setPosition(Mf::Vector2 position); - virtual int getOctant(const Mf::Aabb& aabb) const; + virtual int getOctant(const Mf::Aabb<3>& aabb) const; Tilemap tilemap; Animation animation; diff --git a/src/GameLayer.cc b/src/GameLayer.cc index f61ec3d..41000f3 100644 --- a/src/GameLayer.cc +++ b/src/GameLayer.cc @@ -121,6 +121,17 @@ GameLayer::GameLayer() : void GameLayer::pushed(Mf::Engine& engine) { engine.push(Hud::alloc(mState)); + + mRay.direction.set(1.0, 0.0); + + mLine.a.set(20, 10); + mLine.b.set(19, 14); + + mPlane.normal.set(-1.0, 0.0, 0.0); + mPlane.d = 0.0; + + mSphere.point.set(22, 5); + mSphere.radius = 2; } @@ -132,11 +143,37 @@ void GameLayer::update(Mf::Engine& engine, Mf::Scalar t, Mf::Scalar dt) mState.scene->checkForCollision(*mState.heroine); mState.camera.setPosition(Mf::Vector3(-mState.heroine->getState().position[0], - -mState.heroine->getState().position[1], -10)); + -mState.heroine->getState().position[1], -9)); //mState.camera.lookAt(Mf::promote(mState.heroine->getState().position)); //Mf::Vector3 heroinePosition = Mf::promote(mState.heroine->getState().position); //Mf::Sound::setListenerPosition(heroinePosition); + + mRay.point = mState.heroine->getState().position; + + Mf::Ray<2>::Intersection meh; + + Mf::Scalar d = mLine.intersectRay(mRay, meh); + if (d > 0.0) + { + Mf::logDebug("line: d = %f", d); + Mf::logDebug(" P = <%f,%f>", meh.point[0], meh.point[1]); + Mf::logDebug(" n = <%f,%f>", meh.normal[0], meh.normal[1]); + } + //d = mPlane.intersectRay(mRay, meh); + //if (d > 0.0) + //{ + //Mf::logDebug("plane: d = %f", d); + //Mf::logDebug(" P = <%f,%f>", meh.point[0], meh.point[1]); + //Mf::logDebug(" n = <%f,%f>", meh.normal[0], meh.normal[1]); + //} + d = mSphere.intersectRay(mRay, meh); + if (d > 0.0) + { + Mf::logDebug("sphere: d = %f", d); + Mf::logDebug(" P = <%f,%f>", meh.point[0], meh.point[1]); + Mf::logDebug(" n = <%f,%f>", meh.normal[0], meh.normal[1]); + } } @@ -154,6 +191,10 @@ void GameLayer::draw(Mf::Engine& engine, Mf::Scalar alpha) const mState.heroine->setZCoord(getZCoord(mState.heroine->getState().position)); mState.heroine->draw(alpha); + + mRay.draw(); + mLine.draw(); + mSphere.draw(); } bool GameLayer::handleEvent(Mf::Engine& engine, const Mf::Event& event) @@ -173,6 +214,16 @@ bool GameLayer::handleEvent(Mf::Engine& engine, const Mf::Event& event) mMusic.toggle(); return true; } + else if (event.key.keysym.sym == SDLK_PAGEUP) + { + mRay.direction = cml::rotate_vector_2D(mRay.direction, cml::rad(10.0)); + return true; + } + else if (event.key.keysym.sym == SDLK_PAGEDOWN) + { + mRay.direction = cml::rotate_vector_2D(mRay.direction, cml::rad(-10.0)); + return true; + } return mState.heroine->handleEvent(event); case SDL_KEYUP: diff --git a/src/GameLayer.hh b/src/GameLayer.hh index d75d9dc..f966c70 100644 --- a/src/GameLayer.hh +++ b/src/GameLayer.hh @@ -47,6 +47,11 @@ #include #include +#include +#include +#include +#include + #include "Character.hh" #include "Heroine.hh" #include "Scene.hh" @@ -58,6 +63,7 @@ typedef boost::shared_ptr GameLayerP; class GameLayer : public Mf::Layer { public: + GameLayer(); static GameLayerP alloc() @@ -99,6 +105,11 @@ private: State mState; Mf::Sound mMusic; Mf::Sound mPunchSound; + + Mf::Ray<2> mRay; + Mf::Line<2> mLine; + Mf::Plane mPlane; + Mf::Sphere<2> mSphere; }; diff --git a/src/Hud.cc b/src/Hud.cc index 90f5dd9..3a178f6 100644 --- a/src/Hud.cc +++ b/src/Hud.cc @@ -88,32 +88,32 @@ void ProgressBar::draw(Mf::Scalar alpha) const mTilemap.bind(); glBegin(GL_QUADS); - glTexCoord2(mTexCoords[0], mTexCoords[1]); - glVertex2v(mVertices[0].data()); - glTexCoord2(mMidCoords[0], mTexCoords[3]); - glVertex2v(mVertices[1].data()); - glTexCoord2(mMidCoords[0], mTexCoords[5]); - glVertex2v(mVertices[6].data()); - glTexCoord2(mTexCoords[6], mTexCoords[7]); - glVertex2v(mVertices[7].data()); - - glTexCoord2(mMidCoords[0], mTexCoords[1]); - glVertex2v(mVertices[1].data()); - glTexCoord2(mMidCoords[1], mTexCoords[3]); - glVertex2v(mVertices[2].data()); - glTexCoord2(mMidCoords[1], mTexCoords[5]); - glVertex2v(mVertices[5].data()); - glTexCoord2(mMidCoords[0], mTexCoords[7]); - glVertex2v(mVertices[6].data()); - - glTexCoord2(mMidCoords[1], mTexCoords[1]); - glVertex2v(mVertices[2].data()); - glTexCoord2(mTexCoords[2], mTexCoords[3]); - glVertex2v(mVertices[3].data()); - glTexCoord2(mTexCoords[4], mTexCoords[5]); - glVertex2v(mVertices[4].data()); - glTexCoord2(mMidCoords[1], mTexCoords[7]); - glVertex2v(mVertices[5].data()); + glTexCoord(mTexCoords[0], mTexCoords[1]); + glVertex(mVertices[0]); + glTexCoord(mMidCoords[0], mTexCoords[3]); + glVertex(mVertices[1]); + glTexCoord(mMidCoords[0], mTexCoords[5]); + glVertex(mVertices[6]); + glTexCoord(mTexCoords[6], mTexCoords[7]); + glVertex(mVertices[7]); + + glTexCoord(mMidCoords[0], mTexCoords[1]); + glVertex(mVertices[1]); + glTexCoord(mMidCoords[1], mTexCoords[3]); + glVertex(mVertices[2]); + glTexCoord(mMidCoords[1], mTexCoords[5]); + glVertex(mVertices[5]); + glTexCoord(mMidCoords[0], mTexCoords[7]); + glVertex(mVertices[6]); + + glTexCoord(mMidCoords[1], mTexCoords[1]); + glVertex(mVertices[2]); + glTexCoord(mTexCoords[2], mTexCoords[3]); + glVertex(mVertices[3]); + glTexCoord(mTexCoords[4], mTexCoords[5]); + glVertex(mVertices[4]); + glTexCoord(mMidCoords[1], mTexCoords[7]); + glVertex(mVertices[5]); glEnd(); } diff --git a/src/MainLayer.cc b/src/MainLayer.cc index 38c849e..faa4622 100644 --- a/src/MainLayer.cc +++ b/src/MainLayer.cc @@ -76,7 +76,7 @@ void MainLayer::update(Mf::Engine& engine, Mf::Scalar t, Mf::Scalar dt) if (engine.getSize() == 1) { // this is the only layer left on the stack - engine.push(TitleLayer::alloc()); + //engine.push(TitleLayer::alloc()); } } @@ -206,9 +206,7 @@ void printInfo(int argc, char* argv[]) std::cout << " Executable: " << argv[0] << std::endl << " Version: "VERSION << std::endl -#if defined(__DATE__) && defined(__TIME__) - << " Built: "__DATE__" "__TIME__ << std::endl -#endif + << " Built: " << COMPILE_TIME << std::endl << " Compiler: "COMPILER_STRING << std::endl << " Assets: " << assets << std::endl << "Build options: " diff --git a/src/Makefile.am b/src/Makefile.am index f100272..e2ea2fe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -34,6 +34,7 @@ libmoof_a_SOURCES = \ Moof/Interpolator.hh \ Moof/Layer.hh \ Moof/Library.hh \ + Moof/Line.hh \ Moof/Log.cc \ Moof/Log.hh \ Moof/Math.hh \ @@ -42,6 +43,7 @@ libmoof_a_SOURCES = \ Moof/OpenGL.hh \ Moof/Plane.cc \ Moof/Plane.hh \ + Moof/Ray.hh \ Moof/Rectangle.cc \ Moof/Rectangle.hh \ Moof/Resource.cc \ @@ -50,9 +52,9 @@ libmoof_a_SOURCES = \ Moof/Script.hh \ Moof/Settings.cc \ Moof/Settings.hh \ + Moof/Shape.hh \ Moof/Sound.cc \ Moof/Sound.hh \ - Moof/Sphere.cc \ Moof/Sphere.hh \ Moof/StringTools.cc \ Moof/StringTools.hh \ @@ -104,6 +106,7 @@ yoink_SOURCES = \ TitleLayer.hh \ Typesetter.cc \ Typesetter.hh \ + version.c \ version.h \ $(ENDLIST) @@ -125,3 +128,6 @@ run: all debug: all $(YOINK_ENVIRONMENT) gdb ./yoink +all-local: # always rebuild version.c + @touch version.c + diff --git a/src/Moof/Aabb.cc b/src/Moof/Aabb.cc index 17ce663..692ec36 100644 --- a/src/Moof/Aabb.cc +++ b/src/Moof/Aabb.cc @@ -35,6 +35,7 @@ namespace Mf { + /* void Aabb::getOctant(Aabb& octant, int num) const { Vector3 mid = getCenter(); @@ -80,75 +81,9 @@ void Aabb::getOctant(Aabb& octant, int num) const break; } } +*/ -void Aabb::getCorners(Vector3 corners[8]) const -{ - corners[0][0] = min[0]; corners[0][1] = min[1]; corners[0][2] = max[2]; - corners[1][0] = max[0]; corners[1][1] = min[1]; corners[1][2] = max[2]; - corners[2][0] = max[0]; corners[2][1] = max[1]; corners[2][2] = max[2]; - corners[3][0] = min[0]; corners[3][1] = max[1]; corners[3][2] = max[2]; - corners[4][0] = min[0]; corners[4][1] = min[1]; corners[4][2] = min[2]; - corners[5][0] = max[0]; corners[5][1] = min[1]; corners[5][2] = min[2]; - corners[6][0] = max[0]; corners[6][1] = max[1]; corners[6][2] = min[2]; - corners[7][0] = min[0]; corners[7][1] = max[1]; corners[7][2] = min[2]; -} - - -void Aabb::encloseVertices(const Vector3 vertices[], unsigned count) -{ - min = vertices[0]; - max = vertices[0]; - - for (unsigned i = 1; i < count; ++i) - { - if (vertices[i][0] < min[0]) min[0] = vertices[i][0]; - if (vertices[i][0] > max[0]) max[0] = vertices[i][0]; - if (vertices[i][1] < min[1]) min[1] = vertices[i][1]; - if (vertices[i][1] > max[1]) max[1] = vertices[i][1]; - if (vertices[i][2] < min[2]) min[2] = vertices[i][2]; - if (vertices[i][2] > max[2]) max[2] = vertices[i][2]; - } -} - - -void Aabb::draw(Scalar alpha) const -{ - Scalar vertices[] = {min[0], min[1], min[2], - min[0], max[1], min[2], - max[0], max[1], min[2], - max[0], min[1], min[2], - min[0], max[1], max[2], - min[0], min[1], max[2], - max[0], min[1], max[2], - max[0], max[1], max[2]}; - - GLubyte indices[] = {0, 1, 2, 3, - 1, 2, 7, 4, - 3, 0, 5, 6, - 2, 3, 6, 7, - 5, 0, 1, 4, - 4, 5, 6, 7}; - - glEnableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(3, GL_SCALAR, 0, vertices); - - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - Texture::resetBind(); - - glDrawElements(GL_QUADS, sizeof(indices), GL_UNSIGNED_BYTE, indices); - - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - //glDisableClientState(GL_VERTEX_ARRAY); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -} - -bool Aabb::isVisible(const Frustum& frustum) const -{ - return frustum.contains(*this); -} } // namespace Mf diff --git a/src/Moof/Aabb.hh b/src/Moof/Aabb.hh index 6a7e064..83926b3 100644 --- a/src/Moof/Aabb.hh +++ b/src/Moof/Aabb.hh @@ -33,6 +33,11 @@ #include #include #include +#include + +#include +#include +#include namespace Mf { @@ -42,14 +47,17 @@ namespace Mf { * Axis-aligned Bounding Box */ -struct Aabb : public Cullable, public Drawable +template +struct Aabb : public Cullable, public Drawable, public Shape { - Vector3 min; - Vector3 max; + typedef cml::vector< Scalar, cml::fixed > Vector; + + Vector min; + Vector max; Aabb() {} - Aabb(const Vector3& a, const Vector3& b) + Aabb(const Vector& a, const Vector& b) { init(a, b); } @@ -57,13 +65,13 @@ struct Aabb : public Cullable, public Drawable Aabb(Scalar ax, Scalar ay, Scalar az, Scalar bx, Scalar by, Scalar bz) { - Vector3 a(ax, ay, az); - Vector3 b(bx, by, bz); + Vector a(ax, ay, az); + Vector b(bx, by, bz); init(a, b); } - void init(const Vector3& a, const Vector3& b) + void init(const Vector& a, const Vector& b) { if (a[0] < b[0]) { @@ -97,19 +105,19 @@ struct Aabb : public Cullable, public Drawable } } - Vector3 getCenter() const + Vector getCenter() const { - return Vector3((min[0] + max[0]) / 2.0, + return Vector((min[0] + max[0]) / 2.0, (min[1] + max[1]) / 2.0, (min[2] + max[2]) / 2.0); } - void getOctant(Aabb& octant, int num) const; + //void getOctant(Aabb& octant, int num) const; Plane getPlaneXY() const { Plane plane; - plane.normal = Vector3(0.0, 0.0, 1.0); + plane.normal = Vector(0.0, 0.0, 1.0); plane.d = cml::dot(-plane.normal, getCenter()); return plane; } @@ -117,7 +125,7 @@ struct Aabb : public Cullable, public Drawable Plane getPlaneXZ() const { Plane plane; - plane.normal = Vector3(0.0, 1.0, 0.0); + plane.normal = Vector(0.0, 1.0, 0.0); plane.d = cml::dot(-plane.normal, getCenter()); return plane; } @@ -125,17 +133,84 @@ struct Aabb : public Cullable, public Drawable Plane getPlaneYZ() const { Plane plane; - plane.normal = Vector3(1.0, 0.0, 0.0); + plane.normal = Vector(1.0, 0.0, 0.0); plane.d = cml::dot(-plane.normal, getCenter()); return plane; } + /* void getCorners(Vector3 corners[8]) const; void encloseVertices(const Vector3 vertices[], unsigned count); void draw(Scalar alpha = 0.0) const; bool isVisible(const Frustum& frustum) const; + */ + + +void getCorners(Vector corners[8]) const +{ + corners[0][0] = min[0]; corners[0][1] = min[1]; corners[0][2] = max[2]; + corners[1][0] = max[0]; corners[1][1] = min[1]; corners[1][2] = max[2]; + corners[2][0] = max[0]; corners[2][1] = max[1]; corners[2][2] = max[2]; + corners[3][0] = min[0]; corners[3][1] = max[1]; corners[3][2] = max[2]; + corners[4][0] = min[0]; corners[4][1] = min[1]; corners[4][2] = min[2]; + corners[5][0] = max[0]; corners[5][1] = min[1]; corners[5][2] = min[2]; + corners[6][0] = max[0]; corners[6][1] = max[1]; corners[6][2] = min[2]; + corners[7][0] = min[0]; corners[7][1] = max[1]; corners[7][2] = min[2]; +} + + +void encloseVertices(const Vector vertices[], unsigned count) +{ + min.zero(); + max.zero(); + + for (unsigned i = 1; i < count; ++i) + { + min.minimize(vertices[i]); + max.maximize(vertices[i]); + } +} + + +void draw(Scalar alpha = 0.0) const +{ + Scalar vertices[] = {min[0], min[1], min[2], + min[0], max[1], min[2], + max[0], max[1], min[2], + max[0], min[1], min[2], + min[0], max[1], max[2], + min[0], min[1], max[2], + max[0], min[1], max[2], + max[0], max[1], max[2]}; + + GLubyte indices[] = {0, 1, 2, 3, + 1, 2, 7, 4, + 3, 0, 5, 6, + 2, 3, 6, 7, + 5, 0, 1, 4, + 4, 5, 6, 7}; + + glEnableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(3, GL_SCALAR, 0, vertices); + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + Texture::resetBind(); + + glDrawElements(GL_QUADS, sizeof(indices), GL_UNSIGNED_BYTE, indices); + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + //glDisableClientState(GL_VERTEX_ARRAY); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +} + +bool isVisible(const Frustum& frustum) const +{ + return frustum.contains(*this); +} }; diff --git a/src/Moof/Dispatch.cc b/src/Moof/Dispatch.cc index 17f8f17..8ad29fd 100644 --- a/src/Moof/Dispatch.cc +++ b/src/Moof/Dispatch.cc @@ -121,8 +121,6 @@ Dispatch::Handler::~Handler() Dispatch::Dispatch() : mImpl(new Dispatch::Impl) {} -Dispatch::~Dispatch() {} - Dispatch& Dispatch::getInstance() { diff --git a/src/Moof/Dispatch.hh b/src/Moof/Dispatch.hh index bbf37f3..4483f99 100644 --- a/src/Moof/Dispatch.hh +++ b/src/Moof/Dispatch.hh @@ -108,7 +108,6 @@ public: Dispatch(); - ~Dispatch(); // create and/or get a global instance static Dispatch& getInstance(); diff --git a/src/Moof/Engine.cc b/src/Moof/Engine.cc index 785cb4b..fca5e15 100644 --- a/src/Moof/Engine.cc +++ b/src/Moof/Engine.cc @@ -216,6 +216,8 @@ public: Timer::getNextFire()), Timer::ACTUAL); } while (!mStack.empty()); + + mDispatch.dispatch("engine.stopping"); } void dispatchEvents() diff --git a/src/Moof/Entity.hh b/src/Moof/Entity.hh index 52cb79d..ee0f860 100644 --- a/src/Moof/Entity.hh +++ b/src/Moof/Entity.hh @@ -55,8 +55,8 @@ class Entity : public Cullable, public Drawable { protected: - Aabb mAabb; - Sphere mSphere; + Aabb<3> mAabb; + Sphere<3> mSphere; public: @@ -72,12 +72,12 @@ public: return mSphere.isVisible(frustum) && mAabb.isVisible(frustum); } - const Aabb& getAabb() const + const Aabb<3>& getAabb() const { return mAabb; } - const Sphere& getSphere() const + const Sphere<3>& getSphere() const { return mSphere; } diff --git a/src/Moof/Frustum.cc b/src/Moof/Frustum.cc index 86e4d5b..1db6d25 100644 --- a/src/Moof/Frustum.cc +++ b/src/Moof/Frustum.cc @@ -60,7 +60,7 @@ void Frustum::init(const Matrix4& modelview, Scalar fovy, Scalar aspect, init(modelview, projection); } -Frustum::Collision Frustum::contains(const Aabb& aabb) const +Frustum::Collision Frustum::contains(const Aabb<3>& aabb) const { Vector3 corners[8]; int nTotalInside = 0; @@ -89,7 +89,7 @@ Frustum::Collision Frustum::contains(const Aabb& aabb) const } -Frustum::Collision Frustum::contains(const Sphere& sphere) const +Frustum::Collision Frustum::contains(const Sphere<3>& sphere) const { for (int i = 0; i < 6; ++i) { diff --git a/src/Moof/Frustum.hh b/src/Moof/Frustum.hh index c708c06..406e230 100644 --- a/src/Moof/Frustum.hh +++ b/src/Moof/Frustum.hh @@ -36,8 +36,8 @@ namespace Mf { -class Aabb; -class Sphere; +template class Aabb; +template class Sphere; class Frustum { @@ -66,8 +66,8 @@ public: void init(const Matrix4& modelview, Scalar fovy, Scalar aspect, Scalar abutting, Scalar distant); - Collision contains(const Aabb& aabb) const; - Collision contains(const Sphere& sphere) const; + Collision contains(const Aabb<3>& aabb) const; + Collision contains(const Sphere<3>& sphere) const; }; diff --git a/src/Moof/Line.hh b/src/Moof/Line.hh new file mode 100644 index 0000000..4a54e2d --- /dev/null +++ b/src/Moof/Line.hh @@ -0,0 +1,131 @@ + +/******************************************************************************* + + Copyright (c) 2009, Charles McGarvey + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef _MOOF_LINE_HH_ +#define _MOOF_LINE_HH_ + +#include +#include +#include +#include +#include + +#include + + +namespace Mf { + + +template +struct Line : public Drawable, public Shape +{ + typedef cml::vector< Scalar, cml::fixed > Vector; + + Vector a; + Vector b; + + Scalar intersectRay(const Ray<2>& ray, Ray<2>::Intersection& intersection) + { + // solve: Cx + r*Dx = Ax + s(Bx - Ax) + // Cy + r*Dy = Ay + s(By - Ay) + // where: 0 <= s <= 1 if intersection + // given: A = a + // B = b + // C = ray.point + // D = ray.direction + + Scalar denom = ray.direction[0] * (b[1] - a[1]) + + ray.direction[1] * (a[0] - b[0]); + + // check if the ray and line are parallel + if (isEqual(denom, SCALAR(0.0))) + { + Scalar numer = a[0] * (ray.point[1] - b[1]) + + b[0] * (a[1] - ray.point[1]) + + ray.point[0] * (b[1] - a[1]); + + // check if they are collinear + if (isEqual(numer, SCALAR(0.0))) + { + intersection.point = ray.point; + intersection.normal.set(0.0, 0.0); + return SCALAR(0.0); + } + + return SCALAR(-1.0); + } + + Scalar s = (ray.direction[0] * (ray.point[1] - a[1]) + + ray.direction[1] * (a[0] - ray.point[0])) / denom; + + // check if the ray hits the segment + if (s < SCALAR(0.0) || s > SCALAR(1.0)) return SCALAR(-1.0); + + Scalar r = -(a[0] * (ray.point[1] - b[1]) + + b[0] * (a[1] - ray.point[1]) + + ray.point[0] * (b[1] - a[1])) / denom; + + // make sure we're dealing with the right side of the ray + if (r < SCALAR(0.0)) return SCALAR(-1.0); + + intersection.point = ray.point + r * ray.direction; + + // gotta use the correct normal + Vector n = cml::perp(a - b); + if (cml::dot(a - ray.point, n) < 0) intersection.normal = n; + else intersection.normal = -n; + + return r; + } + + void draw(Scalar alpha = 0.0) const + { + Mf::Texture::resetBind(); + glBegin(GL_LINES); + glVertex(a); + glVertex(b); + glEnd(); + } +}; + + +template +struct Polygon : public Shape +{ + typedef cml::vector< Scalar, cml::fixed > Vector; + + Vector points[N]; +}; + + +} // namespace Mf + +#endif // _MOOF_LINE_HH_ + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ + diff --git a/src/Moof/Math.hh b/src/Moof/Math.hh index c63cfe7..ae747ec 100644 --- a/src/Moof/Math.hh +++ b/src/Moof/Math.hh @@ -37,7 +37,26 @@ #include #include -#include // GLscalar +#include + +#if HAVE_CONFIG_H +#include "config.h" +#endif + + +#if USE_DOUBLE_PRECISION + +typedef GLdouble GLscalar; +#define GL_SCALAR GL_DOUBLE +#define SCALAR(D) (D) + +#else + +typedef GLfloat GLscalar; +#define GL_SCALAR GL_FLOAT +#define SCALAR(F) (F##f) + +#endif namespace Mf { diff --git a/src/Moof/Octree.hh b/src/Moof/Octree.hh index ca464a5..13ece5b 100644 --- a/src/Moof/Octree.hh +++ b/src/Moof/Octree.hh @@ -52,7 +52,7 @@ struct OctreeInsertable { virtual ~OctreeInsertable() {} - virtual int getOctant(const Aabb& aabb) const = 0; + virtual int getOctant(const Aabb<3>& aabb) const = 0; }; @@ -65,7 +65,7 @@ class Octree : public Entity { std::list objects; - Node(const Aabb& aabb) + Node(const Aabb<3>& aabb) { mAabb = aabb; mSphere.point = mAabb.getCenter(); @@ -114,8 +114,8 @@ private: ASSERT(node.valid() && "invalid node passed"); ASSERT(entity && "null entity passed"); - Aabb entityAabb = entity->getAabb(); - Aabb nodeAabb = node->getAabb(); + Aabb<3> entityAabb = entity->getAabb(); + Aabb<3> nodeAabb = node->getAabb(); if (!(entityAabb.max[0] < nodeAabb.max[0] && entityAabb.min[0] > nodeAabb.min[0] && @@ -162,7 +162,7 @@ private: { ASSERT(node.valid() && "invalid node passed"); - Aabb octant; + Aabb<3> octant; for (int i = mTree.children(node); i <= index; ++i) { diff --git a/src/Moof/OpenGL.hh b/src/Moof/OpenGL.hh index e74f601..1e37b5e 100644 --- a/src/Moof/OpenGL.hh +++ b/src/Moof/OpenGL.hh @@ -31,126 +31,97 @@ #include +#include + #if HAVE_CONFIG_H #include "config.h" #endif +// generic function arguments + +#define ARGS_P const GLscalar* p +#define PASS_P p + +#define ARGS_M const Mf::Matrix4& m +#define PASS_M m.data() + +// ordinal function arguments + +#define ARGS_S2 GLscalar a, GLscalar b +#define PASS_S2 a, b +#define ARGS_S3 GLscalar a, GLscalar b, GLscalar c +#define PASS_S3 a, b, c +#define ARGS_S4 GLscalar a, GLscalar b, GLscalar c, GLscalar d +#define PASS_S4 a, b, c, d + +#define ARGS_P2 const Mf::Vector2& p +#define PASS_P2 p.data() +#define ARGS_P3 const Mf::Vector3& p +#define PASS_P3 p.data() +#define ARGS_P4 const Mf::Vector4& p +#define PASS_P4 p.data() + +#define ARGS_V2 const Mf::Vector2& v +#define PASS_V2 v[0], v[1] +#define ARGS_V3 const Mf::Vector3& v +#define PASS_V3 v[0], v[1], v[2] +#define ARGS_V4 const Mf::Vector4& v +#define PASS_V4 v[0], v[1], v[2], v[3] + + #if USE_DOUBLE_PRECISION -typedef GLdouble GLscalar; -#define GL_SCALAR GL_DOUBLE -#define SCALAR(D) (D) - -inline void glGetScalarv(GLenum a, GLscalar* b) -{ glGetDoublev(a, b); } - -inline void glLoadMatrix(const GLscalar* a) -{ glLoadMatrixd(a); } -inline void glMultMatrix(const GLscalar* a) -{ glMultMatrixd(a); } - -inline void glScale(GLscalar a, GLscalar b, GLscalar c) -{ glScaled(a, b, c); } -inline void glRotate(GLscalar a, GLscalar b, GLscalar c, GLscalar d) -{ glRotated(a, b, c, d); } -inline void glTranslate(GLscalar a, GLscalar b, GLscalar c) -{ glTranslated(a, b, c); } - -inline void glColor3(GLscalar a, GLscalar b, GLscalar c) -{ glColor3d(a, b, c); } -inline void glColor4(GLscalar a, GLscalar b, GLscalar c, GLscalar d) -{ glColor4d(a, b, c, d); } -inline void glColor3v(const GLscalar *a) -{ glColor3dv(a); } -inline void glColor4v(const GLscalar *a) -{ glColor4dv(a); } - -inline void glVertex2(GLscalar a, GLscalar b) -{ glVertex2d(a, b); } -inline void glVertex3(GLscalar a, GLscalar b, GLscalar c) -{ glVertex3d(a, b, c); } -inline void glVertex4(GLscalar a, GLscalar b, GLscalar c, GLscalar d) -{ glVertex4d(a, b, c, d); } -inline void glVertex2v(const GLscalar* a) -{ glVertex2dv(a); } -inline void glVertex3v(const GLscalar* a) -{ glVertex3dv(a); } -inline void glVertex4v(const GLscalar* a) -{ glVertex4dv(a); } - -inline void glTexCoord2(GLscalar a, GLscalar b) -{ glTexCoord2d(a, b); } -inline void glTexCoord3(GLscalar a, GLscalar b, GLscalar c) -{ glTexCoord3d(a, b, c); } -inline void glTexCoord4(GLscalar a, GLscalar b, GLscalar c, GLscalar d) -{ glTexCoord4d(a, b, c, d); } -inline void glTexCoord2v(const GLscalar* a) -{ glTexCoord2dv(a); } -inline void glTexCoord3v(const GLscalar* a) -{ glTexCoord3dv(a); } -inline void glTexCoord4v(const GLscalar* a) -{ glTexCoord4dv(a); } +#define OPENGL_GENERIC_FUNC(R, N, L) \ + inline R gl##N(ARGS_##L) { gl##N##d(PASS_##L); }// + +#define OPENGL_ORDINAL_FUNC(R, N, K) \ + inline R gl##N(ARGS_##S##K) { gl##N##K##d(PASS_##S##K); } \ + inline R gl##N(ARGS_##P##K) { gl##N##K##d##v(PASS_##P##K); }// #else -typedef GLfloat GLscalar; -#define GL_SCALAR GL_FLOAT -#define SCALAR(F) (F##f) - -inline void glGetScalarv(GLenum a, GLscalar* b) -{ glGetFloatv(a, b); } - -inline void glLoadMatrix(const GLscalar* a) -{ glLoadMatrixf(a); } -inline void glMultMatrix(const GLscalar* a) -{ glMultMatrixf(a); } - -inline void glScale(GLscalar a, GLscalar b, GLscalar c) -{ glScalef(a, b, c); } -inline void glRotate(GLscalar a, GLscalar b, GLscalar c, GLscalar d) -{ glRotatef(a, b, c, d); } -inline void glTranslate(GLscalar a, GLscalar b, GLscalar c) -{ glTranslatef(a, b, c); } - -inline void glColor3(GLscalar a, GLscalar b, GLscalar c) -{ glColor3f(a, b, c); } -inline void glColor4(GLscalar a, GLscalar b, GLscalar c, GLscalar d) -{ glColor4f(a, b, c, d); } -inline void glColor3v(const GLscalar *a) -{ glColor3fv(a); } -inline void glColor4v(const GLscalar *a) -{ glColor4fv(a); } - -inline void glVertex2(GLscalar a, GLscalar b) -{ glVertex2f(a, b); } -inline void glVertex3(GLscalar a, GLscalar b, GLscalar c) -{ glVertex3f(a, b, c); } -inline void glVertex4(GLscalar a, GLscalar b, GLscalar c, GLscalar d) -{ glVertex4f(a, b, c, d); } -inline void glVertex2v(const GLscalar* a) -{ glVertex2fv(a); } -inline void glVertex3v(const GLscalar* a) -{ glVertex3fv(a); } -inline void glVertex4v(const GLscalar* a) -{ glVertex4fv(a); } - -inline void glTexCoord2(GLscalar a, GLscalar b) -{ glTexCoord2f(a, b); } -inline void glTexCoord3(GLscalar a, GLscalar b, GLscalar c) -{ glTexCoord3f(a, b, c); } -inline void glTexCoord4(GLscalar a, GLscalar b, GLscalar c, GLscalar d) -{ glTexCoord4f(a, b, c, d); } -inline void glTexCoord2v(const GLscalar* a) -{ glTexCoord2fv(a); } -inline void glTexCoord3v(const GLscalar* a) -{ glTexCoord3fv(a); } -inline void glTexCoord4v(const GLscalar* a) -{ glTexCoord4fv(a); } +#define OPENGL_GENERIC_FUNC(R, N, L) \ + inline R gl##N(ARGS_##L) { gl##N##f(PASS_##L); }// + +#define OPENGL_ORDINAL_FUNC(R, N, K) \ + inline R gl##N(ARGS_##S##K) { gl##N##K##f(PASS_##S##K); } \ + inline R gl##N(ARGS_##P##K) { gl##N##K##f##v(PASS_##P##K); }// #endif +OPENGL_GENERIC_FUNC(void, LoadMatrix, P); +OPENGL_GENERIC_FUNC(void, LoadMatrix, M); +OPENGL_GENERIC_FUNC(void, MultMatrix, P); +OPENGL_GENERIC_FUNC(void, MultMatrix, M); + +OPENGL_GENERIC_FUNC(void, Scale, S3); +OPENGL_GENERIC_FUNC(void, Scale, V3); +OPENGL_GENERIC_FUNC(void, Rotate, S4); +OPENGL_GENERIC_FUNC(void, Rotate, V4); +OPENGL_GENERIC_FUNC(void, Translate, S3); +OPENGL_GENERIC_FUNC(void, Translate, V3); + +OPENGL_ORDINAL_FUNC(void, Color, 3); +OPENGL_ORDINAL_FUNC(void, Color, 4); + +OPENGL_ORDINAL_FUNC(void, Vertex, 2); +OPENGL_ORDINAL_FUNC(void, Vertex, 3); +OPENGL_ORDINAL_FUNC(void, Vertex, 4); + +OPENGL_ORDINAL_FUNC(void, TexCoord, 2); +OPENGL_ORDINAL_FUNC(void, TexCoord, 3); +OPENGL_ORDINAL_FUNC(void, TexCoord, 4); + + +#if USE_DOUBLE_PRECISION +inline void glGetScalar(GLenum a, GLscalar* b) { glGetDoublev(a, b); } +#else +inline void glGetScalar(GLenum a, GLscalar* b) { glGetFloatv(a, b); } +#endif + + #endif // _MOOF_OPENGL_HH_ /** vim: set ts=4 sw=4 tw=80: *************************************************/ diff --git a/src/Moof/Plane.cc b/src/Moof/Plane.cc index 5390934..71ea65e 100644 --- a/src/Moof/Plane.cc +++ b/src/Moof/Plane.cc @@ -34,7 +34,7 @@ namespace Mf { -Plane::Halfspace Plane::intersects(const Aabb& aabb) const +Plane::Halfspace Plane::intersects(const Aabb<3>& aabb) const { Vector3 corners[8]; int nPositive = 8; @@ -54,7 +54,7 @@ Plane::Halfspace Plane::intersects(const Aabb& aabb) const else return INTERSECT; } -Plane::Halfspace Plane::intersects(const Sphere& sphere) const +Plane::Halfspace Plane::intersects(const Sphere<3>& sphere) const { Scalar distance = getDistanceToPoint(sphere.point); diff --git a/src/Moof/Plane.hh b/src/Moof/Plane.hh index 06e4abd..5ec59ea 100644 --- a/src/Moof/Plane.hh +++ b/src/Moof/Plane.hh @@ -28,15 +28,16 @@ #ifndef _MOOF_PLANE_HH_ #define _MOOF_PLANE_HH_ - + #include +#include namespace Mf { -class Aabb; -class Sphere; +template class Aabb; +template class Sphere; /* @@ -44,7 +45,7 @@ class Sphere; * is normal to the plane. */ -struct Plane +struct Plane : public Shape<3> { Vector3 normal; Scalar d; @@ -65,8 +66,41 @@ struct Plane d(scalar) {} + Scalar intersectRay(const Ray<3>& ray, Ray<3>::Intersection& intersection) + { + // solve: [(ray.point + t*ray.direction) dot normal] + d = 0 + + Scalar denominator = cml::dot(ray.direction, normal); + + // check for parallel condition + if (denominator == SCALAR(0.0)) + { + if (isEqual(cml::dot(ray.point, normal), -d)) + { + // the ray lies on the plane + intersection.point = ray.point; + intersection.normal = normal; + return SCALAR(0.0); + } + + // no solution + return SCALAR(-1.0); + } + + Scalar t = (cml::dot(ray.point, normal) + d) / denominator; + if (t > SCALAR(0.0)) + { + ray.solve(intersection.point, t); + intersection.normal = normal; + } + + return t; + } + + /* Causes the normal of the plane to become normalized. The scalar may also - * be changed to keep the equation true. */ + * be changed to keep the equation true. Word to the wise: don't normalize + * a plane if the normal is the zero vector. */ void normalize() { Scalar mag = normal.length(); @@ -92,8 +126,8 @@ struct Plane else return POSITIVE; } - Halfspace intersects(const Aabb& aabb) const; - Halfspace intersects(const Sphere& sphere) const; + Halfspace intersects(const Aabb<3>& aabb) const; + Halfspace intersects(const Sphere<3>& sphere) const; }; diff --git a/src/Moof/Ray.hh b/src/Moof/Ray.hh new file mode 100644 index 0000000..15e1d9d --- /dev/null +++ b/src/Moof/Ray.hh @@ -0,0 +1,89 @@ + +/******************************************************************************* + + Copyright (c) 2009, Charles McGarvey + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef _MOOF_RAY_HH_ +#define _MOOF_RAY_HH_ + +#include +#include +#include +#include + + +namespace Mf { + + +/** + * A line that goes to infinity. + */ + +template +struct Ray : public Drawable +{ + typedef cml::vector< Scalar, cml::fixed > Vector; + + // solution = point + t*direction + Vector point; + Vector direction; + + struct Intersection + { + Vector point; // nearest point of intersection + Vector normal; // surface normal at intersection point + }; + + void solve(Vector& p, Scalar t) const + { + p = point + t*direction; + } + + void draw(Scalar alpha = 0.0) const + { + Vector end = point + 1000.0 * direction; + + Mf::Texture::resetBind(); + glBegin(GL_LINES); + glVertex(point); + glVertex(end); + glEnd(); + } + + void normalize() + { + direction.normalize(); + } + +}; + + +} // namespace Mf + +#endif // _MOOF_RAY_HH_ + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ + diff --git a/src/Moof/Shape.hh b/src/Moof/Shape.hh new file mode 100644 index 0000000..b78eaad --- /dev/null +++ b/src/Moof/Shape.hh @@ -0,0 +1,80 @@ + +/******************************************************************************* + + Copyright (c) 2009, Charles McGarvey + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef _MOOF_SHAPE_HH_ +#define _MOOF_SHAPE_HH_ + +#include +#include +#include +#include + + +// Frustum +// Plane (can construct from Triangle<3>) +// Ray +// Shape<> +// +- Line<> +// +- Ball<> +// | Circle <- Ball<2> +// | Sphere <- Ball<3> +// +- Box<> +// | Rectangle <- Box<2> +// | Aabb <- Box<3> +// +- Polygon<> +// | Triangle <- Polygon<3> +// +- Cylinder +// +- Cone + + +namespace Mf { + + +template +class Shape +{ + /** + * Checks if this shape is intersected by a given ray. If so, returns the + * distance from the start of the ray to the shape and information about the + * intersection via the 2nd parameter. A negative value is returned if + * there is no intersection. + */ + virtual Scalar intersectRay(const Ray& ray, + typename Ray::Intersection& intersection) + { + return SCALAR(-1.0); + } +}; + + +} // namespace Mf + +#endif // _MOOF_SHAPE_HH_ + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ + diff --git a/src/Moof/Sphere.cc b/src/Moof/Sphere.cc index 5e43e0d..aa2c139 100644 --- a/src/Moof/Sphere.cc +++ b/src/Moof/Sphere.cc @@ -46,7 +46,8 @@ void Sphere::draw(Scalar alpha) const glPushMatrix(); - glTranslate(point[0], point[1], point[2]); + //glTranslate(point[0], point[1], point[2]); + glTranslate(point); gluSphere(sphereObj, (GLdouble)radius, 16, 16); glPopMatrix(); diff --git a/src/Moof/Sphere.hh b/src/Moof/Sphere.hh index 319a3ae..f7b6a95 100644 --- a/src/Moof/Sphere.hh +++ b/src/Moof/Sphere.hh @@ -31,7 +31,10 @@ #include #include +#include #include +#include +#include namespace Mf { @@ -41,41 +44,134 @@ namespace Mf { * A round object. */ -struct Sphere : public Cullable, public Drawable +template +struct Sphere : public Cullable, public Drawable, public Shape { - Vector3 point; + typedef cml::vector< Scalar, cml::fixed > Vector; + + // (solution - point)^2 - radius^2 = 0 + Vector point; Scalar radius; Sphere() {} - Sphere(const Vector3& p, Scalar r) : + Sphere(const Vector& p, Scalar r) : point(p), radius(r) {} - Sphere(Scalar x, Scalar y, Scalar z, Scalar r) : - point(x, y, z), - radius(r) {} + //Sphere(Scalar x, Scalar y, Scalar z, Scalar r) : + //point(x, y, z), + //radius(r) {} - void init(const Vector3& p, Scalar r) + void init(const Vector& p, Scalar r) { point = p; radius = r; } - void init(const Vector3& p, const Vector3& o) + void init(const Vector& p, const Vector& o) { point = p; radius = (o - p).length(); } - void encloseVertices(const Vector3 vertices[], unsigned count); - void draw(Scalar alpha = 0.0) const; - bool isVisible(const Frustum& frustum) const; + // a ray inside the sphere will not intersect on its way out + Scalar intersectRay(const Ray& ray, + typename Ray::Intersection& intersection) + { + Vector b = point - ray.point; + Scalar z = cml::dot(b, ray.direction); + + // check if the ball is behind the ray + if (z < SCALAR(0.0)) return SCALAR(-1.0); + + Scalar d2 = cml::dot(b, b) - z*z; + Scalar r2 = radius * radius; + + // check for an intersection + if (d2 > r2) return SCALAR(-1.0); + + Scalar t = z - std::sqrt(r2 - d2); + ray.solve(intersection.point, t); + intersection.normal = intersection.point - point; + + return t; + } + + + //void encloseVertices(const Vector vertices[], unsigned count); + + //void draw(Scalar alpha = 0.0) const; + //bool isVisible(const Frustum& frustum) const; + +void encloseVertices(const Vector vertices[], unsigned count) +{ + // TODO +} + +void draw(Scalar alpha = 0.0) const; +//{ + //GLUquadricObj* sphereObj = gluNewQuadric(); + //gluQuadricDrawStyle(sphereObj, GLU_LINE); + + //glPushMatrix(); + + //glTranslate(point); + //gluSphere(sphereObj, GLdouble(radius), 16, 16); + + //glPopMatrix(); + + //gluDeleteQuadric(sphereObj); +//} + +bool isVisible(const Frustum& frustum) const +{ + return true; +} }; -inline bool checkCollision(const Sphere& a, const Sphere& b) +template <> +inline bool Sphere<3>::isVisible(const Frustum& frustum) const +{ + return frustum.contains(*this); +} + +template <> +inline void Sphere<2>::draw(Scalar alpha) const +{ + GLUquadricObj* sphereObj = gluNewQuadric(); + gluQuadricDrawStyle(sphereObj, GLU_LINE); + + glPushMatrix(); + + glTranslate(promote(point)); + gluSphere(sphereObj, GLdouble(radius), 16, 16); + + glPopMatrix(); + + gluDeleteQuadric(sphereObj); +} + +template <> +inline void Sphere<3>::draw(Scalar alpha) const +{ + GLUquadricObj* sphereObj = gluNewQuadric(); + gluQuadricDrawStyle(sphereObj, GLU_LINE); + + glPushMatrix(); + + glTranslate(point); + gluSphere(sphereObj, GLdouble(radius), 16, 16); + + glPopMatrix(); + + gluDeleteQuadric(sphereObj); +} + +template +inline bool checkCollision(const Sphere& a, const Sphere& b) { Scalar d = (a.point - b.point).length(); return d < (a.radius + b.radius); diff --git a/src/Moof/Transition.hh b/src/Moof/Transition.hh index ab09c02..310e8ea 100644 --- a/src/Moof/Transition.hh +++ b/src/Moof/Transition.hh @@ -97,15 +97,15 @@ public: glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); - glColor4(1.0, 1.0, 1.0, alpha); + glColor(1.0, 1.0, 1.0, alpha); Mf::Texture::resetBind(); //glRectf(-1.0f, -1.0f, 1.0f, 1.0f); glBegin(GL_QUADS); - glVertex3f(-1.0, -1.0, -0.1); - glVertex3f(1.0, -1.0, -0.1); - glVertex3f(1.0, 1.0, -0.1); - glVertex3f(-1.0, 1.0, -0.1); + glVertex(-1.0, -1.0, -0.1); + glVertex(1.0, -1.0, -0.1); + glVertex(1.0, 1.0, -0.1); + glVertex(-1.0, 1.0, -0.1); glEnd(); glDisable(GL_BLEND); diff --git a/src/Scene.cc b/src/Scene.cc index 9b4d1fd..452cc13 100644 --- a/src/Scene.cc +++ b/src/Scene.cc @@ -34,6 +34,7 @@ #include #include #include +#include #include #include //#include @@ -156,9 +157,10 @@ struct Scene::Impl : public Mf::Library std::string mTexture; //Mf::Octree::Ptr mOctree; - std::list< boost::shared_ptr > mObjects; + std::list< boost::shared_ptr > mObjects; + std::list< Mf::Line<2> > mLines; - Mf::Aabb mBounds; + Mf::Aabb<3> mBounds; enum AXIS @@ -219,7 +221,7 @@ struct Scene::Impl : public Mf::Library } - static int loadBox(Mf::Script& script, Mf::Aabb& aabb) + static int loadBox(Mf::Script& script, Mf::Aabb<3>& aabb) { Mf::Script::Value table[] = { @@ -413,6 +415,14 @@ struct Scene::Impl : public Mf::Library Quad* quad = new Quad(demotedVertices, mTexture, indices[h][w]); quad->setSurface(surface); + if (surface != Quad::NONE) + { + // need a 2d line for collisions + // assuming the camera always looks directly to -z when the + // scene is built, simply demoting the vector again should + // project the points to the xy-plane + } + boost::shared_ptr quadPtr(quad); //mOctree->insert(quadPtr); mObjects.push_back(quadPtr); @@ -545,7 +555,7 @@ bool Scene::checkForCollision(Character& character) std::list< boost::shared_ptr >::const_iterator it; int collisions = 0; - Mf::Sphere sphere = character.getSphere(); + Mf::Sphere<3> sphere = character.getSphere(); for (it = objects.begin(); it != objects.end(); ++it) { diff --git a/src/version.c b/src/version.c new file mode 100644 index 0000000..9e78b78 --- /dev/null +++ b/src/version.c @@ -0,0 +1,40 @@ + +/******************************************************************************* + + Copyright (c) 2009, Charles McGarvey + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "version.h" + + +#if defined(__DATE__) && defined(__TIME__) +const char* COMPILE_TIME = __DATE__" "__TIME__; +#else +const char* COMPILE_TIME = "Unknown"; +#endif + + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ + diff --git a/src/version.h b/src/version.h index 3ea5cf2..a6e48d5 100644 --- a/src/version.h +++ b/src/version.h @@ -30,6 +30,10 @@ #define _VERSION_H_ +// the time and date of the compilation +extern const char* COMPILE_TIME; + + // yoinked from fluxbox #ifdef __VERSION__ -- 2.45.2