From: Charles McGarvey Date: Sat, 17 Oct 2009 07:15:47 +0000 (-0600) Subject: fixed layer bugs; generalized octree X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=commitdiff_plain;h=a4debfe4a5f5d339410788971b698ba00cb7f09c fixed layer bugs; generalized octree --- diff --git a/configure.ac b/configure.ac index f7e75b0..245a183 100644 --- a/configure.ac +++ b/configure.ac @@ -94,6 +94,11 @@ AC_ARG_WITH([log-level], [log_level=$withval], [log_level=3]) +AC_ARG_ENABLE([double], + [ --enable-double use double-precision numbers], + [double=$enableval], + [double=no]) + if test x$developer = xyes then @@ -128,6 +133,13 @@ then CXXFLAGS="$CXXFLAGS -Wextra -Wno-unused-parameter" fi +if test x$double = xyes +then + AC_DEFINE([USE_DOUBLE_PRECISION], 1, + [Define to 1 if you want to use double-precison numbers.]) +fi + + AC_DEFINE_UNQUOTED([YOINK_LOGLEVEL], [$log_level], [Define to detail level of logging.]) diff --git a/data/yoinkrc b/data/yoinkrc index bcb0f06..86b333d 100644 --- a/data/yoinkrc +++ b/data/yoinkrc @@ -12,12 +12,12 @@ print "loading yoinkrc..." detail = 3 -- Set the amount of time in seconds between each update of the physics --- state. A value of 0.01 or lower is ideal for accurate physics --- approximations. Values that are much higher cause the CPU to do less +-- state. A value of 100 or higher is ideal for accurate physics +-- approximations. Values that are much lower cause the CPU to do less -- work, but accuracy will suffer. Errors could be introduced in the game --- with extremely high values. +-- with extremely low values. -timestep = 0.01 +timestep = 80 -- Set the maximum number of frames that can be drawn per second. A value -- of 50 is pretty good. If your computer is really old, you can get away @@ -30,7 +30,7 @@ timestep = 0.01 -- not be able to update the physics on schedule which could actually -- significantly lower the quality of the animation. -maxfps = 45 +maxfps = 40 -- Set whether or not to print the current actual framerate to the console. diff --git a/doc/yoink.6.in b/doc/yoink.6.in index 2432bd5..5742a5e 100644 --- a/doc/yoink.6.in +++ b/doc/yoink.6.in @@ -78,8 +78,8 @@ unlike that of other configuration files you are already familiar with. The syntax used is lua. .B yoink looks for configuration files and loads them in this order, the options from -each subsequent configuration files taking precedence over the same options from -previous files. +each subsequent configuration files taking precedence over the same options if +they exist in previous files. .TP 1. @DATADIR@/yoinkrc This is the base configuration file which should be considered read-only. Look @@ -96,8 +96,9 @@ This is an optional environment variable you can set to point to a configuration file. .PP Options that are passed as arguments take precedence over options loaded from -the configuration file(s). This mechanism is good for running the game with a -temporary setting which you do not intend to retain. Examples: +the configuration file(s). This mechanism can be used to play the game with +temporary settings which you do not intend to retain. Here are some examples of +passing options on the command-line: .PP .TP yoink fullscreen=true @@ -123,58 +124,60 @@ as the numbers 1024 and 768. The video size will be 1024x768. Here is a list of some of the options available: .TP .B detail -The level of detail. Possible values are high, medium, and low. This effects -the number of objects drawn to the screen. A high level of detail will draw -everything but could cause poor frame rates if the graphics driver can't keep up -with the load. Lower levels will omit certain details which aren't crucial for -playing the game with the benefit of higher frame rates. See the Notes for more -ways to get good performance. +The level of detail. Possible values are 1, 2, or 3, 1 meaning the least amount +of detail and 3 meaning the most. This effects the number of objects drawn to +the screen. A high level of detail will draw everything but could cause poor +frame rates if the graphics driver can't keep up with the load. Lower levels +will omit certain details which aren't crucial for playing the game with the +benefit of higher frame rates. See the Notes for more ways to increase the +game's performance. The default value is 3. .TP .B doublebuffer -If true, double-buffering will be used to render animations with minimal -distortions. Otherwise, a single buffer will be used. The recommended value is -true. +If true, double-buffering will be used to help minimize distortion and artifacts +caused by the animation of the game. Otherwise, a single buffer will be used. +The default value is true. .TP .B fullscreen If true, the window will capture the display and render the game in full screen -splendor. A value of false means the game will run in a window. +splendor. A value of false means the game will run in a window. The default +value is false. .TP .B maxfps -The maximum number of frames to be drawn per second. A value of 50 is pretty -good. If your computer is pretty old, can get away with decreasing this value -and still have reasonably smooth animation. You can set this to a very high -number to effectively render as many frames as is possible, but the actual rate -could be limited by vertical display synchronization, depending on the X11 -driver and settings used. You should not set this option higher than the point -where the vertical synchronization effectively limits the draw rate or else the -game may not be able to update the physics on schedule which could actually -significantly lower the quality of the animation. +The maximum number of frames to be drawn per second. If your computer is really +old, you can get away with decreasing this value and still have reasonably +smooth animation. You can set this to a very high number to effectively render +as many frames as is possible, but the actual rate could be limited by vertical +display synchronization, depending on the X11 driver and settings used. You +should not set this option higher than the point where the vertical +synchronization effectively limits the draw rate or else the game may not be +able to update the physics on schedule which could actually significantly lower +the quality of the animation. The default value is 40. .TP .B printfps -If true, the current number of frames being draw per second will be printed to -the console. This is usually off by default, but you can set this to true if -you're interested in the draw rate you're actually getting. +If true, the current number of frames being drawn per second will be printed to +the console. The default value is false. .TP .B resizable If true, the window will be resizable by the window manager. This option is -meaningless if the game is drawing to the full screen. +meaningless if the game is drawing to the full screen. The default option is +true. .TP .B showcursor This option effects the visibility of the cursor while it is "hovering" over the -window. If the value is true, the cursor will be visible. Otherwise, the -cursor will be hidden. +display. If the value is true, the cursor will be visible. Otherwise, the +cursor will be hidden. The default value is true. .TP .B timestep -The amount of time in seconds between each update of the physics state. A value -of 0.01 or lower is ideal for accurate physics approximations. Values that are -much higher cause the CPU to do less work, but accuracy will suffer. Errors -could be introduced in the game with extremely high values. +The number of times per second the simulation state will be updated. A value +of 100 or higher is ideal for a better physical simulation. Values that are +much lower cause the CPU to do less work, but accuracy will suffer. Errors +could be introduced in the game with extremely low values. The default value +is 80. .TP .B videomode The resolution or size of the window. The value is an array with three number elements representing the width, height, and bits per pixel that make up the -video mode. A typical value is {800,600} for a size of 800x600 pixels with -millions of colors (the third number is optional). +video mode. The third number is optional. The default value is {800, 600}. .PP This is only a list of the more useful options. You'll have to use the source to find out about the more esoteric options, but you probably won't need to. @@ -189,10 +192,7 @@ If set to a path of a valid directory (presumably a user's home directory), .B yoink will look for a file at .I $HOME/.yoinkrc -and load it as a configuration file. Saving options within the game will cause -this file to be over-written with the new options, unless the -.I YOINKRC -variable is set. +and load it as a configuration file. .TP USER .B yoink @@ -218,27 +218,34 @@ Yoink may or may not be playable with acceptable frame rates without a hardware accelerated OpenGL driver installed and working, depending on how fast your CPU is. Yoink is really not all that heavy on graphics, but it doesn't take much to overload a software implementation. If you're stuck without hardware -acceleration, there are some things you can do to get better frame rates: +acceleration, there are some things you can do to get better frame rates, in +order of effectiveness: .TP 1. Decrease the resolution. Use the .I videomode -option. This speeds up software renderers considerably. +option or just resize the window if the +.I fullscreen +option is false and the +.I resizable +option is true. This speeds up software renderers considerably. .TP -2. Decrease the level of rendering detail. +2. Decrease the timestep. +Use the +.I timestep +option. You can set the timestep to be as low as the your +.I maxfps +option, but it is not recommended to set this lower than the target frame rate. +Remember the trade-off here is decreased simulation accuracy. Try this to set +your frame rate to 30Hz and your timestep to 60Hz: +.PP +yoink maxfps=30 timestep=maxfps\\*2 +.TP +3. Decrease the level of rendering detail. Use the .I detail option. The game world may look sparse or incomplete, but that may be better than choppy animation. -.PP -On the other hand, if you already get high frame rates, you may also want to cap -the rate so that your computer doesn't do more work than it really needs to. -You can get reasonably smooth animation at around 30fps, but you can probably -tell a difference between that and a higher rate like 50fps. The latter will -look noticeably smoother and nice, while the former is just "okay." See -the -.I maxfps -option. .br .SH BUGS .PP diff --git a/src/Character.cc b/src/Character.cc index c6ad2a0..8e5a4c6 100644 --- a/src/Character.cc +++ b/src/Character.cc @@ -49,7 +49,7 @@ Character::Character(const std::string& name) : previous = current; - updateContainers(); + //updateContainers(); } @@ -72,85 +72,33 @@ void Character::update(Mf::Scalar t, Mf::Scalar dt) animation_.update(t, dt); - updateContainers(); + //updateContainers(); } -void Character::updateContainers() -{ - aabb_.init(Mf::Vector3(current.position[0]-16.0, current.position[1]-16.0, z), - Mf::Vector3(current.position[0]+16.0, current.position[1]+16.0, z)); - sphere_.point = Mf::Vector3(current.position[0], current.position[1], z); - sphere_.radius = (aabb_.min - sphere_.point).length(); -} - -void Character::handleEvent(const Mf::Event& event) -{ - // really just for heroine... - - Mf::Scalar force = 4000.0; - - Mf::Vector2 left = Mf::Vector2(-force, 0.0); - Mf::Vector2 right = Mf::Vector2(force, 0.0); - Mf::Vector2 down = Mf::Vector2(0.0, -force); - Mf::Vector2 up = Mf::Vector2(0.0, force); - - switch (event.type) - { - case SDL_KEYDOWN: - if (event.key.keysym.sym == SDLK_a) - { - userForce += left; - } - else if (event.key.keysym.sym == SDLK_d) - { - userForce += right; - } - else if (event.key.keysym.sym == SDLK_s) - { - userForce += down; - } - else if (event.key.keysym.sym == SDLK_w) - { - userForce += up; - } - break; - - case SDL_KEYUP: - if (event.key.keysym.sym == SDLK_a) - { - userForce -= left; - } - else if (event.key.keysym.sym == SDLK_d) - { - userForce -= right; - } - else if (event.key.keysym.sym == SDLK_s) - { - userForce -= down; - } - else if (event.key.keysym.sym == SDLK_w) - { - userForce -= up; - } - break; - } - - //Mf::logInfo("current force [%f %f]", current.force[0], current.force[1]); - //std::cerr << "current force: " << current.force << std::endl; -} +//void Character::updateContainers() +//{ + //aabb_.init(Mf::Vector3(current.position[0]-16.0, current.position[1]-16.0, z), + //Mf::Vector3(current.position[0]+16.0, current.position[1]+16.0, z)); + //sphere_.point = Mf::Vector3(current.position[0], current.position[1], z); + //sphere_.radius = (aabb_.min - sphere_.point).length(); +//} void Character::draw(Mf::Scalar alpha) const { State state = cml::lerp(previous, current, alpha); - glColor3f(1.0f, 1.0f, 1.0f); + //glColor3f(1.0f, 1.0f, 1.0f); tilemap_.bind(); Mf::Tilemap::Index frame = animation_.getFrame(); + Mf::Tilemap::Orientation orientation = Mf::Tilemap::NORMAL; + + if (current.velocity[0] < 0.0) orientation = Mf::Tilemap::REVERSE; + Mf::Scalar coords[8]; - tilemap_.getTileCoords(frame, coords); + tilemap_.getTileCoords(frame, coords, orientation); Mf::Scalar s = 16.0; @@ -165,7 +113,7 @@ void Character::draw(Mf::Scalar alpha) const glVertex3(state.position[0]-s, state.position[1]+s, z); glEnd(); - glColor3f(0.0f, 0.0f, 0.0f); + //glColor3f(0.0f, 0.0f, 0.0f); Mf::Texture::resetBind(); glBegin(GL_TRIANGLES); @@ -174,7 +122,7 @@ void Character::draw(Mf::Scalar alpha) const glVertex3(500.0, 210.0, 64.0); glEnd(); - glColor3f(1.0f, 1.0f, 1.0f); + //glColor3f(1.0f, 1.0f, 1.0f); } diff --git a/src/Character.hh b/src/Character.hh index 0a3f9f4..c19206c 100644 --- a/src/Character.hh +++ b/src/Character.hh @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -136,33 +135,27 @@ struct Character : public Mf::Entity State previous; State current; - Mf::OctreeNodeP treeNode; - private: static const Mf::Scalar z = 96.0; - Mf::Vector2 userForce; - Mf::Tilemap tilemap_; Mf::Animation animation_; - void updateContainers(); + //void updateContainers(); -public: +protected: - static CharacterP alloc(const std::string& name) - { - return CharacterP(new Character(name)); - } + Mf::Vector2 userForce; + +public: Character(const std::string& name); virtual ~Character() {} - void update(Mf::Scalar t, Mf::Scalar dt); - void handleEvent(const Mf::Event& event); - void draw(Mf::Scalar alpha) const; + virtual void update(Mf::Scalar t, Mf::Scalar dt); + virtual void draw(Mf::Scalar alpha) const; Mf::Tilemap& getTilemap(); Mf::Animation& getAnimation(); diff --git a/src/GameLayer.cc b/src/GameLayer.cc index dfdadaa..3371069 100644 --- a/src/GameLayer.cc +++ b/src/GameLayer.cc @@ -30,6 +30,7 @@ #include #include #include +#include #include "GameLayer.hh" @@ -39,58 +40,46 @@ GameLayer::GameLayer() : - music("NightFusionIntro"), + music("BeatTheCube"), punchSound("Thump") { music.setLooping(true); music.enqueue("NightFusionLoop"); music.stream(); - heroine = Character::alloc("RobotTrooper"); - heroine->getAnimation().startSequence("Run"); + heroine = Heroine::alloc(); + heroine->getAnimation().startSequence("FlyDiagonallyUp"); Mf::Scalar a[6] = {0.0, 1.5, -0.5, 3.0, -2.0, 1.0}; interp.init(a, 2.0, Mf::Interpolator::OSCILLATE); - Mf::Scalar b[2] = {1.0, 0.0}; - fadeIn.init(b, 1.0); + scene = Scene::alloc("Classic"); - octree = Mf::loadScene("Classic"); - heroine->treeNode = octree->insert(heroine); + setProjection(); - camera.setProjection(cml::rad(60.0), 1.33333, 32.0, 2500.0); - camera.uploadProjectionToGL(); + hud = Hud::alloc(); } void GameLayer::pushed(Mf::Engine& engine) { - hud = Hud::alloc(); - engine.pushLayer(hud); + engine.push(hud); } void GameLayer::update(Mf::Scalar t, Mf::Scalar dt) { - //dt *= 0.7; - - fadeIn.update(dt); camera.update(t, dt); heroine->update(t, dt); - // reinsert heroine - heroine->treeNode = octree->reinsert(heroine, heroine->treeNode); - octree->print(heroine->treeNode); - //camera.lookAt(heroine->getSphere().point); camera.setPosition(Mf::Vector3(-heroine->current.position[0], -heroine->current.position[1], -256)); - Mf::Vector3 heroinePosition; - Mf::promoteVector(heroinePosition, heroine->current.position); - Mf::Sound::setListenerPosition(heroinePosition); - - interp.update(dt); + //Mf::Vector3 heroinePosition = Mf::promote(heroine->current.position); + //Mf::Sound::setListenerPosition(heroinePosition); + + interp.update(t, dt); hud->setBar1Progress(interp.getState(dt)); hud->setBar2Progress(1.0 - interp.getState(dt)); } @@ -98,8 +87,7 @@ void GameLayer::update(Mf::Scalar t, Mf::Scalar dt) void GameLayer::draw(Mf::Scalar alpha) const { - glMatrixMode(GL_MODELVIEW); - glLoadMatrix(camera.getModelviewMatrix().data()); + camera.uploadToGL(); // DRAW THE SCENE Mf::Texture::resetBind(); @@ -107,36 +95,9 @@ void GameLayer::draw(Mf::Scalar alpha) const glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - octree->drawIfVisible(alpha, camera.getFrustum()); - - //heroine->draw(alpha); - heroine->getAabb().draw(); - - // DRAW FADE - glEnable(GL_BLEND); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glColor4f(0.0f, 0.0f, 0.0f, fadeIn.getState(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); - glEnd(); - - glDisable(GL_BLEND); + scene->drawIfVisible(alpha, camera.getFrustum()); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); + heroine->draw(alpha); } bool GameLayer::handleEvent(const Mf::Event& event) @@ -146,7 +107,7 @@ bool GameLayer::handleEvent(const Mf::Event& event) case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_SPACE) { - heroine->getAnimation().startSequence("Punch"); + heroine->getAnimation().startSequence("Flattened"); Mf::logInfo("thump!"); punchSound.play(); return true; @@ -158,7 +119,7 @@ bool GameLayer::handleEvent(const Mf::Event& event) } else if (event.key.keysym.sym == SDLK_y) { - Mf::Engine::getInstance().popLayer(); + Mf::Engine::getInstance().pop(); return true; } @@ -172,10 +133,7 @@ bool GameLayer::handleEvent(const Mf::Event& event) return true; case SDL_VIDEORESIZE: - glViewport(0, 0, event.resize.w, event.resize.h); - camera.setProjection(cml::rad(60.0), - double(event.resize.w) / double(event.resize.h), 32.0, 2500.0); - camera.uploadProjectionToGL(); + setProjection(Mf::Scalar(event.resize.w), Mf::Scalar(event.resize.h)); break; } @@ -183,5 +141,17 @@ bool GameLayer::handleEvent(const Mf::Event& event) } +void GameLayer::setProjection() +{ + Mf::Video& video = Mf::Engine::getInstance().getVideo(); + setProjection(video.getWidth(), video.getHeight()); +} + +void GameLayer::setProjection(Mf::Scalar width, Mf::Scalar height) +{ + camera.setProjection(cml::rad(60.0), width / height, 32.0, 2500.0); +} + + /** vim: set ts=4 sw=4 tw=80: *************************************************/ diff --git a/src/GameLayer.hh b/src/GameLayer.hh index b2df7ef..c4c5420 100644 --- a/src/GameLayer.hh +++ b/src/GameLayer.hh @@ -44,11 +44,12 @@ #include #include #include -#include #include #include "Character.hh" +#include "Heroine.hh" #include "Hud.hh" +#include "Scene.hh" class GameLayer; @@ -71,16 +72,18 @@ public: private: + void setProjection(); + void setProjection(Mf::Scalar width, Mf::Scalar height); + Mf::Sound music; - CharacterP heroine; + HeroineP heroine; + SceneP scene; Mf::Sound punchSound; Mf::PolynomialInterpolator<5> interp; - Mf::Lerp fadeIn; Mf::Camera camera; - Mf::OctreeP octree; HudP hud; }; diff --git a/src/Heroine.cc b/src/Heroine.cc new file mode 100644 index 0000000..314f2c9 --- /dev/null +++ b/src/Heroine.cc @@ -0,0 +1,97 @@ + +/******************************************************************************* + + 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 + +#include "Heroine.hh" +#include "Log.hh" + + +Heroine::Heroine() : + Character("Heroine") {} + + +void Heroine::handleEvent(const Mf::Event& event) +{ + // really just for heroine... + + Mf::Scalar force = 4000.0; + + Mf::Vector2 left = Mf::Vector2(-force, 0.0); + Mf::Vector2 right = Mf::Vector2(force, 0.0); + Mf::Vector2 down = Mf::Vector2(0.0, -force); + Mf::Vector2 up = Mf::Vector2(0.0, force); + + switch (event.type) + { + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_a) + { + userForce += left; + } + else if (event.key.keysym.sym == SDLK_d) + { + userForce += right; + } + else if (event.key.keysym.sym == SDLK_s) + { + userForce += down; + } + else if (event.key.keysym.sym == SDLK_w) + { + userForce += up; + } + break; + + case SDL_KEYUP: + if (event.key.keysym.sym == SDLK_a) + { + userForce -= left; + } + else if (event.key.keysym.sym == SDLK_d) + { + userForce -= right; + } + else if (event.key.keysym.sym == SDLK_s) + { + userForce -= down; + } + else if (event.key.keysym.sym == SDLK_w) + { + userForce -= up; + } + break; + } + + //Mf::logInfo("current force [%f %f]", current.force[0], current.force[1]); + //std::cerr << "current force: " << current.force << std::endl; +} + + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ + diff --git a/src/Heroine.hh b/src/Heroine.hh new file mode 100644 index 0000000..9ee49d1 --- /dev/null +++ b/src/Heroine.hh @@ -0,0 +1,70 @@ + +/******************************************************************************* + + 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 _HEROINE_HH_ +#define _HEROINE_HH_ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "Character.hh" + + +struct Heroine; +typedef boost::shared_ptr HeroineP; + + +/** + * Parent class of animate objects with "personalities." This basically + * includes the heroine herself and the bad guys. + */ + +struct Heroine : public Character +{ + Heroine(); + + static HeroineP alloc() + { + return HeroineP(new Heroine); + } + + void handleEvent(const Mf::Event& event); +}; + + +#endif // _HEROINE_HH_ + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ + diff --git a/src/Hud.cc b/src/Hud.cc index c535da5..b336b28 100644 --- a/src/Hud.cc +++ b/src/Hud.cc @@ -129,10 +129,10 @@ Hud::Hud() : void Hud::resize(int width, int height) { - cml::matrix_orthographic_RH( projection_, - 0.0f, - Mf::Scalar(width), 0.0f, Mf::Scalar(height), - 1.0f, -1.0f, cml::z_clip_neg_one); + cml::matrix_orthographic_RH(projection_, + SCALAR(0.0), + Mf::Scalar(width), SCALAR(0.0), Mf::Scalar(height), + SCALAR(1.0), SCALAR(-1.0), cml::z_clip_neg_one); // position the two progress bars at the top-left of the screen bar1_.resize(Mf::Rectangle(20, height - 51, diff --git a/src/MainLayer.cc b/src/MainLayer.cc index 51881a7..2266326 100644 --- a/src/MainLayer.cc +++ b/src/MainLayer.cc @@ -26,7 +26,7 @@ *******************************************************************************/ -#include // getenv +#include // atexit, getenv #include #include #include @@ -36,10 +36,12 @@ #include #include #include +#include #include #include "GameLayer.hh" #include "MainLayer.hh" +#include "TitleLayer.hh" #if HAVE_CONFIG_H #include "config.h" @@ -62,13 +64,28 @@ MainLayer::~MainLayer() void MainLayer::pushed(Mf::Engine& e) { engine = &e; - engine->pushLayer(GameLayer::alloc()); + + //Mf::Scalar coeff[] = {0.0, 1.0}; + //Mf::Lerp interp(coeff, 0.25); + + //Mf::LayerP gameLayer = GameLayer::alloc(); + //Mf::Transition::Ptr transition = + //Mf::Transition::alloc(gameLayer, Mf::LayerP(), interp); + //engine->push(transition); + //engine->push(GameLayer::alloc()); + engine->push(TitleLayer::alloc()); } void MainLayer::draw(Mf::Scalar alpha) const { - glClear(GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); } bool MainLayer::handleEvent(const Mf::Event& event) @@ -78,7 +95,7 @@ bool MainLayer::handleEvent(const Mf::Event& event) case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_ESCAPE) { - engine->clearLayers(); + quit(); } else if (event.key.keysym.sym == SDLK_f) { @@ -92,47 +109,55 @@ bool MainLayer::handleEvent(const Mf::Event& event) } else if (event.key.keysym.sym == SDLK_y) { - engine->pushLayer(GameLayer::alloc()); + engine->push(GameLayer::alloc()); } break; + case SDL_VIDEORESIZE: + glViewport(0, 0, event.resize.w, event.resize.h); + break; + case SDL_QUIT: - engine->clearLayers(); + quit(); break; } return false; } +void MainLayer::quit() +{ +#if NDEBUG + // we don't really need to unwind the stack and shut everything down because + // the operating system will take care of cleaning up + exit(0); +#else + engine->clear(); +#endif +} + void MainLayer::setupGL() { glEnable(GL_TEXTURE_2D); - - //glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); + glEnable(GL_LINE_SMOOTH); + glEnable(GL_POLYGON_SMOOTH); glShadeModel(GL_SMOOTH); - //glEnable(GL_POLYGON_SMOOTH); - //int texSize; - //glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize); - //std::cout << "texture size: " << texSize << std::endl; - //glEnable(GL_BLEND); //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.0); - glClearColor(1.0, 0.0, 0.0, 1.0); + glClearColor(0.0, 0.0, 0.0, 1.0); - //glMatrixMode(GL_PROJECTION); - //glLoadIdentity(); - //gluPerspective(60.0, 1.33333, 1.0, 2500.0); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60.0, 1.33333, 1.0, 2500.0); - //glMatrixMode(GL_MODELVIEW); - - //glLineWidth(10.0f); + glMatrixMode(GL_MODELVIEW); } void MainLayer::contextRecreated(const Mf::Notification* note) @@ -162,6 +187,11 @@ void printUsage() << "See documentation for more options." << std::endl; } +void goodbye() +{ + std::cout << std::endl << "Goodbye..." << std::endl << std::endl; +} + int main(int argc, char* argv[]) { if (argc > 1 && @@ -176,6 +206,8 @@ int main(int argc, char* argv[]) << "Send patches and bug reports to <" PACKAGE_BUGREPORT << ">." << std::endl << std::endl; + atexit(goodbye); + #if YOINK_LOGLEVEL >= 4 Mf::setLogLevel(Mf::LOG_DEBUG); @@ -227,7 +259,7 @@ int main(int argc, char* argv[]) try { Mf::Engine app(argc, argv, PACKAGE_STRING, iconFile, configFiles); - app.pushLayer(MainLayer::alloc()); + app.push(MainLayer::alloc()); app.run(); } @@ -238,7 +270,6 @@ int main(int argc, char* argv[]) throw e; } - std::cout << std::endl << "Goodbye..." << std::endl << std::endl; return 0; } diff --git a/src/MainLayer.hh b/src/MainLayer.hh index db529a1..44a0f23 100644 --- a/src/MainLayer.hh +++ b/src/MainLayer.hh @@ -62,6 +62,8 @@ struct MainLayer : public Mf::Layer void draw(Mf::Scalar alpha) const; bool handleEvent(const Mf::Event& event); + void quit(); + private: /** diff --git a/src/Makefile.am b/src/Makefile.am index ff31804..aeab798 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,7 +41,6 @@ libmoof_a_SOURCES = \ Moof/Log.hh \ Moof/Math.hh \ Moof/Mippleton.hh \ - Moof/Octree.cc \ Moof/Octree.hh \ Moof/OpenGL.hh \ Moof/Plane.cc \ @@ -53,8 +52,6 @@ libmoof_a_SOURCES = \ Moof/Resource.cc \ Moof/Resource.hh \ Moof/RK4.hh \ - Moof/Scene.cc \ - Moof/Scene.hh \ Moof/Script.hh \ Moof/Serializable.cc \ Moof/Serializable.hh \ @@ -75,6 +72,7 @@ libmoof_a_SOURCES = \ Moof/Tilemap.hh \ Moof/Timer.cc \ Moof/Timer.hh \ + Moof/Transition.hh \ Moof/Video.cc \ Moof/Video.hh \ Moof/fastevents.c \ @@ -113,12 +111,18 @@ yoink_SOURCES = \ Character.hh \ GameLayer.cc \ GameLayer.hh \ + Heroine.cc \ + Heroine.hh \ Hud.cc \ Hud.hh \ MainLayer.cc \ MainLayer.hh \ + Scene.cc \ + Scene.hh \ TilemapFont.cc \ TilemapFont.hh \ + TitleLayer.cc \ + TitleLayer.hh \ Typesetter.cc \ Typesetter.hh \ $(ENDLIST) diff --git a/src/Moof/Camera.cc b/src/Moof/Camera.cc index 06261a1..6b6cfa1 100644 --- a/src/Moof/Camera.cc +++ b/src/Moof/Camera.cc @@ -60,12 +60,13 @@ void Camera::setProjection(Scalar fovy, Scalar aspect, Scalar abutting, } -void Camera::uploadProjectionToGL() const +void Camera::uploadToGL() const { glMatrixMode(GL_PROJECTION); - glLoadMatrix(projection_.data()); + glMultMatrix(projection_.data()); glMatrixMode(GL_MODELVIEW); + glMultMatrix(modelview_.data()); } void Camera::update(Scalar t, Scalar dt) diff --git a/src/Moof/Camera.hh b/src/Moof/Camera.hh index b5927f4..827c47f 100644 --- a/src/Moof/Camera.hh +++ b/src/Moof/Camera.hh @@ -46,7 +46,7 @@ public: Camera() : position_(0.0, 0.0, 0.0) { - cml::quaternion_rotation_world_y(rotation_, 0.0f); + cml::quaternion_rotation_world_y(rotation_, SCALAR(0.0)); calculateSecondary(); } @@ -56,7 +56,7 @@ public: void setProjection(const Matrix4& projection); void setProjection(Scalar fovy, Scalar aspect, Scalar near, Scalar far); - void uploadProjectionToGL() const; + void uploadToGL() const; void lookAt(const Vector3& point); diff --git a/src/Moof/Engine.cc b/src/Moof/Engine.cc index 5bfaaf3..16da8d4 100644 --- a/src/Moof/Engine.cc +++ b/src/Moof/Engine.cc @@ -82,11 +82,13 @@ public: if (settings.get("rngseed", randomSeed)) setSeed(randomSeed); else setSeed(); - settings.get("timestep", timestep); + Scalar timeStep = 80.0; + settings.get("timestep", timeStep); + timestep = 1.0 / timeStep; - long maxFps = 40; + Scalar maxFps = 40.0; settings.get("maxfps", maxFps); - drawRate = 1.0 / Scalar(maxFps); + drawRate = 1.0 / maxFps; settings.get("printfps", printFps); @@ -246,55 +248,66 @@ public: } - void pushLayer(LayerP layer) + void push(LayerP layer) { ASSERT(layer && "cannot push null layer"); stack.push_front(layer); + logInfo(" push: %d", stack.size()); layer->pushed(interface); } - void popLayer() + LayerP pop() { bool fixIt = false; if (stack.begin() == stackIt) fixIt = true; LayerP popped = stack.front(); stack.pop_front(); + logInfo(" pop: %d", stack.size()); popped->popped(interface); if (fixIt) stackIt = --stack.begin(); + + return popped; } - void popLayer(Layer* layer) + LayerP pop(Layer* layer) { bool fixIt = false; + std::list popped; + std::list::iterator it; for (it = stack.begin(); it != stack.end(); ++it) { + popped.push_back(*it); + if (it == stackIt) fixIt = true; if ((*it).get() == layer) { ++it; - do + stack.erase(stack.begin(), it); + + for (it = popped.begin(); it != popped.end(); ++it) { - LayerP popped = stack.front(); - stack.pop_front(); - popped->popped(interface); + (*it)->popped(interface); } - while (stack.begin() != it); if (fixIt) stackIt = --stack.begin(); - return; + + return popped.back(); } } + + return LayerP(); } - void clearLayers() + void clear() { stack.clear(); stackIt = stack.begin(); + logInfo("clear: %d", stack.size()); } @@ -327,6 +340,8 @@ Engine& Engine::getInstance() { ASSERT(instance && "dereferencing null pointer"); return *instance; + //static Engine engine; + //return engine; } @@ -367,28 +382,28 @@ long Engine::getFrameRate() const } -void Engine::pushLayer(LayerP layer) +void Engine::push(LayerP layer) { // pass through - impl_->pushLayer(layer); + impl_->push(layer); } -void Engine::popLayer() +LayerP Engine::pop() { // pass through - impl_->popLayer(); + return impl_->pop(); } -void Engine::popLayer(Layer* layer) +LayerP Engine::pop(Layer* layer) { // pass through - impl_->popLayer(layer); + return impl_->pop(layer); } -void Engine::clearLayers() +void Engine::clear() { // pass through - impl_->clearLayers(); + impl_->clear(); } diff --git a/src/Moof/Engine.hh b/src/Moof/Engine.hh index a0c2300..e49f44d 100644 --- a/src/Moof/Engine.hh +++ b/src/Moof/Engine.hh @@ -61,10 +61,11 @@ struct Engine Video& getVideo() const; long getFrameRate() const; - void pushLayer(LayerP layer); - void popLayer(); - void popLayer(Layer* layer); - void clearLayers(); + void push(LayerP layer); + LayerP pop(); + // pops a specific layer and all layers above it + LayerP pop(Layer* layer); + void clear(); struct Exception : public Mf::Exception { diff --git a/src/Moof/Entity.hh b/src/Moof/Entity.hh index 310e0a1..dc60010 100644 --- a/src/Moof/Entity.hh +++ b/src/Moof/Entity.hh @@ -56,24 +56,10 @@ class Entity : public Cullable, public Drawable public: virtual ~Entity() {} - const Aabb& getAabb() const - { - return aabb_; - } - - const Sphere& getSphere() const - { - return sphere_; - } - - void drawIfVisible(Scalar alpha, const Frustum& frustum) const + virtual void drawIfVisible(Scalar alpha, const Frustum& frustum) const { if (isVisible(frustum)) draw(alpha); } - -protected: - Aabb aabb_; - Sphere sphere_; }; diff --git a/src/Moof/Interpolator.hh b/src/Moof/Interpolator.hh index 7ded928..4de3f69 100644 --- a/src/Moof/Interpolator.hh +++ b/src/Moof/Interpolator.hh @@ -29,6 +29,7 @@ #ifndef _MOOF_INTERPOLATOR_HH_ #define _MOOF_INTERPOLATOR_HH_ +#include #include @@ -47,7 +48,7 @@ class Interpolator { case STOP: value = 1.0; - stopped_ = true; + done_ = true; break; case REPEAT: value -= 1.0; @@ -64,7 +65,7 @@ class Interpolator { case STOP: value = 0.0; - stopped_ = true; + done_ = true; break; case REPEAT: value += 1.0; @@ -96,13 +97,13 @@ public: void setMode(Mode mode) { mode_ = mode; - stopped_ = false; + done_ = false; } - void update(Scalar dt) + void update(Scalar t, Scalar dt) { - if (!stopped_) + if (!done_) { alpha_ += dt * scale_; clamp(alpha_); @@ -110,13 +111,19 @@ public: } } + bool isDone() const + { + return done_; + } + virtual void calculate(Scalar alpha) = 0; private: + Scalar alpha_; Mode mode_; Scalar scale_; - bool stopped_; + bool done_; }; template diff --git a/src/Moof/Math.hh b/src/Moof/Math.hh index eb411e0..6665a19 100644 --- a/src/Moof/Math.hh +++ b/src/Moof/Math.hh @@ -62,36 +62,24 @@ typedef cml::quaternion< Scalar, cml::fixed<>, cml::vector_first, typedef cml::constants Constants; -inline Vector3& demoteVector(Vector3& left, const Vector4& right) +inline Vector3 demote(const Vector4& vec) { - left[0] = right[0]; - left[1] = right[1]; - left[2] = right[2]; - return left; + return Vector3(vec[0], vec[1], vec[2]); } -inline Vector2& demoteVector(Vector2& left, const Vector3& right) +inline Vector2 demote(const Vector3& vec) { - left[0] = right[0]; - left[1] = right[1]; - return left; + return Vector2(vec[0], vec[1]); } -inline Vector4& promoteVector(Vector4& left, const Vector3& right, Scalar extra = 1.0) +inline Vector4 promote(const Vector3& vec, Scalar extra = 1.0) { - left[0] = right[0]; - left[1] = right[1]; - left[2] = right[2]; - left[3] = extra; - return left; + return Vector4(vec[0], vec[1], vec[2], extra); } -inline Vector3& promoteVector(Vector3& left, const Vector2& right, Scalar extra = 1.0) +inline Vector3 promote(const Vector2& vec, Scalar extra = 1.0) { - left[0] = right[0]; - left[1] = right[1]; - left[3] = extra; - return left; + return Vector3(vec[0], vec[1], extra); } diff --git a/src/Moof/Octree.cc b/src/Moof/Octree.cc deleted file mode 100644 index 062788d..0000000 --- a/src/Moof/Octree.cc +++ /dev/null @@ -1,293 +0,0 @@ - -/******************************************************************************* - - 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 "Frustum.hh" -#include "Log.hh" -#include "Octree.hh" - - -namespace Mf { - - -void Octree::sort() -{ - stlplus::ntree::prefix_iterator it; - - for (it = tree_.prefix_begin(); it != tree_.prefix_end(); ++it) - { - it->sort(); - } -} - - -OctreeNodeP Octree::insert(EntityP entity, OctreeNodeP node) -{ - ASSERT(node.valid() && "invalid node passed"); - ASSERT(entity && "null entity passed"); - - int octantNum = -1; - - Plane::Halfspace halfspace; - - // TODO this method needs a lot of work - Plane xy = node->getAabb().getPlaneXY(); - - - // make sure the entity is fully inside the volume - if (!(entity->getAabb().max[0] < node->getAabb().max[0] && - entity->getAabb().min[0] > node->getAabb().min[0] && - entity->getAabb().max[1] < node->getAabb().max[1] && - entity->getAabb().min[1] > node->getAabb().min[1] && - entity->getAabb().max[2] < node->getAabb().max[2] && - entity->getAabb().min[2] > node->getAabb().min[2])) - { - // TODO this check is only needed for the root node, if we're inside the - // volume of the root node, we'll be fully inside the child as - // determined by trying to insert the parent node - goto done; - } - - halfspace = xy.intersects(entity->getSphere()); - if (halfspace == Plane::INTERSECT) - { - halfspace = xy.intersects(entity->getAabb()); - } - - if (halfspace == Plane::POSITIVE) - { - Plane xz = node->getAabb().getPlaneXZ(); - halfspace = xz.intersects(entity->getSphere()); - if (halfspace == Plane::INTERSECT) - { - halfspace = xz.intersects(entity->getAabb()); - } - - if (halfspace == Plane::POSITIVE) - { - Plane yz = node->getAabb().getPlaneYZ(); - halfspace = yz.intersects(entity->getSphere()); - if (halfspace == Plane::INTERSECT) - { - halfspace = yz.intersects(entity->getAabb()); - } - - if (halfspace == Plane::POSITIVE) - { - octantNum = 2; - } - else if (halfspace == Plane::NEGATIVE) - { - octantNum = 3; - } - } - else if (halfspace == Plane::NEGATIVE) - { - Plane yz = node->getAabb().getPlaneYZ(); - halfspace = yz.intersects(entity->getSphere()); - if (halfspace == Plane::INTERSECT) - { - halfspace = yz.intersects(entity->getAabb()); - } - - if (halfspace == Plane::POSITIVE) - { - octantNum = 1; - } - else if (halfspace == Plane::NEGATIVE) - { - octantNum = 0; - } - } - } - else if (halfspace == Plane::NEGATIVE) - { - Plane xz = node->getAabb().getPlaneXZ(); - halfspace = xz.intersects(entity->getSphere()); - if (halfspace == Plane::INTERSECT) - { - halfspace = xz.intersects(entity->getAabb()); - } - - if (halfspace == Plane::POSITIVE) - { - Plane yz = node->getAabb().getPlaneYZ(); - halfspace = yz.intersects(entity->getSphere()); - if (halfspace == Plane::INTERSECT) - { - halfspace = yz.intersects(entity->getAabb()); - } - - if (halfspace == Plane::POSITIVE) - { - octantNum = 6; - } - else if (halfspace == Plane::NEGATIVE) - { - octantNum = 7; - } - } - else if (halfspace == Plane::NEGATIVE) - { - Plane yz = node->getAabb().getPlaneYZ(); - halfspace = yz.intersects(entity->getSphere()); - if (halfspace == Plane::INTERSECT) - { - halfspace = yz.intersects(entity->getAabb()); - } - - if (halfspace == Plane::POSITIVE) - { - octantNum = 5; - } - else if (halfspace == Plane::NEGATIVE) - { - octantNum = 4; - } - } - } - -done: - - if (octantNum == -1) - { - node->objects.push_front(entity); - return node; - } - else - { - if ((int)tree_.children(node) <= octantNum) - { - addChild(node, octantNum); - } - - OctreeNodeP child = tree_.child(node, octantNum); - ASSERT(child.valid() && "expected valid child node"); - - return insert(entity, child); - } -} - -OctreeNodeP Octree::reinsert(EntityP entity, OctreeNodeP node) -{ - ASSERT(entity && "null entity passed"); - ASSERT(node.valid() && "invalid node passed"); - - std::list::iterator it; - it = std::find(node->objects.begin(), node->objects.end(), entity); - - if (it != node->objects.end()) - { - node->objects.erase(it); - } - - return insert(entity); -} - - -void Octree::addChild(OctreeNodeP node, int index) -{ - ASSERT(node.valid() && "invalid node passed"); - - Aabb octant; - - for (int i = tree_.children(node); i <= index; ++i) - { - node->getAabb().getOctant(octant, i); - tree_.append(node, octant); - } -} - - -void Octree::draw(Scalar alpha, OctreeNodeP node) -{ - ASSERT(node.valid() && "invalid node passed"); - - node->draw(alpha); - - for (unsigned i = 0; i < tree_.children(node); ++i) - { - OctreeNodeP child = tree_.child(node, i); - ASSERT(child.valid() && "expected valid child node"); - - draw(alpha, child); - } -} - -void Octree::drawIfVisible(Scalar alpha, const Frustum& frustum, OctreeNodeP node) -{ - ASSERT(node.valid() && "invalid node passed"); - - // try to cull by sphere - Frustum::Collision collision = - frustum.contains(node->getSphere()); - if (collision == Frustum::OUTSIDE) return; - - // try to cull by aabb - collision = frustum.contains(node->getAabb()); - if (collision == Frustum::OUTSIDE) return; - - - if (collision == Frustum::INSIDE) - { - node->draw(alpha); - } - else // collision == Frustum::INTERSECT - { - node->drawIfVisible(alpha, frustum); - } - - if (tree_.children(node) > 0) - { - if (collision == Frustum::INSIDE) - { - for (unsigned i = 0; i < tree_.children(node); ++i) - { - OctreeNodeP child = tree_.child(node, i); - ASSERT(child.valid() && "expected valid child node"); - - draw(alpha, child); - } - } - else // collision == Frustum::INTERSECT - { - for (unsigned i = 0; i < tree_.children(node); ++i) - { - OctreeNodeP child = tree_.child(node, i); - ASSERT(child.valid() && "expected valid child node"); - - drawIfVisible(alpha, frustum, child); - } - } - } -} - - -} // namespace Mf - -/** vim: set ts=4 sw=4 tw=80: *************************************************/ - diff --git a/src/Moof/Octree.hh b/src/Moof/Octree.hh index e3e2225..cdac62a 100644 --- a/src/Moof/Octree.hh +++ b/src/Moof/Octree.hh @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -47,136 +48,260 @@ namespace Mf { -class Frustum; +//class Octree; +//typedef boost::shared_ptr OctreeP; +//class Octree::Node; +//typedef stlplus::ntree::iterator OctreeNodeP; -struct OctreeNode; -typedef stlplus::ntree::iterator OctreeNodeP; -class Octree; -typedef boost::shared_ptr OctreeP; +struct OctreeInsertable +{ + virtual ~OctreeInsertable() {} + + virtual bool isInsideAabb(const Aabb& aabb) const = 0; + virtual int getOctant(const Aabb& aabb) const = 0; +}; -struct OctreeNode : public Entity +template +class Octree : public Entity { - std::list objects; + typedef boost::shared_ptr InsertableP; - OctreeNode() + struct Node : public Entity { - aabb_.min = Vector3(-1.0, -1.0, -1.0); - aabb_.max = Vector3(1.0, 1.0, 1.0); - sphere_.init(Vector3(0.0, 0.0, 0.0), 1.41421); - } + std::list objects; - OctreeNode(const Aabb& aabb) - { - aabb_ = aabb; - sphere_.point = aabb.getCenter(); - sphere_.radius = (aabb.min - sphere_.point).length(); - } + Aabb aabb; + Sphere sphere; - void draw(Scalar alpha) const - { - std::list::const_iterator it; + Node(const Aabb& box) : + aabb(box) + { + sphere.point = aabb.getCenter(); + sphere.radius = (aabb.min - sphere.point).length(); + } - for (it = objects.begin(); it != objects.end(); ++it) + void draw(Scalar alpha) const { - (*it)->draw(alpha); + typename std::list::const_iterator it; + + for (it = objects.begin(); it != objects.end(); ++it) + { + (*it)->draw(alpha); + } + + if (!objects.empty()) + aabb.draw(); // temporary } - if (!objects.empty()) - aabb_.draw(); // temporary - } + void drawIfVisible(Scalar alpha, const Frustum& frustum) const + { + typename std::list::const_iterator it; + + for (it = objects.begin(); it != objects.end(); ++it) + { + (*it)->drawIfVisible(alpha, frustum); + } + + if (!objects.empty()) + { + //aabb.draw(); + //sphere.draw(); + } + } - void drawIfVisible(Scalar alpha, const Frustum& frustum) const - { - std::list::const_iterator it; - for (it = objects.begin(); it != objects.end(); ++it) + bool isVisible(const Frustum& frustum) const { - (*it)->drawIfVisible(alpha, frustum); + if (sphere.isVisible(frustum)) + { + return aabb.isVisible(frustum); + } + + return false; } + }; - if (!objects.empty()) + +public: + + typedef boost::shared_ptr Ptr; + typedef typename stlplus::ntree::iterator NodeP; + +private: + + + NodeP insert(InsertableP entity, NodeP node) + { + ASSERT(node.valid() && "invalid node passed"); + ASSERT(entity && "null entity passed"); + + if (entity->isInsideAabb(node->aabb)) { - aabb_.draw(); - //sphere_.draw(); + return insert_recurse(entity, node); + } + else + { + node->objects.push_back(entity); + return node; } } - - bool isVisible(const Frustum& frustum) const + NodeP insert_recurse(InsertableP entity, NodeP node) { - if (sphere_.isVisible(frustum)) + ASSERT(node.valid() && "invalid node passed"); + ASSERT(entity && "null entity passed"); + + int octantNum = entity->getOctant(node->aabb); + if (octantNum == -1) { - return aabb_.isVisible(frustum); + node->objects.push_back(entity); + return node; } + else + { + if ((int)tree_.children(node) <= octantNum) + { + addChild(node, octantNum); + } - return false; - } + NodeP child = tree_.child(node, octantNum); + ASSERT(child.valid() && "expected valid child node"); + return insert(entity, child); + } + } - static bool compareZOrder(EntityP a, EntityP b) + void addChild(NodeP node, int index) { - return a->getSphere().point[2] < b->getSphere().point[2]; + ASSERT(node.valid() && "invalid node passed"); + + Aabb octant; + + for (int i = tree_.children(node); i <= index; ++i) + { + node->aabb.getOctant(octant, i); + tree_.append(node, octant); + } } - void sort() + + void draw(Scalar alpha, NodeP node) const { - //std::sort(objects.begin(), objects.end(), compareZOrder); - objects.sort(compareZOrder); + ASSERT(node.valid() && "invalid node passed"); + + node->draw(alpha); + + for (unsigned i = 0; i < tree_.children(node); ++i) + { + NodeP child = tree_.child(node, i); + ASSERT(child.valid() && "expected valid child node"); + + draw(alpha, child); + } } -}; + void drawIfVisible(Scalar alpha, const Frustum& frustum, NodeP node) const + { + ASSERT(node.valid() && "invalid node passed"); -class Octree -{ - OctreeNodeP insert(EntityP entity, OctreeNodeP node); - - void addChild(OctreeNodeP node, int index); + // try to cull by sphere + Frustum::Collision collision = frustum.contains(node->sphere); + if (collision == Frustum::OUTSIDE) return; + + // try to cull by aabb + collision = frustum.contains(node->aabb); + if (collision == Frustum::OUTSIDE) return; + + + if (collision == Frustum::INSIDE) + { + node->draw(alpha); + } + else // collision == Frustum::INTERSECT + { + node->drawIfVisible(alpha, frustum); + } - void draw(Scalar alpha, OctreeNodeP node); - void drawIfVisible(Scalar alpha, const Frustum& frustum, OctreeNodeP node); + if (tree_.children(node) > 0) + { + if (collision == Frustum::INSIDE) + { + for (unsigned i = 0; i < tree_.children(node); ++i) + { + NodeP child = tree_.child(node, i); + ASSERT(child.valid() && "expected valid child node"); + + draw(alpha, child); + } + } + else // collision == Frustum::INTERSECT + { + for (unsigned i = 0; i < tree_.children(node); ++i) + { + NodeP child = tree_.child(node, i); + ASSERT(child.valid() && "expected valid child node"); + + drawIfVisible(alpha, frustum, child); + } + } + } + } + + mutable stlplus::ntree tree_; - stlplus::ntree tree_; public: - void print(OctreeNodeP node) + void print(NodeP node) { //logDebug("-----"); //logDebug("depth to node: %d", tree_.depth(node)); //logDebug("size of node: %d", tree_.size(node)); } - static OctreeP alloc(const OctreeNode& rootNode) + static Ptr alloc(const Node& rootNode) { - return OctreeP(new Octree(rootNode)); + return Ptr(new Octree(rootNode)); } - explicit Octree(const OctreeNode& rootNode) + explicit Octree(const Node& rootNode) { tree_.insert(rootNode); } - OctreeNodeP insert(EntityP entity) + NodeP insert(InsertableP entity) { return insert(entity, tree_.root()); } - OctreeNodeP reinsert(EntityP entity, OctreeNodeP node); + NodeP reinsert(InsertableP entity, NodeP node) + { + ASSERT(entity && "null entity passed"); + ASSERT(node.valid() && "invalid node passed"); + + typename std::list::iterator it; + it = std::find(node->objects.begin(), node->objects.end(), entity); - void draw(Scalar alpha) + if (it != node->objects.end()) + { + node->objects.erase(it); + } + + return insert(entity); + } + + void draw(Scalar alpha) const { draw(alpha, tree_.root()); } - void drawIfVisible(Scalar alpha, const Frustum& frustum) + void drawIfVisible(Scalar alpha, const Frustum& frustum) const { drawIfVisible(alpha, frustum, tree_.root()); } - - void sort(); }; diff --git a/src/Moof/OpenGL.hh b/src/Moof/OpenGL.hh index a5ae3a0..c16d701 100644 --- a/src/Moof/OpenGL.hh +++ b/src/Moof/OpenGL.hh @@ -31,76 +31,122 @@ #include - -/* Define to 1 if you want to use double precision floating-point numbers. */ -//#define USE_DOUBLE_PRECISION 1 +#if HAVE_CONFIG_H +#include "config.h" +#endif #if USE_DOUBLE_PRECISION typedef GLdouble GLscalar; #define GL_SCALAR GL_DOUBLE - -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 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); } #else typedef GLfloat GLscalar; #define GL_SCALAR GL_FLOAT - -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 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); } #endif diff --git a/src/Moof/Scene.cc b/src/Moof/Scene.cc deleted file mode 100644 index b331312..0000000 --- a/src/Moof/Scene.cc +++ /dev/null @@ -1,414 +0,0 @@ - -/******************************************************************************* - - 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 -#include - -#include "Aabb.hh" -#include "Camera.hh" -#include "Entity.hh" -#include "Log.hh" -#include "Math.hh" -#include "Scene.hh" -#include "Script.hh" -#include "Settings.hh" -#include "Tilemap.hh" - - -namespace Mf { - - -static std::string getPath(const std::string& name) -{ - return Resource::getPath("scenes/" + name + ".lua"); -} - - -struct Meh -{ - Matrix4 transform; - std::string texture; - - OctreeP octree; - - enum AXIS - { - X = 0, - Y = 1, - Z = 2 - }; - - Meh() - { - octree = Octree::alloc(Aabb()); - } - - static int loadBox(Script& script, Aabb& aabb) - { - Script::Value table[] = {script[1], script[2]}; - - if (!table[0].isTable() || !table[1].isTable()) - { - logWarning("wrong arguments to setPlayfieldBounds; ignoring..."); - return 0; - } - - for (int i = 0; i <= 1; ++i) - { - for (int j = 1; j <= 3; ++j) - { - script.push((long)j); - table[i].pushField(); - } - } - - script[3].get(aabb.min[0]); - script[4].get(aabb.min[1]); - script[5].get(aabb.min[2]); - script[6].get(aabb.max[0]); - script[7].get(aabb.max[1]); - script[8].get(aabb.max[2]); - - return 0; - } - - int setPlayfieldBounds(Script& script) - { - Aabb bounds; - return loadBox(script, bounds); - } - - int setMaximumBounds(Script& script) - { - Aabb bounds; - int ret = loadBox(script, bounds); - octree = Octree::alloc(bounds); - return ret; - } - - int resetTransform(Script& script) - { - transform.identity(); - return 0; - } - - int translate(Script& script) - { - Script::Value x = script[1].requireNumber(); - Script::Value y = script[2].requireNumber(); - Script::Value z = script[3].requireNumber(); - - Vector3 vec; - x.get(vec[0]); - y.get(vec[1]); - z.get(vec[2]); - - Matrix4 translation; - cml::matrix_translation(translation, vec); - transform = translation * transform; - - return 0; - } - - int scale(Script& script) - { - if (script.getSize() == 3) - { - Vector3 vec; - script[1].requireNumber().get(vec[0]); - script[2].requireNumber().get(vec[1]); - script[3].requireNumber().get(vec[2]); - - Matrix4 scaling; - cml::matrix_scale(scaling, vec); - transform = scaling * transform; - } - else if (script.getSize() == 1) - { - Scalar value = 1.0; - script[1].requireNumber().get(value); - - Matrix4 scaling; - cml::matrix_uniform_scale(scaling, value); - transform = scaling * transform; - } - else - { - script.getTop().throwError("wrong number of arguments"); - } - - return 0; - } - - int rotate(Script& script) - { - Script::Value axis = script[1].requireString(); - Script::Value angle = script[2].requireNumber(); - - size_t index = 0; - axis.get(index); - - Scalar value; - angle.get(value); - - cml::matrix_rotate_about_world_axis(transform, index, cml::rad(value)); - - return 0; - } - - int setTexture(Script& script) - { - Script::Value name = script[1].requireString(); - - name.get(texture); - - return 0; - } - - int makeTilemap(Script& script) - { - Script::Value table = script[1].requireTable(); - Script::Value top = script[-1]; - - long width = 1; - long height = 1; - - table.pushField("width"); - top.get(width); - - long nTiles = 0; - - table.pushField("tiles"); - Script::Value tiles = script.getTop(); - nTiles = tiles.getLength(); - - if (nTiles % width != 0) table.throwError("invalid number of tiles"); - - std::vector< std::vector > indices; - - int i, w, h; - - height = nTiles / width; - indices.resize(height); - - // the indices are stored upside-down in the scene file so that they - // are easier to edit as text, so we'll need to load them last row - // first - - i = 1; - for (h = height - 1; h >= 0; --h) - { - std::vector row; - - for (w = 0; w < width; ++w, ++i) - { - script.checkStack(2); - script.push(long(i)); - tiles.pushField(); - - long index; - top.get(index); - - row.push_back(Tilemap::Index(index)); - } - - indices[h] = row; - } - - Vector4 vertices[height+1][width+1]; - - Matrix4 transposedTransform = transform; - transposedTransform.transpose(); - - for (int h = 0; h <= height; ++h) - { - for (int w = 0; w <= width; ++w) - { - vertices[h][w] = Vector4(Scalar(w), Scalar(h), 0.0, 1.0) * - transposedTransform; - } - } - - for (int h = 0; h < height; ++h) - { - for (int w = 0; w < width; ++w) - { - if (indices[h][w] == Tilemap::NO_TILE) continue; - - Vector3 quadVertices[4]; - - demoteVector(quadVertices[0], vertices[h][w]); - demoteVector(quadVertices[1], vertices[h][w+1]); - demoteVector(quadVertices[2], vertices[h+1][w+1]); - demoteVector(quadVertices[3], vertices[h+1][w]); - - Quad* quad = new Quad(quadVertices, texture, indices[h][w]); - boost::shared_ptr quadPtr(quad); - - octree->insert(quadPtr); - } - } - - return 0; - } - - int makeBillboard(Script& script) - { - Script::Value table = script[1]; - Script::Value top = script[-1]; - - long index = 0; - long width = 1; - bool blending = false; - bool fog = false; - - if (table.isTable()) - { - table.pushField("tile"); - top.get(index); - - table.pushField("u_scale"); - top.get(width); - - table.pushField("blend"); - top.get(blending); - - table.pushField("fog"); - top.get(fog); - } - - Vector4 vertices[2][width+1]; - - Matrix4 transposedTransform = transform; - transposedTransform.transpose(); - - Scalar xf; - Scalar increment = 1.0 / Scalar(width); - - for (int h = 0; h <= 1; ++h) - { - xf = 0.0; - for (int w = 0; w <= width; ++w, xf += increment) - { - vertices[h][w] = Vector4(xf, Scalar(h), 0.0, 1.0) * - transposedTransform; - } - } - - for (int w = 0; w < width; ++w) - { - Vector3 quadVertices[4]; - - demoteVector(quadVertices[0], vertices[0][w]); - demoteVector(quadVertices[1], vertices[0][w+1]); - demoteVector(quadVertices[2], vertices[1][w+1]); - demoteVector(quadVertices[3], vertices[1][w]); - - Quad* quad = new Quad(quadVertices, texture, Tilemap::Index(index)); - quad->setBlending(blending); - quad->setFog(fog); - - boost::shared_ptr quadPtr(quad); - - octree->insert(quadPtr); - } - - return 0; - } -}; - - -static void importSceneBindings(Script& script, Meh& scene) -{ - script.importFunction("SetPlayfieldBounds", - boost::bind(&Meh::setPlayfieldBounds, &scene, _1)); - script.importFunction("SetMaximumBounds", - boost::bind(&Meh::setMaximumBounds, &scene, _1)); - script.importFunction("ResetTransform", - boost::bind(&Meh::resetTransform, &scene, _1)); - script.importFunction("Translate", - boost::bind(&Meh::translate, &scene, _1)); - script.importFunction("Scale", - boost::bind(&Meh::scale, &scene, _1)); - script.importFunction("Rotate", - boost::bind(&Meh::rotate, &scene, _1)); - script.importFunction("SetTexture", - boost::bind(&Meh::setTexture, &scene, _1)); - script.importFunction("MakeTilemap", - boost::bind(&Meh::makeTilemap, &scene, _1)); - script.importFunction("MakeBillboard", - boost::bind(&Meh::makeBillboard, &scene, _1)); - - long detail = 3; - Settings::getInstance().get("detail", detail); - script.push(detail); - script.set("detail"); - - script.push(Quad::LEFT); - script.set("LEFT"); - script.push(Quad::RIGHT); - script.set("RIGHT"); - script.push(Quad::TOP); - script.set("TOP"); - - script.push(Meh::X); - script.set("X"); - script.push(Meh::Y); - script.set("Y"); - script.push(Meh::Z); - script.set("Z"); -} - - -OctreeP loadScene(const std::string& name) -{ - std::string filePath = getPath(name); - - Meh cool; - - Script script; - script.importStandardLibraries(); - importLogScript(script); - importSceneBindings(script, cool); - - if (script.doFile(filePath) != Script::SUCCESS) - { - std::string str; - script[-1].get(str); - logScript("%s", str.c_str()); - } - - cool.octree->sort(); - return cool.octree; -} - - -} // namespace Mf - -/** vim: set ts=4 sw=4 tw=80: *************************************************/ - diff --git a/src/Moof/Scene.hh b/src/Moof/Scene.hh deleted file mode 100644 index ce57bcd..0000000 --- a/src/Moof/Scene.hh +++ /dev/null @@ -1,146 +0,0 @@ - -/******************************************************************************* - - 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_SCENE_HH_ -#define _MOOF_SCENE_HH_ - -#include - -#include - -#include -#include -#include -#include -#include - - -namespace Mf { - - -OctreeP loadScene(const std::string& name); - - -class Quad : public Entity -{ - Scalar vertices_[12]; - Scalar texCoords_[8]; - - Tilemap tilemap_; - - bool blending_; - bool fog_; - -public: - - enum SURFACE_TYPE - { - LEFT = 1, - RIGHT = 2, - TOP = 3 - }; - - Quad(const Vector3 vertices[4], const std::string& texture, - Tilemap::Index tileIndex) : - tilemap_(texture), - blending_(false), - fog_(false) - { - for (int i = 0, num = 0; i < 4; ++i) - { - for (int j = 0; j < 3; ++j, ++num) - { - vertices_[num] = vertices[i][j]; - } - } - - if (!tilemap_.getTileCoords(tileIndex, texCoords_)) - { - logWarning("no index %d in texture %s", tileIndex, - texture.c_str()); - - texCoords_[0] = texCoords_[1] = - texCoords_[3] = texCoords_[6] = 0.0; - texCoords_[2] = texCoords_[4] = - texCoords_[5] = texCoords_[7] = 1.0; - } - - aabb_.encloseVertices(vertices, 4); - sphere_.point = aabb_.getCenter(); - sphere_.radius = (aabb_.min - sphere_.point).length(); - } - - void setBlending(bool blending) - { - blending_ = blending; - } - - void setFog(bool fog) - { - fog_ = fog; - } - - void draw(Scalar alpha = 0.0) const - { - if (blending_) - { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - if (fog_) - { - glEnable(GL_FOG); - glFogi(GL_FOG_MODE, GL_LINEAR); - } - - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - tilemap_.bind(); - - glVertexPointer(3, GL_SCALAR, 0, vertices_); - glTexCoordPointer(2, GL_SCALAR, 0, texCoords_); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glDisable(GL_BLEND); - glDisable(GL_FOG); - } - - bool isVisible(const Frustum& frustum) const - { - return sphere_.isVisible(frustum); - } -}; - - -} // namespace Mf - -#endif // _MOOF_SCENE_HH_ - -/** vim: set ts=4 sw=4 tw=80: *************************************************/ - diff --git a/src/Moof/Transition.hh b/src/Moof/Transition.hh new file mode 100644 index 0000000..cf1595c --- /dev/null +++ b/src/Moof/Transition.hh @@ -0,0 +1,177 @@ + +/******************************************************************************* + + 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_TRANSITION_HH_ +#define _MOOF_TRANSITION_HH_ + +#include + +#include +#include +#include +#include +#include +#include +#include + + +namespace Mf { + + +template +class Transition : public Layer +{ + LayerP to; + LayerP from; + + T interpolator; + + Engine* engine; + +public: + + Transition(LayerP t, LayerP f, const T& interp) : + to(t), + from(f), + interpolator(interp), + engine(0) {} + + typedef boost::shared_ptr Ptr; + + static Ptr alloc(LayerP t, LayerP f, const T& interp) + { + return Ptr(new Transition(t, f, interp)); + } + + + void pushed(Engine& e) + { + engine = &e; + } + + void popped(Engine& e) + { + if (to) e.push(to); + } + + void update(Scalar t, Scalar dt) + { + interpolator.update(t, dt); + + if (from) from->update(t, dt); + if (to) to->update(t, dt); + + if (interpolator.isDone()) + { + // to should /replace/ this + engine->pop(this); + } + } + + void drawFade(Scalar alpha) const + { + // DRAW FADE + glDisable(GL_DEPTH_TEST); + glDisable(GL_ALPHA_TEST); + glEnable(GL_BLEND); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glColor4(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); + glEnd(); + + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glEnable(GL_ALPHA_TEST); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + } + + void draw(Scalar alpha) const + { + Scalar a = interpolator.getState(alpha); + logInfo("draw state: %f", a); + + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + if (from) + { + glPushMatrix(); + glLoadIdentity(); + glRotate(180.0 * a, 0.0, 1.0, 0.0); + from->draw(alpha); + glPopMatrix(); + } + //drawFade(a); + + if (to) + { + glPushMatrix(); + glLoadIdentity(); + glRotate(180.0 * (1.0 - a), 0.0, 1.0, 0.0); + to->draw(alpha); + glPopMatrix(); + } + //drawFade(1.0 - a); + } + + bool handleEvent(const Event& event) + { + if (to) + { + return to->handleEvent(event); + } + else if (from) + { + return from->handleEvent(event); + } + return false; + } +}; + + +} // namespace Mf + +#endif // _MOOF_TRANSITION_HH_ + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ + diff --git a/src/Moof/Video.cc b/src/Moof/Video.cc index ef966c7..8de161a 100644 --- a/src/Moof/Video.cc +++ b/src/Moof/Video.cc @@ -288,6 +288,17 @@ void Video::swap() } +int Video::getWidth() const +{ + return context_->w; +} + +int Video::getHeight() const +{ + return context_->h; +} + + Video::Attributes::Attributes() { // Set some sane GL and window defaults (see SDL_video.c:217) diff --git a/src/Moof/Video.hh b/src/Moof/Video.hh index d640ad2..5f56f9e 100644 --- a/src/Moof/Video.hh +++ b/src/Moof/Video.hh @@ -128,6 +128,9 @@ public: void makeActive(); void swap(); + int getWidth() const; + int getHeight() const; + struct Exception : public Mf::Exception { diff --git a/src/Scene.cc b/src/Scene.cc new file mode 100644 index 0000000..bd9c034 --- /dev/null +++ b/src/Scene.cc @@ -0,0 +1,647 @@ + +/******************************************************************************* + + 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Scene.hh" + + +struct Scene::Impl : public Mf::Mippleton +{ + class Quad : public Mf::Entity, public Mf::OctreeInsertable + { + Mf::Scalar vertices_[12]; + Mf::Scalar texCoords_[8]; + + Mf::Tilemap tilemap_; + + bool blending_; + bool fog_; + + Mf::Aabb aabb_; + Mf::Sphere sphere_; + + public: + + enum SURFACE_TYPE + { + LEFT = 1, + RIGHT = 2, + TOP = 3 + }; + + Quad(const Mf::Vector3 vertices[4], const std::string& texture, + Mf::Tilemap::Index tileIndex) : + tilemap_(texture), + blending_(false), + fog_(false) + { + for (int i = 0, num = 0; i < 4; ++i) + { + for (int j = 0; j < 3; ++j, ++num) + { + vertices_[num] = vertices[i][j]; + } + } + + if (!tilemap_.getTileCoords(tileIndex, texCoords_)) + { + Mf::logWarning("no index %d in texture %s", tileIndex, + texture.c_str()); + + texCoords_[0] = texCoords_[1] = + texCoords_[3] = texCoords_[6] = 0.0; + texCoords_[2] = texCoords_[4] = + texCoords_[5] = texCoords_[7] = 1.0; + } + + aabb_.encloseVertices(vertices, 4); + sphere_.point = aabb_.getCenter(); + sphere_.radius = (aabb_.min - sphere_.point).length(); + } + + void setBlending(bool blending) + { + blending_ = blending; + } + + void setFog(bool fog) + { + fog_ = fog; + } + + void draw(Mf::Scalar alpha = 0.0) const + { + if (blending_) + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + if (fog_) + { + glEnable(GL_FOG); + glFogi(GL_FOG_MODE, GL_LINEAR); + } + + //glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + tilemap_.bind(); + + glVertexPointer(3, GL_SCALAR, 0, vertices_); + glTexCoordPointer(2, GL_SCALAR, 0, texCoords_); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glDisable(GL_BLEND); + glDisable(GL_FOG); + } + + bool isVisible(const Mf::Frustum& frustum) const + { + return sphere_.isVisible(frustum); + } + + + bool isInsideAabb(const Mf::Aabb& aabb) const + { + // make sure the entity is fully inside the volume + if (!(aabb_.max[0] < aabb.max[0] && + aabb_.min[0] > aabb.min[0] && + aabb_.max[1] < aabb.max[1] && + aabb_.min[1] > aabb.min[1] && + aabb_.max[2] < aabb.max[2] && + aabb_.min[2] > aabb.min[2])) + { + return false; + } + + return true; + } + + int getOctant(const Mf::Aabb& aabb) const + { + int octantNum = -1; + + Mf::Plane::Halfspace halfspace; + + Mf::Plane xy = aabb.getPlaneXY(); + halfspace = xy.intersects(sphere_); + if (halfspace == Mf::Plane::INTERSECT) + { + halfspace = xy.intersects(aabb_); + } + + if (halfspace == Mf::Plane::POSITIVE) + { + Mf::Plane xz = aabb.getPlaneXZ(); + halfspace = xz.intersects(sphere_); + if (halfspace == Mf::Plane::INTERSECT) + { + halfspace = xz.intersects(aabb_); + } + + if (halfspace == Mf::Plane::POSITIVE) + { + Mf::Plane yz = aabb.getPlaneYZ(); + halfspace = yz.intersects(sphere_); + if (halfspace == Mf::Plane::INTERSECT) + { + halfspace = yz.intersects(aabb_); + } + + if (halfspace == Mf::Plane::POSITIVE) + { + octantNum = 2; + } + else if (halfspace == Mf::Plane::NEGATIVE) + { + octantNum = 3; + } + } + else if (halfspace == Mf::Plane::NEGATIVE) + { + Mf::Plane yz = aabb.getPlaneYZ(); + halfspace = yz.intersects(sphere_); + if (halfspace == Mf::Plane::INTERSECT) + { + halfspace = yz.intersects(aabb_); + } + + if (halfspace == Mf::Plane::POSITIVE) + { + octantNum = 1; + } + else if (halfspace == Mf::Plane::NEGATIVE) + { + octantNum = 0; + } + } + } + else if (halfspace == Mf::Plane::NEGATIVE) + { + Mf::Plane xz = aabb.getPlaneXZ(); + halfspace = xz.intersects(sphere_); + if (halfspace == Mf::Plane::INTERSECT) + { + halfspace = xz.intersects(aabb_); + } + + if (halfspace == Mf::Plane::POSITIVE) + { + Mf::Plane yz = aabb.getPlaneYZ(); + halfspace = yz.intersects(sphere_); + if (halfspace == Mf::Plane::INTERSECT) + { + halfspace = yz.intersects(aabb_); + } + + if (halfspace == Mf::Plane::POSITIVE) + { + octantNum = 6; + } + else if (halfspace == Mf::Plane::NEGATIVE) + { + octantNum = 7; + } + } + else if (halfspace == Mf::Plane::NEGATIVE) + { + Mf::Plane yz = aabb.getPlaneYZ(); + halfspace = yz.intersects(sphere_); + if (halfspace == Mf::Plane::INTERSECT) + { + halfspace = yz.intersects(aabb_); + } + + if (halfspace == Mf::Plane::POSITIVE) + { + octantNum = 5; + } + else if (halfspace == Mf::Plane::NEGATIVE) + { + octantNum = 4; + } + } + } + + return octantNum; + } + }; + + + + Mf::Script script; + + Mf::Matrix4 transform; + std::string texture; + + Mf::Octree::Ptr octree; + + + enum AXIS + { + X = 0, + Y = 1, + Z = 2 + }; + + + + explicit Impl(const std::string& name) : + Mf::Mippleton(name) + { + script.importStandardLibraries(); + importLogScript(script); + + importSceneBindings(script); + loadFromFile(); + } + + void importSceneBindings(Mf::Script& script) + { + script.importFunction("SetPlayfieldBounds", + boost::bind(&Impl::setPlayfieldBounds, this, _1)); + script.importFunction("SetMaximumBounds", + boost::bind(&Impl::setMaximumBounds, this, _1)); + script.importFunction("ResetTransform", + boost::bind(&Impl::resetTransform, this, _1)); + script.importFunction("Translate", + boost::bind(&Impl::translate, this, _1)); + script.importFunction("Scale", + boost::bind(&Impl::scale, this, _1)); + script.importFunction("Rotate", + boost::bind(&Impl::rotate, this, _1)); + script.importFunction("SetTexture", + boost::bind(&Impl::setTexture, this, _1)); + script.importFunction("MakeTilemap", + boost::bind(&Impl::makeTilemap, this, _1)); + script.importFunction("MakeBillboard", + boost::bind(&Impl::makeBillboard, this, _1)); + + long detail = 3; + Mf::Settings::getInstance().get("detail", detail); + script.push(detail); script.set("detail"); + + script.push(Quad::LEFT); script.set("LEFT"); + script.push(Quad::RIGHT); script.set("RIGHT"); + script.push(Quad::TOP); script.set("TOP"); + + script.push(X); script.set("X"); + script.push(Y); script.set("Y"); + script.push(Z); script.set("Z"); + } + + + void loadFromFile() + { + std::string filePath = Scene::getPath(getName()); + + if (script.doFile(filePath) != Mf::Script::SUCCESS) + { + std::string str; + script[-1].get(str); + Mf::logScript("%s", str.c_str()); + } + } + + + static int loadBox(Mf::Script& script, Mf::Aabb& aabb) + { + Mf::Script::Value table[] = + { + script[1].requireTable(), + script[2].requireTable() + }; + + if (!table[0].isTable() || !table[1].isTable()) + { + Mf::logWarning("wrong arguments to setPlayfieldBounds; ignoring..."); + return 0; + } + + for (int i = 0; i <= 1; ++i) + { + for (int j = 1; j <= 3; ++j) + { + script.push((long)j); + table[i].pushField(); + } + } + + script[3].get(aabb.min[0]); + script[4].get(aabb.min[1]); + script[5].get(aabb.min[2]); + script[6].get(aabb.max[0]); + script[7].get(aabb.max[1]); + script[8].get(aabb.max[2]); + + return 0; + } + + int setPlayfieldBounds(Mf::Script& script) + { + Mf::Aabb bounds; + return loadBox(script, bounds); + } + + int setMaximumBounds(Mf::Script& script) + { + Mf::Aabb bounds; + int ret = loadBox(script, bounds); + octree = Mf::Octree::alloc(bounds); + return ret; + } + + int resetTransform(Mf::Script& script) + { + transform.identity(); + return 0; + } + + int translate(Mf::Script& script) + { + Mf::Script::Value x = script[1].requireNumber(); + Mf::Script::Value y = script[2].requireNumber(); + Mf::Script::Value z = script[3].requireNumber(); + + Mf::Vector3 vec; + x.get(vec[0]); + y.get(vec[1]); + z.get(vec[2]); + + Mf::Matrix4 translation; + cml::matrix_translation(translation, vec); + transform = translation * transform; + + return 0; + } + + int scale(Mf::Script& script) + { + if (script.getSize() == 3) + { + Mf::Vector3 vec; + script[1].requireNumber().get(vec[0]); + script[2].requireNumber().get(vec[1]); + script[3].requireNumber().get(vec[2]); + + Mf::Matrix4 scaling; + cml::matrix_scale(scaling, vec); + transform = scaling * transform; + } + else if (script.getSize() == 1) + { + Mf::Scalar value = 1.0; + script[1].requireNumber().get(value); + + Mf::Matrix4 scaling; + cml::matrix_uniform_scale(scaling, value); + transform = scaling * transform; + } + else + { + script.getTop().throwError("wrong number of arguments"); + } + + return 0; + } + + int rotate(Mf::Script& script) + { + Mf::Script::Value axis = script[1].requireString(); + Mf::Script::Value angle = script[2].requireNumber(); + + size_t index = 0; + axis.get(index); + + Mf::Scalar value; + angle.get(value); + + cml::matrix_rotate_about_world_axis(transform, index, cml::rad(value)); + + return 0; + } + + int setTexture(Mf::Script& script) + { + Mf::Script::Value name = script[1].requireString(); + + name.get(texture); + + return 0; + } + + int makeTilemap(Mf::Script& script) + { + Mf::Script::Value table = script[1].requireTable(); + Mf::Script::Value top = script[-1]; + + long width = 1; + long height = 1; + + table.pushField("width"); + top.get(width); + + long nTiles = 0; + + table.pushField("tiles"); + Mf::Script::Value tiles = script.getTop(); + nTiles = tiles.getLength(); + + if (nTiles % width != 0) table.throwError("invalid number of tiles"); + + std::vector< std::vector > indices; + + int i, w, h; + + height = nTiles / width; + indices.resize(height); + + // the indices are stored upside-down in the scene file so that they + // are easier to edit as text, so we'll need to load them last row + // first + + i = 1; + for (h = height - 1; h >= 0; --h) + { + std::vector row; + + for (w = 0; w < width; ++w, ++i) + { + script.checkStack(2); + script.push(long(i)); + tiles.pushField(); + + long index; + top.get(index); + + row.push_back(Mf::Tilemap::Index(index)); + } + + indices[h] = row; + } + + Mf::Vector4 vertices[height+1][width+1]; + + Mf::Matrix4 transposedTransform = transform; + transposedTransform.transpose(); + + for (int h = 0; h <= height; ++h) + { + for (int w = 0; w <= width; ++w) + { + vertices[h][w] = Mf::Vector4(Mf::Scalar(w), Mf::Scalar(h), 0.0, 1.0) * + transposedTransform; + } + } + + for (int h = 0; h < height; ++h) + { + for (int w = 0; w < width; ++w) + { + if (indices[h][w] == Mf::Tilemap::NO_TILE) continue; + + Mf::Vector3 quadVertices[4]; + + quadVertices[0] = Mf::demote(vertices[h][w]); + quadVertices[1] = Mf::demote(vertices[h][w+1]); + quadVertices[2] = Mf::demote(vertices[h+1][w+1]); + quadVertices[3] = Mf::demote(vertices[h+1][w]); + + Quad* quad = new Quad(quadVertices, texture, indices[h][w]); + boost::shared_ptr quadPtr(quad); + + octree->insert(quadPtr); + } + } + + return 0; + } + + int makeBillboard(Mf::Script& script) + { + Mf::Script::Value table = script[1]; + Mf::Script::Value top = script[-1]; + + long index = 0; + long width = 1; + bool blending = false; + bool fog = false; + + if (table.isTable()) + { + table.pushField("tile"); + top.get(index); + + table.pushField("u_scale"); + top.get(width); + + table.pushField("blend"); + top.get(blending); + + table.pushField("fog"); + top.get(fog); + } + + Mf::Vector4 vertices[2][width+1]; + + Mf::Matrix4 transposedTransform = transform; + transposedTransform.transpose(); + + Mf::Scalar xf; + Mf::Scalar increment = 1.0 / Mf::Scalar(width); + + for (int h = 0; h <= 1; ++h) + { + xf = 0.0; + for (int w = 0; w <= width; ++w, xf += increment) + { + vertices[h][w] = Mf::Vector4(xf, Mf::Scalar(h), 0.0, 1.0) * + transposedTransform; + } + } + + for (int w = 0; w < width; ++w) + { + Mf::Vector3 quadVertices[4]; + + quadVertices[0] = Mf::demote(vertices[0][w]); + quadVertices[1] = Mf::demote(vertices[0][w+1]); + quadVertices[2] = Mf::demote(vertices[1][w+1]); + quadVertices[3] = Mf::demote(vertices[1][w]); + + Quad* quad = new Quad(quadVertices, texture, Mf::Tilemap::Index(index)); + quad->setBlending(blending); + quad->setFog(fog); + + boost::shared_ptr quadPtr(quad); + + octree->insert(quadPtr); + } + + return 0; + } +}; + + +Scene::Scene(const std::string& name) : + // pass through + impl_(Scene::Impl::getInstance(name)) {} + + +void Scene::draw(Mf::Scalar alpha) const +{ + impl_->octree->draw(alpha); +} + +void Scene::drawIfVisible(Mf::Scalar alpha, const Mf::Frustum& frustum) const +{ + impl_->octree->drawIfVisible(alpha, frustum); +} + + +std::string Scene::getPath(const std::string& name) +{ + return Mf::Resource::getPath("scenes/" + name + ".lua"); +} + + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ + diff --git a/src/Scene.hh b/src/Scene.hh new file mode 100644 index 0000000..ca96aea --- /dev/null +++ b/src/Scene.hh @@ -0,0 +1,68 @@ + +/******************************************************************************* + + 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 _SCENE_HH_ +#define _SCENE_HH_ + +#include + +#include + +#include +#include +#include + + +class Scene; +typedef boost::shared_ptr SceneP; + +class Scene : public Mf::Cullable, public Mf::Drawable, public Mf::Resource +{ + class Impl; + boost::shared_ptr impl_; + +public: + + Scene(const std::string& name); + + static SceneP alloc(const std::string& name) + { + return SceneP(new Scene(name)); + } + + void draw(Mf::Scalar alpha) const; + void drawIfVisible(Mf::Scalar alpha, const Mf::Frustum& frustum) const; + + static std::string getPath(const std::string& name); +}; + + +#endif // _SCENE_HH_ + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ + diff --git a/src/TitleLayer.cc b/src/TitleLayer.cc new file mode 100644 index 0000000..a12168a --- /dev/null +++ b/src/TitleLayer.cc @@ -0,0 +1,81 @@ + +/******************************************************************************* + + 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 +#include +#include + +#include "GameLayer.hh" +#include "TitleLayer.hh" + + +void TitleLayer::pushed(Mf::Engine& e) +{ + engine = &e; + + Mf::Scalar coeff[] = {0.0, 1.0}; + fadeIn.init(coeff, 0.1); + + gameLayer = GameLayer::alloc(); +} + +void TitleLayer::update(Mf::Scalar t, Mf::Scalar dt) +{ + if (!fadeIn.isDone()) fadeIn.update(t, dt); +} + +void TitleLayer::draw(Mf::Scalar alpha) const +{ + glClearColor(0.0, 0.0, fadeIn.getState(alpha), 1.0); + glClear(GL_COLOR_BUFFER_BIT); +} + +bool TitleLayer::handleEvent(const Mf::Event& event) +{ + switch (event.type) + { + case SDL_KEYUP: + Mf::LayerP titleLayer = engine->pop(this); + //engine->pushLayer(GameLayer::alloc()); + + Mf::Scalar coeff[] = {0.0, 1.0}; + Mf::Lerp interp(coeff, 0.2); + + //Mf::LayerP gameLayer = GameLayer::alloc(); + Mf::Transition::Ptr transition = + Mf::Transition::alloc(gameLayer, titleLayer, interp); + engine->push(transition); + return true; + } + + return false; +} + + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ + diff --git a/src/TitleLayer.hh b/src/TitleLayer.hh new file mode 100644 index 0000000..da4b4c5 --- /dev/null +++ b/src/TitleLayer.hh @@ -0,0 +1,67 @@ + +/******************************************************************************* + + 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 _TITLELAYER_HH_ +#define _TITLELAYER_HH_ + +#include + +#include +#include +#include + + +class TitleLayer; +typedef boost::shared_ptr TitleLayerP; + +struct TitleLayer : public Mf::Layer +{ + static TitleLayerP alloc() + { + return TitleLayerP(new TitleLayer); + } + + void pushed(Mf::Engine& engine); + + void update(Mf::Scalar t, Mf::Scalar dt); + void draw(Mf::Scalar alpha) const; + bool handleEvent(const Mf::Event& event); + +private: + + Mf::Lerp fadeIn; + Mf::Engine* engine; + + Mf::LayerP gameLayer; +}; + + +#endif // _TITLELAYER_HH_ + +/** vim: set ts=4 sw=4 tw=80: *************************************************/ +