From: Charles McGarvey Date: Mon, 28 Sep 2009 17:45:50 +0000 (-0600) Subject: new timer class X-Git-Url: https://git.dogcows.com/gitweb?a=commitdiff_plain;h=33842c860fe18ca8cf087905992885687434320c;p=chaz%2Fyoink new timer class --- diff --git a/Makefile.am b/Makefile.am index b1ac384..b8f7420 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,17 +12,32 @@ debug: all if WIN32 -installer: all + +INSTALLER_NAME = yoinksetup-$(VERSION).exe + +.PHONY: package +package: $(INSTALLER_NAME) + +$(INSTALLER_NAME): all @echo "Creating win32 installer..." - @(sh make-win32-installer.sh 2> installer.log 1>&2 && \ + @(sh make-win32-installer.sh $(INSTALLER_NAME) 2> installer.log 1>&2 && \ rm installer.log && echo "Done.") || \ (echo "Installer compilation failed!"; \ echo "Check installer.log for details."; exit 1) -endif +else +if LINUX -RPMBUILD = rpmbuild +.PHONY: package +package: rpm rpm: dist-bzip2 - $(RPMBUILD) -ba --nodeps extra/yoink.spec + @echo "Creating RPM package..." + @($(RPMBUILD) -ba --nodeps extra/yoink.spec 2> rpmbuild.log 1>&2 && \ + rm rpmbuild.log && echo "Done.") || \ + (echo "rpmbuild failed!"; \ + echo "Check rpmbuild.log for details."; exit 1) + +endif +endif diff --git a/README b/README index 39092e7..b645786 100644 --- a/README +++ b/README @@ -1,24 +1,24 @@ -Yoink is a game originally developed by Neil Carter for Mac OS X. You play -the part of a flying alien heroine who must defend her home on Earth from -other airborne alien invaders. +Yoink is a game originally developed by Neil Carter for Mac OS. You play the +part of a flying alien heroine who must defend her home on Earth from other +airborne alien invaders. -This version of the game uses rewritten code and modern frameworks to bring +This version of the game uses all new code and modern frameworks to bring this simple, fast-moving action game to a wider audience. -The new code is released under the Simplified BSD License. The old code and -original resources are provided under the zlib/libpng License. See COPYING -for complete details. +The new code is released under the BSD-2 license. The old code and original +resources are provided under the zlib/libpng License. See COPYING for complete +details. Dependencies: boost headers OpenGL (libGL, libGL or opengl32, glu32) -libSDL -libSDL_image (with libpng support) -libSDL_sound (with libogg support) -libopenal -libalut +SDL +SDL_image (with libpng support) +libvorbisfile +OpenAL +freealut Notes regarding the code: diff --git a/configure.ac b/configure.ac index 561b39e..a2db4cf 100644 --- a/configure.ac +++ b/configure.ac @@ -53,8 +53,14 @@ case "${host}" in MACOSX=yes LIBS="$LIBS -Wl,-framework" ;; + *-linux-gnu*) + LINUX=yes + AC_PATH_PROGS([RPMBUILD], [rpmbuild]) + AC_SUBST(RPMBUILD) + ;; esac +AM_CONDITIONAL([LINUX], test "$LINUX" = "yes") AM_CONDITIONAL([WIN32], test "$WIN32" = "yes") diff --git a/make-win32-installer.sh.in b/make-win32-installer.sh.in index f88dd5e..b5c4d9a 100644 --- a/make-win32-installer.sh.in +++ b/make-win32-installer.sh.in @@ -17,6 +17,7 @@ ROOT_DIR="$PWD" COMPRESSION="/solid lzma" DEST="tmp-yoink-win32" SCRIPT="$DEST/yoink.nsi" +OUT_FILE=${1:-yoinksetup-@VERSION@.exe} # DLL dependencies DLLS="SDL SDL_image zlib1 libpng12-0 OpenAL32 libalut-0 libvorbis-0 libogg-0" @@ -75,7 +76,7 @@ VIAddVersionKey "ProductVersion" "@VERSION@" VIAddVersionKey "LegalCopyright" "Copyright 2009 Charles McGarvey et al." ;General -OutFile "$ROOT_DIR/yoinksetup-@VERSION@.exe" +OutFile "$ROOT_DIR/$OUT_FILE" SetCompressor $COMPRESSION ShowInstDetails show ShowUninstDetails show diff --git a/src/Moof/Dispatcher.cc b/src/Moof/Dispatcher.cc index fd93ccf..2d9d337 100644 --- a/src/Moof/Dispatcher.cc +++ b/src/Moof/Dispatcher.cc @@ -76,7 +76,7 @@ struct Dispatcher::Impl for (CallbackIter jt = first; jt != last; ++jt) { - if (((*jt).second).first == id) + if ((*jt).second.first == id) { callbacks.erase(jt); break; @@ -135,7 +135,7 @@ void Dispatcher::dispatch(const std::string& message, const Notification* param) for (Impl::CallbackIter it = callbacks.first; it != callbacks.second; ++it) { - Function callback = ((*it).second).second; + Function callback = (*it).second.second; callback(param); } } diff --git a/src/Moof/Dispatcher.hh b/src/Moof/Dispatcher.hh index 0d75390..14d8998 100644 --- a/src/Moof/Dispatcher.hh +++ b/src/Moof/Dispatcher.hh @@ -31,6 +31,7 @@ #include +#include #include #include @@ -105,6 +106,7 @@ inline void dispatch(const std::string& message, const Notification* param = 0) } // namespace dispatch + } // namespace Mf #endif // _MOOF_DISPATCHER_HH_ diff --git a/src/Moof/Engine.cc b/src/Moof/Engine.cc index 80a203e..e97c8b5 100644 --- a/src/Moof/Engine.cc +++ b/src/Moof/Engine.cc @@ -54,9 +54,9 @@ public: interface(outer) { #if defined(_WIN32) || defined (_WIN64) || defined(__WIN32__) - if (SDL_Init(SDL_INIT_EVERYTHING) != 0) + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) #else - if (SDL_Init(SDL_INIT_EVERYTHING | SDL_INIT_EVENTTHREAD) != 0) + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTTHREAD) != 0) #endif { logError("sdl is complaining: %s", SDL_GetError()); @@ -112,7 +112,7 @@ public: int run() { - Scalar ticksNow = getTicks(); + Scalar ticksNow = Timer::getTicks(); Scalar nextStep = ticksNow; Scalar nextDraw = ticksNow; @@ -128,13 +128,15 @@ public: running = true; do { - Scalar newTicks = getTicks(); + Scalar newTicks = Timer::getTicks(); deltaTime = newTicks - ticksNow; ticksNow = newTicks; if (deltaTime >= 0.25) deltaTime = 0.25; accumulator += deltaTime; + Timer::fireIfExpired(ticksNow); + while (accumulator >= timestep) { dispatchEvents(); @@ -183,7 +185,8 @@ public: } // be a good citizen and give back what you don't need - sleep(std::min(nextStep, nextDraw), true); + Timer::sleep(std::min(std::min(nextStep, nextDraw), + Timer::getNextFire()), true); } while (running); diff --git a/src/Moof/RK4.hh b/src/Moof/RK4.hh index 00c0b64..a2e0f1c 100644 --- a/src/Moof/RK4.hh +++ b/src/Moof/RK4.hh @@ -75,15 +75,6 @@ inline void integrate(S& state, Scalar t, Scalar dt) } -//template -//inline T spring(Scalar k, Scalar b) -//{ - //current.force = -15 * (current.position - Mf::Vector2(200.0, 200.0)) - //- 15.0 * current.velocity; - //return -//} - - } // namespace Mf #endif // _MOOF_RK4_HH_ diff --git a/src/Moof/Sound.cc b/src/Moof/Sound.cc index f912b31..460f7bb 100644 --- a/src/Moof/Sound.cc +++ b/src/Moof/Sound.cc @@ -38,6 +38,7 @@ #include "Log.hh" #include "Mippleton.hh" #include "Sound.hh" +#include "Timer.hh" #define BUFFER_SIZE (64 * 1024) //#define BUFFER_SIZE (5*2048) @@ -161,7 +162,7 @@ struct Sound::Impl } - void beginStream(ALuint source, int nBuffers = 4) + void beginStream(ALuint source, int nBuffers = 8) { if (!oggStream.datasource) openFile(); if (!oggStream.datasource) return; @@ -299,6 +300,9 @@ struct Sound::Impl alSourcei(source_, AL_LOOPING, AL_FALSE); alSourcePlay(source_); playing_ = true; + + streamTimer.init(boost::bind(&Impl::streamUpdate, this, _1, _2), 1.0, + Timer::REPEAT); } inline void update() @@ -446,6 +450,14 @@ struct Sound::Impl std::queue queue_; std::vector expired_; + + Timer streamTimer; + + void streamUpdate(Timer& timer, Scalar t) + { + // don't let the music die! + update(); + } }; Sound::Sound(const std::string& name) : @@ -459,19 +471,12 @@ void Sound::play() impl_->play(); } - void Sound::stream() { // pass through impl_->stream(); } -void Sound::update(Scalar t, Scalar dt) -{ - // pass through - impl_->update(); -} - void Sound::stop() { diff --git a/src/Moof/Sound.hh b/src/Moof/Sound.hh index 4953774..26c2b42 100644 --- a/src/Moof/Sound.hh +++ b/src/Moof/Sound.hh @@ -64,9 +64,7 @@ public: void play(); - void stream(); - void update(Scalar t, Scalar dt); void stop(); void pause(); diff --git a/src/Moof/Thread.hh b/src/Moof/Thread.hh index a5e0225..274f717 100644 --- a/src/Moof/Thread.hh +++ b/src/Moof/Thread.hh @@ -31,7 +31,7 @@ /** * @file Thread.hh - * Light C++ wrapper around SDL threads. + * Light C++ wrapper around the SDL threads API. */ #include @@ -51,34 +51,33 @@ typedef SDL_Thread* Thread; typedef boost::function Function; -int detach_(void* arg) +inline int detach_(void* arg) { - Function function = *(Function*)arg; - int ret = function(); + //Function function = *(Function*)arg; + int code = (*(Function*)arg)(); delete (Function*)arg; - return ret; + return code; } -Thread detachFunction(const Function& function) +inline Thread detachFunction(const Function& function) { - Thread thread; Function* fcopy = new Function(function); + Thread thread = SDL_CreateThread(detach_, (void*)fcopy); - thread = SDL_CreateThread(detach_, (void*)fcopy); if (thread == 0) delete fcopy; return thread; } -int waitOnThread(Thread thread) +inline int waitOnThread(Thread thread) { int i; SDL_WaitThread(thread, &i); return i; } -void killThread(Thread thread) +inline void killThread(Thread thread) { SDL_KillThread(thread); } @@ -88,12 +87,12 @@ void killThread(Thread thread) // The identifier function returns a unique integer for the calling thread. // -unsigned int getThreadIdentifier() +inline unsigned getThreadIdentifier() { return SDL_ThreadID(); } -unsigned int getThreadIdentifier(Thread thread) +inline unsigned getThreadIdentifier(Thread thread) { return SDL_GetThreadID(thread); } diff --git a/src/Moof/Timer.cc b/src/Moof/Timer.cc index bc7aae2..d28d5e8 100644 --- a/src/Moof/Timer.cc +++ b/src/Moof/Timer.cc @@ -28,6 +28,7 @@ #include #include +#include #include #include "Log.hh" @@ -43,6 +44,129 @@ namespace Mf { +Scalar Timer::nextFire_ = std::numeric_limits::max(); +std::map Timer::timers_; + + +unsigned Timer::getNewID() +{ + static unsigned id = 1; + return id++; +} + + +void Timer::init(const Function& function, Scalar seconds, Mode mode) +{ + invalidate(); + + mode_ = mode; + + if (mode_ != INVALID) + { + function_ = function; + + if (mode == ABSOLUTEE) + { + absolute_ = seconds; + } + else + { + absolute_ = seconds - getTicks(); + interval_ = seconds; + } + + id_ = getNewID(); + timers_.insert(std::pair(id_, *this)); + + if (absolute_ < nextFire_) nextFire_ = absolute_; + } +} + + +bool Timer::isValid() const +{ + return mode_ != INVALID; +} + +void Timer::invalidate() +{ + if (mode_ != INVALID) + { + timers_.erase(id_); + mode_ = INVALID; + + if (isEqual(absolute_, nextFire_)) nextFire_ = findNextFire(); + } +} + + +void Timer::fire() +{ + Scalar t = getTicks(); + + if (function_) function_(*this, t); + + if (isRepeating()) + { + Scalar absolute = absolute_; + + if (isEqual(absolute_, t, 1.0)) absolute_ += interval_; + else absolute_ = interval_ + t; + + if (isEqual(absolute, nextFire_)) nextFire_ = findNextFire(); + } + else + { + invalidate(); + } +} + + +Scalar Timer::findNextFire() +{ + std::map::iterator it; + Scalar nextFire = std::numeric_limits::max(); + + for (it = timers_.begin(); it != timers_.end(); ++it) + { + Scalar absolute = (*it).second.absolute_; + if (absolute < nextFire) nextFire = absolute; + } + + return nextFire; +} + + +Scalar Timer::getSecondsRemaining() const +{ + return absolute_ - getTicks(); +} + +bool Timer::isExpired() const +{ + return getSecondsRemaining() < 0.0; +} + +bool Timer::isRepeating() const +{ + return mode_ == REPEAT; +} + + +void Timer::fireIfExpired(Scalar t) +{ + std::map::iterator it; + + if (nextFire_ > t) return; + + for (it = timers_.begin(); it != timers_.end(); ++it) + { + Timer& timer = (*it).second; + if (timer.isExpired()) timer.fire(); + } +} + + #if HAVE_CLOCK_GETTIME // Since the monotonic clock will provide us with the timer since the computer @@ -67,7 +191,7 @@ static time_t setReference_() static const time_t reference = setReference_(); -Scalar getTicks() +Scalar Timer::getTicks() { struct timespec ts; @@ -79,7 +203,7 @@ Scalar getTicks() return Scalar(ts.tv_sec - reference) + Scalar(ts.tv_nsec) / 1000000000.0; } -void sleep(Scalar seconds, bool absolute) +void Timer::sleep(Scalar seconds, bool absolute) { struct timespec ts; int ret; @@ -103,13 +227,13 @@ void sleep(Scalar seconds, bool absolute) // SDL only promises centisecond accuracy, but that's better than a kick in the // butt. -Scalar getTicks() +Scalar Timer::getTicks() { Uint32 ms = SDL_GetTicks(); return Scalar(ms / 1000) + Scalar(ms % 1000) / 1000.0; } -void sleep(Scalar seconds, bool absolute) +void Timer::sleep(Scalar seconds, bool absolute) { if (absolute) seconds -= getTicks(); SDL_Delay(Uint32(cml::clamp(int(seconds * 1000.0), 0, 1000))); diff --git a/src/Moof/Timer.hh b/src/Moof/Timer.hh index 340f79f..6c1af56 100644 --- a/src/Moof/Timer.hh +++ b/src/Moof/Timer.hh @@ -34,30 +34,96 @@ * Functions for measuring time in a friendly unit. */ +#include + +#include +#include + #include namespace Mf { -/** - * Get the number of seconds since a fixed, arbitrary point in the past. - * @return Seconds. - */ +struct Timer +{ + enum Mode + { + INVALID = -1, + NORMAL = 0, + ABSOLUTEE = 1, // the ABSOLUTE keyword isn't available on win32... + REPEAT = 2 + }; -Scalar getTicks(); + typedef boost::function Function; -/** - * Put the thread to sleep for a certain period of time. If absolute is true, - * then it will sleep until seconds after the fixed time in the past. If - * absolute is false, it will sleep for seconds starting now. Unlike system - * sleep functions, this one automatically resumes sleep if sleep was - * interrupted by a signal. Therefore, calling this function is guaranteed to - * sleep for the requested amount of time. - */ + Timer() : + mode_(INVALID) {} + + Timer(const Function& function, Scalar seconds, Mode mode = NORMAL) + { + init(function, seconds, mode); + } + + ~Timer() + { + invalidate(); + } + + void init(const Function& function, Scalar seconds, Mode mode = NORMAL); + + bool isValid() const; + void invalidate(); + + void fire(); + + Scalar getSecondsRemaining() const; + bool isExpired() const; + bool isRepeating() const; + + + /** + * Get the number of seconds since a fixed, arbitrary point in the past. + * @return Seconds. + */ + + static Scalar getTicks(); + + + /** + * Put the thread to sleep for a certain period of time. If absolute is true, + * then it will sleep until seconds after the fixed time in the past. If + * absolute is false, it will sleep for seconds starting now. Unlike system + * sleep functions, this one automatically resumes sleep if sleep was + * interrupted by a signal. Therefore, calling this function is guaranteed to + * sleep for the requested amount of time (and maybe longer). + */ + + static void sleep(Scalar seconds, bool absolute = false); + + + static Scalar getNextFire() + { + return nextFire_; + } + + static void fireIfExpired(Scalar t); + +private: + + static unsigned getNewID(); + static Scalar findNextFire(); + + Function function_; + Mode mode_; + Scalar absolute_; + Scalar interval_; + unsigned id_; -void sleep(Scalar seconds, bool absolute = false); + static Scalar nextFire_; + static std::map timers_; +}; } // namespace Mf diff --git a/src/Moof/Video.cc b/src/Moof/Video.cc index 63970e4..1ed24c7 100644 --- a/src/Moof/Video.cc +++ b/src/Moof/Video.cc @@ -31,6 +31,7 @@ #include #include "Dispatcher.hh" +#include "Log.hh" #include "Serializable.hh" #include "Settings.hh" #include "Video.hh" @@ -84,7 +85,6 @@ void Video::recreateContext() SDL_FreeSurface(context_); context_ = 0; setVideoMode(attribs_.mode); - Mf::Dispatcher::getInstance().dispatch("video.context_recreated"); } void Video::setOpenGLAttributes() @@ -129,6 +129,14 @@ void Video::setVideoMode(const long mode[3]) attribs_.mode[0] = mode[0]; attribs_.mode[1] = mode[1]; attribs_.mode[2] = mode[2]; + +#if defined(_WIN32) || defined (_WIN64) || defined(__WIN32__) + // on win32, creating a new context via SDL_SetVideoMode will wipe + // out the GL state, so we gotta notify everyone to reload their + // state after the change + Mf::dispatcher::dispatch("video.context_recreated"); + logInfo("video context recreated"); +#endif } else throw Exception(SDL_GetError()); } diff --git a/src/YoinkApp.cc b/src/YoinkApp.cc index 77f5c73..a9b8f13 100644 --- a/src/YoinkApp.cc +++ b/src/YoinkApp.cc @@ -30,13 +30,12 @@ #include #include -#include - #include #include #include #include #include +#include #include #include @@ -100,6 +99,28 @@ static std::string iconFile() } +void YoinkApp::myFunc(Mf::Timer& timer, Mf::Scalar t) +{ + std::cout << "timer: " << t << std::endl; + + //timer.invalidate(); +} + +int YoinkApp::myThread() +{ + Mf::Scalar timer = Mf::Timer::getTicks(); + + for (;;) + { + std::cout << "thread awake: " << Mf::Timer::getTicks() << std::endl; + + timer += 3.0; + Mf::Timer::sleep(timer, true); + } + return 0; +} + + YoinkApp::YoinkApp(int argc, char* argv[]) : Mf::Engine(argc, argv, configFiles(), PACKAGE_STRING, iconFile()), music("NightFusionIntro"), @@ -124,6 +145,11 @@ YoinkApp::YoinkApp(int argc, char* argv[]) : octree = Mf::loadScene("Test"); heroine->treeNode = octree->insert(heroine); + + //myTimer.init(boost::bind(&YoinkApp::myFunc, this, _1, _2), + //0.0, Mf::Timer::REPEAT); + //Mf::Thread thread = Mf::detachFunction(boost::bind(&YoinkApp::myThread, this)); + //std::cout << "thread " << thread << " detached." << std::endl; } YoinkApp::~YoinkApp() @@ -176,7 +202,6 @@ void YoinkApp::update(Mf::Scalar t, Mf::Scalar dt) { //dt *= 0.7; - music.update(t, dt); fadeIn.update(dt); camera.update(t, dt); heroine->update(t, dt); @@ -186,7 +211,8 @@ void YoinkApp::update(Mf::Scalar t, Mf::Scalar dt) octree->print(heroine->treeNode); //camera.lookAt(heroine->getSphere().point); - camera.setPosition(Mf::Vector3(-heroine->current.position[0], -heroine->current.position[1], -256)); + camera.setPosition(Mf::Vector3(-heroine->current.position[0], + -heroine->current.position[1], -256)); interp.update(dt); hud.setBar1Progress(interp.getState(dt)); @@ -294,7 +320,8 @@ void YoinkApp::handleEvent(const Mf::Event& event) case SDL_VIDEORESIZE: glViewport(0, 0, event.resize.w, event.resize.h); hud.resize(event.resize.w, event.resize.h); - camera.setProjection(cml::rad(60.0), double(event.resize.w / event.resize.h), 32.0, 2500.0); + camera.setProjection(cml::rad(60.0), + double(event.resize.w) / double(event.resize.h), 32.0, 2500.0); camera.uploadProjectionToGL(); break; } diff --git a/src/YoinkApp.hh b/src/YoinkApp.hh index 950d319..24865c9 100644 --- a/src/YoinkApp.hh +++ b/src/YoinkApp.hh @@ -77,6 +77,10 @@ private: Mf::Camera camera; Mf::OctreeP octree; + void myFunc(Mf::Timer& timer, Mf::Scalar t); + Mf::Timer myTimer; + int myThread(); + Hud hud; };