diff --git a/blockanim.cpp b/blockanim.cpp new file mode 100644 index 0000000..0d505b1 --- /dev/null +++ b/blockanim.cpp @@ -0,0 +1,59 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#include "blockanim.h" + +namespace OpenGTA { + BlockAnimCtrl::BlockAnimCtrl(const DataAnimVector & v) { + for (size_t i = 0; i < v.size(); i++) { + OpenGTA::GraphicsBase::LoadedAnim *da = v[i]; + anims.push_back(new BlockAnim(da)); + } + /* while (i != v.end()) { + OpenGTA::GraphicsBase::LoadedAnim * da = *i; + anims.push_back(new BlockAnim(da)); + i++; + }*/ + + }; + + BlockAnim* BlockAnimCtrl::getAnim(uint8_t area, uint8_t id) { + for (size_t i = 0; i < anims.size(); i++) { + if ((anims[i]->ad_ptr->which == area) && (anims[i]->ad_ptr->block == id)) { + return anims[i]; + } + } + return NULL; + } + + void BlockAnimCtrl::update(uint32_t ticks) { + for (size_t i = 0; i < anims.size(); i++) + anims[i]->update(ticks); + } + + BlockAnimCtrl::~BlockAnimCtrl() { + for (size_t i = 0; i < anims.size(); i++) { + delete anims[i]; + } + anims.clear(); + } +} diff --git a/blockanim.h b/blockanim.h new file mode 100644 index 0000000..4b3f7a9 --- /dev/null +++ b/blockanim.h @@ -0,0 +1,59 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#include "opengta.h" +#include "animation.h" +namespace OpenGTA { + class BlockAnim : public Util::Animation { + public: + BlockAnim(GraphicsBase::LoadedAnim * anim_data) : + // fix for STYLE001.G24 water anim seems one frame longer than data exists! + Util::Animation( + (anim_data->frameCount == 11 && anim_data->which == 1 ? anim_data->frameCount : anim_data->frameCount + 1), + 5), + ad_ptr(anim_data) { + set(PLAY_FORWARD, LOOP); + /* + INFO << "ANIM: " << int(anim_data->block) << " " << int(anim_data->which)<< std::endl; + for (int i= 0; i < anim_data->frameCount; i++) { + INFO << "FRAME " << int(anim_data->frame[i]) << std::endl; + }*/ + } + uint8_t getFrame(uint8_t num) { + return ad_ptr->frame[num]; + } + GraphicsBase::LoadedAnim * ad_ptr; + }; + + class BlockAnimCtrl { + public: + typedef std::vector DataAnimVector; + typedef std::vector BlockAnimVector; + BlockAnimCtrl(const DataAnimVector & v); + ~BlockAnimCtrl(); + void update(uint32_t ticks); + BlockAnim * getAnim(uint8_t area, uint8_t id); + private: + BlockAnimVector anims; + + }; +} diff --git a/blockdata.cpp b/blockdata.cpp index f2a653d..120490b 100644 --- a/blockdata.cpp +++ b/blockdata.cpp @@ -1,3 +1,25 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ #include "blockdata.h" namespace OpenGTA { float BlockData::slope_raw_data[numBlockTypes][numFaces][4][3] = { diff --git a/blockdata.h b/blockdata.h index 27d0a28..a29e07e 100644 --- a/blockdata.h +++ b/blockdata.h @@ -1,3 +1,25 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ #ifndef OPENGTA_BLOCKDATA #define OPENGTA_BLOCKDATA #include diff --git a/bugs.rec b/bugs.rec new file mode 100644 index 0000000..407e6d0 --- /dev/null +++ b/bugs.rec @@ -0,0 +1,19 @@ +Bug: style001.gry bridge texture artifacts +Image: http://skybound.portland.co.uk/ogta/bugs_in_transparent_texture_2006-10-03.jpg +black pixel inside a side texture (nyc.cmp)... thus begins the +'how many errors can there be about black vs. transparent contest'. +%% +Bug: wrong block texture coords +Image: http://lh6.google.com/image/under.northern.sky/RZnek0op0yI/AAAAAAAAAB4/zfCFvPS8gWg/still_slope_tex_errors_2007-01-01.jpg +Most likely the side that is a triangle and not a quad. +Needs research if 'flipping' the texture is related. +%% +Bug: transparent pixel in g24 tiles +Image: http://lh4.google.com/image/under.northern.sky/Rh58SCRd8kI/AAAAAAAAAEQ/FK6KLriTfOs/nyc_gry_block_transparent_pixel_bug_2007-04-12.jpg +Those should probably just be black. It is not a very obvious +error, but it should be fixed. +%% +Bug: black border around sprites +Image: http://lh4.google.com/image/under.northern.sky/Rh58SCRd8lI/AAAAAAAAAEY/tnMwSk8IVok/g24_obj_black_border_2007-04-12.jpg +Simply doesn't look good, especially with g24 graphics. +%% diff --git a/coldet/math3d.cpp b/coldet/math3d.cpp index 99631fc..fcc4fb9 100644 --- a/coldet/math3d.cpp +++ b/coldet/math3d.cpp @@ -91,3 +91,11 @@ void Matrix3D::Translate(const Vector3D & v) m[3][1] += v.x * m[0][1] + v.y * m[1][1] + v.z * m[2][1]; m[3][2] += v.x * m[0][2] + v.y * m[1][2] + v.z * m[2][2]; } + +void Matrix3D::RotZ(float angle) { + const float TO_RAD = M_PI / 180.0f; + m[0][0] = cosf(angle*TO_RAD); + m[1][0] = sinf(angle*TO_RAD); + m[0][1] = -sinf(angle*TO_RAD); + m[1][1] = cosf(angle*TO_RAD); +} diff --git a/coldet/math3d.h b/coldet/math3d.h index d7dc4e2..a31d6c3 100644 --- a/coldet/math3d.h +++ b/coldet/math3d.h @@ -140,6 +140,7 @@ struct Matrix3D float operator() (int i, int j) const { return m[i][j]; } float& operator() (int i, int j) { return m[i][j]; } + void RotZ(float v); }; struct Plane diff --git a/datahelper.cpp b/datahelper.cpp new file mode 100644 index 0000000..825132f --- /dev/null +++ b/datahelper.cpp @@ -0,0 +1,27 @@ +#include "datahelper.h" +#include "opengta.h" +#include "cistring.h" +#include "m_exceptions.h" +#include "log.h" + +namespace OpenGTA { + namespace Helper { + // level-filename to index-into-message-db + // needed for area-name lookup + size_t mapFileName2Number(const std::string & file) { + size_t num = 0; + Util::ci_string ci_file(file.c_str()); +#define STRING_TEST(n) ci_file.find(n) != std::string::npos + if (STRING_TEST("nyc.cmp")) + num = 1; + else if (STRING_TEST("sanb.cmp")) + num = 2; + else if (STRING_TEST("miami.cmp")) + num = 3; + else + ERROR << "unknown level: " << file << std::endl; +#undef STRING_TEST + return num; + } + } +} diff --git a/datahelper.h b/datahelper.h new file mode 100644 index 0000000..71f0982 --- /dev/null +++ b/datahelper.h @@ -0,0 +1,7 @@ +#include + +namespace OpenGTA { + namespace Helper { + size_t mapFileName2Number(const std::string & file); + } +} diff --git a/dataholder.cpp b/dataholder.cpp index 3bf8296..e0e73c8 100644 --- a/dataholder.cpp +++ b/dataholder.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * @@ -34,7 +34,8 @@ namespace OpenGTA { } template<> GraphicsBase & ActiveStyle::get() { - assert(m_data); + if (!m_data) + throw E_NOTSUPPORTED("Load a style-file first!"); return *m_data; } @@ -81,7 +82,8 @@ namespace OpenGTA { } template<> Map & ActiveMap::get() { - assert(m_data); + if (!m_data) + throw E_NOTSUPPORTED("Load a map-file first!"); return *m_data; } @@ -97,4 +99,30 @@ namespace OpenGTA { assert(m_data); } + template<> MainMsgLookup::ActiveData() { + m_data = 0; + } + + template<> MainMsgLookup::~ActiveData() { + unload(); + } + + template<> MessageDB & MainMsgLookup::get() { + if (!m_data) + throw E_NOTSUPPORTED("Load a message-file first!"); + return *m_data; + } + + template<> void MainMsgLookup::load(const std::string & file) { + unload(); + try { + m_data = new MessageDB(file); + } + catch (const Exception & e) { + ERROR << "loading message-db failed: " << e.what(); + m_data = 0; + } + assert(m_data); + } + } diff --git a/dataholder.h b/dataholder.h index 9db4982..f2c0ded 100644 --- a/dataholder.h +++ b/dataholder.h @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * @@ -28,18 +28,11 @@ #include "Singleton.h" namespace OpenGTA { -/* - class ActiveStyle { - public: - ActiveStyle(); - ~ActiveStyle(); - GraphicsBase & getStyle(); - void load(const std::string & file); - private: - void unload(); - GraphicsBase* m_style; - }; -*/ + /** Wrapper around resource-holding classes. + * - you have to call 'load' before 'get' + * + * - you may call load repeatedly + */ template class ActiveData { public: @@ -52,13 +45,30 @@ namespace OpenGTA { T* m_data; }; + /** The wrapper around the GRY/G24 data interface. + */ typedef ActiveData< GraphicsBase > ActiveStyle; + /** The wrapper around the map data interface. + */ typedef ActiveData< Map > ActiveMap; + /** The wrapper around the message-string data interface. + */ + typedef ActiveData< MessageDB > MainMsgLookup; + /** Singleton: Graphics + */ typedef Loki::SingletonHolder< ActiveStyle, Loki::CreateUsingNew, Loki::DefaultLifetime, Loki::SingleThreaded> StyleHolder; + /** Singleton: Map + */ typedef Loki::SingletonHolder< ActiveMap, Loki::CreateUsingNew, Loki::DefaultLifetime, Loki::SingleThreaded> MapHolder; + /** Singleton: Message strings + */ + typedef Loki::SingletonHolder< MainMsgLookup, Loki::CreateUsingNew, Loki::DefaultLifetime, + Loki::SingleThreaded> MainMsgHolder; + + } #endif diff --git a/doc/doc_links.txt b/doc/doc_links.txt index c950869..d963234 100644 --- a/doc/doc_links.txt +++ b/doc/doc_links.txt @@ -17,6 +17,7 @@ Corrections and Notes regarding DMA GTA technical doument [cds.doc v12.10] http://www.fifengr.com/gtacars/topic.html --- other links --- + A Stream-based Time Synchronization Technique For Networked Computer Games http://www.mine-control.com/zack/timesync/timesync.html diff --git a/doc/hacking.txt b/doc/hacking.txt index 0eb692b..01362a7 100644 --- a/doc/hacking.txt +++ b/doc/hacking.txt @@ -48,7 +48,7 @@ the most important formats. Reading _(cds.doc) is probably vital; you may want them all. So in no particular order: -include(`doc/doc_links.txt')dnl ~oh m4, your glorious thing~ +include(`doc/doc_links.txt')dnl ~oh m4, you glorious thing~ Support for the following formats is implemented: - CMP (compressed map) #OpenGTA::Map @@ -68,12 +68,14 @@ using the graphics loaded inside a derived instance of CityView maintains a couple of #OpenGL::TextureCache (s) to store the texture-ids (for the static city blocks). +In case of animated block textures #OpenGTA::BlockAnim and +#OpenGTA::BlockAnimCtrl are used to display a sequence of textures. + #OpenGTA::BlockData contains the vertex data and texture coords for each of the of the possible blocks; this corresponds to #OpenGTA::Map::BlockInfo::slopeType. -Drawing of objects (sprites) is being moved into #OpenGTA::SpriteManager, -though this is not yet complete. +Drawing of objects (sprites) is done in #OpenGTA::SpriteManager. #OpenGL::DrawableFont can display strings using the bitmaps from a #OpenGTA::Font. diff --git a/entity_controller.cpp b/entity_controller.cpp new file mode 100644 index 0000000..6f66809 --- /dev/null +++ b/entity_controller.cpp @@ -0,0 +1,198 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#include "entity_controller.h" +#include "log.h" +#include "m_exceptions.h" + +namespace OpenGTA { + EntityController::EntityController() : + rawData(0), + dataSet(sizeof(rawData) * 8, (unsigned char*)&rawData) {} + + EntityController::EntityController(const EntityController & other) : + rawData(other.rawData), + dataSet(sizeof(rawData) * 8, (unsigned char*)&rawData) {} + + void EntityController::zero() { + rawData = 0; + } + + void EntityController::setRaw(Storage_T v) { + rawData = v; + } + + void PedController::setTurnLeft(bool press) { + dataSet.set_item(0, press); + } + + void PedController::setTurnRight(bool press) { + dataSet.set_item(1, press); + } + + void PedController::setMoveForward(bool press) { + dataSet.set_item(2, press); + } + + void PedController::setMoveBack(bool press) { + dataSet.set_item(3, press); + } + + void PedController::setAction(bool press) { + dataSet.set_item(4, press); + } + + void PedController::setJump(bool press) { + dataSet.set_item(5, press); + } + + void PedController::setFireWeapon(bool press) { + dataSet.set_item(6, press); + } + + signed char PedController::getTurn() { + if (dataSet.get_item(0) && dataSet.get_item(1)) // special: straight ahead + return 0; + if (dataSet.get_item(0)) + return 1; + else if (dataSet.get_item(1)) + return -1; + return 0; + } + + signed char PedController::getMove() { + if (dataSet.get_item(2) && dataSet.get_item(3)) // special: evens out + return 0; + if (dataSet.get_item(2)) + return 1; + else if (dataSet.get_item(3)) + return -1; + return 0; + } + + bool PedController::getAction() { + return dataSet.get_item(4); + } + + bool PedController::getJump() { + return dataSet.get_item(5); + } + + bool PedController::getFireWeapon() { + return dataSet.get_item(6); + } + + void PedController::setRunning(bool yes) { + dataSet.set_item(7, yes); + } + + bool PedController::getRunning() { + return dataSet.get_item(7); + } + + unsigned char PedController::getActiveWeapon() { + // 0 .. k + unsigned char r = 0; + for (int j = 0; j < 3; ++j) { + if (dataSet.get_item(j + 8)) + r += (1 << j); + } + return r; + } + + void PedController::setActiveWeapon(unsigned char k) { + if (k > 7) { + throw E_OUTOFRANGE("foo"); + } + for (int j = 0; j < 3; ++j) { + if (k & 1u) + dataSet.set_item(j + 8, true); + else + dataSet.set_item(j + 8, false); + k >>= 1; + } + } + +#if 0 +#include +#include "localplayer.h" +class ConfigurableKeyConsumer { + static const SDLKey sym_array[]; + static const int TURN_LEFT = 0; + static const int TURN_RIGHT = 1; + static const int MOVE_FORWARD = 2; + static const int MOVE_BACKWARD = 3; + public: + void handle(const SDL_keysym & ks, bool press) { + PedController & pc = LocalPlayer::Instance().getCtrl(); + if (ks.sym == sym_array[TURN_LEFT]) { + pc.setTurnLeft(true); + return; + } + else if (ks.sym == sym_array[TURN_RIGHT]) { + pc.setTurnRight(true); + return; + } + } +}; +#endif + +#if 0 +#include +#include "localplayer.h" + + template + class ClassicKeyConsumer { + public: + bool handle(const SDL_keysym & ks, bool press); + }; + + template <> bool ClassicKeyConsumer::handle(const SDL_keysym & ks, bool press) { + bool swallow_event = true; + PedController & pc = LocalPlayer::Instance().getEntity().m_control; + switch(ks.sym) { + case SDLK_LEFT: + pc.setTurnLeft(press); + break; + case SDLK_RIGHT: + pc.setTurnRight(press); + break; + case SDLK_UP: + pc.setMoveForward(press); + break; + case SDLK_DOWN: + pc.setMoveBack(press); + break; + case SDLK_RETURN: + pc.setAction(press); + break; + case SDLK_SPACE: + pc.setJump(press); + break; + default: + swallow_event = false; + break; + } + return swallow_event; + } +#endif +} diff --git a/entity_controller.h b/entity_controller.h new file mode 100644 index 0000000..ab2f9ca --- /dev/null +++ b/entity_controller.h @@ -0,0 +1,102 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#ifndef OBJECT_CONTROLLER_H +#define OBJECT_CONTROLLER_H + +#include +#include "set.h" + +namespace OpenGTA { + class EntityController { + public: + EntityController(); + + void zero(); + typedef uint32_t Storage_T; + void setRaw(Storage_T v); + protected: + EntityController(const EntityController & other); + Storage_T rawData; + Util::Set dataSet; + }; + + class Pedestrian; + class PedController : public EntityController { + public: + PedController() {} + PedController(const PedController & other) : EntityController(other) {} + void setTurnLeft(bool press = true); + inline void releaseTurnLeft() { setTurnLeft(false); } + void setTurnRight(bool press = true); + inline void releaseTurnRight() { setTurnRight(false); } + signed char getTurn(); + void setMoveForward(bool press = true); + inline void releaseMoveForward() { setMoveForward(false); } + void setMoveBack(bool press = true); + inline void releaseMoveBack() { setMoveBack(false); } + signed char getMove(); + void setAction(bool press = true); + inline void releaseAction() { setAction(false); } + bool getAction(); + // bool getAction(); + void setJump(bool press = true); + inline void releaseJump() { setJump(false); } + bool getJump(); + // bool getJump(); + void setFireWeapon(bool press = true); + inline void releaseFireWeapon() { setFireWeapon(false); } + bool getFireWeapon(); + + void setActiveWeapon(unsigned char); + unsigned char getActiveWeapon(); + + void setRunning(bool yes = true); + inline void releaseRunning() { setRunning(false); } + bool getRunning(); + + // weapons, equip, shoot + }; + + class VehicleController : public EntityController { + public: + VehicleController() {} + VehicleController(const VehicleController & other) : EntityController(other) {} + void setTurnLeft(bool press = true); + inline void releaseTurnLeft() { setTurnLeft(false); } + void setTurnRight(bool press = true); + inline void releaseTurnRight() { setTurnRight(false); } + void setAccelerate(bool press = true); + inline void releaseAccelerate() { setAccelerate(false); } + void setReverse(bool press = true); + inline void releaseReverse() { setReverse(false); } + void setHandbrake(bool press = true); + inline void releaseHandbrake() { setHandbrake(false); } + void setAction(bool press = true); + inline void releaseAction() { setAction(false); } + + // vehicle specials + }; + + // HeliController? +} +#endif diff --git a/font_cache.cpp b/font_cache.cpp index 91fae9b..1bd9146 100644 --- a/font_cache.cpp +++ b/font_cache.cpp @@ -1,3 +1,25 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ #include "font_cache.h" namespace OpenGTA { @@ -5,6 +27,10 @@ namespace OpenGTA { } FontCache::~FontCache() { + for (FontMap::iterator i = loadedFonts.begin(); i != loadedFonts.end(); i++) { + delete i->second; + } + loadedFonts.clear(); } OpenGL::DrawableFont & FontCache::getFont(const std::string & file, diff --git a/font_cache.h b/font_cache.h index bfa2802..cd0b357 100644 --- a/font_cache.h +++ b/font_cache.h @@ -1,3 +1,25 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ #ifndef FONT_CACHE_H #define FONT_CACHE_H #include diff --git a/fx_sdt.h b/fx_sdt.h index dc540e9..175a5b5 100644 --- a/fx_sdt.h +++ b/fx_sdt.h @@ -5,7 +5,7 @@ */ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * diff --git a/pedestrian.cpp b/game_objects.cpp similarity index 53% rename from pedestrian.cpp rename to game_objects.cpp index 42a5799..8685ab8 100644 --- a/pedestrian.cpp +++ b/game_objects.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * @@ -20,80 +20,21 @@ * 3. This notice may not be removed or altered from any source * * distribution. * ************************************************************************/ -#include "pedestrian.h" +#include "game_objects.h" #include "spritemanager.h" -#include "opengta.h" #include "dataholder.h" -#include "log.h" +#include "cell_iterator.h" +#include "timer.h" +#include "Functor.h" + +#define INT2FLOAT_WRLD(c) (float(c >> 6) + float(c % 64) / 64.0f) +#define INT2F_DIV64(v) (float(v) / 64.0f) +#define INT2F_DIV128(v) (float(v) / 128.0f) float slope_height_offset(unsigned char slope_type, float dx, float dz); + namespace OpenGTA { - Projectile::Projectile(uint8_t id, float r, Vector3D p, Vector3D d, Uint32 now) : - typeId(id), rot(r), pos(p), delta(d), endsAtTick(now + 5000) {} - - SpriteObject::Animation::Animation() : - Util::Animation(7, 7), - firstFrameOffset(0), moveSpeed(0.0f) {} - - SpriteObject::Animation::Animation(const Animation & other) : - Util::Animation(other.numFrames, 1000 / other.delay), - firstFrameOffset(other.firstFrameOffset), - //numFrames(other.numFrames), - moveSpeed(other.moveSpeed) {} - - SpriteObject::Animation::Animation(Uint16 foff, Uint8 num) : - Util::Animation(num, 7), - firstFrameOffset(foff), moveSpeed(0.0f) {} - - SpriteObject::Animation::Animation(Uint16 foff, Uint8 num, float speed) : - Util::Animation(num, 7), - firstFrameOffset(foff), moveSpeed(speed) {} - - SpriteObject::SpriteObject(const Vector3D & p) : - pos(p), //animRef(&SpriteManagerHolder::Instance().getAnimationById(0)) { - anim(SpriteManagerHolder::Instance().getAnimationById(0)) { - sprNum = 0; - remap = -1; - //curFrame = 0; - lastFrameUpdateAt = 0; - lastUpdateAt = 0; - rot = 0.0f; - animActive = false; - sprType = GraphicsBase::SpriteNumbers::ARROW; - } - - Uint8 SpriteObject::calcCurrentFrame(Uint32 ticks) { - Uint32 delta = ticks - lastFrameUpdateAt; - //assert(animRef); - if (delta > 100) { - //curFrame += 1; - //INFO << "new frame: " << int(curFrame) << " total: " << sprNum + curFrame + anim.firstFrameOffset << std::endl; - lastFrameUpdateAt = ticks; - } - /* - if (curFrame > anim.numFrames) - curFrame = 0; - */ - return 0;//curFrame; - } - - SpriteObject::SpriteObject(const SpriteObject & other) : - pos(other.pos), anim(other.anim) { - copyValues(other); - } - - void SpriteObject::copyValues(const SpriteObject & other) { - sprNum = other.sprNum; - //curFrame = other.curFrame; - remap = other.remap; - lastFrameUpdateAt = other.lastFrameUpdateAt; - lastUpdateAt = other.lastUpdateAt; - rot = other.rot; - sprType = other.sprType; - animActive = other.animActive; - } - - float SpriteObject::heightOverTerrain(const Vector3D & v) { + float GameObject_common::heightOverTerrain(const Vector3D & v) { float x, y, z; x = floor(v.x); y = floor(v.y); @@ -102,9 +43,18 @@ namespace OpenGTA { x_b = (PHYSFS_uint8)x; z_b = (PHYSFS_uint8)z; if (y < 0.0f) { - ERROR << "Below level! at coords: " << v.x << ", " << v.y << ", " << v.z << std::endl; + //ERROR << "Below level! at coords: " << v.x << ", " << v.y << ", " << v.z << std::endl; return 1.0f; } + if (x < 0 || x > 255 || z < 0 || z > 255) { + //ERROR << "x = " << x << "(" << v.x << ") z = " << z << " (" << v.z << ")" << std::endl; + throw E_OUTOFRANGE("invalid x/z pos"); + } + if (y > 20) { + INFO << y << " seems a bit high; going to 20" << std::endl; + INFO << x << " " << z << std::endl; + y = 20; + } OpenGTA::Map & map = OpenGTA::MapHolder::Instance().get(); while (y >= map.getNumBlocksAtNew(x_b, z_b) && y > 0.0f) y -= 1.0f; @@ -135,75 +85,184 @@ namespace OpenGTA { return 1.0f; } - Pedestrian::Pedestrian(const Vector3D & e, - const Vector3D & p) : SpriteObject(p), - OBox(RollMatrix3D(0), e * 0.5f) { - m_M.Translate(p); - pedId = 0; - m_control = 0; - animId = 0; - inGroundContact = 0; - sprType = GraphicsBase::SpriteNumbers::PED; - activeWeapon = 0; - speedForces = Vector3D(0, 0, 0); - weaponReloadedAt = 0; - } + Sprite::Animation::Animation() : + Util::Animation(7, 7), + firstFrameOffset(0), moveSpeed(0.0f) {} - Pedestrian::Pedestrian(const Vector3D & e, - const Vector3D & p, const Uint32 & asId) : SpriteObject(p), - OBox(RollMatrix3D(0), e * 0.5f) { - m_M.Translate(p); - pedId = asId; - m_control = 0; - animId = 0; - inGroundContact = 0; - sprType = GraphicsBase::SpriteNumbers::PED; - activeWeapon = 0; - speedForces = Vector3D(0, 0, 0); - weaponReloadedAt = 0; - } + Sprite::Animation::Animation(const Animation & other) : + //Util::Animation(other.numFrames, 1000 / other.delay), + Util::Animation(other), + firstFrameOffset(other.firstFrameOffset), + //numFrames(other.numFrames), + moveSpeed(other.moveSpeed) { + set(other.get(), other.getDone()); + } - Pedestrian::Pedestrian(const Pedestrian & other) : SpriteObject(other), - OBox(other.m_M, other.m_Extent) { - //animRef(SpriteManagerHolder::Instance().getAnimationById(other.animId)) { - copyValues(other); - } + Sprite::Animation::Animation(Uint16 foff, Uint8 num) : + Util::Animation(num, 7), + firstFrameOffset(foff), moveSpeed(0.0f) {} - void Pedestrian::switchToAnim(const Uint32 & newId) { + Sprite::Animation::Animation(Uint16 foff, Uint8 num, float speed) : + Util::Animation(num, 7), + firstFrameOffset(foff), moveSpeed(speed) {} + + Sprite::Sprite() : + sprNum(0), remap(-1), + //anim(SpriteManagerHolder::Instance().getAnimationById(0)), + anim(), animId(), + sprType(GraphicsBase::SpriteNumbers::ARROW) { + } + + Sprite::Sprite(Uint16 sprN, Sint16 rem, GraphicsBase::SpriteNumbers::SpriteTypes sprT) : + sprNum(sprN), remap(rem), + anim(), animId(), + sprType(sprT) {} + + Sprite::Sprite(const Sprite & other) : + sprNum(other.sprNum), remap(other.remap), anim(other.anim), animId(other.animId), + sprType(other.sprType) { + } + + void Sprite::switchToAnim(const Uint32 & newId) { + INFO << "switching to anim " << newId << std::endl; anim = Animation(SpriteManagerHolder::Instance().getAnimationById(newId)); anim.set(Util::Animation::PLAY_FORWARD, Util::Animation::LOOP); animId = newId; - //curFrame = 0; } - void SpriteObject::setAnimation(Animation & otherAnim) { - anim = Animation(otherAnim); - //curFrame = 0; - // FIXME: animId? + Pedestrian::Pedestrian(Vector3D e, const Vector3D & p, uint32_t id, Sint16 remapId) : + GameObject_common(p), + Sprite(0, remapId, GraphicsBase::SpriteNumbers::PED), + OBox(TranslateMatrix3D(p), e * 0.5f), + m_control(), + speedForces(0, 0, 0) { + m_M = TranslateMatrix3D(p); + m_M.RotZ(rot); + pedId = id; + animId = 0; + isDead = 0; + lastUpdateAt = TimerHolder::Instance().getRealTime(); + inGroundContact = 0; + } + + Pedestrian::Pedestrian(const Pedestrian & other) : + GameObject_common(other), Sprite(other), OBox(other), + + pedId(other.pedId), + m_control(), + speedForces(other.speedForces) { + lastUpdateAt = other.lastUpdateAt; + inGroundContact = other.inGroundContact; + animId = other.animId; + isDead = other.isDead; + m_M = TranslateMatrix3D(other.pos); + m_M.RotZ(other.rot); + } + + extern void ai_step_fake(Pedestrian*); + void Pedestrian::update(Uint32 ticks) { + if (isDead) { + anim.update(ticks); + lastUpdateAt = ticks; + return; + } + if (pedId < 0xffffffff) + ai_step_fake(this); + uint8_t activeWeapon = m_control.getActiveWeapon(); + switch(m_control.getMove()) { + case 1: + //if (!(animId == 2u + activeWeapon*3)) + // switchToAnim(2 + activeWeapon*3); + if (m_control.getRunning()) { + if (!(animId == 3u + activeWeapon*3)) + switchToAnim(3 + activeWeapon*3); + } + else { + if (!(animId == 2u + activeWeapon*2)) + switchToAnim(2 + activeWeapon*2); + } + break; + /* + case 2: + if (!(animId == 3u + activeWeapon*3)) + switchToAnim(3 + activeWeapon*3); + break; + */ + case 0: + if (!(animId == 1u + activeWeapon*3)) + switchToAnim(1 + activeWeapon*3); + break; + case -1: + if (!(animId == 2u + activeWeapon*3)) { + switchToAnim(2 + activeWeapon*3); + anim.set(Util::Animation::PLAY_BACKWARD, Util::Animation::LOOP); + } + } + anim.update(ticks); + Uint32 delta = ticks - lastUpdateAt; + //INFO << "delta = " << delta << " t: " << ticks << " lt: " << lastUpdateAt << std::endl; + Vector3D moveDelta(0, 0, 0); + switch(m_control.getTurn()) { + case -1: + rot -= 0.2f * delta; + //INFO << "rot: "<< rot << std::endl; + break; + case 1: + rot += 0.2f * delta; + //INFO << "rot: "<< rot << std::endl; + break; + case 0: + break; + } + if (rot >= 360.0f) + rot -= 360.0f; + if (rot < 0.0f) + rot += 360.0f; + switch(m_control.getMove()) { + case -1: + moveDelta.x -= sin(rot * M_PI / 180.0f) * anim.moveSpeed * delta; + moveDelta.z -= cos(rot * M_PI / 180.0f) * anim.moveSpeed * delta; + break; + case 1: + moveDelta.x += sin(rot * M_PI / 180.0f) * anim.moveSpeed * delta; + moveDelta.z += cos(rot * M_PI / 180.0f) * anim.moveSpeed * delta; + break; + case 2: + moveDelta.x += sin(rot * M_PI / 180.0f) * anim.moveSpeed * delta; + moveDelta.z += cos(rot * M_PI / 180.0f) * anim.moveSpeed * delta; + break; + case 0: + break; + } + tryMove(pos + moveDelta); + if (!inGroundContact) { + speedForces.y += 0.0005f *delta; + pos.y -= speedForces.y; + if (speedForces.y < 0.2f) + INFO << "bridge step? height: " << pos.y << " speed: " << speedForces.y << std::endl; + else + INFO << "FALLING " << pos.y << " speed " << speedForces.y << std::endl; + } + else { + if (speedForces.y > 0.1) + INFO << "impacting with speed: " << speedForces.y << std::endl; + speedForces.y = 0.0f; + } + m_M = TranslateMatrix3D(pos); + m_M.RotZ(rot); + if (m_control.getFireWeapon() && ticks - lastWeaponTick > 400) { + Vector3D d1( + //Vector3D(-cos(rot * M_PI/180.0f), 0, sin(rot * M_PI/180.0f)).Normalized() * 0.05f + Vector3D(sin(rot * M_PI/180.0f), 0, cos(rot * M_PI/180.0f)).Normalized() * 0.01f + ); + SpriteManagerHolder::Instance().createProjectile(0, rot, pos, d1, ticks, pedId); + lastWeaponTick = ticks; + } + //INFO << pos.x << " " << pos.y << " " << pos.z << std::endl; + lastUpdateAt = ticks; } - void Pedestrian::copyValues(const Pedestrian & other) { - - m_control = other.m_control; - animId = other.animId; - pedId = other.pedId; - inGroundContact = other.inGroundContact; - sprType = other.sprType; - speedForces = other.speedForces; - activeWeapon = other.activeWeapon; - inventory = other.inventory; - weaponReloadedAt = other.weaponReloadedAt; - } - - void Pedestrian::giveItem(uint8_t id, uint32_t amount) { - InventoryType::iterator i = inventory.find(id); - if (i == inventory.end()) - inventory[id] = amount; - else - i->second += amount; - } - - void Pedestrian::tryMove(Vector3D nPos) { + void Pedestrian::tryMove(Vector3D nPos) { float x, y, z; x = floor(nPos.x); y = floor(nPos.y); @@ -212,7 +271,7 @@ namespace OpenGTA { OpenGTA::GraphicsBase & graphics = OpenGTA::StyleHolder::Instance().get(); //INFO << heightOverTerrain(nPos) << std::endl; float hot = heightOverTerrain(nPos); - if (hot > 0.3f) + if (hot > 0.1f) inGroundContact = 0; else if (hot < 0.0) { INFO << "gone below: " << hot << " at " << nPos.x << ", " << nPos.y << ", " << nPos.z << std::endl; @@ -222,6 +281,10 @@ namespace OpenGTA { } else { inGroundContact = 1; + if (isDead) + nPos.y -= hot - 0.05f; + else + nPos.y -= hot - 0.1f; } if (y < map.getNumBlocksAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z)) && y > 0.0f) { //INFO << x << ", " << y << ", " << z << ": " << int(map.getNumBlocksAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z))) << std::endl; @@ -259,7 +322,9 @@ namespace OpenGTA { nPos.x = pos.x; } else { +#ifdef DEBUG_OLD_PED_BLOCK INFO << "xblock left: " << x - pos.x << " tex: " << int(block->left) << std::endl; +#endif if (x - pos.x > 0 && x - pos.x < 0.2f) nPos.x = pos.x; else if (x - pos.x < 0 && x - pos.x > -0.2f) @@ -267,7 +332,9 @@ namespace OpenGTA { } } if (block->right && block->isFlat() == false) { +#ifdef DEBUG_OLD_PED_BLOCK INFO << "xblock right: " << pos.x - x - 1 << " tex: " << int(block->right) << std::endl; +#endif if (pos.x - x - 1 > 0 && pos.x - x - 1 < 0.2f) { nPos.x = pos.x; } @@ -276,14 +343,18 @@ namespace OpenGTA { } if (block->top && graphics.isBlockingSide(block->top)) { // && block->isFlat() == false) { if (block->isFlat()) { +#ifdef DEBUG_OLD_PED_BLOCK INFO << "zblock top: " << z - pos.z << " tex: " << int(block->top) << std::endl; +#endif if (z - pos.z > 0 && z - pos.z < 0.2f) nPos.z = pos.z; else if (z - pos.z < 0 && z - pos.z > -0.2f) nPos.z = (nPos.z < pos.z) ? pos.z : nPos.z; } else { +#ifdef DEBUG_OLD_PED_BLOCK INFO << "zblock top: " << z - pos.z << " tex: " << int(block->top)<< std::endl; +#endif if (z - pos.z > 0 && z - pos.z < 0.2f) nPos.z = pos.z; else if (z - pos.z < 0 && z - pos.z > -0.2f) @@ -291,7 +362,9 @@ namespace OpenGTA { } } if (block->bottom && block->isFlat() == false) { +#ifdef DEBUG_OLD_PED_BLOCK INFO << "zblock bottom: " << pos.z - z - 1<< " tex: " << int(block->bottom)<< std::endl; +#endif if (pos.z - z - 1 > 0 && pos.z - z - 1 < 0.2f) { nPos.z = pos.z; } @@ -301,7 +374,9 @@ namespace OpenGTA { if (x >= 1 && y < map.getNumBlocksAtNew(PHYSFS_uint8(x-1), PHYSFS_uint8(z))) { block = map.getBlockAtNew(PHYSFS_uint8(x-1), PHYSFS_uint8(z), PHYSFS_uint8(y)); if (block->right && block->isFlat() == false) { +#ifdef DEBUG_OLD_PED_BLOCK INFO << "xblock right: " << pos.x - x << " tex: " << int(block->right)<< std::endl; +#endif if (pos.x - x < 0.2f) { nPos.x = (nPos.x < pos.x ? pos.x : nPos.x); } @@ -310,7 +385,9 @@ namespace OpenGTA { if (x < 255 && y < map.getNumBlocksAtNew(PHYSFS_uint8(x+1), PHYSFS_uint8(z))) { block = map.getBlockAtNew(PHYSFS_uint8(x+1), PHYSFS_uint8(z), PHYSFS_uint8(y)); if (block->left && graphics.isBlockingSide(block->left)) { // && block->isFlat() == false) { +#ifdef DEBUG_OLD_PED_BLOCK INFO << "xblock left: " << x + 1 - pos.x << " tex: " << int(block->left)<< std::endl; +#endif if (block->isFlat()) { if (x + 1 - pos.x > 0 && x + 1 - pos.x < 0.2f) nPos.x = (nPos.x < pos.x ? nPos.x : pos.x); @@ -324,7 +401,9 @@ namespace OpenGTA { if (z >= 1 && y < map.getNumBlocksAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z-1))) { block = map.getBlockAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z-1), PHYSFS_uint8(y)); if (block->bottom && block->isFlat() == false) { +#ifdef DEBUG_OLD_PED_BLOCK INFO << "zblock bottom: " << pos.z - z<< " tex: " << int(block->bottom)<< std::endl; +#endif if (pos.z - z < 0.2f) { nPos.z = (nPos.z < pos.z ? pos.z : nPos.z); } @@ -333,7 +412,9 @@ namespace OpenGTA { if (z < 255 && y < map.getNumBlocksAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z+1))) { block = map.getBlockAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z+1), PHYSFS_uint8(y)); if (block->top && graphics.isBlockingSide(block->top)) { // && block->isFlat() == false) { +#ifdef DEBUG_OLD_PED_BLOCK INFO << "zblock top: " << z + 1 - pos.z<< " tex: " << int(block->top) << std::endl; +#endif if (block->isFlat()) { if (z + 1 - pos.z > 0 && z + 1 - pos.z < 0.2f) nPos.z = (nPos.z < pos.z ? nPos.z : pos.z); @@ -354,162 +435,152 @@ namespace OpenGTA { } - void Pedestrian::equip(uint8_t id) { - if (id == 0) { - activeWeapon = 0; - } - else { - InventoryType::iterator i = inventory.find(id); - if (i != inventory.end()) { - activeWeapon = i->first; - } - else - ERROR << "Ped does not have item type " << int(id) << std::endl; - } + void Pedestrian::die() { + INFO << "DIE!!!" << std::endl; + switchToAnim(42); } - void Pedestrian::fireWeapon(Uint32 ticks) { - if (activeWeapon == 0) - return; // FIXME: punching! - InventoryType::iterator i = inventory.find(activeWeapon); - if (i->second == 0) - return; // no ammo - if (ticks < weaponReloadedAt) - return; - - weaponReloadedAt = ticks + 2000; - OpenGTA::SpriteManagerHolder::Instance().createProjectile(i->first, rot, pos, Vector3D(0.2f, 0, 0.2f), ticks); - + void Pedestrian::getShot(bool front) { + isDead = 1; + switchToAnim(45); + anim.set(Util::Animation::PLAY_FORWARD, Util::Animation::FCALLBACK); + Loki::Functor cmd(this, &Pedestrian::die); + anim.setCallback(cmd); } - void Pedestrian::update(Uint32 ticks) { - // update the animation - if (m_control) { - switch(m_control->move) { - case 1: - if (!(animId == 2u + activeWeapon*3)) - switchToAnim(2 + activeWeapon*3); - break; - case 2: - if (!(animId == 3u + activeWeapon*3)) - switchToAnim(3 + activeWeapon*3); - break; - case 0: - if (!(animId == 1u + activeWeapon*3)) - switchToAnim(1 + activeWeapon*3); - break; - case -1: - if (!(animId == 2u + activeWeapon*3)) { - switchToAnim(2 + activeWeapon*3); - anim.set(Util::Animation::PLAY_BACKWARD, Util::Animation::LOOP); - } - } - } - anim.update(ticks); - // update position/rotation - Uint32 delta = ticks - lastUpdateAt; - Vector3D moveDelta(0, 0, 0); - if (m_control) { - switch(m_control->turn) { - case -1: - rot -= 0.2f * delta; - break; - case 1: - rot += 0.2f * delta; - break; - case 0: - break; - } - if (rot >= 360.0f) - rot -= 360.0f; - if (rot < 0.0f) - rot += 360.0f; - switch(m_control->move) { - case -1: - moveDelta.x -= sin(rot * M_PI / 180.0f) * anim.moveSpeed * delta; - moveDelta.z -= cos(rot * M_PI / 180.0f) * anim.moveSpeed * delta; - break; - case 1: - moveDelta.x += sin(rot * M_PI / 180.0f) * anim.moveSpeed * delta; - moveDelta.z += cos(rot * M_PI / 180.0f) * anim.moveSpeed * delta; - break; - case 2: - moveDelta.x += sin(rot * M_PI / 180.0f) * anim.moveSpeed * delta; - moveDelta.z += cos(rot * M_PI / 180.0f) * anim.moveSpeed * delta; - break; - case 0: - break; - } - } - tryMove(pos + moveDelta); - if (!inGroundContact) { - speedForces.y += 0.1f; - pos.y -= speedForces.y; - if (speedForces.y < 0.2f) - INFO << "bridge step? height: " << pos.y << " speed: " << speedForces.y << std::endl; - else - INFO << "FALLING" << pos.y << " speed " << speedForces.y << std::endl; - } - else { - if (speedForces.y > 0.1) - INFO << "impacting with speed: " << speedForces.y << std::endl; - speedForces.y = 0.0f; - } - lastUpdateAt = ticks; - - } - -#define INT2FLOAT_WRLD(c) (float(c >> 6) + float(c % 64) / 64.0f) -#define INT2F_DIV64(v) (float(v) / 64.0f) -#define INT2F_DIV128(v) (float(v) / 128.0f) - - Car::Car(const OpenGTA::Map::ObjectPosition & op) : - SpriteObject(Vector3D(INT2FLOAT_WRLD(op.x), 6.05f-INT2FLOAT_WRLD(op.z), INT2FLOAT_WRLD(op.y))), - OBox(RollMatrix3D(0), Vector3D()), - c_info(*StyleHolder::Instance().get().findCarByModel(op.type)) { + Car::Car(OpenGTA::Map::ObjectPosition& op, uint32_t id) : + GameObject_common(Vector3D(INT2FLOAT_WRLD(op.x), 6.05f-INT2FLOAT_WRLD(op.z), INT2FLOAT_WRLD(op.y))), + Sprite(0, -1, GraphicsBase::SpriteNumbers::CAR), OBox(), + carInfo(*StyleHolder::Instance().get().findCarByModel(op.type)){ + carId = id; type = op.type; - sprType = GraphicsBase::SpriteNumbers::CAR; - sprNum = c_info.sprNum; - m_Extent = Vector3D(INT2F_DIV128(c_info.width), - INT2F_DIV128(c_info.depth), - INT2F_DIV128(c_info.height)); - m_M.Translate(pos); + sprNum = carInfo.sprNum; + m_Extent = Vector3D(INT2F_DIV128(carInfo.width), + INT2F_DIV128(carInfo.depth), + INT2F_DIV128(carInfo.height)); + m_M = TranslateMatrix3D(pos); + m_M.RotZ(rot); + rot = op.rotation * 360 / 1024; } - Car::Car(const Car & other) : SpriteObject(other), - OBox(other.m_M, other.m_Extent), - c_info(*StyleHolder::Instance().get().findCarByModel(other.type)) { - copyValues(other); - } - - void Car::copyValues(const Car & other) { - sprType = other.sprType; - delta = other.delta; - carId = other.carId; + Car::Car(const Car & other) : + GameObject_common(other), Sprite(other), OBox(other), + carInfo(*StyleHolder::Instance().get().findCarByModel(other.type)) { type = other.type; + m_M = TranslateMatrix3D(pos); + m_M.RotZ(rot); + + carId = other.carId; } - GameObject::GameObject(const OpenGTA::Map::ObjectPosition & op) : - SpriteObject(Vector3D(INT2FLOAT_WRLD(op.x), 6.05f-INT2FLOAT_WRLD(op.z), INT2FLOAT_WRLD(op.y))), - OBox(RollMatrix3D(0), Vector3D()) { - sprType = GraphicsBase::SpriteNumbers::OBJECT; + void Car::update(Uint32 ticks) { + } + + SpriteObject::SpriteObject(OpenGTA::Map::ObjectPosition& op, uint32_t id) : + GameObject_common(Vector3D(INT2FLOAT_WRLD(op.x), 6.05f-INT2FLOAT_WRLD(op.z), INT2FLOAT_WRLD(op.y))), + Sprite(0, -1, GraphicsBase::SpriteNumbers::OBJECT), OBox() { + objId = id; GraphicsBase & style = StyleHolder::Instance().get(); sprNum = style.objectInfos[op.type]->sprNum; m_Extent = Vector3D(INT2F_DIV128(style.objectInfos[op.type]->width), INT2F_DIV128(style.objectInfos[op.type]->depth), INT2F_DIV128(style.objectInfos[op.type]->height)); - m_M.Translate(pos); + m_M = TranslateMatrix3D(pos); + m_M.RotZ(rot); rot = op.rotation * 360 / 1024; - + isActive = true; } - GameObject::GameObject(const GameObject & other) : SpriteObject(other), - OBox(other.m_M, other.m_Extent) { - copyValues(other); + SpriteObject::SpriteObject(Vector3D pos, Uint16 sprNum, OpenGTA::GraphicsBase::SpriteNumbers::SpriteTypes sprT) : + GameObject_common(pos), Sprite(sprNum, -1, sprT), OBox() { + isActive = true; + m_M = TranslateMatrix3D(pos); + m_M.RotZ(rot); } - void GameObject::copyValues(const GameObject & other) { - sprType = other.sprType; + SpriteObject::SpriteObject(const SpriteObject & other) : + GameObject_common(other), Sprite(other), OBox(other), + + objId(other.objId) { + m_M = TranslateMatrix3D(pos); + m_M.RotZ(rot); + + isActive = other.isActive; + } + + void SpriteObject::update(Uint32 ticks) { + anim.update(ticks); + } + + Projectile::Projectile(unsigned char t, float r, Vector3D p, Vector3D d, uint32_t ticks, uint32_t o) : + GameObject_common(p, r), + typeId(t), delta(d), endsAtTick(ticks), + owner(o), lastUpdateAt(ticks) { + endsAtTick = lastUpdateAt + 1000; + } + + Projectile::Projectile(const Projectile & other) : + GameObject_common(other), + typeId(other.typeId), delta(other.delta), endsAtTick(other.endsAtTick), + owner(other.owner), lastUpdateAt(other.lastUpdateAt) {} + + void Projectile::update(uint32_t ticks) { + Uint32 dt = ticks - lastUpdateAt; + Vector3D new_pos(pos + delta * dt); + /*INFO << "p-m " << pos.x << " " << pos.y << " " << pos.z << + " to " << new_pos.x << " " << new_pos.y << " " << new_pos.z << std::endl; + */ + std::list & list = SpriteManagerHolder::Instance().getList(); + for (std::list::iterator i = list.begin(); i != list.end(); ++i) { + Pedestrian & ped = *i; + if (ped.id() == owner) + continue; + if (ped.isDead) + continue; + /*INFO << "ped " << ped.id() << " pos: " << ped.pos.x << " " << ped.pos.y << " " << ped.pos.z << std::endl; + Vector3D p = ped.GetCenterPoint(); + INFO << "CP " << p.x << " " << p.y << " " << p.z << std::endl; + p = ped.m_Extent; + INFO << "extent " << p.x << " " << p.y << " " << p.z << std::endl; + for (int i=0; i < 4; i++) { + for (int j=0; j < 4; j++) { + std::cout << "M " << ped.m_M.m[i][j] << " "; + } + std::cout << std::endl; + }*/ + + + if (ped.IsLineInBox( pos, new_pos ) ) { + INFO << "HIT ped " << ped.id() << std::endl; + ped.getShot(true); + //ped.sprType = GraphicsBase::SpriteNumbers::OBJECT; + //ped.remap = -1; + //SpriteManagerHolder::Instance().removePed(ped.pedId); + endsAtTick = 0; + } + } + + /* + Util::CellIterator oi(pos); + + Util::CellIterator ni(new_pos); + //FIXME ni valid? + + if (oi.isValid() && ni.isValid()) { + if (oi == ni) { // only one cell to check + Math::line_intersect(pos, new_pos);//, oi.getBlock()); + } + else { // crosses cell boundary + Math::line_intersect(pos, new_pos);//, oi.getBlock()); + //Math::line_intersect(pos, new_pos);//, ni.getBlock()); + } + } + else + INFO << "NEITHER VALID!"<< oi.x << " " << oi.y << " " << oi.z < ProximityToken; + typedef OpenSteer::AbstractProximityDatabase ProximityDatabase; + struct GameObject_common { + Vector3D pos; + float rot; + float bSphereRadius; + //uint8_t activeState; + GameObject_common() : + pos(0, 0, 0), rot(0), bSphereRadius(0.1f) {} + GameObject_common(const Vector3D & p) : pos(p), rot(0) {} + GameObject_common(const Vector3D & p, float r) : pos(p), rot(r) {} + GameObject_common(const GameObject_common & o) : + pos(o.pos), rot(o.rot), bSphereRadius(o.bSphereRadius) {} + float heightOverTerrain(const Vector3D &); + ProximityToken* proxToken; + }; + + class Sprite { + public: + struct Animation : public Util::Animation { + Animation(); + Animation(const Animation & other); + Animation(Uint16 foff, Uint8 num); + Animation(Uint16 foff, Uint8 num, float speed); + Uint16 firstFrameOffset; + //Uint8 numFrames; + float moveSpeed; + }; + Sprite(); + Sprite(Uint16 sprN, Sint16 rem, GraphicsBase::SpriteNumbers::SpriteTypes sprT); + Sprite(const Sprite & o); + Uint16 sprNum; + Sint16 remap; + Animation anim; + Uint32 animId; + GraphicsBase::SpriteNumbers::SpriteTypes sprType; + Uint8 calcCurrentFrame(Uint32 ticks); + void switchToAnim(const Uint32 & newId); + }; + + class Pedestrian : public GameObject_common, public Sprite, public OBox { + public: + Pedestrian(Vector3D, const Vector3D &, uint32_t id, Sint16 remapId = -1); + Pedestrian(const Pedestrian & o); + uint32_t pedId; + inline uint32_t id() const { return pedId; } + void equip(uint8_t eq_id); + void giveItem(uint8_t id, uint32_t amount); + PedController m_control; + void update(Uint32 ticks); + Uint32 lastUpdateAt; + Uint32 lastWeaponTick; + Vector3D speedForces; + bool inGroundContact; + void tryMove(Vector3D nPos); + uint8_t isDead; + void getShot(bool front = true); + void die(); + }; + + class Car : public GameObject_common, public Sprite, public OBox { + public: + Car(const Car & o); + Car(OpenGTA::Map::ObjectPosition&, uint32_t id); + uint32_t carId; + inline uint32_t id() const { return carId; } + GraphicsBase::CarInfo & carInfo; + uint8_t type; + void update(Uint32 ticks); + Uint32 lastUpdateAt; + }; + + class SpriteObject : public GameObject_common, public Sprite, public OBox { + public: + SpriteObject(OpenGTA::Map::ObjectPosition&, uint32_t id); + SpriteObject(Vector3D pos, Uint16 spriteNum, GraphicsBase::SpriteNumbers::SpriteTypes st); + SpriteObject(const SpriteObject & o); + uint32_t objId; + inline uint32_t id() const { return objId; } + void update(Uint32 ticks); + Uint32 lastUpdateAt; + + bool isActive; + + }; + + /* + class TrainSegment : public GameObject_common, public OBox { + public: + TrainSegment(uint32_t id, Util::CellIterator & cell); + TrainSegment(const TrainSegment & o); + uint32_t trainId; + inline uint32_t id() const { return trainId; } + };*/ + + class Projectile : public GameObject_common { + public: + Projectile(uint8_t, float, Vector3D, Vector3D, uint32_t, uint32_t); + Projectile(const Projectile & other); + uint8_t typeId; + Vector3D delta; + uint32_t endsAtTick; + uint32_t owner; + void update(Uint32 ticks); + Uint32 lastUpdateAt; + }; + +} + +#endif diff --git a/gfx_extract.cpp b/gfx_extract.cpp index 778fcf3..d2fca2a 100644 --- a/gfx_extract.cpp +++ b/gfx_extract.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * @@ -197,15 +197,15 @@ int main(int argc, char* argv[]) { switch(section) { case 0: - graphics.getSide(idx, remap, rgba); + graphics.getSide(idx, 0, rgba); image = get_image(graphics.getTmpBuffer(rgba), 64,64); break; case 1: - graphics.getLid(idx, remap, rgba); + graphics.getLid(idx, 0, rgba); image = get_image(graphics.getTmpBuffer(rgba), 64, 64); break; case 2: - graphics.getAux(idx, remap, rgba); + graphics.getAux(idx, 0, rgba); image = get_image(graphics.getTmpBuffer(rgba), 64, 64); break; case 3: diff --git a/gl_base.cpp b/gl_base.cpp index 36a9d5f..baa4d9a 100644 --- a/gl_base.cpp +++ b/gl_base.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * diff --git a/gl_base.h b/gl_base.h index ab5faf2..6f7e3ef 100644 --- a/gl_base.h +++ b/gl_base.h @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * diff --git a/gl_camera.cpp b/gl_camera.cpp index 310262b..038ee44 100644 --- a/gl_camera.cpp +++ b/gl_camera.cpp @@ -26,7 +26,18 @@ namespace OpenGL { void Camera::update_game(Uint32 ticks) { Vector3D delta(center - *followTarget); //INFO << delta.x << ", " << delta.y << ", " << delta.z << std::endl; + float height_dist = fabs(delta.y); delta.y = 0; + if (camGravity) { + if (center.y - followTarget->y > 4.1) { + delta.y = 0.001f * height_dist; + } + else if (center.y - followTarget->y < 3.9) { + delta.y = -0.001f * height_dist; + } + } + //INFO << center.y << " " << followTarget->y<< " " << height_dist << std::endl; + center += -delta; eye += -delta; gluLookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, diff --git a/gl_cityview.cpp b/gl_cityview.cpp index d6f2560..b3fd76f 100644 --- a/gl_cityview.cpp +++ b/gl_cityview.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * @@ -34,6 +34,7 @@ #include "gl_screen.h" #include "blockdata.h" #include "image_loader.h" +#include "blockanim.h" float slope_height_offset(unsigned char slope_type, float dx, float dz); namespace OpenGTA { @@ -84,6 +85,8 @@ namespace OpenGTA { loadedMap = NULL; sideCache = NULL; lidCache = NULL; + auxCache = NULL; + blockAnims = NULL; camVec[0] = 0.0f; camVec[1] = 1.0f; camVec[2] = 0.0f; @@ -105,6 +108,7 @@ namespace OpenGTA { void CityView::resetTextures() { sideCache->clearAll(); lidCache->clearAll(); + auxCache->clearAll(); } void CityView::setVisibleRange(int r) { visibleRange = r; @@ -124,6 +128,10 @@ namespace OpenGTA { delete sideCache; if (lidCache) delete lidCache; + if (auxCache) + delete auxCache; + if (blockAnims) + delete blockAnims; if (scene_display_list) glDeleteLists(scene_display_list, 1); setNull(); @@ -138,10 +146,20 @@ namespace OpenGTA { loadedMap = &MapHolder::Instance().get(); StyleHolder::Instance().load(style_f); style = &StyleHolder::Instance().get(); + /* + for (size_t i = 0; i < style->carInfos.size(); ++i) { + OpenGTA::GraphicsBase::CarInfo * cinfo = style->carInfos[i]; + assert(cinfo); + INFO << cinfo->numDoors << std::endl; + }*/ + sideCache = new OpenGL::TextureCache("SideCache"); lidCache = new OpenGL::TextureCache("LidCache"); + auxCache = new OpenGL::TextureCache("AuxCache"); sideCache->setClearMagic(5); lidCache->setClearMagic(8); + auxCache->setClearMagic(5); + blockAnims = new BlockAnimCtrl(style->animations); scene_is_dirty = true; lastCacheEmptyTicks = 0; @@ -151,16 +169,20 @@ namespace OpenGTA { for (PHYSFS_uint16 oc = 0; oc < loadedMap->numObjects; oc++) { createLevelObject(&loadedMap->objects[oc]); } + //SpriteManagerHolder::Instance().trainSystem.loadStations(*loadedMap); } void CityView::createLevelObject(OpenGTA::Map::ObjectPosition *obj) { SpriteManager & s_man = SpriteManagerHolder::Instance(); if (obj->remap >= 128) { - Car car(*obj); - s_man.addCar(car); + Car car(*obj, 0); + s_man.add(car); + //s_man.addCar(car); } else { - GameObject gobj(*obj); - s_man.addObject(gobj); + //GameObject gobj(*obj); + SpriteObject gobj(*obj, 0); + s_man.add(gobj); + //s_man.addObject(gobj); } } void CityView::setZoom(const GLfloat zoom) { @@ -341,6 +363,17 @@ namespace OpenGTA { if (y2 > 255) y2 = 255; + activeRect.x = x1; + activeRect.y = y1; + activeRect.w = x2 - x1; + activeRect.h = y2 - y1; + //INFO << "Active area: " << x1 << " - " << x2 << " , " << y1 << " - " << y2 << std::endl; + int xd1, xd2, yd1, yd2; + xd2 = 0; + yd2 = 0; + xd1 = x2; + yd1 = y2; + bool use_display_list = false; GL_CHECKERROR; @@ -358,6 +391,12 @@ namespace OpenGTA { for (int j= x1; j <= x2; j++) { if (!frustum.BlockInFrustum(0.5f+j, 0.5f+i, 0.5f)) continue; + if (j < xd1) + xd1 = j; + xd2 = j; + if (i < yd1) + yd1 = i; + yd2 = i; glPushMatrix(); glTranslatef(1.0f*j, 0.0f, 1.0f*i); //PHYSFS_uint16 emptycount = loadedMap->getNumBlocksAt(j,i); @@ -374,6 +413,11 @@ namespace OpenGTA { } //glPopMatrix(); } + drawnRect.x = xd1; + drawnRect.y = yd1; + drawnRect.w = xd2 - xd1; + drawnRect.h = yd2 - yd1; + //INFO << "area drawn: " << xd1 << " - " << xd2 << " , " << yd1 << " - " << yd2 << std::endl; if (use_display_list) { glEndList(); glCallList(scene_display_list); @@ -388,14 +432,8 @@ namespace OpenGTA { (loadedMap->objects[oc].y >> 6) + 0.5f, 0.5f)) drawObject(&loadedMap->objects[oc]); }*/ - SDL_Rect r; - r.x = x1; - r.y = y1; - r.w = x2 - x1; - r.h = y2 - y1; - //INFO << "active rect: " << r.x << "," < 4000) { @@ -540,49 +578,138 @@ namespace OpenGTA { // FIXME: no remaps used! if (bi->lid) { - if (!lidCache->hasTexture(bi->lid)) { - lid_tex = ImageUtil::createGLTexture(64, 64, is_flat, - style->getLid(static_cast(bi->lid), 0, is_flat)); - lidCache->addTexture(bi->lid, lid_tex); + int frame_num = -1;//style->checkBlockAnimation(0, bi->lid); + BlockAnim * banim = blockAnims->getAnim(1, bi->lid); + if (banim) { + frame_num = banim->getCurrentFrameNumber(); + } + if (frame_num <= 0) { + if (!lidCache->hasTexture(bi->lid)) { + lid_tex = ImageUtil::createGLTexture(64, 64, is_flat, + style->getLid(static_cast(bi->lid), 0, is_flat)); + lidCache->addTexture(bi->lid, lid_tex); + } + else + lid_tex = lidCache->getTextureWithId(bi->lid); + } + else { + uint8_t aux_id = banim->getFrame(frame_num - 1); + if (!auxCache->hasTexture(aux_id)) { + lid_tex = ImageUtil::createGLTexture(64, 64, is_flat, + style->getAux(static_cast(aux_id), 0, is_flat)); + auxCache->addTexture(aux_id, lid_tex); + } + else + lid_tex = auxCache->getTextureWithId(aux_id); } - else - lid_tex = lidCache->getTextureWithId(bi->lid); } if (bi->left) { - if (!sideCache->hasTexture(bi->left)) { - left_tex = ImageUtil::createGLTexture(64, 64, is_flat, - style->getSide(static_cast(bi->left), 0, is_flat)); - sideCache->addTexture(bi->left, left_tex); + int frame_num = -1; + BlockAnim * banim = blockAnims->getAnim(0, bi->left); + if (banim) { + frame_num = banim->getCurrentFrameNumber(); + } + if (frame_num <= 0) { + if (!sideCache->hasTexture(bi->left)) { + left_tex = ImageUtil::createGLTexture(64, 64, is_flat, + style->getSide(static_cast(bi->left), 0, is_flat)); + sideCache->addTexture(bi->left, left_tex); + } + else + left_tex = sideCache->getTextureWithId(bi->left); + } + else { + uint8_t aux_id = banim->getFrame(frame_num - 1); + if (!auxCache->hasTexture(aux_id)) { + left_tex = ImageUtil::createGLTexture(64, 64, is_flat, + style->getAux(static_cast(aux_id), 0, is_flat)); + auxCache->addTexture(aux_id, left_tex); + } + else + left_tex = auxCache->getTextureWithId(aux_id); + } - else - left_tex = sideCache->getTextureWithId(bi->left); } if (bi->right) { - if (!sideCache->hasTexture(bi->right)) { - right_tex = ImageUtil::createGLTexture(64, 64, is_flat, - style->getSide(static_cast(bi->right), 0, is_flat)); - sideCache->addTexture(bi->right, right_tex); + int frame_num = -1; + BlockAnim * banim = blockAnims->getAnim(0, bi->right); + if (banim) { + frame_num = banim->getCurrentFrameNumber(); + } + if (frame_num <= 0) { + if (!sideCache->hasTexture(bi->right)) { + right_tex = ImageUtil::createGLTexture(64, 64, is_flat, + style->getSide(static_cast(bi->right), 0, is_flat)); + sideCache->addTexture(bi->right, right_tex); + } + else + right_tex = sideCache->getTextureWithId(bi->right); + } + else { + uint8_t aux_id = banim->getFrame(frame_num - 1); + if (!auxCache->hasTexture(aux_id)) { + right_tex = ImageUtil::createGLTexture(64, 64, is_flat, + style->getAux(static_cast(aux_id), 0, is_flat)); + auxCache->addTexture(aux_id, right_tex); + } + else + right_tex = auxCache->getTextureWithId(aux_id); } - else - right_tex = sideCache->getTextureWithId(bi->right); } if (bi->top) { - if (!sideCache->hasTexture(bi->top)) { - top_tex = ImageUtil::createGLTexture(64, 64, is_flat, - style->getSide(static_cast(bi->top), 0, is_flat)); - sideCache->addTexture(bi->top, top_tex); + int frame_num = -1; + BlockAnim * banim = blockAnims->getAnim(0, bi->top); + if (banim) { + frame_num = banim->getCurrentFrameNumber(); + } + if (frame_num <= 0) { + + if (!sideCache->hasTexture(bi->top)) { + top_tex = ImageUtil::createGLTexture(64, 64, is_flat, + style->getSide(static_cast(bi->top), 0, is_flat)); + sideCache->addTexture(bi->top, top_tex); + } + else + top_tex = sideCache->getTextureWithId(bi->top); + } + else { + uint8_t aux_id = banim->getFrame(frame_num - 1); + if (!auxCache->hasTexture(aux_id)) { + top_tex = ImageUtil::createGLTexture(64, 64, is_flat, + style->getAux(static_cast(aux_id), 0, is_flat)); + auxCache->addTexture(aux_id, top_tex); + } + else + top_tex = auxCache->getTextureWithId(aux_id); } - else - top_tex = sideCache->getTextureWithId(bi->top); } if (bi->bottom) { - if (!sideCache->hasTexture(bi->bottom)) { - bottom_tex = ImageUtil::createGLTexture(64, 64, is_flat, - style->getSide(static_cast(bi->bottom), 0, is_flat)); - sideCache->addTexture(bi->bottom, bottom_tex); + int frame_num = -1; + BlockAnim * banim = blockAnims->getAnim(0, bi->bottom); + if (banim) { + frame_num = banim->getCurrentFrameNumber(); + } + if (frame_num <= 0) { + + if (!sideCache->hasTexture(bi->bottom)) { + bottom_tex = ImageUtil::createGLTexture(64, 64, is_flat, + style->getSide(static_cast(bi->bottom), 0, is_flat)); + sideCache->addTexture(bi->bottom, bottom_tex); + } + else + bottom_tex = sideCache->getTextureWithId(bi->bottom); + } + else { + uint8_t aux_id = banim->getFrame(frame_num - 1); + if (!auxCache->hasTexture(aux_id)) { + bottom_tex = ImageUtil::createGLTexture(64, 64, is_flat, + style->getAux(static_cast(aux_id), 0, is_flat)); + auxCache->addTexture(aux_id, bottom_tex); + } + else + bottom_tex = auxCache->getTextureWithId(aux_id); + } - else - bottom_tex = sideCache->getTextureWithId(bi->bottom); } // handle flat/transparent case @@ -1094,9 +1221,9 @@ namespace OpenGTA { HEIGHT_VERTEX(0.8f, 0.1f, 0.5f); glEnd(); } - glEnable(GL_TEXTURE_2D); // block lid normals -#if 0 +//#if 0 + glColor3f(1, 0, 0); #define NORMAL_POS(a, b) glVertex3f(a, slope_height_offset(which, a, b), b) #define NORMAL_POS2(a, b) glVertex3f(a + nx, slope_height_offset(which, a, b) + ny, b + nz) glBegin(GL_LINES); @@ -1104,9 +1231,30 @@ namespace OpenGTA { NORMAL_POS(0.5f, 0.5f); NORMAL_POS2(0.5f, 0.5f); } + glColor3f(0, 1, 0); + if (bi->left) { + glVertex3f(0, 0.5f, 0.5f); + glVertex3f(-0.4f, 0.5f, 0.5f); + } + glColor3f(0, 0, 1); + if (bi->right && !bi->isFlat()) { + glVertex3f(1, 0.5f, 0.5f); + glVertex3f(1.4f, 0.5f, 0.5f); + } + glColor3f(0, 1, 0); + if (bi->top) { + glVertex3f(0.5f, 0.5f, 0.0f); + glVertex3f(0.5f, 0.5f, -0.4f); + } + glColor3f(0, 0, 1); + if (bi->bottom && !bi->isFlat()) { + glVertex3f(0.5f, 0.5f, 1.0f); + glVertex3f(0.5f, 0.5f, 1.4f); + } glEnd(); + glColor3f(1, 1, 1); +//#endif glEnable(GL_TEXTURE_2D); -#endif GL_CHECKERROR; } diff --git a/gl_cityview.h b/gl_cityview.h index b8d7f3f..abd90a2 100644 --- a/gl_cityview.h +++ b/gl_cityview.h @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * @@ -31,6 +31,7 @@ namespace OpenGTA { + class BlockAnimCtrl; class CityView { public: CityView(); @@ -59,6 +60,9 @@ namespace OpenGTA { void CityView::setDrawLines(bool v); void resetTextures(); + const SDL_Rect & getActiveRect() { return activeRect; } + const SDL_Rect & getOnScreenRect() { return drawnRect; } + BlockAnimCtrl* blockAnims; protected: void setNull(); @@ -69,6 +73,7 @@ namespace OpenGTA { Util::CFrustum frustum; OpenGL::TextureCache* sideCache; OpenGL::TextureCache* lidCache; + OpenGL::TextureCache* auxCache; Map* loadedMap; OpenGTA::GraphicsBase* style; GLfloat zoomLevel; @@ -79,6 +84,9 @@ namespace OpenGTA { bool drawTextured; bool drawLines; + SDL_Rect activeRect; + SDL_Rect drawnRect; + int scene_rendered_vertices; int scene_rendered_blocks; diff --git a/gl_font.cpp b/gl_font.cpp index 669a6b6..bf67bf5 100644 --- a/gl_font.cpp +++ b/gl_font.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * diff --git a/gl_font.h b/gl_font.h index 985337d..3be6d9d 100644 --- a/gl_font.h +++ b/gl_font.h @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * diff --git a/gl_pagedtexture.h b/gl_pagedtexture.h index 44dcae0..d5596f9 100644 --- a/gl_pagedtexture.h +++ b/gl_pagedtexture.h @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * diff --git a/gl_screen.cpp b/gl_screen.cpp index 1282bbc..4352242 100644 --- a/gl_screen.cpp +++ b/gl_screen.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * @@ -56,6 +56,12 @@ namespace OpenGL { setSystemMouseCursor(false); } + void Screen::setupGlVars( float fov, float near_p, float far_p) { + fieldOfView = fov; + nearPlane = near_p; + farPlane = far_p; + } + void Screen::setSystemMouseCursor(bool visible) { SDL_ShowCursor((visible ? SDL_ENABLE : SDL_DISABLE)); } @@ -103,14 +109,73 @@ namespace OpenGL { if (err) //throw "SDL_Init failed: " + std::string(SDL_GetError()); throw E_INVALIDFORMAT("SDL_Init failed: " + std::string(SDL_GetError())); - SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8); + + const char* sdl_err = SDL_GetError(); + if (strlen(sdl_err) > 0) + INFO << "sdl_init complained: " << sdl_err << std::endl; + SDL_ClearError(); + + const SDL_VideoInfo *vInfo = SDL_GetVideoInfo(); + + if (vInfo == NULL) + throw E_NOTSUPPORTED("SDL_GetVideoInfo failed: " + std::string(SDL_GetError())); + + if (vInfo->hw_available == 1) + videoFlags |= SDL_HWSURFACE; + else + videoFlags |= SDL_SWSURFACE; + + if (vInfo->blit_hw) + videoFlags |= SDL_HWACCEL; + + bpp = vInfo->vfmt->BitsPerPixel; + + INFO << "video-probe:" << std::endl << + " hw-surface: " << (vInfo->hw_available == 1 ? "on" : "off") << std::endl << + " hw-blit: " << (vInfo->blit_hw ? "on" : "off") << std::endl << + " bpp: " << int (bpp) << std::endl; + + size_t color_depth_triple[3]; + switch(bpp) { + case 32: + case 24: + for (int i=0; i < 3; ++i) + color_depth_triple[i] = 8; + break; + case 16: + color_depth_triple[0] = 5; + color_depth_triple[1] = 6; + color_depth_triple[2] = 5; + break; + case 15: + for (int i=0; i < 3; ++i) + color_depth_triple[i] = 5; + break; + case 8: + color_depth_triple[0] = 2; + color_depth_triple[1] = 3; + color_depth_triple[2] = 3; + break; + default: + throw E_NOTSUPPORTED("Invalid bit-per-pixel setting"); + } + + SDL_GL_SetAttribute( SDL_GL_RED_SIZE, color_depth_triple[0]); + SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, color_depth_triple[1]); + SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, color_depth_triple[2]); SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16); + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1); +#ifdef HAVE_SDL_VSYNC SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 1); +#endif + + sdl_err = SDL_GetError(); + if (strlen(sdl_err) > 0) + ERROR << "setting sdl_gl attributes: " << sdl_err << std::endl; } void Screen::initGL() { + GL_CHECKERROR; //GLfloat LightAmbient[] = { 0.8f, 0.8f, 0.8f, 1.0f }; //GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; //GLfloat LightPosition[] = { 128.0f, 200.0f, 128.0f, 1.0f }; @@ -128,15 +193,24 @@ namespace OpenGL { glCullFace(GL_BACK); //glPolygonMode(GL_FRONT, GL_FILL); //glPolygonMode(GL_BACK, GL_LINE); + GL_CHECKERROR; } void Screen::resize(Uint32 w, Uint32 h) { if (h == 0) h = 1; surface = SDL_SetVideoMode(w, h, bpp, videoFlags); + if (surface == NULL) { + ERROR << "vide-mode: " << w << ", " << h << " bpp: " << bpp << + " hw-surface: " << (videoFlags & SDL_HWSURFACE == SDL_HWSURFACE ? "on" : "off") << + " hw-blit: " << (videoFlags & SDL_HWACCEL == SDL_HWACCEL ? "on" : "off") << std::endl; + throw E_NOTSUPPORTED(SDL_GetError()); + } + glViewport(0, 0, w, h); width = w; height = h; + GL_CHECKERROR; } void Screen::set3DProjection() { diff --git a/gl_screen.h b/gl_screen.h index 27229a8..0a81a13 100644 --- a/gl_screen.h +++ b/gl_screen.h @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * @@ -44,6 +44,11 @@ namespace OpenGL { Uint32 getHeight(); bool getFullscreen(); void makeScreenshot(const char* filename); + inline float getFieldOfView() { return fieldOfView; } + inline float getNearPlane() { return nearPlane; } + inline float getFarPlane() { return farPlane; } + void setupGlVars( float fov, float near_p, float far_p); + private: void initGL(); void initSDL(); @@ -54,7 +59,8 @@ namespace OpenGL { float nearPlane; float farPlane; static const Uint32 defaultVideoFlags = - SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE | SDL_HWACCEL; + SDL_OPENGL | SDL_GL_DOUBLEBUFFER;// | SDL_HWPALETTE | SDL_HWACCEL; + //FIXME: use ^ here as well? not just SDL_GL_SetAttribute? SDL_Surface *surface; }; diff --git a/gl_spritecache.cpp b/gl_spritecache.cpp index a824f8a..e3c293c 100644 --- a/gl_spritecache.cpp +++ b/gl_spritecache.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * @@ -22,11 +22,14 @@ ************************************************************************/ #include #include +#include #include "gl_spritecache.h" #include "opengta.h" #include "dataholder.h" #include "buffercache.h" #include "log.h" +//#include "physfsrwops.h" +//#include "image_loader.h" namespace OpenGL { SpriteIdentifier::SpriteIdentifier() : sprNum(0), remap(-1), delta(0) {} @@ -187,6 +190,26 @@ namespace OpenGL { getSpriteBitmap(sprite_num, remap , delta); unsigned int glwidth = 1; unsigned int glheight = 1; + #if 0 + if (sprite_num == 257) { + info->w = 72; + info->h = 72; + SDL_RWops * rwops = PHYSFSRWOPS_openRead("tree.png");//file.c_str()); + SDL_Surface *surface = IMG_Load_RW(rwops, 1); + assert(surface); + uint16_t bpp = surface->format->BytesPerPixel; + ImageUtil::NextPowerOfTwo npot(surface->w, surface->h); + uint8_t * buffer = Util::BufferCacheHolder::Instance().requestBuffer(npot.w * npot.h * bpp); + SDL_LockSurface(surface); + ImageUtil::copyImage2Image(buffer, (uint8_t*)surface->pixels, surface->pitch, surface->h, + npot.w * bpp); + SDL_UnlockSurface(surface); + + GLuint texture = ImageUtil::createGLTexture(npot.w, npot.h, (bpp == 4) ? true : false, buffer); + return OpenGL::PagedTexture(texture, 0, 0, GLfloat(surface->w)/npot.w, GLfloat(surface->h)/npot.h); + + } + #endif while(glwidth < info->w) glwidth <<= 1; diff --git a/gl_spritecache.h b/gl_spritecache.h index 574108b..1840e78 100644 --- a/gl_spritecache.h +++ b/gl_spritecache.h @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * diff --git a/gl_texturecache.cpp b/gl_texturecache.cpp index 0cc812b..32a61eb 100644 --- a/gl_texturecache.cpp +++ b/gl_texturecache.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * diff --git a/gl_texturecache.h b/gl_texturecache.h index 75f60d9..e9624d2 100644 --- a/gl_texturecache.h +++ b/gl_texturecache.h @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * diff --git a/id_sys.cpp b/id_sys.cpp new file mode 100644 index 0000000..874cc51 --- /dev/null +++ b/id_sys.cpp @@ -0,0 +1,8 @@ +#include "id_sys.h" + +namespace OpenGTA { + uint32_t TypeIdBlackBox::nextId = 0; + uint32_t TypeIdBlackBox::firstPlayerId = 0xffffffff - 32; + uint32_t TypeIdBlackBox::lastPlayerId = 0xffffffff; + +} diff --git a/id_sys.h b/id_sys.h new file mode 100644 index 0000000..8274fba --- /dev/null +++ b/id_sys.h @@ -0,0 +1,29 @@ +#ifndef ID_COUNTER_SYS_H +#define ID_COUNTER_SYS_H + +#include "game_objects.h" +#include "m_exceptions.h" + +namespace OpenGTA { + + class TypeIdBlackBox { + public: + static uint32_t requestId() { + if (nextId + 1 >= firstPlayerId) { + throw E_OUTOFRANGE("Player id range reached!"); + } + return nextId++; + } + static uint32_t getPlayerId() { + return lastPlayerId; + } + private: + static uint32_t nextId; + static uint32_t firstPlayerId; + static uint32_t lastPlayerId; + + }; + +} + +#endif diff --git a/license.txt b/license.txt index 05ff6a4..1909e3a 100644 --- a/license.txt +++ b/license.txt @@ -1,4 +1,4 @@ -Copyright (c) 2005-2006 tok@openlinux.org.uk +Copyright (c) 2005-2007 tok@openlinux.org.uk This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from @@ -18,7 +18,7 @@ the following restrictions: Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. -5. This notice may not be removed or altered from any distribution. +4. This notice may not be removed or altered from any distribution. *************************************************************************** The file formats of the data files are described in documentation released @@ -54,6 +54,15 @@ these remain under their respective licenses. notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. +* OpenSteer + Copyright (c) 2002-2005, Sony Computer Entertainment America + Original author: Craig Reynolds + MIT license + +* ColDet - C++ 3D Collision Detection Library + Copyright (C) 2000 Amir Geva + GNU Library General Public License + *************************************************************************** Please do not redistribute the data files of the original game together with this software. diff --git a/localplayer.h b/localplayer.h index 044dfa9..14a503f 100644 --- a/localplayer.h +++ b/localplayer.h @@ -1,13 +1,28 @@ #ifndef OGTA_LOCAL_PLAYER_H #define OGTA_LOCAL_PLAYER_H #include "Singleton.h" -#include "pedestrian.h" +#include "game_objects.h" +#include "entity_controller.h" +#include "id_sys.h" namespace OpenGTA { - class PlayerController : public Pedestrian::Controller { + class PlayerController { // : public PedController { //public Pedestrian::Controller { public: - PlayerController() { turn = 0; move = 0; } + PlayerController() { + playerId = TypeIdBlackBox::getPlayerId(); + pc_ptr = NULL; + } + PedController & getCtrl() { + assert(pc_ptr); + return *pc_ptr; + } + void setCtrl(PedController & pc) { + pc_ptr = &pc; + } + private: + uint32_t playerId; + PedController * pc_ptr; }; typedef Loki::SingletonHolder +#include "read_ini.h" +#include "lua.hpp" + +namespace OpenGTA { + namespace Script { + class IniScriptBridge : public ScriptParser { + public: + IniScriptBridge(const std::string &file); + ~IniScriptBridge(); + lua_State *L; + void loadLevel(PHYSFS_uint32 level); + protected: + void reset(); + void acceptDefinition(const char*); + void acceptCommand(const char*); + + }; + } +} + +#endif diff --git a/lua_addon/lua_spritecache.cpp b/lua_addon/lua_spritecache.cpp new file mode 100644 index 0000000..2a30dd1 --- /dev/null +++ b/lua_addon/lua_spritecache.cpp @@ -0,0 +1,26 @@ +#include "lua_spritecache.h" + +namespace OpenGTA { + namespace Script { +using namespace OpenGL; + int SpriteCache::getScale2x(lua_State *L) { + bool b = SpriteCacheHolder::Instance().getScale2x(); + lua_pushboolean(L, b); + return 1; + } + int SpriteCache::setScale2x(lua_State *L) { + bool b = SpriteCacheHolder::Instance().getScale2x(); + bool v = lua_toboolean(L, 1); + if (b != v) + SpriteCacheHolder::Instance().setScale2x(v); + return 0; + } +#define method(name) {#name, SpriteCache::name} + const luaL_reg SpriteCache::methods[] = { + method(setScale2x), + method(getScale2x), + {NULL, NULL} + }; + + } +} diff --git a/lua_addon/lua_spritecache.h b/lua_addon/lua_spritecache.h new file mode 100644 index 0000000..16b2909 --- /dev/null +++ b/lua_addon/lua_spritecache.h @@ -0,0 +1,19 @@ +#ifndef LUA_OGTA_SPRITECACHE_H +#define LUA_OGTA_SPRITECACHE_H + +#include "gl_spritecache.h" +#include "lua.hpp" + +namespace OpenGTA { + namespace Script { + + class SpriteCache { + public: + static int getScale2x(lua_State *L); + static int setScale2x(lua_State *L); + + static const luaL_reg methods[]; + }; + } +} +#endif diff --git a/lua_addon/lua_vm.cpp b/lua_addon/lua_vm.cpp index e437c1d..3d76936 100644 --- a/lua_addon/lua_vm.cpp +++ b/lua_addon/lua_vm.cpp @@ -1,6 +1,7 @@ #include #include "lua_vm.h" #include "lunar.h" +#include "lua_map.h" #include "lua_cityview.h" #include "lua_stackguard.h" #include "lua_camera.h" @@ -33,22 +34,42 @@ namespace OpenGTA { void LuaVM::prepare() { LGUARD(L); if (!_registered) { + Lunar::Register2(L); + Lunar::Register2(L); + /* Lunar::Register2(L); luaL_openlib(L, "camera", Camera::methods, 0); luaL_openlib(L, "screen", Screen::methods, 0); luaL_openlib(L, "spritecache", SpriteCache::methods, 0); + */ } _registered = true; } + lua_State* LuaVM::getInternalState() { + return(L); + } + + void LuaVM::setMap(OpenGTA::Map & map) { + LGUARD(L); + LMap * mptr = static_cast(&map); + lua_gettable(L, LUA_GLOBALSINDEX); + int scv_ref = Lunar::push(L, mptr, false); + lua_pushliteral(L, "map"); + lua_pushvalue(L, scv_ref); + lua_settable(L, LUA_GLOBALSINDEX); + } + void LuaVM::setCityView(OpenGTA::CityView & cv) { LGUARD(L); + /* CityView *scv = static_cast(&cv); lua_gettable(L, LUA_GLOBALSINDEX); int scv_ref = Lunar::push(L, scv, false); lua_pushliteral(L, "city_view"); lua_pushvalue(L, scv_ref); lua_settable(L, LUA_GLOBALSINDEX); + */ } void LuaVM::runString(const char* _str) { diff --git a/lua_addon/lua_vm.h b/lua_addon/lua_vm.h index be00c4a..d489086 100644 --- a/lua_addon/lua_vm.h +++ b/lua_addon/lua_vm.h @@ -14,18 +14,20 @@ namespace OpenGTA { void runString(const char*); void runFile(const char*); void callSimpleFunction(const char*); - void prepare(); void setCityView(OpenGTA::CityView &); + void setMap(OpenGTA::Map &); int getGlobalInt(const char*); float getGlobalFloat(const char*); const char* getGlobalString(const char*); void setGlobalInt(const char*, int); void setGlobalFloat(const char*, float); void setGlobalString(const char*, const char*); + lua_State *getInternalState(); protected: lua_State *L; private: bool _registered; + void prepare(); }; typedef Loki::SingletonHolder LuaVMHolder; diff --git a/main2.cpp b/main2.cpp index c4f88d4..48c4398 100644 --- a/main2.cpp +++ b/main2.cpp @@ -6,7 +6,7 @@ extern void parse_args(int argc, char* argv[]); extern void on_exit(); -extern void run_init(); +extern void run_init(const char*); extern void run_main(); int global_EC = 0; @@ -30,10 +30,10 @@ int main(int argc, char* argv[]) { INFO << "ignoring exceptions" << std::endl; if (!catch_exceptions) - run_init(); + run_init(argv[0]); else { try { - run_init(); + run_init(argv[0]); } catch (Exception & e) { ERROR << "Exception during startup: " << e.what() << endl; diff --git a/makefile b/makefile index ec6a03a..e547374 100644 --- a/makefile +++ b/makefile @@ -1,7 +1,7 @@ include src_list.make INC_EX_LIBS = $(PHYSFS_INC) $(SDL_INC) $(LUA_INC) -INC_INTERN = -I. -Iloki/include/loki -Iutil -Icoldet -Imath +INC_INTERN = -I. -Iloki/include/loki -Iutil -Icoldet -Imath -Iopensteer/include INC = $(INC_INTERN) $(INC_EX_LIBS) @@ -44,7 +44,7 @@ coldet/libcoldet.a: make -C coldet -f makefile.g++ all clean: - rm -f tags depend *.o tools/*.o coldet/*.o lua_addon/*.o math/*.o util/*.o \ + rm -f tags depend *.o tools/*.o coldet/*.o lua_addon/*.o math/*.o util/*.o opensteer/src/Clock.o \ spriteplayer gfxextract viewer $(TOOLS) objdump objdump_map minimap slopeview luaviewer g24 html: doxy_main.h @@ -70,9 +70,12 @@ rclean: libclean: make -C coldet -f makefile.g++ clean + make -c loki clean + rm -f loki/lib/libloki.* + rm -f $(OSTEER_OBJ) depend: loki src_list.make $(RM) depend - $(CXX) $(CXXFLAGS) -DGCC -E -MM $(GL_SRC) $(OGTA_SRC) $(UTIL_SRC) > depend + $(CXX) $(CXXFLAGS) -E -MM $(GL_SRC) $(OGTA_SRC) $(UTIL_SRC) > depend diff --git a/math/interpolate.hpp b/math/interpolate.hpp new file mode 100644 index 0000000..e1deafe --- /dev/null +++ b/math/interpolate.hpp @@ -0,0 +1,218 @@ +#ifndef MMATH_INTERPOLATE_H +#define MMATH_INTERPOLATE_H +#include + +namespace Math { + namespace Interpolator { + + /** Interpolate between values - creating data out of nothing. + * + * The math mainly comes from: + * http://local.wasp.uwa.edu.au/~pbourke/other/interpolation/ + * + * Capsuled into classes which store the values to allow usage + * as a kind of data - consumer/producer. + * + * This idea comes from here: */ + // http://exult.cvs.sourceforge.net/*checkout*/exult/exult/audio/Audio.cc + + template + class Linear { + public: + Linear(const T & y1, const T & y2); + T getAt(const T & mu) const; + void shiftAndFeed(const T & y_i); + private: + T v1, v2; + }; + + template + class Cubic { + public: + Cubic(const T & y0, + const T & y1, const T & y2, const T & y3); + Cubic(const T & y1, + const T & y2, const T & y3); + + void shiftAndFeed(const T & y_i); + void shift(); + T getAt(const T & mu) const; + + private: + void setCoefficients(const T y0, + const T y1, const T y2, const T y3); + T a0, a1, a2, a3; + T v2, v3; + }; + + template + class Cosine { + public: + Cosine(const T & y1, const T & y2); + + T getAt(const T & mu) const; + void shiftAndFeed(const T & y_i); + + private: + T v1, v2; + }; + + template + class Hermite { + public: + Hermite(const T & y1, const T & y2, const T & y3, + const T & _tension, const T & _bias); + Hermite(const T & y0, const T & y1, const T & y2, + const T & y3, const T & _tension, const T & _bias); + + T getAt(const T & mu) const; + void shiftAndFeed(const T & y_i); + void shift(); + void setTension(const T & _tension); + void setBias(const T & _bias); + + private: + void setCoefficients(const T y0, const T y1, const T y2, + const T y3); + void updateCoefficients(); + T m0, m1; + T v0, v1, v2, v3; + T tension, bias; + }; + + // implementation + + template + Linear::Linear(const T & y1, const T & y2) : v1(y1), v2(y2) {} + + template + T Linear::getAt(const T & mu) const { + return v1 * (1 - mu) + v2 * mu; + } + + template + void Linear::shiftAndFeed(const T & y_i) { + v1 = v2; + v2 = y_i; + } + + // Cubic + + template + Cubic::Cubic(const T & y0, + const T & y1, const T & y2, const T & y3) { + setCoefficients(y0, y1, y2, y3); + } + + template + Cubic::Cubic(const T & y1, + const T & y2, const T & y3) { + setCoefficients(2 * y1 - y2, y1, y2, y3); + } + + template + void Cubic::shiftAndFeed(const T & y_i) { + setCoefficients(a3, v2, v3, y_i); + } + + template + void Cubic::shift() { + setCoefficients(a3, v2, v3, 2 * v2 - a3); + } + + template + void Cubic::setCoefficients(const T y0, + const T y1, const T y2, const T y3) { + v2 = y2; v3 = y3; + + a0 = y3 - y2 - y0 + y1; + a1 = y0 - y1 - a0; + a2 = y2 - y0; + a3 = y1; + } + + template + T Cubic::getAt(const T & mu) const { + const T mu_sq = mu * mu; + return(a0 * mu * mu_sq + a1 * mu_sq + a2 * mu + a3); + } + + // Cosine + + template + Cosine::Cosine(const T & y1, const T & y2) : v1(y1), v2(y2) {} + + template + T Cosine::getAt(const T & mu) const { + T mu2 = (1 - cos(mu * M_PI)) / 2; + return v1 * (1 - mu2) + v2 * mu2; + } + + template + void Cosine::shiftAndFeed(const T & y_i) { + v1 = v2; + v2 = y_i; + } + + // Hermite + + template + Hermite::Hermite(const T & y1, const T & y2, const T & y3, + const T & _tension, const T & _bias) : tension(_tension), bias(_bias) { + setCoefficients(2 * y1 - y2, y1, y2, y3); + } + + template + T Hermite::getAt(const T & mu) const { + const T mu_sq = mu * mu; + const T mu_cu = mu_sq * mu; + + T a0 = 2 * mu_cu - 3 * mu_sq + 1; + T a1 = mu_cu - 2 * mu_sq + mu; + T a2 = mu_cu - mu_sq; + T a3 =-2 * mu_cu + 3 * mu_sq; + + return a0 * v1 + a1 * m0 + a2 * m1 + a3 * v2; + } + + template + void Hermite::setCoefficients(const T y0, const T y1, const T y2, + const T y3) { + v0 = y0; v1 = y1; v2 = y2; v3 = y3; + updateCoefficients(); + } + + template + void Hermite::updateCoefficients() { + m0 = (v1 - v0) * (1 + bias) * (1 - tension) / 2; + m0 += (v2 - v1) * (1 - bias) * (1 - tension) / 2; + m1 = (v2 - v1) * (1 + bias) * (1 - tension) / 2; + m1 += (v3 - v2) * (1 - bias) * (1 - tension) / 2; + } + + template + void Hermite::setTension(const T & _tension) { + tension = _tension; + updateCoefficients(); + } + + template + void Hermite::setBias(const T & _bias) { + bias = _bias; + updateCoefficients(); + } + + template + void Hermite::shiftAndFeed(const T & y_i) { + setCoefficients(v1, v2, v3, y_i); + } + + template + void Hermite::shift() { + setCoefficients(v1, v2, v3, 2 * v2 - v1); + } + + } +} + +#endif diff --git a/math/obox.cpp b/math/obox.cpp index ab647e7..57456a6 100644 --- a/math/obox.cpp +++ b/math/obox.cpp @@ -8,7 +8,7 @@ // // Check if a point is in this bounding box // -bool OBox::IsPointInBox(const Vector3D &InP) +bool OBox::IsPointInBox(const Vector3D &InP) const { // Rotate the point into the box's coordinates Vector3D P = Transform(InP, m_M.Inverse()); @@ -23,7 +23,7 @@ bool OBox::IsPointInBox(const Vector3D &InP) // // Check if a sphere overlaps any part of this bounding box // -bool OBox::IsSphereInBox( const Vector3D &InP, float fRadius) +bool OBox::IsSphereInBox( const Vector3D &InP, float fRadius) const { float fDist; float fDistSq = 0; @@ -44,7 +44,7 @@ bool OBox::IsSphereInBox( const Vector3D &InP, float fRadius) // // Check if the bounding box is completely behind a plane( defined by a normal and a point ) // -bool OBox::BoxOutsidePlane( const Vector3D &InNorm, const Vector3D &InP ) +bool OBox::BoxOutsidePlane( const Vector3D &InNorm, const Vector3D &InP ) const { // Plane Normal in Box Space Vector3D Norm = rotateVector(InNorm, m_M.Inverse() ); @@ -62,7 +62,7 @@ bool OBox::BoxOutsidePlane( const Vector3D &InNorm, const Vector3D &InP ) // // Does the Line (L1, L2) intersect the Box? // -bool OBox::IsLineInBox( const Vector3D& L1, const Vector3D& L2 ) +bool OBox::IsLineInBox( const Vector3D& L1, const Vector3D& L2 ) const { // Put line in box space Matrix3D MInv = m_M.Inverse(); @@ -90,7 +90,7 @@ bool OBox::IsLineInBox( const Vector3D& L1, const Vector3D& L2 ) // // Returns a 3x3 rotation matrix as vectors // -inline void OBox::GetInvRot( Vector3D *pvRot ) +inline void OBox::GetInvRot( Vector3D *pvRot ) const { pvRot[0] = Vector3D( m_M.m[0][0], m_M.m[0][1], m_M.m[0][2] ); pvRot[1] = Vector3D( m_M.m[1][0], m_M.m[1][1], m_M.m[1][2] ); @@ -101,7 +101,7 @@ inline void OBox::GetInvRot( Vector3D *pvRot ) // Check if any part of a box is inside any part of another box // Uses the separating axis test. // -bool OBox::IsBoxInBox( OBox &BBox ) +bool OBox::IsBoxInBox( OBox &BBox ) const { Vector3D SizeA = m_Extent; Vector3D SizeB = BBox.m_Extent; diff --git a/math/obox.h b/math/obox.h index ef66a8b..62545a0 100644 --- a/math/obox.h +++ b/math/obox.h @@ -12,6 +12,8 @@ class OBox { Set( m, extent ); } OBox( const Matrix3D & m, const Vector3D & low, const Vector3D & high ) { Set( m, low, high ); } + OBox( const OBox & other) + { Set( other.m_M, other.m_Extent ); } void Set( const Matrix3D & m, const Vector3D & extent ) { @@ -25,17 +27,17 @@ class OBox m_Extent = 0.5f * (high - low); } - Vector3D GetSize() + Vector3D GetSize() const { return 2.0f * m_Extent; } - Vector3D GetCenterPoint() + Vector3D GetCenterPoint() const { return m_M.GetTranslate(); } - void GetInvRot( Vector3D *pvRot ); + void GetInvRot( Vector3D *pvRot ) const; - bool IsPointInBox( const Vector3D & p ); - bool IsBoxInBox( OBox & box ); - bool IsSphereInBox( const Vector3D & p, float fRadius ); - bool IsLineInBox( const Vector3D & l1, const Vector3D & l2 ); - bool BoxOutsidePlane( const Vector3D & normal, const Vector3D & p ); + bool IsPointInBox( const Vector3D & p ) const ; + bool IsBoxInBox( OBox & box ) const ; + bool IsSphereInBox( const Vector3D & p, float fRadius ) const ; + bool IsLineInBox( const Vector3D & l1, const Vector3D & l2 ) const ; + bool BoxOutsidePlane( const Vector3D & normal, const Vector3D & p ) const ; // Data Matrix3D m_M; diff --git a/math/rectangle.hpp b/math/rectangle.hpp new file mode 100644 index 0000000..824a9d9 --- /dev/null +++ b/math/rectangle.hpp @@ -0,0 +1,108 @@ +#ifndef RECTANGLE_2D_H +#define RECTANGLE_2D_H + +#include + +namespace Math { + + template struct Rectangle { + U x; + U y; + U w; + U h; + + Rectangle() : x(0), y(0), w(0), h(0) {} + + Rectangle(U _x, U _y, U _w, U _h) : + x(_x), y(_y), w(_w), h(_h) {} + + Rectangle(const Rectangle & o) : + x(o.x), y(o.y), w(o.w), h(o.h) {} + + inline bool operator == (const Rectangle & o) const { + return ((x == o.x) && (y == o.y) && (w == o.w) && (h == o.h)); + } + + inline bool isInside(U _x, U _y) const { + return ((_x >= x) && (_y >= y) && + (_x <= x + w) && (_y <= y + h) ); + } + + }; + + template bool rectangle_test_inside ( + const Rectangle & larger, + const Rectangle & smaller ) { + return (larger.isInside( smaller.x, smaller.y ) && + larger.isInside( smaller.x + smaller.w, smaller.y ) && + larger.isInside( smaller.x, smaller.y + smaller.h ) && + larger.isInside( smaller.x + smaller.w, smaller.y + smaller.h)); + } + + template bool rectangle_test_leftborder ( + const Rectangle & larger, + const Rectangle & smaller ) { + return (larger.x == smaller.x); + } + + template bool rectangle_test_rightborder ( + const Rectangle & larger, + const Rectangle & smaller ) { + return (larger.x + larger.w == smaller.x + smaller.w); + } + + template bool rectangle_test_bottomborder ( + const Rectangle & larger, + const Rectangle & smaller ) { + return (larger.y == smaller.y); + } + + template bool rectangle_test_topborder ( + const Rectangle & larger, + const Rectangle & smaller ) { + return (larger.y + larger.h == smaller.y + smaller.h); + } + + + template class RectangleGeometry { + public: + typedef std::list< Rectangle < U > > ListOfRectangleU; + /* void Union (ListOfRectangleU & list, const Rectangle< U > & first, + const Rectangle< U > & second); + void Intersection(ListOfRectangleU & list, const Rectangle< U > & first, + const Rectangle< U > & second); + */ + static void difference(ListOfRectangleU & list, const Rectangle< U > & first, + const Rectangle< U > & second); + }; + + template void RectangleGeometry::difference(ListOfRectangleU & list, + const Rectangle< U > & first, const Rectangle< U > & second) { + // assume first is larger, second is smaller + if (! rectangle_test_leftborder(first, second)) { + /* + ### # + #x# split off the left col # + ### # + */ + list.push_back( Rectangle( first.x, first.y, second.x - first.x, first.h ) ); + } + if (! rectangle_test_rightborder(first, second)) { + // split of the right column + list.push_back( Rectangle( second.x + second.w, first.y, + first.x + first.w - (second.x + second.w), first.h)); + } + if (! rectangle_test_topborder(first, second)) { + // remainder of the top row + list.push_back( Rectangle( second.x, second.y + second.h, + second.w, first.y + first.h - (second.y + second.h))); + } + if (! rectangle_test_bottomborder(first, second)) { + // remainder of the bottom row + list.push_back( Rectangle(second.x, first.y, + second.w, second.y - first.y)); + } + } +} + +#endif diff --git a/math/vector.hpp b/math/vector.hpp index 62252e0..4965cd4 100644 --- a/math/vector.hpp +++ b/math/vector.hpp @@ -149,6 +149,23 @@ public: { return fabs (x - v.x) < e && fabs (y - v.y) < e && fabs (z - v.z) < e; } + + // component-wise maximum + const Vector max(const Vector & other) const { + Vector _res; + _res.x = (x > other.x) ? x : other.x; + _res.y = (y > other.y) ? y : other.y; + _res.z = (z > other.x) ? z : other.z; + return _res; + } + + const Vector abs() const { + Vector _res; + _res.x = (x >= 0) ? x : -x; + _res.y = (y >= 0) ? y : -y; + _res.z = (z >= 0) ? z : -z; + return _res; + } }; // // A 3D position diff --git a/math/weighted_set.cpp b/math/weighted_set.cpp new file mode 100644 index 0000000..77962f9 --- /dev/null +++ b/math/weighted_set.cpp @@ -0,0 +1,34 @@ +#include "weighted_set.h" + +namespace Math { + WeightedSet::WeightedSet(unsigned int seed) : + elements(), + rng(seed) { + } + + void WeightedSet::add(unsigned int w, unsigned int e) { + while (w > 0) { + elements.push_back(e); + --w; + } + } + + unsigned int WeightedSet::getRandom() { + //unsigned int rnd = (int) (totalWeight * (rand() / (RAND_MAX + 1.0))); + unsigned int rnd = rng.nextUint(elements.size()); + return elements[rnd]; + } +} + +/* +#include +int main(int argc, char* argv[]) { + Util::Math::WeightedSet set(int(getpid()) ^ int(time(0))); + set.add(1, 1); + set.add(2, 2); + set.add(2, 3); + set.add(3, 4); + set.add(3, 5); + + std::cout << set.getRandom() << std::endl; +}*/ diff --git a/math/weighted_set.h b/math/weighted_set.h new file mode 100644 index 0000000..7d12cfb --- /dev/null +++ b/math/weighted_set.h @@ -0,0 +1,20 @@ +#ifndef WEIGHTED_SET_H +#define WEIGHTED_SET_H + +#include +#include "yasli/random.h" + +namespace Math { + + class WeightedSet { + public: + WeightedSet(unsigned int seed); + void add(unsigned int w, unsigned int e); + unsigned int getRandom(); + private: + std::vector elements; + Random rng; + }; +} + +#endif diff --git a/navdata.cpp b/navdata.cpp index 3dbf252..e77203a 100644 --- a/navdata.cpp +++ b/navdata.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This file contains code derived from information copyrighted by * * DMA Design. It may not be used in a commercial product. * @@ -11,8 +11,10 @@ #include #include #include +#include #include "navdata.h" #include "log.h" +#include "dataholder.h" #include "m_exceptions.h" namespace OpenGTA { @@ -67,27 +69,30 @@ namespace OpenGTA { return res; } - NavData::Sector::Sector(PHYSFS_file* fd) : Rect2D() { + NavData::Sector::Sector(PHYSFS_file* fd) : Rect2D(), sam(0), name("") { sam = 0; isADummy = 0; - std::memset(&name, 0, 30); assert(fd); + //memset(name2, 0, 30); PHYSFS_read(fd, static_cast(&x), 1, 1); PHYSFS_read(fd, static_cast(&y), 1, 1); PHYSFS_read(fd, static_cast(&w), 1, 1); PHYSFS_read(fd, static_cast(&h), 1, 1); PHYSFS_read(fd, static_cast(&sam), 1, 1); - PHYSFS_read(fd, static_cast(&name), 30, 1); + // seek over the name embedded in the mapfile; use sample-num to + // lookup in msg-db + //PHYSFS_read(fd, static_cast(&name2), 30, 1); + PHYSFS_seek(fd, PHYSFS_tell(fd) + 30); } - NavData::Sector::Sector() : Rect2D() { + NavData::Sector::Sector() : Rect2D(), sam(0), name("") { x = 0; y = 0; w = 255; h = 255; sam = 0; - std::memset(&name, 0, 30); isADummy = 1; + //memset(name2, 0, 30); } const char* NavData::Sector::getFullName() { @@ -117,7 +122,7 @@ namespace OpenGTA { return n.c_str(); } - NavData::NavData(PHYSFS_uint32 size, PHYSFS_file *fd) { + NavData::NavData(PHYSFS_uint32 size, PHYSFS_file *fd, const size_t level_num) { if (size % 35) { std::ostringstream o; o << "Navdata size: " << size << " % 35 != 0"; @@ -126,6 +131,8 @@ namespace OpenGTA { } PHYSFS_uint32 c = size / 35; assert(fd); + + MessageDB & msg = MainMsgHolder::Instance().get(); for (PHYSFS_uint32 i = 0; i < c; ++i) { Sector *sec = new Sector(fd); if (sec->getSize() == 0) { // workaround for 'NYC.CMP' (empty sectors) @@ -133,16 +140,25 @@ namespace OpenGTA { WARN << "skipping zero size sector" << std::endl; continue; } - else + else { + std::ostringstream os; + os << std::setfill('0') << std::setw(3) << level_num << "area" << std::setfill('0') << + std::setw(3) << int(sec->sam); + + //INFO << i << " " << sec->name2 << std::endl << os.str() << " : " << msg.getText(os.str()) << std::endl; + sec->name = msg.getText(os.str()); + areas.insert(std::pair(sec->getSize(), sec)); + } } // dummy catch-all sector for gta london maps areas.insert(std::pair(255*255, new Sector())); + /* std::cout << "map areas (by size)" << std::endl; SectorMapType::iterator i = areas.begin(); while (i != areas.end()) { - std::cout << " " << i->first << " : " << i->second->name << " @ " << + std::cout << " " << i->first << " : " << i->second->name2 << " @ " << int(i->second->x) << "," << int(i->second->y) << " " << int(i->second->w) << "x" << int(i->second->h) << " sample " << int(i->second->sam) << std::endl; ++i; diff --git a/navdata.h b/navdata.h index 4124ed2..5380582 100644 --- a/navdata.h +++ b/navdata.h @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This file contains code derived from information copyrighted by * * DMA Design. It may not be used in a commercial product. * @@ -11,6 +11,7 @@ #ifndef NAVDATA_H #define NAVDATA_H #include +#include #include namespace OpenGTA { @@ -77,14 +78,15 @@ namespace OpenGTA { * 2) probably sound? */ PHYSFS_uint8 sam; // sample number - char name[30]; // FIXME: should not be used + //char name2[30]; // FIXME: should not be used + std::string name; /** Returns the name prefixed with sub-area location. */ const char* getFullName(); private: bool isADummy; }; - NavData(PHYSFS_uint32 size, PHYSFS_file *fd); + NavData(PHYSFS_uint32 size, PHYSFS_file *fd, const size_t level_num); ~NavData(); Sector* getSectorAt(PHYSFS_uint8, PHYSFS_uint8); private: diff --git a/ogta_version b/ogta_version new file mode 100644 index 0000000..9c173cf --- /dev/null +++ b/ogta_version @@ -0,0 +1 @@ +2007-04-16 diff --git a/opengta.h b/opengta.h index 91ea175..412e974 100644 --- a/opengta.h +++ b/opengta.h @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This file contains code derived from information copyrighted by * * DMA Design. It may not be used in a commercial product. * @@ -179,10 +179,13 @@ namespace OpenGTA { void prepareSideTexture(unsigned int idx, unsigned char* dst); void prepareLidTexture(unsigned int idx, unsigned char* dst); void prepareAuxTexture(unsigned int idx, unsigned char* dst); + unsigned int getRandomPedRemapNumber(); + unsigned int getPedRemapNumberType(unsigned int _type); SpriteNumbers spriteNumbers; CarInfo* findCarByModel(PHYSFS_uint8); + size_t getNumCarModels() { return carInfos.size(); } unsigned char* getTmpBuffer(bool rgba); SpriteInfo* getSprite(size_t id) { return spriteInfos[id]; } @@ -253,6 +256,9 @@ namespace OpenGTA { bool delta_is_a_set; Util::Set sideTexBlockMove; + + unsigned int firstValidPedRemap; + unsigned int lastValidPedRemap; }; // just a forward declaration @@ -468,7 +474,7 @@ namespace OpenGTA { void loadObjects(); void loadRoutes(); void loadLocations(); - void loadNavData(); + void loadNavData(const size_t level_num); static const PHYSFS_uint8 _topHeaderSize = 28; static const PHYSFS_uint64 _baseSize = 262144; }; diff --git a/opensteer/COPYING.OPENSTEER b/opensteer/COPYING.OPENSTEER new file mode 100644 index 0000000..8c4dcb5 --- /dev/null +++ b/opensteer/COPYING.OPENSTEER @@ -0,0 +1,30 @@ +OpenSteer -- Steering Behaviors for Autonomous Characters + + +Copyright (c) 2002-2005, Sony Computer Entertainment America +Original author: Craig Reynolds + + +OpenSteer is open source software distributed in accordance with the MIT +License (http://www.opensource.org/licenses/mit-license.php) which says: + + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + + diff --git a/opensteer/include/OpenSteer/Clock.h b/opensteer/include/OpenSteer/Clock.h new file mode 100644 index 0000000..2edf125 --- /dev/null +++ b/opensteer/include/OpenSteer/Clock.h @@ -0,0 +1,205 @@ +// ---------------------------------------------------------------------------- +// +// +// OpenSteer -- Steering Behaviors for Autonomous Characters +// +// Copyright (c) 2002-2005, Sony Computer Entertainment America +// Original author: Craig Reynolds +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// +// ---------------------------------------------------------------------------- +// +// +// discrete time simulation clock for OpenSteerDemo +// +// Keeps track of real clock time and simulation time. Encapsulates the time +// API of the underlying operating system. Can be put in either "as fast as +// possible" variable time step mode (where simulation time steps are based on +// real time elapsed between updates), or in fixed "target FPS" mode where the +// simulation steps are constrained to start on 1/FPS boundaries (e.g. on a 60 +// hertz video game console). Also handles the notion of "pausing" simulation +// time. +// +// Usage: allocate a clock, set its "paused" or "targetFPS" parameters, then +// call updateGlobalSimulationClock before each simulation step. +// +// 10-04-04 bk: put everything into the OpenSteer namespace +// 11-11-03 cwr: another overhaul: support aniamtion mode, switch to +// functional API, move smoothed stats inside this class +// 09-24-02 cwr: major overhaul +// 06-26-02 cwr: created +// +// +// ---------------------------------------------------------------------------- + + +#ifndef OPENSTEER_CLOCK_H +#define OPENSTEER_CLOCK_H + +#include "OpenSteer/Utilities.h" + +#if defined (_XBOX) + #include +#elif defined (_WIN32) + #include +#endif + + +namespace OpenSteer { + + class Clock + { + public: + + // constructor + Clock (); + + // update this clock, called exactly once per simulation step ("frame") + void update (void); + + // returns the number of seconds of real time (represented as a float) + // since the clock was first updated. + float realTimeSinceFirstClockUpdate (void); + + // force simulation time ahead, ignoring passage of real time. + // Used for OpenSteerDemo's "single step forward" and animation mode + float advanceSimulationTimeOneFrame (void); + void advanceSimulationTime (const float seconds); + + // "wait" until next frame time + void frameRateSync (void); + + + // main clock modes: variable or fixed frame rate, real-time or animation + // mode, running or paused. + private: + // run as fast as possible, simulation time is based on real time + bool variableFrameRateMode; + + // fixed frame rate (ignored when in variable frame rate mode) in + // real-time mode this is a "target", in animation mode it is absolute + int fixedFrameRate; + + // used for offline, non-real-time applications + bool animationMode; + + // is simulation running or paused? + bool paused; + public: + int getFixedFrameRate (void) {return fixedFrameRate;} + int setFixedFrameRate (int ffr) {return fixedFrameRate = ffr;} + + bool getAnimationMode (void) {return animationMode;} + bool setAnimationMode (bool am) {return animationMode = am;} + + bool getVariableFrameRateMode (void) {return variableFrameRateMode;} + bool setVariableFrameRateMode (bool vfrm) + {return variableFrameRateMode = vfrm;} + + bool togglePausedState (void) {return (paused = !paused);}; + bool getPausedState (void) {return paused;}; + bool setPausedState (bool newPS) {return paused = newPS;}; + + + // clock keeps track of "smoothed" running average of recent frame rates. + // When a fixed frame rate is used, a running average of "CPU load" is + // kept (aka "non-wait time", the percentage of each frame time (time + // step) that the CPU is busy). + private: + float smoothedFPS; + float smoothedUsage; + void updateSmoothedRegisters (void) + { + const float rate = getSmoothingRate (); + if (elapsedRealTime > 0) + blendIntoAccumulator (rate, 1 / elapsedRealTime, smoothedFPS); + if (! getVariableFrameRateMode ()) + blendIntoAccumulator (rate, getUsage (), smoothedUsage); + } + public: + float getSmoothedFPS (void) const {return smoothedFPS;} + float getSmoothedUsage (void) const {return smoothedUsage;} + float getSmoothingRate (void) const + { + if (smoothedFPS == 0) return 1; else return elapsedRealTime * 1.5f; + } + float getUsage (void) + { + // run time per frame over target frame time (as a percentage) + return ((100 * elapsedNonWaitRealTime) / (1.0f / fixedFrameRate)); + } + + + // clock state member variables and public accessors for them + private: + // real "wall clock" time since launch + float totalRealTime; + + // total time simulation has run + float totalSimulationTime; + + // total time spent paused + float totalPausedTime; + + // sum of (non-realtime driven) advances to simulation time + float totalAdvanceTime; + + // interval since last simulation time + // (xxx does this need to be stored in the instance? xxx) + float elapsedSimulationTime; + + // interval since last clock update time + // (xxx does this need to be stored in the instance? xxx) + float elapsedRealTime; + + // interval since last clock update, + // exclusive of time spent waiting for frame boundary when targetFPS>0 + float elapsedNonWaitRealTime; + public: + float getTotalRealTime (void) {return totalRealTime;} + float getTotalSimulationTime (void) {return totalSimulationTime;} + float getTotalPausedTime (void) {return totalPausedTime;} + float getTotalAdvanceTime (void) {return totalAdvanceTime;} + float getElapsedSimulationTime (void) {return elapsedSimulationTime;} + float getElapsedRealTime (void) {return elapsedRealTime;} + float getElapsedNonWaitRealTime (void) {return elapsedNonWaitRealTime;} + + + private: + // "manually" advance clock by this amount on next update + float newAdvanceTime; + + // "Calendar time" when this clock was first updated + #ifdef _WIN32 + // from QueryPerformanceCounter on Windows + LONGLONG basePerformanceCounter; + #else + // from gettimeofday on Linux and Mac OS X + int baseRealTimeSec; + int baseRealTimeUsec; + #endif + }; + +} // namespace OpenSteer + + +// ---------------------------------------------------------------------------- +#endif // OPENSTEER_CLOCK_H diff --git a/opensteer/include/OpenSteer/Proximity.h b/opensteer/include/OpenSteer/Proximity.h new file mode 100644 index 0000000..b899154 --- /dev/null +++ b/opensteer/include/OpenSteer/Proximity.h @@ -0,0 +1,337 @@ +// ---------------------------------------------------------------------------- +// +// +// OpenSteer -- Steering Behaviors for Autonomous Characters +// +// Copyright (c) 2002-2005, Sony Computer Entertainment America +// Original author: Craig Reynolds +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// +// ---------------------------------------------------------------------------- +// +// +// Proximity +// +// Data structures for accelerating proximity/locality/neighborhood queries +// +// 10-04-04 bk: put everything into the OpenSteer namespace +// 06-20-01 cwr: created +// +// +// ---------------------------------------------------------------------------- + + +#ifndef OPENSTEER_PROXIMITY_H +#define OPENSTEER_PROXIMITY_H + + +#include +#include +#include "OpenSteer/Vec3.h" +#include "OpenSteer/lq.h" // XXX temp? + + +namespace OpenSteer { + + + // ---------------------------------------------------------------------------- + // "tokens" are the objects manipulated by the spatial database + + + template + class AbstractTokenForProximityDatabase + { + public: + + virtual ~AbstractTokenForProximityDatabase () {} + + // the client object calls this each time its position changes + virtual void updateForNewPosition (const Vec3& position) = 0; + + // find all neighbors within the given sphere (as center and radius) + virtual void findNeighbors (const Vec3& center, + const float radius, + std::vector& results) = 0; + +#ifndef NO_LQ_BIN_STATS + // only meaningful for LQProximityDatabase, provide dummy default + virtual void getBinPopulationStats (int& min, int& max, float& average) + {min=max=0; average=0.0;} +#endif // NO_LQ_BIN_STATS + }; + + + // ---------------------------------------------------------------------------- + // abstract type for all kinds of proximity databases + + + template + class AbstractProximityDatabase + { + public: + + // type for the "tokens" manipulated by this spatial database + typedef AbstractTokenForProximityDatabase tokenType; + + + virtual ~AbstractProximityDatabase() { /* Nothing to do? */ } + + // allocate a token to represent a given client object in this database + virtual tokenType* allocateToken (ContentType parentObject) = 0; + + // insert + // XXX maybe this should return an iterator? + // XXX see http://www.sgi.com/tech/stl/set.html + // virtual void insert (const ContentType& x) = 0; + + // XXX name? + // returns the number of tokens in the proximity database + virtual int getPopulation (void) = 0; + }; + + + // ---------------------------------------------------------------------------- + // This is the "brute force" O(n^2) approach implemented in terms of the + // AbstractProximityDatabase protocol so it can be compared directly to other + // approaches. (e.g. the Boids plugin allows switching at runtime.) + + + template + class BruteForceProximityDatabase + : public AbstractProximityDatabase + { + public: + + // constructor + BruteForceProximityDatabase (void) + { + } + + // destructor + virtual ~BruteForceProximityDatabase () + { + } + + // "token" to represent objects stored in the database + class tokenType : public AbstractTokenForProximityDatabase + { + public: + + // constructor + tokenType (ContentType parentObject, BruteForceProximityDatabase& pd) + { + // store pointer to our associated database and the object this + // token represents, and store this token on the database's vector + bfpd = &pd; + object = parentObject; + bfpd->group.push_back (this); + } + + // destructor + virtual ~tokenType () + { + // remove this token from the database's vector + bfpd->group.erase (std::find (bfpd->group.begin(), + bfpd->group.end(), + this)); + } + + // the client object calls this each time its position changes + void updateForNewPosition (const Vec3& newPosition) + { + position = newPosition; + } + + // find all neighbors within the given sphere (as center and radius) + void findNeighbors (const Vec3& center, + const float radius, + std::vector& results) + { + // loop over all tokens + const float r2 = radius * radius; + for (tokenIterator i = bfpd->group.begin(); + i != bfpd->group.end(); + i++) + { + const Vec3 offset = center - (**i).position; + const float d2 = offset.lengthSquared(); + + // push onto result vector when within given radius + if (d2 < r2) results.push_back ((**i).object); + } + } + + private: + BruteForceProximityDatabase* bfpd; + ContentType object; + Vec3 position; + }; + + typedef std::vector tokenVector; + typedef typename tokenVector::const_iterator tokenIterator; + + // allocate a token to represent a given client object in this database + tokenType* allocateToken (ContentType parentObject) + { + return new tokenType (parentObject, *this); + } + + // return the number of tokens currently in the database + int getPopulation (void) + { + return (int) group.size(); + } + + private: + // STL vector containing all tokens in database + tokenVector group; + }; + + + // ---------------------------------------------------------------------------- + // A AbstractProximityDatabase-style wrapper for the LQ bin lattice system + + + template + class LQProximityDatabase : public AbstractProximityDatabase + { + public: + + // constructor + LQProximityDatabase (const Vec3& center, + const Vec3& dimensions, + const Vec3& divisions) + { + const Vec3 halfsize (dimensions * 0.5f); + const Vec3 origin (center - halfsize); + + lq = lqCreateDatabase (origin.x, origin.y, origin.z, + dimensions.x, dimensions.y, dimensions.z, + (int) round (divisions.x), + (int) round (divisions.y), + (int) round (divisions.z)); + } + + // destructor + virtual ~LQProximityDatabase () + { + lqDeleteDatabase (lq); + lq = NULL; + } + + // "token" to represent objects stored in the database + class tokenType : public AbstractTokenForProximityDatabase + { + public: + + // constructor + tokenType (ContentType parentObject, LQProximityDatabase& lqsd) + { + lqInitClientProxy (&proxy, parentObject); + lq = lqsd.lq; + } + + // destructor + virtual ~tokenType (void) + { + lqRemoveFromBin (&proxy); + } + + // the client object calls this each time its position changes + void updateForNewPosition (const Vec3& p) + { + lqUpdateForNewLocation (lq, &proxy, p.x, p.y, p.z); + } + + // find all neighbors within the given sphere (as center and radius) + void findNeighbors (const Vec3& center, + const float radius, + std::vector& results) + { + lqMapOverAllObjectsInLocality (lq, + center.x, center.y, center.z, + radius, + perNeighborCallBackFunction, + (void*)&results); + } + + // called by LQ for each clientObject in the specified neighborhood: + // push that clientObject onto the ContentType vector in void* + // clientQueryState + // (parameter names commented out to prevent compiler warning from "-W") + static void perNeighborCallBackFunction (void* clientObject, + float /*distanceSquared*/, + void* clientQueryState) + { + typedef std::vector ctv; + ctv& results = *((ctv*) clientQueryState); + results.push_back ((ContentType) clientObject); + } + +#ifndef NO_LQ_BIN_STATS + // Get statistics about bin populations: min, max and + // average of non-empty bins. + void getBinPopulationStats (int& min, int& max, float& average) + { + lqGetBinPopulationStats (lq, &min, &max, &average); + } +#endif // NO_LQ_BIN_STATS + + private: + lqClientProxy proxy; + lqDB* lq; + }; + + + // allocate a token to represent a given client object in this database + tokenType* allocateToken (ContentType parentObject) + { + return new tokenType (parentObject, *this); + } + + // count the number of tokens currently in the database + int getPopulation (void) + { + int count = 0; + lqMapOverAllObjects (lq, counterCallBackFunction, &count); + return count; + } + + // (parameter names commented out to prevent compiler warning from "-W") + static void counterCallBackFunction (void* /*clientObject*/, + float /*distanceSquared*/, + void* clientQueryState) + { + int& counter = *(int*)clientQueryState; + counter++; + } + + + private: + lqDB* lq; + }; + +} // namespace OpenSteer + + + +// ---------------------------------------------------------------------------- +#endif // OPENSTEER_PROXIMITY_H diff --git a/opensteer/include/OpenSteer/Utilities.h b/opensteer/include/OpenSteer/Utilities.h new file mode 100644 index 0000000..606fbe4 --- /dev/null +++ b/opensteer/include/OpenSteer/Utilities.h @@ -0,0 +1,514 @@ +// ---------------------------------------------------------------------------- +// +// +// OpenSteer -- Steering Behaviors for Autonomous Characters +// +// Copyright (c) 2002-2005, Sony Computer Entertainment America +// Original author: Craig Reynolds +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// +// ---------------------------------------------------------------------------- +// +// +// Utilities for OpenSteering +// +// 08-06-05 bk: added functions to clamp values to a certain value range, to +// compare values using a tolerance, and so on. +// 10-04-04 bk: put everything into the OpenSteer namespace +// 07-09-02 cwr: created +// +// +// ---------------------------------------------------------------------------- + + +#ifndef OPENSTEER_UTILITIES_H +#define OPENSTEER_UTILITIES_H + + +#include // for ostream, <<, etc. +#include // for rand, etc. +#include // for FLT_MAX, etc. +#include // for sqrt, etc. +#include // for std::vector +#include // for assert +#include // for numeric_limits + +// ---------------------------------------------------------------------------- +// For the sake of Windows, apparently this is a "Linux/Unix thing" + + +#ifndef OPENSTEER_M_PI +#define OPENSTEER_M_PI 3.14159265358979323846f +#endif + +#ifdef _MSC_VER +#undef min +#undef max +#endif + + +namespace OpenSteer { + + // ---------------------------------------------------------------------------- + // Generic interpolation + + + template inline T interpolate (float alpha, const T& x0, const T& x1) + { + return x0 + ((x1 - x0) * alpha); + } + + + // ---------------------------------------------------------------------------- + // Random number utilities + + + // Returns a float randomly distributed between 0 and 1 + + inline float frandom01 (void) + { + return (((float) rand ()) / ((float) RAND_MAX)); + } + + + // Returns a float randomly distributed between lowerBound and upperBound + + inline float frandom2 (float lowerBound, float upperBound) + { + return lowerBound + (frandom01 () * (upperBound - lowerBound)); + } + + + // ---------------------------------------------------------------------------- + // Constrain a given value (x) to be between two (ordered) bounds: min + // and max. Returns x if it is between the bounds, otherwise returns + // the nearer bound. + + + inline float clip (const float x, const float min, const float max) + { + if (x < min) return min; + if (x > max) return max; + return x; + } + + + // ---------------------------------------------------------------------------- + // remap a value specified relative to a pair of bounding values + // to the corresponding value relative to another pair of bounds. + // Inspired by (dyna:remap-interval y y0 y1 z0 z1) + + + inline float remapInterval (float x, + float in0, float in1, + float out0, float out1) + { + // uninterpolate: what is x relative to the interval in0:in1? + float relative = (x - in0) / (in1 - in0); + + // now interpolate between output interval based on relative x + return interpolate (relative, out0, out1); + } + + + // Like remapInterval but the result is clipped to remain between + // out0 and out1 + + + inline float remapIntervalClip (float x, + float in0, float in1, + float out0, float out1) + { + // uninterpolate: what is x relative to the interval in0:in1? + float relative = (x - in0) / (in1 - in0); + + // now interpolate between output interval based on relative x + return interpolate (clip (relative, 0, 1), out0, out1); + } + + + // ---------------------------------------------------------------------------- + // classify a value relative to the interval between two bounds: + // returns -1 when below the lower bound + // returns 0 when between the bounds (inside the interval) + // returns +1 when above the upper bound + + + inline int intervalComparison (float x, float lowerBound, float upperBound) + { + if (x < lowerBound) return -1; + if (x > upperBound) return +1; + return 0; + } + + + + // ---------------------------------------------------------------------------- + + + inline float scalarRandomWalk (const float initial, + const float walkspeed, + const float min, + const float max) + { + const float next = initial + (((frandom01() * 2) - 1) * walkspeed); + if (next < min) return min; + if (next > max) return max; + return next; + } + + + // ---------------------------------------------------------------------------- + + + inline float square (float x) + { + return x * x; + } + + + // ---------------------------------------------------------------------------- + // for debugging: prints one line with a given C expression, an equals sign, + // and the value of the expression. For example "angle = 35.6" + + + #define debugPrint(e) (std::cout << #e" = " << (e) << std::endl << std::flush) + + + // ---------------------------------------------------------------------------- + // blends new values into an accumulator to produce a smoothed time series + // + // Modifies its third argument, a reference to the float accumulator holding + // the "smoothed time series." + // + // The first argument (smoothRate) is typically made proportional to "dt" the + // simulation time step. If smoothRate is 0 the accumulator will not change, + // if smoothRate is 1 the accumulator will be set to the new value with no + // smoothing. Useful values are "near zero". + // + // Usage: + // blendIntoAccumulator (dt * 0.4f, currentFPS, smoothedFPS); + + + template + inline void blendIntoAccumulator (const float smoothRate, + const T& newValue, + T& smoothedAccumulator) + { + smoothedAccumulator = interpolate (clip (smoothRate, 0, 1), + smoothedAccumulator, + newValue); + } + + + // ---------------------------------------------------------------------------- + // given a new Angle and an old angle, adjust the new for angle wraparound (the + // 0->360 flip), returning a value equivalent to newAngle, but closest in + // absolute value to oldAngle. For radians fullCircle = OPENSTEER_M_PI*2, for degrees + // fullCircle = 360. Based on code in stuart/bird/fish demo's camera.cc + // + // (not currently used) + + /* + inline float distance1D (const float a, const float b) + { + const float d = a - b; + return (d > 0) ? d : -d; + } + + + float adjustForAngleWraparound (float newAngle, + float oldAngle, + float fullCircle) + { + // adjust newAngle for angle wraparound: consider its current value (a) + // as well as the angle 2pi larger (b) and 2pi smaller (c). Select the + // one closer (magnitude of difference) to the current value of oldAngle. + const float a = newAngle; + const float b = newAngle + fullCircle; + const float c = newAngle - fullCircle; + const float ad = distance1D (a, oldAngle); + const float bd = distance1D (b, oldAngle); + const float cd = distance1D (c, oldAngle); + + if ((bd < ad) && (bd < cd)) return b; + if ((cd < ad) && (cd < bd)) return c; + return a; + } + */ + + + // ---------------------------------------------------------------------------- + // Functions to encapsulate cross-platform differences for several + // functions. Specifically, the C++ standard says that these functions are + // in the std namespace (std::sqrt, etc.) Apparently the MS VC6 compiler (or + // its header files) do not implement this correctly and the function names + // are in the global namespace. We hope these -XXX versions are a temporary + // expedient, to be removed later. + + + #ifdef _WIN32 + + inline float floorXXX (float x) {return ::floor (x);} + inline float sqrtXXX (float x) {return ::sqrt (x);} + inline float sinXXX (float x) {return ::sin (x);} + inline float cosXXX (float x) {return ::cos (x);} + inline float absXXX (float x) {return ::abs (x);} + inline int absXXX (int x) {return ::abs (x);} + inline float maxXXX (float x, float y) {if (x > y) return x; else return y;} + inline float minXXX (float x, float y) {if (x < y) return x; else return y;} + + #else + + inline float floorXXX (float x) {return std::floor (x);} + inline float sqrtXXX (float x) {return std::sqrt (x);} + inline float sinXXX (float x) {return std::sin (x);} + inline float cosXXX (float x) {return std::cos (x);} + inline float absXXX (float x) {return std::abs (x);} + inline int absXXX (int x) {return std::abs (x);} + inline float maxXXX (float x, float y) {return std::max (x, y);} + inline float minXXX (float x, float y) {return std::min (x, y);} + + #endif + + + // ---------------------------------------------------------------------------- + // round (x) "round off" x to the nearest integer (as a float value) + // + // This is a Gnu-sanctioned(?) post-ANSI-Standard(?) extension (as in + // http://www.opengroup.org/onlinepubs/007904975/basedefs/math.h.html) + // which may not be present in all C++ environments. It is defined in + // math.h headers in Linux and Mac OS X, but apparently not in Win32: + + + #ifdef _WIN32 + + inline float round (float x) + { + if (x < 0) + return -floorXXX (0.5f - x); + else + return floorXXX (0.5f + x); + } + + #else + + inline float round( float x ) + { + return ::round( x ); + } + + #endif + + + /** + * Returns @a valueToClamp clamped to the range @a minValue - @a maxValue. + */ + template< typename T > + T + clamp( T const& valueToClamp, T const& minValue, T const& maxValue) { + assert( minValue <= maxValue && "minValue must be lesser or equal to maxValue." ); + + if ( valueToClamp < minValue ) { + return minValue; + } else if ( valueToClamp > maxValue ) { + return maxValue; + } + + return valueToClamp; + } + + + /** + * Returns the floating point remainder of the division of @a x by @a y. + * If @a y is @c 0 the behavior is undefined. + */ + inline float modulo( float x, float y ) { + assert( 0.0f != y && "Division by zero." ); + return std::fmod( x, y ); + } + + /** + * Returns the floating point remainder of the division of @a x by @a y. + * If @a y is @c 0 the behavior is undefined. + */ + inline double modulo( double x, double y ) { + assert( 0.0 != y && "Division by zero." ); + return std::fmod( x, y ); + } + + /** + * Returns the floating point remainder of the division of @a x by @a y. + * If @a y is @c 0 the behavior is undefined. + */ + inline long double modulo( long double x, long double y ) { + assert( 0.0 != y && "Division by zero." ); + return std::fmod( x, y ); + } + + /** + * Returns the floating point remainder of the division of @a x by @a y. + * If @a y is @c 0 the behavior is undefined. + */ + inline short modulo( short x, short y ) { + assert( 0 != y && "Division by zero." ); + return x % y; + } + + /** + * Returns the floating point remainder of the division of @a x by @a y. + * If @a y is @c 0 the behavior is undefined. + */ + inline int modulo( int x, int y ) { + assert( 0 != y && "Division by zero." ); + return x % y; + } + + /** + * Returns the floating point remainder of the division of @a x by @a y. + * If @a y is @c 0 the behavior is undefined. + */ + inline long modulo( long x, long y ) { + assert( 0 != y && "Division by zero." ); + return x % y; + } + + + /** + * Returns value if value >= 0 , otherwise + * -value. + */ + template< typename T > + T abs( T const& value ) { + return absXXX( value ); + } + + /** + * Returns the maximum of the three values @a v0, @a v1, and @a v2. + * + * @todo Write a unit test. + */ + template< typename T > + T + max( T const& v0, T const& v1, T const& v2 ) { + return maxXXX( v0, maxXXX( v1, v2 ) ); + } + + + /** + * Returns the minimum of the three values @a v0, @a v1, and @a v2. + * + * @todo Write a unit test. + */ + template< typename T > + T + min( T const& v0, T const& v1, T const& v2 ) { + return minXXX( v0, minXXX( v1, v2 ) ); + } + + + /** + * Compares the absolute value of @a v with @a tolerance. + * + * See Christer Ericson, Real-Time Collision Detection, Morgan Kaufmann, + * 2005, pp. 441--443. + * + * @todo Write a unit test. + */ + template< typename T > + bool + isZero( T const& v, T const& tolerance = std::numeric_limits< T >::epsilon() ) { + return abs( v ) <= tolerance; + } + + + /** + * Compares @a lhs with @a rhs given a specific @a tolerance. + * + * @attention Adapt @a tolerance to the range of values of @a lhs and + * @a rhs. + * See Christer Ericson, Real-Time Collision Detection, Morgan Kaufmann, + * 2005, pp. 441--443. + * + * @return abs( lhs - rhs ) <= tolerance + * + * @todo Write a unit test. + */ + template< typename T > + bool + equalsAbsolute( T const& lhs, T const& rhs, T const& tolerance = std::numeric_limits< T >::epsilon() ) { + return isZero( lhs - rhs, tolerance ); + } + + + /** + * Compares @a lhs with @a rhs given a specific @a tolerance taking the + * range of values into account. + * + * See Christer Ericson, Real-Time Collision Detection, Morgan Kaufmann, + * 2005, pp. 441--443. + * + * @return abs( lhs - rhs ) <= tolerance * max( abs( lhs ), abs( rhs ), 1 ) + * + * @todo Write a unit test. + */ + template< typename T > + bool + equalsRelative( T const& lhs, T const& rhs, T const& tolerance = std::numeric_limits< T >::epsilon() ) { + return isZero( lhs - rhs, tolerance * max( abs( lhs ), abs( rhs ), T( 1 ) ) ); + } + + + /** + * Approximately compares @a lhs with @a rhs given a specific @a tolerance + * taking the range of values into account. + * + * See Christer Ericson, Real-Time Collision Detection, Morgan Kaufmann, + * 2005, pp. 441--443. + * + * @return abs( lhs - rhs ) <= tolerance * ( abs( lhs ) + abs( rhs ) + 1 ) + * + * @todo Write a unit test. + */ + template< typename T > + bool + equalsRelativeApproximately( T const& lhs, T const& rhs, T const& tolerance = std::numeric_limits< T >::epsilon() ) { + return isZero( lhs - rhs, tolerance * ( abs( lhs ) + abs( rhs ) + T( 1 ) ) ); + } + + + /** + * Shrinks the capacity of a std::vector to fit its content. + * + * See Scott Meyer, Effective STL, Addison-Wesley, 2001, pp. 77--79. + */ + template< typename T > + void shrinkToFit( std::vector< T >& v ) { + std::vector< T >( v ).swap( v ); + } + + + +} // namespace OpenSteer + + +// ---------------------------------------------------------------------------- +#endif // OPENSTEER_UTILITIES_H diff --git a/opensteer/include/OpenSteer/Vec3.h b/opensteer/include/OpenSteer/Vec3.h new file mode 100644 index 0000000..41bcc35 --- /dev/null +++ b/opensteer/include/OpenSteer/Vec3.h @@ -0,0 +1,382 @@ +// ---------------------------------------------------------------------------- +// +// +// OpenSteer -- Steering Behaviors for Autonomous Characters +// +// Copyright (c) 2002-2005, Sony Computer Entertainment America +// Original author: Craig Reynolds +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// +// ---------------------------------------------------------------------------- +// +// Vec3: OpenSteer's generic type for 3d vectors +// +// This file defines the class Vec3, which is used throughout OpenSteer to +// manipulate 3d geometric data. It includes standard vector operations (like +// vector addition, subtraction, scale, dot, cross...) and more idiosyncratic +// utility functions. +// +// When integrating OpenSteer into a preexisting 3d application, it may be +// important to use the 3d vector type of that application. In that case Vec3 +// can be changed to inherit from the preexisting application' vector type and +// to match the interface used by OpenSteer to the interface provided by the +// preexisting 3d vector type. +// +// 10-04-04 bk: put everything into the OpenSteer namespace +// 03-26-03 cwr: created to replace for Hiranabe-san's execellent but larger +// vecmath package (http://objectclub.esm.co.jp/vecmath/) +// +// ---------------------------------------------------------------------------- + + +#ifndef OPENSTEER_VEC3_H +#define OPENSTEER_VEC3_H + + +#include "OpenSteer/Utilities.h" // for interpolate, etc. + + +namespace OpenSteer { + + // ---------------------------------------------------------------------------- + + + class Vec3 + { + public: + + // ----------------------------------------- generic 3d vector operations + + // three-dimensional Cartesian coordinates + float x, y, z; + + // constructors + Vec3 (void): x( 0.0f ), y( 0.0f ), z( 0.0f ) {} + Vec3 (float X, float Y, float Z) : x( X ), y( Y ), z( Z ) {} + + // vector addition + Vec3 operator+ (const Vec3& v) const {return Vec3 (x+v.x, y+v.y, z+v.z);} + + // vector subtraction + Vec3 operator- (const Vec3& v) const {return Vec3 (x-v.x, y-v.y, z-v.z);} + + // unary minus + Vec3 operator- (void) const {return Vec3 (-x, -y, -z);} + + // vector times scalar product (scale length of vector times argument) + Vec3 operator* (const float s) const {return Vec3 (x * s, y * s, z * s);} + + // vector divided by a scalar (divide length of vector by argument) + Vec3 operator/ (const float s) const {return Vec3 (x / s, y / s, z / s);} + + // dot product + float dot (const Vec3& v) const {return (x * v.x) + (y * v.y) + (z * v.z);} + + // length + float length (void) const {return sqrtXXX (lengthSquared ());} + + // length squared + float lengthSquared (void) const {return this->dot (*this);} + + // normalize: returns normalized version (parallel to this, length = 1) + Vec3 normalize (void) const + { + // skip divide if length is zero + const float len = length (); + return (len>0) ? (*this)/len : (*this); + } + + // cross product (modify "*this" to be A x B) + // [XXX side effecting -- deprecate this function? XXX] + void cross(const Vec3& a, const Vec3& b) + { + *this = Vec3 ((a.y * b.z) - (a.z * b.y), + (a.z * b.x) - (a.x * b.z), + (a.x * b.y) - (a.y * b.x)); + } + + // assignment + Vec3 operator= (const Vec3& v) {x=v.x; y=v.y; z=v.z; return *this;} + + // set XYZ coordinates to given three floats + Vec3 set (const float _x, const float _y, const float _z) + {x = _x; y = _y; z = _z; return *this;} + + // += + Vec3 operator+= (const Vec3& v) {return *this = (*this + v);} + + // -= + Vec3 operator-= (const Vec3& v) {return *this = (*this - v);} + + // *= + Vec3 operator*= (const float& s) {return *this = (*this * s);} + + + Vec3 operator/=( float d ) { return *this = (*this / d); } + + // equality/inequality + bool operator== (const Vec3& v) const {return x==v.x && y==v.y && z==v.z;} + bool operator!= (const Vec3& v) const {return !(*this == v);} + + // @todo Remove - use @c distance from the Vec3Utilitites header instead. + // XXX experimental (4-1-03 cwr): is this the right approach? defining + // XXX "Vec3 distance (vec3, Vec3)" collided with STL's distance template. + static float distance (const Vec3& a, const Vec3& b){ return(a-b).length();} + + // --------------------------- utility member functions used in OpenSteer + + // return component of vector parallel to a unit basis vector + // (IMPORTANT NOTE: assumes "basis" has unit magnitude (length==1)) + + inline Vec3 parallelComponent (const Vec3& unitBasis) const + { + const float projection = this->dot (unitBasis); + return unitBasis * projection; + } + + // return component of vector perpendicular to a unit basis vector + // (IMPORTANT NOTE: assumes "basis" has unit magnitude (length==1)) + + inline Vec3 perpendicularComponent (const Vec3& unitBasis) const + { + return (*this) - parallelComponent (unitBasis); + } + + // clamps the length of a given vector to maxLength. If the vector is + // shorter its value is returned unaltered, if the vector is longer + // the value returned has length of maxLength and is paralle to the + // original input. + + Vec3 truncateLength (const float maxLength) const + { + const float maxLengthSquared = maxLength * maxLength; + const float vecLengthSquared = this->lengthSquared (); + if (vecLengthSquared <= maxLengthSquared) + return *this; + else + return (*this) * (maxLength / sqrtXXX (vecLengthSquared)); + } + + // forces a 3d position onto the XZ (aka y=0) plane + + Vec3 setYtoZero (void) const {return Vec3 (this->x, 0, this->z);} + + // rotate this vector about the global Y (up) axis by the given angle + + Vec3 rotateAboutGlobalY (float angle) const + { + const float s = sinXXX (angle); + const float c = cosXXX (angle); + return Vec3 ((this->x * c) + (this->z * s), + (this->y), + (this->z * c) - (this->x * s)); + } + + // version for caching sin/cos computation + Vec3 rotateAboutGlobalY (float angle, float& sin, float& cos) const + { + // is both are zero, they have not be initialized yet + if (sin==0 && cos==0) + { + sin = sinXXX (angle); + cos = cosXXX (angle); + } + return Vec3 ((this->x * cos) + (this->z * sin), + (this->y), + (this->z * cos) - (this->x * sin)); + } + + // if this position is outside sphere, push it back in by one diameter + + Vec3 sphericalWrapAround (const Vec3& center, float radius) + { + const Vec3 offset = *this - center; + const float r = offset.length(); + if (r > radius) + return *this + ((offset/r) * radius * -2); + else + return *this; + } + + // names for frequently used vector constants + static const Vec3 zero; + static const Vec3 side; + static const Vec3 up; + static const Vec3 forward; + }; + + + // ---------------------------------------------------------------------------- + // scalar times vector product ("float * Vec3") + + + inline Vec3 operator* (float s, const Vec3& v) {return v*s;} + + + // return cross product a x b + inline Vec3 crossProduct(const Vec3& a, const Vec3& b) + { + Vec3 result((a.y * b.z) - (a.z * b.y), + (a.z * b.x) - (a.x * b.z), + (a.x * b.y) - (a.y * b.x)); + return result; + } + + + // ---------------------------------------------------------------------------- + // default character stream output method + +#ifndef NOT_OPENSTEERDEMO // only when building OpenSteerDemo + + inline std::ostream& operator<< (std::ostream& o, const Vec3& v) + { + return o << "(" << v.x << "," << v.y << "," << v.z << ")"; + } + +#endif // NOT_OPENSTEERDEMO + + // ---------------------------------------------------------------------------- + // Returns a position randomly distributed inside a sphere of unit radius + // centered at the origin. Orientation will be random and length will range + // between 0 and 1 + + + Vec3 RandomVectorInUnitRadiusSphere (void); + + + // ---------------------------------------------------------------------------- + // Returns a position randomly distributed on a disk of unit radius + // on the XZ (Y=0) plane, centered at the origin. Orientation will be + // random and length will range between 0 and 1 + + + Vec3 randomVectorOnUnitRadiusXZDisk (void); + + + // ---------------------------------------------------------------------------- + // Returns a position randomly distributed on the surface of a sphere + // of unit radius centered at the origin. Orientation will be random + // and length will be 1 + + + inline Vec3 RandomUnitVector (void) + { + return RandomVectorInUnitRadiusSphere().normalize(); + } + + + // ---------------------------------------------------------------------------- + // Returns a position randomly distributed on a circle of unit radius + // on the XZ (Y=0) plane, centered at the origin. Orientation will be + // random and length will be 1 + + + inline Vec3 RandomUnitVectorOnXZPlane (void) + { + return RandomVectorInUnitRadiusSphere().setYtoZero().normalize(); + } + + + // ---------------------------------------------------------------------------- + // used by limitMaxDeviationAngle / limitMinDeviationAngle below + + + Vec3 vecLimitDeviationAngleUtility (const bool insideOrOutside, + const Vec3& source, + const float cosineOfConeAngle, + const Vec3& basis); + + + // ---------------------------------------------------------------------------- + // Enforce an upper bound on the angle by which a given arbitrary vector + // diviates from a given reference direction (specified by a unit basis + // vector). The effect is to clip the "source" vector to be inside a cone + // defined by the basis and an angle. + + + inline Vec3 limitMaxDeviationAngle (const Vec3& source, + const float cosineOfConeAngle, + const Vec3& basis) + { + return vecLimitDeviationAngleUtility (true, // force source INSIDE cone + source, + cosineOfConeAngle, + basis); + } + + + // ---------------------------------------------------------------------------- + // Enforce a lower bound on the angle by which a given arbitrary vector + // diviates from a given reference direction (specified by a unit basis + // vector). The effect is to clip the "source" vector to be outside a cone + // defined by the basis and an angle. + + + inline Vec3 limitMinDeviationAngle (const Vec3& source, + const float cosineOfConeAngle, + const Vec3& basis) + { + return vecLimitDeviationAngleUtility (false, // force source OUTSIDE cone + source, + cosineOfConeAngle, + basis); + } + + + // ---------------------------------------------------------------------------- + // Returns the distance between a point and a line. The line is defined in + // terms of a point on the line ("lineOrigin") and a UNIT vector parallel to + // the line ("lineUnitTangent") + + + inline float distanceFromLine (const Vec3& point, + const Vec3& lineOrigin, + const Vec3& lineUnitTangent) + { + const Vec3 offset = point - lineOrigin; + const Vec3 perp = offset.perpendicularComponent (lineUnitTangent); + return perp.length(); + } + + + // ---------------------------------------------------------------------------- + // given a vector, return a vector perpendicular to it (note that this + // arbitrarily selects one of the infinitude of perpendicular vectors) + + + Vec3 findPerpendicularIn3d (const Vec3& direction); + + + // ---------------------------------------------------------------------------- + // candidates for global utility functions + // + // dot + // cross + // length + // distance + // normalized + + +} // namespace OpenSteer + + +// ---------------------------------------------------------------------------- +#endif // OPENSTEER_VEC3_H diff --git a/opensteer/include/OpenSteer/Vec3Utilities.h b/opensteer/include/OpenSteer/Vec3Utilities.h new file mode 100644 index 0000000..b39db78 --- /dev/null +++ b/opensteer/include/OpenSteer/Vec3Utilities.h @@ -0,0 +1,96 @@ +// ---------------------------------------------------------------------------- +// +// +// OpenSteer -- Steering Behaviors for Autonomous Characters +// +// Copyright (c) 2002-2005, Sony Computer Entertainment America +// Original author: Craig Reynolds +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// +// ---------------------------------------------------------------------------- +// +// Utilities to work with Vec3. +// +// 05-12-05 bk: Created based on code of PolylinePathway. +// +// ---------------------------------------------------------------------------- + +#ifndef OPENSTEER_VEC3UTILITIES_H +#define OPENSTEER_VEC3UTILITIES_H + + +// Include OpenSteer::Vec3 +#include "OpenSteer/Vec3.h" + +// Include OpenSteer::size_t +#include "OpenSteer/StandardTypes.h" + +// Include OpenSteer::equalsRelative +#include "OpenSteer/Utilities.h" + + + +namespace OpenSteer { + + /** + * Returns the nearest point on the segment @a segmentPoint0 to + * @a segmentPoint1 from @a point. + */ + OpenSteer::Vec3 nearestPointOnSegment( const Vec3& point, + const Vec3& segmentPoint0, + const Vec3& segmentPoint1 ); + + /** + * Computes minimum distance from @a point to the line segment defined by + * @a segmentPoint0 and @a segmentPoint1. + */ + float pointToSegmentDistance( const Vec3& point, + const Vec3& segmentPoint0, + const Vec3& segmentPoint1); + + /** + * Retuns distance between @a a and @a b. + */ + inline float distance (const Vec3& a, const Vec3& b) { + return (a-b).length(); + } + + + /** + * Elementwise relative tolerance comparison of @a lhs and @a rhs taking + * the range of the elements into account. + * + * See Christer Ericson, Real-Time Collision Detection, Morgan Kaufmann, + * 2005, pp. 441--443. + * + * @todo Rewrite using the stl or providing an own range based function. + */ + inline + bool + equalsRelative( Vec3 const& lhs, + Vec3 const& rhs, + float const& tolerance = std::numeric_limits< float >::epsilon() ) { + return equalsRelative( lhs.x, rhs.x, tolerance ) && equalsRelative( lhs.y, rhs.y ) && equalsRelative( lhs.z, rhs.z ); + } + +} // namespace OpenSteer + +#endif // OPENSTEER_VEC3UTILITIES_H diff --git a/opensteer/include/OpenSteer/lq.h b/opensteer/include/OpenSteer/lq.h new file mode 100644 index 0000000..087ffff --- /dev/null +++ b/opensteer/include/OpenSteer/lq.h @@ -0,0 +1,323 @@ +/* +// ---------------------------------------------------------------------------- +// +// +// OpenSteer -- Steering Behaviors for Autonomous Characters +// +// Copyright (c) 2002-2005, Sony Computer Entertainment America +// Original author: Craig Reynolds +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +*/ + +/* ------------------------------------------------------------------ */ +/* */ +/* Locality Query (LQ) Facility */ +/* */ +/* ------------------------------------------------------------------ */ +/* + + This utility is a spatial database which stores objects each of + which is associated with a 3d point (a location in a 3d space). + The points serve as the "search key" for the associated object. + It is intended to efficiently answer "sphere inclusion" queries, + also known as range queries: basically questions like: + + Which objects are within a radius R of the location L? + + In this context, "efficiently" means significantly faster than the + naive, brute force O(n) testing of all known points. Additionally + it is assumed that the objects move along unpredictable paths, so + that extensive preprocessing (for example, constructing a Delaunay + triangulation of the point set) may not be practical. + + The implementation is a "bin lattice": a 3d rectangular array of + brick-shaped (rectangular parallelepipeds) regions of space. Each + region is represented by a pointer to a (possibly empty) doubly- + linked list of objects. All of these sub-bricks are the same + size. All bricks are aligned with the global coordinate axes. + + Terminology used here: the region of space associated with a bin + is called a sub-brick. The collection of all sub-bricks is called + the super-brick. The super-brick should be specified to surround + the region of space in which (almost) all the key-points will + exist. If key-points move outside the super-brick everything will + continue to work, but without the speed advantage provided by the + spatial subdivision. For more details about how to specify the + super-brick's position, size and subdivisions see lqCreateDatabase + below. + + Overview of usage: an application using this facility would first + create a database with lqCreateDatabase. For each client object + the application wants to put in the database it creates a + lqClientProxy and initializes it with lqInitClientProxy. When a + client object moves, the application calls lqUpdateForNewLocation. + To perform a query lqMapOverAllObjectsInLocality is passed an + application-supplied call-back function to be applied to all + client objects in the locality. See lqCallBackFunction below for + more detail. The lqFindNearestNeighborWithinRadius function can + be used to find a single nearest neighbor using the database. + + Note that "locality query" is also known as neighborhood query, + neighborhood search, near neighbor search, and range query. For + additional information on this and related topics see: + http://www.red3d.com/cwr/boids/ips.html + + For some description and illustrations of this database in use, + see this paper: http://www.red3d.com/cwr/papers/2000/pip.html + +*/ + +#ifndef _lq_h +#define _lq_h + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/* ------------------------------------------------------------------ */ +/* */ +/* Data types use by LQ */ +/* */ +/* ------------------------------------------------------------------ */ +/* This structure represents the spatial database. Typically one of + these would be created (by a call to lqCreateDatabase) for a given + application. */ + + +typedef struct lqInternalDB lqDB; + + +/* ------------------------------------------------------------------ */ +/* This structure is a proxy for (and contains a pointer to) a client + (application) object in the spatial database. One of these exists + for each client object. This might be included within the + structure of a client object, or could be allocated separately. */ + + +typedef struct lqClientProxy +{ + /* previous object in this bin, or NULL */ + struct lqClientProxy* prev; + + /* next object in this bin, or NULL */ + struct lqClientProxy* next; + + /* bin ID (pointer to pointer to bin contents list) */ + struct lqClientProxy** bin; + + /* pointer to client object */ + void* object; + + /* the object's location ("key point") used for spatial sorting */ + float x; + float y; + float z; +} lqClientProxy; + + +/* ------------------------------------------------------------------ */ +/* */ +/* Basic API */ +/* */ +/* ------------------------------------------------------------------ */ +/* Allocate and initialize an LQ database, returns a pointer to it. + The application needs to call this before using the LQ facility. + The nine parameters define the properties of the "super-brick": + (1) origin: coordinates of one corner of the super-brick, its + minimum x, y and z extent. + (2) size: the width, height and depth of the super-brick. + (3) the number of subdivisions (sub-bricks) along each axis. + This routine also allocates the bin array, and initialize its + contents. */ + + +lqDB* lqCreateDatabase (float originx, float originy, float originz, + float sizex, float sizey, float sizez, + int divx, int divy, int divz); + + +/* ------------------------------------------------------------------ */ +/* Deallocates the LQ database */ + + +void lqDeleteDatabase (lqDB*); + + +/* ------------------------------------------------------------------ */ +/* The application needs to call this once on each lqClientProxy at + setup time to initialize its list pointers and associate the proxy + with its client object. */ + + +void lqInitClientProxy (lqClientProxy* proxy, void* clientObject); + + +/* ------------------------------------------------------------------ */ +/* Call for each client object every time its location changes. For + example, in an animation application, this would be called each + frame for every moving object. */ + + +void lqUpdateForNewLocation (lqDB* lq, + lqClientProxy* object, + float x, float y, float z); + + +/* ------------------------------------------------------------------ */ +/* Apply an application-specific function to all objects in a certain + locality. The locality is specified as a sphere with a given + center and radius. All objects whose location (key-point) is + within this sphere are identified and the function is applied to + them. The application-supplied function takes three arguments: + + (1) a void* pointer to an lqClientProxy's "object". + (2) the square of the distance from the center of the search + locality sphere (x,y,z) to object's key-point. + (3) a void* pointer to the caller-supplied "client query state" + object -- typically NULL, but can be used to store state + between calls to the lqCallBackFunction. + + This routine uses the LQ database to quickly reject any objects in + bins which do not overlap with the sphere of interest. Incremental + calculation of index values is used to efficiently traverse the + bins of interest. */ + + +/* type for a pointer to a function used to map over client objects */ +typedef void (* lqCallBackFunction) (void* clientObject, + float distanceSquared, + void* clientQueryState); + + +void lqMapOverAllObjectsInLocality (lqDB* lq, + float x, float y, float z, + float radius, + lqCallBackFunction func, + void* clientQueryState); + + +/* ------------------------------------------------------------------ */ +/* */ +/* Other API */ +/* */ +/* ------------------------------------------------------------------ */ +/* Search the database to find the object whose key-point is nearest + to a given location yet within a given radius. That is, it finds + the object (if any) within a given search sphere which is nearest + to the sphere's center. The ignoreObject argument can be used to + exclude an object from consideration (or it can be NULL). This is + useful when looking for the nearest neighbor of an object in the + database, since otherwise it would be its own nearest neighbor. + The function returns a void* pointer to the nearest object, or + NULL if none is found. */ + + +void* lqFindNearestNeighborWithinRadius (lqDB* lq, + float x, float y, float z, + float radius, + void* ignoreObject); + + +/* ------------------------------------------------------------------ */ +/* Adds a given client object to a given bin, linking it into the bin + contents list. */ + + +void lqAddToBin (lqClientProxy* object, lqClientProxy** bin); + + +/* ------------------------------------------------------------------ */ +/* Removes a given client object from its current bin, unlinking it + from the bin contents list. */ + + +void lqRemoveFromBin (lqClientProxy* object); + + +/* ------------------------------------------------------------------ */ +/* Given an LQ database object and the nine basic parameters: fill in + the object's slots, allocate the bin array, and initialize its + contents. Normally the application does NOT call this directly, it + is called by lqCreateDatabase. */ + + +void lqInitDatabase (lqDB* lq, + float originx, float originy, float originz, + float sizex, float sizey, float sizez, + int divx, int divy, int divz); + + +/* ------------------------------------------------------------------ */ +/* Find the bin ID for a location in space. The location is given in + terms of its XYZ coordinates. The bin ID is a pointer to a pointer + to the bin contents list. */ + + +lqClientProxy** lqBinForLocation (lqDB* lq, float x, float y, float z); + + +/* ------------------------------------------------------------------ */ +/* Apply a user-supplied function to all objects in the database, + regardless of locality (cf lqMapOverAllObjectsInLocality) */ + + +void lqMapOverAllObjects (lqDB* lq, + lqCallBackFunction func, + void* clientQueryState); + + +/* ------------------------------------------------------------------ */ +/* Removes (all proxies for) all objects from all bins */ + + +void lqRemoveAllObjects (lqDB* lq); + + +/* ------------------------------------------------------------------ */ +/* Get statistics about bin populations: min, max and average of + non-empty bins. */ + + +#ifndef NO_LQ_BIN_STATS +void lqGetBinPopulationStats (lqDB* lq, + int* min, + int* max, + float* average); +#endif /* NO_LQ_BIN_STATS */ + +/* ------------------------------------------------------------------ */ + + +#ifndef NULL +#define NULL 0 +#endif + + +/* ------------------------------------------------------------------ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _lq_h */ diff --git a/opensteer/ogta_opensteer.txt b/opensteer/ogta_opensteer.txt new file mode 100644 index 0000000..6988b8d --- /dev/null +++ b/opensteer/ogta_opensteer.txt @@ -0,0 +1,5 @@ +OpenSteer_0_8_2_source.zip + +This is only a subset of OpenSteer; didn't want to add code that I don't use. + +The docs are gone as well. diff --git a/opensteer/src/Clock.cpp b/opensteer/src/Clock.cpp new file mode 100644 index 0000000..f3dc8af --- /dev/null +++ b/opensteer/src/Clock.cpp @@ -0,0 +1,310 @@ +// ---------------------------------------------------------------------------- +// +// +// OpenSteer -- Steering Behaviors for Autonomous Characters +// +// Copyright (c) 2002-2005, Sony Computer Entertainment America +// Original author: Craig Reynolds +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// +// ---------------------------------------------------------------------------- +// +// +// discrete time simulation clock for OpenSteerDemo +// +// Keeps track of real clock time and simulation time. Encapsulates OS's +// time API. Can be put in either "as fast as possible" variable time step +// mode (where simulation time steps are based on real time elapsed between +// updates), or in fixed "target FPS" mode where the simulation steps are +// constrained to start on 1/FPS boundaries (e.g. on a 60 hertz video game +// console). Also handles the notion of "pausing" simulation time. +// +// Usage: allocate a clock, set its "paused" or "targetFPS" parameters, +// then call updateGlobalSimulationClock before each simulation step. +// +// 10-04-04 bk: put everything into the OpenSteer namespace +// 09-24-02 cwr: major overhaul +// 06-26-02 cwr: created +// +// +// ---------------------------------------------------------------------------- + + +#include "OpenSteer/Clock.h" + + +// ---------------------------------------------------------------------------- +// XXX This is a bit ad hoc. Need to revisit conditionalization on operating +// XXX system. As of 5-5-03, this module knows about Win32 (code thanks to +// XXX Leaf Garland and Bruce Mitchener) and Linux/Unix (Craig's original +// XXX version). It tests for Xbox and Win32 and assumes Linux/Unix +// XXX otherwise. + + +#if defined (_XBOX) + #include +#elif defined (_WIN32) + #include +#else + #include +#endif + + +// ---------------------------------------------------------------------------- +// Constructor + + +OpenSteer::Clock::Clock (void) +{ + // default is "real time, variable frame rate" and not paused + setFixedFrameRate (0); + setPausedState (false); + setAnimationMode (false); + setVariableFrameRateMode (true); + + // real "wall clock" time since launch + totalRealTime = 0; + + // time simulation has run + totalSimulationTime = 0; + + // time spent paused + totalPausedTime = 0; + + // sum of (non-realtime driven) advances to simulation time + totalAdvanceTime = 0; + + // interval since last simulation time + elapsedSimulationTime = 0; + + // interval since last clock update time + elapsedRealTime = 0; + + // interval since last clock update, + // exclusive of time spent waiting for frame boundary when targetFPS>0 + elapsedNonWaitRealTime = 0; + + // "manually" advance clock by this amount on next update + newAdvanceTime = 0; + + // "Calendar time" when this clock was first updated +#ifdef _WIN32 + basePerformanceCounter = 0; // from QueryPerformanceCounter on Windows +#else + baseRealTimeSec = 0; // from gettimeofday on Linux and Mac OS X + baseRealTimeUsec = 0; +#endif + + // clock keeps track of "smoothed" running average of recent frame rates. + // When a fixed frame rate is used, a running average of "CPU load" is + // kept (aka "non-wait time", the percentage of each frame time (time + // step) that the CPU is busy). + smoothedFPS = 0; + smoothedUsage = 0; +} + + +// ---------------------------------------------------------------------------- +// update this clock, called once per simulation step ("frame") to: +// +// track passage of real time +// manage passage of simulation time (modified by Paused state) +// measure time elapsed between time updates ("frame rate") +// optionally: "wait" for next realtime frame boundary + + +void +OpenSteer::Clock::update (void) +{ + // keep track of average frame rate and average usage percentage + updateSmoothedRegisters (); + + // wait for next frame time (when targetFPS>0) + // XXX should this be at the end of the update function? + frameRateSync (); + + // save previous real time to measure elapsed time + const float previousRealTime = totalRealTime; + + // real "wall clock" time since this application was launched + totalRealTime = realTimeSinceFirstClockUpdate (); + + // time since last clock update + elapsedRealTime = totalRealTime - previousRealTime; + + // accumulate paused time + if (paused) totalPausedTime += elapsedRealTime; + + // save previous simulation time to measure elapsed time + const float previousSimulationTime = totalSimulationTime; + + // update total simulation time + if (getAnimationMode ()) + { + // for "animation mode" use fixed frame time, ignore real time + const float frameDuration = 1.0f / getFixedFrameRate (); + totalSimulationTime += paused ? newAdvanceTime : frameDuration; + if (!paused) newAdvanceTime += frameDuration - elapsedRealTime; + } + else + { + // new simulation time is total run time minus time spent paused + totalSimulationTime = (totalRealTime + + totalAdvanceTime + - totalPausedTime); + } + + + // update total "manual advance" time + totalAdvanceTime += newAdvanceTime; + + // how much time has elapsed since the last simulation step? + elapsedSimulationTime = (paused ? + newAdvanceTime : + (totalSimulationTime - previousSimulationTime)); + + // reset advance amount + newAdvanceTime = 0; +} + + +// ---------------------------------------------------------------------------- +// "wait" until next frame time (actually spin around this tight loop) +// +// +// (xxx there are probably a smarter ways to do this (using events or +// thread waits (eg usleep)) but they are likely to be unportable. xxx) + + +void +OpenSteer::Clock::frameRateSync (void) +{ + // when in real time fixed frame rate mode + // (not animation mode and not variable frame rate mode) + if ((! getAnimationMode ()) && (! getVariableFrameRateMode ())) + { + // find next (real time) frame start time + const float targetStepSize = 1.0f / getFixedFrameRate (); + const float now = realTimeSinceFirstClockUpdate (); + const int lastFrameCount = (int) (now / targetStepSize); + const float nextFrameTime = (lastFrameCount + 1) * targetStepSize; + + // record usage ("busy time", "non-wait time") for OpenSteerDemo app + elapsedNonWaitRealTime = now - totalRealTime; + + // wait until next frame time + do {} while (realTimeSinceFirstClockUpdate () < nextFrameTime); + } +} + + +// ---------------------------------------------------------------------------- +// force simulation time ahead, ignoring passage of real time. +// Used for OpenSteerDemo's "single step forward" and animation mode + + +float +OpenSteer::Clock::advanceSimulationTimeOneFrame (void) +{ + // decide on what frame time is (use fixed rate, average for variable rate) + const float fps = (getVariableFrameRateMode () ? + getSmoothedFPS () : + getFixedFrameRate ()); + const float frameTime = 1 / fps; + + // bump advance time + advanceSimulationTime (frameTime); + + // return the time value used (for OpenSteerDemo) + return frameTime; +} + + +void +OpenSteer::Clock::advanceSimulationTime (const float seconds) +{ + if (seconds < 0) { + /// @todo - throw? how to handle error conditions? Not by crashing an app! + std::cerr << "negative arg to advanceSimulationTime - results will not be valid"; + } + else + newAdvanceTime += seconds; +} + + +namespace { + +// ---------------------------------------------------------------------------- +// Returns the number of seconds of real time (represented as a float) since +// the clock was first updated. +// +// XXX Need to revisit conditionalization on operating system. + + + + float + clockErrorExit (void) + { + /// @todo - throw? how to handle error conditions? Not by crashing an app! + std::cerr << "Problem reading system clock - results will not be valid"; + return 0.0f; + } + +} // anonymous namespace + +float +OpenSteer::Clock::realTimeSinceFirstClockUpdate (void) +#ifdef _WIN32 +{ + // get time from Windows + LONGLONG counter, frequency; + bool clockOK = (QueryPerformanceCounter ((LARGE_INTEGER *)&counter) && + QueryPerformanceFrequency ((LARGE_INTEGER *)&frequency)); + if (!clockOK) return clockErrorExit (); + + // ensure the base counter is recorded once after launch + if (basePerformanceCounter == 0) basePerformanceCounter = counter; + + // real "wall clock" time since launch + const LONGLONG counterDifference = counter - basePerformanceCounter; + return ((float) counterDifference) / ((float)frequency); +} +#else +{ + // get time from Linux (Unix, Mac OS X, ...) + timeval t; + if (gettimeofday (&t, 0) != 0) return clockErrorExit (); + + // ensure the base time is recorded once after launch + if (baseRealTimeSec == 0) + { + baseRealTimeSec = t.tv_sec; + baseRealTimeUsec = t.tv_usec; + } + + // real "wall clock" time since launch + return (( t.tv_sec - baseRealTimeSec) + + ((t.tv_usec - baseRealTimeUsec) / 1000000.0f)); +} +#endif + + +// ---------------------------------------------------------------------------- diff --git a/opensteer/src/Vec3.cpp b/opensteer/src/Vec3.cpp new file mode 100644 index 0000000..e821111 --- /dev/null +++ b/opensteer/src/Vec3.cpp @@ -0,0 +1,213 @@ +// ---------------------------------------------------------------------------- +// +// +// OpenSteer -- Steering Behaviors for Autonomous Characters +// +// Copyright (c) 2002-2005, Sony Computer Entertainment America +// Original author: Craig Reynolds +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// +// ---------------------------------------------------------------------------- +// +// +// Vec3: OpenSteer's generic type for 3d vectors +// +// This file defines the class Vec3, which is used throughout OpenSteer to +// manipulate 3d geometric data. It includes standard vector operations (like +// vector addition, subtraction, scale, dot, cross...) and more idiosyncratic +// utility functions. +// +// When integrating OpenSteer into a preexisting 3d application, it may be +// important to use the 3d vector type of that application. In that case Vec3 +// can be changed to inherit from the preexisting application' vector type and +// to match the interface used by OpenSteer to the interface provided by the +// preexisting 3d vector type. +// +// 10-04-04 bk: put everything into the OpenSteer namespace +// 03-26-03 cwr: created to replace for Hiranabe-san's execellent but larger +// vecmath package (http://objectclub.esm.co.jp/vecmath/) +// +// +// ---------------------------------------------------------------------------- + + +#include "OpenSteer/Vec3.h" + + +// ---------------------------------------------------------------------------- +// names for frequently used vector constants + + +const OpenSteer::Vec3 OpenSteer::Vec3::zero (0, 0, 0); +const OpenSteer::Vec3 OpenSteer::Vec3::up (0, 1, 0); +const OpenSteer::Vec3 OpenSteer::Vec3::forward (0, 0, 1); + +// XXX This should be unified with LocalSpace::rightHanded, but I don't want +// XXX Vec3 to be based on LocalSpace which is based on Vec3. Perhaps there +// XXX should be a tiny chirality.h header to define a const? That could +// XXX then be included by both Vec3.h and LocalSpace.h + +const OpenSteer::Vec3 OpenSteer::Vec3::side (-1, 0, 0); + +// ---------------------------------------------------------------------------- +// Returns a position randomly distributed inside a sphere of unit radius +// centered at the origin. Orientation will be random and length will range +// between 0 and 1 + + +OpenSteer::Vec3 +OpenSteer::RandomVectorInUnitRadiusSphere (void) +{ + Vec3 v; + + do + { + v.set ((frandom01()*2) - 1, + (frandom01()*2) - 1, + (frandom01()*2) - 1); + } + while (v.length() >= 1); + + return v; +} + + +// ---------------------------------------------------------------------------- +// Returns a position randomly distributed on a disk of unit radius +// on the XZ (Y=0) plane, centered at the origin. Orientation will be +// random and length will range between 0 and 1 + + +OpenSteer::Vec3 +OpenSteer::randomVectorOnUnitRadiusXZDisk (void) +{ + Vec3 v; + + do + { + v.set ((frandom01()*2) - 1, + 0, + (frandom01()*2) - 1); + } + while (v.length() >= 1); + + return v; +} + + +// ---------------------------------------------------------------------------- +// Does a "ceiling" or "floor" operation on the angle by which a given vector +// deviates from a given reference basis vector. Consider a cone with "basis" +// as its axis and slope of "cosineOfConeAngle". The first argument controls +// whether the "source" vector is forced to remain inside or outside of this +// cone. Called by vecLimitMaxDeviationAngle and vecLimitMinDeviationAngle. + + +OpenSteer::Vec3 +OpenSteer::vecLimitDeviationAngleUtility (const bool insideOrOutside, + const Vec3& source, + const float cosineOfConeAngle, + const Vec3& basis) +{ + // immediately return zero length input vectors + float sourceLength = source.length(); + if (sourceLength == 0) return source; + + // measure the angular diviation of "source" from "basis" + const Vec3 direction = source / sourceLength; + float cosineOfSourceAngle = direction.dot (basis); + + // Simply return "source" if it already meets the angle criteria. + // (note: we hope this top "if" gets compiled out since the flag + // is a constant when the function is inlined into its caller) + if (insideOrOutside) + { + // source vector is already inside the cone, just return it + if (cosineOfSourceAngle >= cosineOfConeAngle) return source; + } + else + { + // source vector is already outside the cone, just return it + if (cosineOfSourceAngle <= cosineOfConeAngle) return source; + } + + // find the portion of "source" that is perpendicular to "basis" + const Vec3 perp = source.perpendicularComponent (basis); + + // normalize that perpendicular + const Vec3 unitPerp = perp.normalize (); + + // construct a new vector whose length equals the source vector, + // and lies on the intersection of a plane (formed the source and + // basis vectors) and a cone (whose axis is "basis" and whose + // angle corresponds to cosineOfConeAngle) + float perpDist = sqrtXXX (1 - (cosineOfConeAngle * cosineOfConeAngle)); + const Vec3 c0 = basis * cosineOfConeAngle; + const Vec3 c1 = unitPerp * perpDist; + return (c0 + c1) * sourceLength; +} + + +// ---------------------------------------------------------------------------- +// given a vector, return a vector perpendicular to it. arbitrarily selects +// one of the infinitely many perpendicular vectors. a zero vector maps to +// itself, otherwise length is irrelevant (empirically, output length seems to +// remain within 20% of input length). + + +OpenSteer::Vec3 +OpenSteer::findPerpendicularIn3d (const Vec3& direction) +{ + // to be filled in: + Vec3 quasiPerp; // a direction which is "almost perpendicular" + Vec3 result; // the computed perpendicular to be returned + + // three mutually perpendicular basis vectors + const Vec3 i (1, 0, 0); + const Vec3 j (0, 1, 0); + const Vec3 k (0, 0, 1); + + // measure the projection of "direction" onto each of the axes + const float id = i.dot (direction); + const float jd = j.dot (direction); + const float kd = k.dot (direction); + + // set quasiPerp to the basis which is least parallel to "direction" + if ((id <= jd) && (id <= kd)) + { + quasiPerp = i; // projection onto i was the smallest + } + else + { + if ((jd <= id) && (jd <= kd)) + quasiPerp = j; // projection onto j was the smallest + else + quasiPerp = k; // projection onto k was the smallest + } + + // return the cross product (direction x quasiPerp) + // which is guaranteed to be perpendicular to both of them + result.cross (direction, quasiPerp); + return result; +} + + +// ---------------------------------------------------------------------------- diff --git a/opensteer/src/Vec3Utilities.cpp b/opensteer/src/Vec3Utilities.cpp new file mode 100644 index 0000000..a0bd920 --- /dev/null +++ b/opensteer/src/Vec3Utilities.cpp @@ -0,0 +1,88 @@ +/** + * OpenSteer -- Steering Behaviors for Autonomous Characters + * + * Copyright (c) 2002-2005, Sony Computer Entertainment America + * Original author: Craig Reynolds + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * + * @author Bjoern Knafla + */ + +#include "OpenSteer/Vec3Utilities.h" + +// Include assert +#include + + + +// Include OpenSteer::clamp +#include "OpenSteer/Utilities.h" + +/** + * @todo Is this useful? +std::pair< Vec3, Vec3 > +OpenSteer::convertPointAndSegmentToVectors( const Vec3& point, + const Vec3& segmentPoint0, + const Vec3& segmentPoint1 ) +{ + + + + +} +*/ + +OpenSteer::Vec3 +OpenSteer::nearestPointOnSegment( const Vec3& point, + const Vec3& segmentPoint0, + const Vec3& segmentPoint1 ) +{ + // convert the test point to be "local" to ep0 + Vec3 const local( point - segmentPoint0 ); + + // find the projection of "local" onto "segmentNormal" + Vec3 const segment( segmentPoint1 - segmentPoint0 ); + float const segmentLength( segment.length() ); + + assert( 0 != segmentLength && "Segment mustn't be of length zero." ); + + Vec3 const segmentNormalized( segment / segmentLength ); + float segmentProjection = segmentNormalized.dot (local); + + segmentProjection = clamp( segmentProjection, 0.0f, segmentLength ); + + Vec3 result( segmentNormalized * segmentProjection ); + result += segmentPoint0; + return result; + +} + + + +float +OpenSteer::pointToSegmentDistance ( const Vec3& point, + const Vec3& segmentPoint0, + const Vec3& segmentPoint1) +{ + return distance( point, nearestPointOnSegment( point, segmentPoint0, segmentPoint1 ) ); +} + + diff --git a/opensteer/src/lq.c b/opensteer/src/lq.c new file mode 100644 index 0000000..b99afeb --- /dev/null +++ b/opensteer/src/lq.c @@ -0,0 +1,712 @@ +/* +// ---------------------------------------------------------------------------- +// +// +// OpenSteer -- Steering Behaviors for Autonomous Characters +// +// Copyright (c) 2002-2005, Sony Computer Entertainment America +// Original author: Craig Reynolds +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +*/ +/* ------------------------------------------------------------------ */ +/* */ +/* Locality Query facility */ +/* */ +/* (by Craig Reynolds, see lq.h file for documentation) */ +/* */ +/* 5-17-99: created */ +/* 5-20-99: found elusive "allocate 0 bins" bug */ +/* 5-28-99: lqMapOverAllObjectsInLocality: clipped, incremental */ +/* 6- 7-99: clean up, split off annotation stuff into debuglq.c */ +/* 6- 8-99: tried screening by sum of coords ("first mean"?) but */ +/* it was slightly slower, moved unused code to debuglq */ +/* 10-19-99: Change lqClientObject, lqObject from: "struct x {};" to */ +/* "typedef struct x {} x;" for EE compiler. */ +/* 12- 2-00: Make lqObject "private" using lqInternalDB. */ +/* 12- 5-00: Rename lqObject to lqDB, lqClientObject to lqClientProxy */ +/* 12- 6-00: Change lqCallBackFunction from arglist of (void*) to: */ +/* (void* clientObject, float distanceSquared, void* */ +/* clientQueryState). Add void* clientQueryState arg to */ +/* lqMapOverAllObjectsInLocality and its helper functions */ +/* lqMapOverAllObjectsInLocalityClipped and */ +/* lqMapOverAllOutsideObjects. Change macro */ +/* lqTraverseBinClientObjectList to invoke callback */ +/* function with three arguments, add "state" to its */ +/* arglist. Remove extern lqDistanceSquared. */ +/* 12- 7-00: Rename lqInitClientObject to lqInitClientProxy, make */ +/* "func" be an argument to lqTraverseBinClientObjectList, */ +/* add comments. */ +/* 12- 8-00: Add lqFindNearestNeighborWithinRadius and related */ +/* definitions: lqFindNearestHelper lqFindNearestState */ +/* Add lqMapOverAllObjects and lqRemoveAllObjects (plus: */ +/* lqMapOverAllObjectsInBin and lqRemoveAllObjectsInBin) */ +/* */ +/* ------------------------------------------------------------------ */ + + +#include +#include +#include /* for INT_MAX */ +#include "OpenSteer/lq.h" + +/* for debugging and graphical annotation (normally unused) */ +#ifdef BOIDS_LQ_DEBUG +#include "OpenSteer/debuglq.c" +#endif + +#ifndef WIN32 +#define USUSED_PARAM __attribute__ ((unused)) +#else +#define USUSED_PARAM +#endif + + +/* ------------------------------------------------------------------ */ +/* This structure represents the spatial database. Typically one of + these would be created, by a call to lqCreateDatabase, for a given + application. */ + + +typedef struct lqInternalDB +{ + + /* the origin is the super-brick corner minimum coordinates */ + float originx, originy, originz; + + /* length of the edges of the super-brick */ + float sizex, sizey, sizez; + + /* number of sub-brick divisions in each direction */ + int divx, divy, divz; + + /* pointer to an array of pointers, one for each bin */ + lqClientProxy** bins; + + /* extra bin for "everything else" (points outside super-brick) */ + lqClientProxy* other; + +} lqInternalDB; + + +/* ------------------------------------------------------------------ */ +/* Allocate and initialize an LQ database, return a pointer to it. + The application needs to call this before using the LQ facility. + The nine parameters define the properties of the "super-brick": + (1) origin: coordinates of one corner of the super-brick, its + minimum x, y and z extent. + (2) size: the width, height and depth of the super-brick. + (3) the number of subdivisions (sub-bricks) along each axis. + This routine also allocates the bin array, and initialize its + contents. */ + + +lqInternalDB* lqCreateDatabase (float originx, float originy, float originz, + float sizex, float sizey, float sizez, + int divx, int divy, int divz) +{ + lqInternalDB* lq = ((lqInternalDB*) malloc (sizeof (lqInternalDB))); + + lqInitDatabase (lq, + originx, originy, originz, + sizex, sizey, sizez, + divx, divy, divz); + return lq; +} + + +/* ------------------------------------------------------------------ */ +/* Deallocate the memory used by the LQ database */ + + +void lqDeleteDatabase(lqDB* lq) +{ + free (lq->bins); + free (lq); +} + + +/* ------------------------------------------------------------------ */ +/* Given an LQ database object and the nine basic parameters: fill in + the object's slots, allocate the bin array, and initialize its + contents. */ + + +void lqInitDatabase (lqInternalDB* lq, + float originx, float originy, float originz, + float sizex, float sizey, float sizez, + int divx, int divy, int divz) +{ + lq->originx = originx; + lq->originy = originy; + lq->originz = originz; + lq->sizex = sizex; + lq->sizey = sizey; + lq->sizez = sizez; + lq->divx = divx; + lq->divy = divy; + lq->divz = divz; + { + int i; + int bincount = divx * divy * divz; + int arraysize = sizeof (lqClientProxy*) * bincount; + lq->bins = (lqClientProxy**) malloc (arraysize); + for (i=0; ibins[i] = NULL; + } + lq->other = NULL; +} + + +/* ------------------------------------------------------------------ */ +/* Determine index into linear bin array given 3D bin indices */ + + +#define lqBinCoordsToBinIndex(lq, ix, iy, iz) \ + ((ix * (lq)->divy * (lq)->divz) + (iy * (lq)->divz) + iz) + + +/* ------------------------------------------------------------------ */ +/* Find the bin ID for a location in space. The location is given in + terms of its XYZ coordinates. The bin ID is a pointer to a pointer + to the bin contents list. */ + + +lqClientProxy** lqBinForLocation (lqInternalDB* lq, + float x, float y, float z) +{ + int i, ix, iy, iz; + + /* if point outside super-brick, return the "other" bin */ + if (x < lq->originx) return &(lq->other); + if (y < lq->originy) return &(lq->other); + if (z < lq->originz) return &(lq->other); + if (x >= lq->originx + lq->sizex) return &(lq->other); + if (y >= lq->originy + lq->sizey) return &(lq->other); + if (z >= lq->originz + lq->sizez) return &(lq->other); + + /* if point inside super-brick, compute the bin coordinates */ + ix = (int) (((x - lq->originx) / lq->sizex) * lq->divx); + iy = (int) (((y - lq->originy) / lq->sizey) * lq->divy); + iz = (int) (((z - lq->originz) / lq->sizez) * lq->divz); + + /* convert to linear bin number */ + i = lqBinCoordsToBinIndex (lq, ix, iy, iz); + + /* return pointer to that bin */ + return &(lq->bins[i]); +} + + +/* ------------------------------------------------------------------ */ +/* The application needs to call this once on each lqClientProxy at + setup time to initialize its list pointers and associate the proxy + with its client object. */ + + +void lqInitClientProxy (lqClientProxy* proxy, void* clientObject) +{ + proxy->prev = NULL; + proxy->next = NULL; + proxy->bin = NULL; + proxy->object = clientObject; +} + + +/* ------------------------------------------------------------------ */ +/* Adds a given client object to a given bin, linking it into the bin + contents list. */ + + +void lqAddToBin (lqClientProxy* object, lqClientProxy** bin) +{ + /* if bin is currently empty */ + if (*bin == NULL) + { + object->prev = NULL; + object->next = NULL; + *bin = object; + } + else + { + object->prev = NULL; + object->next = *bin; + (*bin)->prev = object; + *bin = object; + } + + /* record bin ID in proxy object */ + object->bin = bin; +} + + +/* ------------------------------------------------------------------ */ +/* Removes a given client object from its current bin, unlinking it + from the bin contents list. */ + + +void lqRemoveFromBin (lqClientProxy* object) +{ + /* adjust pointers if object is currently in a bin */ + if (object->bin != NULL) + { + /* If this object is at the head of the list, move the bin + pointer to the next item in the list (might be NULL). */ + if (*(object->bin) == object) *(object->bin) = object->next; + + /* If there is a prev object, link its "next" pointer to the + object after this one. */ + if (object->prev != NULL) object->prev->next = object->next; + + /* If there is a next object, link its "prev" pointer to the + object before this one. */ + if (object->next != NULL) object->next->prev = object->prev; + } + + /* Null out prev, next and bin pointers of this object. */ + object->prev = NULL; + object->next = NULL; + object->bin = NULL; +} + + +/* ------------------------------------------------------------------ */ +/* Call for each client object every time its location changes. For + example, in an animation application, this would be called each + frame for every moving object. */ + + +void lqUpdateForNewLocation (lqInternalDB* lq, + lqClientProxy* object, + float x, float y, float z) +{ + /* find bin for new location */ + lqClientProxy** newBin = lqBinForLocation (lq, x, y, z); + + /* store location in client object, for future reference */ + object->x = x; + object->y = y; + object->z = z; + + /* has object moved into a new bin? */ + if (newBin != object->bin) + { + lqRemoveFromBin (object); + lqAddToBin (object, newBin); + } +} + + +/* ------------------------------------------------------------------ */ +/* Given a bin's list of client proxies, traverse the list and invoke + the given lqCallBackFunction on each object that falls within the + search radius. */ + + +#define lqTraverseBinClientObjectList(co, radiusSquared, func, state) \ + while (co != NULL) \ + { \ + /* compute distance (squared) from this client */ \ + /* object to given locality sphere's centerpoint */ \ + float dx = x - co->x; \ + float dy = y - co->y; \ + float dz = z - co->z; \ + float distanceSquared = (dx * dx) + (dy * dy) + (dz * dz); \ + \ + /* apply function if client object within sphere */ \ + if (distanceSquared < radiusSquared) \ + (*func) (co->object, distanceSquared, state); \ + \ + /* consider next client object in bin list */ \ + co = co->next; \ + } + + +/* ------------------------------------------------------------------ */ +/* This subroutine of lqMapOverAllObjectsInLocality efficiently + traverses of subset of bins specified by max and min bin + coordinates. */ + +void lqMapOverAllObjectsInLocalityClipped (lqInternalDB* lq, + float x, float y, float z, + float radius, + lqCallBackFunction func, + void* clientQueryState, + int minBinX, + int minBinY, + int minBinZ, + int maxBinX, + int maxBinY, + int maxBinZ); + +void lqMapOverAllObjectsInLocalityClipped (lqInternalDB* lq, + float x, float y, float z, + float radius, + lqCallBackFunction func, + void* clientQueryState, + int minBinX, + int minBinY, + int minBinZ, + int maxBinX, + int maxBinY, + int maxBinZ) +{ + int i, j, k; + int iindex, jindex, kindex; + int slab = lq->divy * lq->divz; + int row = lq->divz; + int istart = minBinX * slab; + int jstart = minBinY * row; + int kstart = minBinZ; + lqClientProxy* co; + lqClientProxy** bin; + float radiusSquared = radius * radius; + +#ifdef BOIDS_LQ_DEBUG + if (lqAnnoteEnable) drawBallGL (x, y, z, radius); +#endif + + /* loop for x bins across diameter of sphere */ + iindex = istart; + for (i = minBinX; i <= maxBinX; i++) + { + /* loop for y bins across diameter of sphere */ + jindex = jstart; + for (j = minBinY; j <= maxBinY; j++) + { + /* loop for z bins across diameter of sphere */ + kindex = kstart; + for (k = minBinZ; k <= maxBinZ; k++) + { + /* get current bin's client object list */ + bin = &lq->bins[iindex + jindex + kindex]; + co = *bin; + +#ifdef BOIDS_LQ_DEBUG + if (lqAnnoteEnable) drawBin (lq, bin); +#endif + /* traverse current bin's client object list */ + lqTraverseBinClientObjectList (co, + radiusSquared, + func, + clientQueryState); + kindex += 1; + } + jindex += row; + } + iindex += slab; + } +} + + +/* ------------------------------------------------------------------ */ +/* If the query region (sphere) extends outside of the "super-brick" + we need to check for objects in the catch-all "other" bin which + holds any object which are not inside the regular sub-bricks */ + +void lqMapOverAllOutsideObjects (lqInternalDB* lq, + float x, float y, float z, + float radius, + lqCallBackFunction func, + void* clientQueryState); + +void lqMapOverAllOutsideObjects (lqInternalDB* lq, + float x, float y, float z, + float radius, + lqCallBackFunction func, + void* clientQueryState) +{ + lqClientProxy* co = lq->other; + float radiusSquared = radius * radius; + + /* traverse the "other" bin's client object list */ + lqTraverseBinClientObjectList (co, + radiusSquared, + func, + clientQueryState); +} + + +/* ------------------------------------------------------------------ */ +/* Apply an application-specific function to all objects in a certain + locality. The locality is specified as a sphere with a given + center and radius. All objects whose location (key-point) is + within this sphere are identified and the function is applied to + them. The application-supplied function takes three arguments: + + (1) a void* pointer to an lqClientProxy's "object". + (2) the square of the distance from the center of the search + locality sphere (x,y,z) to object's key-point. + (3) a void* pointer to the caller-supplied "client query state" + object -- typically NULL, but can be used to store state + between calls to the lqCallBackFunction. + + This routine uses the LQ database to quickly reject any objects in + bins which do not overlap with the sphere of interest. Incremental + calculation of index values is used to efficiently traverse the + bins of interest. */ + + +void lqMapOverAllObjectsInLocality (lqInternalDB* lq, + float x, float y, float z, + float radius, + lqCallBackFunction func, + void* clientQueryState) +{ + int partlyOut = 0; + int completelyOutside = + (((x + radius) < lq->originx) || + ((y + radius) < lq->originy) || + ((z + radius) < lq->originz) || + ((x - radius) >= lq->originx + lq->sizex) || + ((y - radius) >= lq->originy + lq->sizey) || + ((z - radius) >= lq->originz + lq->sizez)); + int minBinX, minBinY, minBinZ, maxBinX, maxBinY, maxBinZ; + + /* is the sphere completely outside the "super brick"? */ + if (completelyOutside) + { + lqMapOverAllOutsideObjects (lq, x, y, z, radius, func, + clientQueryState); + return; + } + + /* compute min and max bin coordinates for each dimension */ + minBinX = (int) ((((x - radius) - lq->originx) / lq->sizex) * lq->divx); + minBinY = (int) ((((y - radius) - lq->originy) / lq->sizey) * lq->divy); + minBinZ = (int) ((((z - radius) - lq->originz) / lq->sizez) * lq->divz); + maxBinX = (int) ((((x + radius) - lq->originx) / lq->sizex) * lq->divx); + maxBinY = (int) ((((y + radius) - lq->originy) / lq->sizey) * lq->divy); + maxBinZ = (int) ((((z + radius) - lq->originz) / lq->sizez) * lq->divz); + + /* clip bin coordinates */ + if (minBinX < 0) {partlyOut = 1; minBinX = 0;} + if (minBinY < 0) {partlyOut = 1; minBinY = 0;} + if (minBinZ < 0) {partlyOut = 1; minBinZ = 0;} + if (maxBinX >= lq->divx) {partlyOut = 1; maxBinX = lq->divx - 1;} + if (maxBinY >= lq->divy) {partlyOut = 1; maxBinY = lq->divy - 1;} + if (maxBinZ >= lq->divz) {partlyOut = 1; maxBinZ = lq->divz - 1;} + + /* map function over outside objects if necessary (if clipped) */ + if (partlyOut) + lqMapOverAllOutsideObjects (lq, x, y, z, radius, func, + clientQueryState); + + /* map function over objects in bins */ + lqMapOverAllObjectsInLocalityClipped (lq, + x, y, z, + radius, + func, + clientQueryState, + minBinX, minBinY, minBinZ, + maxBinX, maxBinY, maxBinZ); +} + + +/* ------------------------------------------------------------------ */ +/* internal helper function */ + + +typedef struct lqFindNearestState +{ + void* ignoreObject; + void* nearestObject; + float minDistanceSquared; + +} lqFindNearestState; + + +void lqFindNearestHelper (void* clientObject, + float distanceSquared, + void* clientQueryState); + +void lqFindNearestHelper (void* clientObject, + float distanceSquared, + void* clientQueryState) +{ + lqFindNearestState* fns = (lqFindNearestState*) clientQueryState; + + /* do nothing if this is the "ignoreObject" */ + if (fns->ignoreObject != clientObject) + { + /* record this object if it is the nearest one so far */ + if (fns->minDistanceSquared > distanceSquared) + { + fns->nearestObject = clientObject; + fns->minDistanceSquared = distanceSquared; + } + } +} + + +/* ------------------------------------------------------------------ */ +/* Search the database to find the object whose key-point is nearest + to a given location yet within a given radius. That is, it finds + the object (if any) within a given search sphere which is nearest + to the sphere's center. The ignoreObject argument can be used to + exclude an object from consideration (or it can be NULL). This is + useful when looking for the nearest neighbor of an object in the + database, since otherwise it would be its own nearest neighbor. + The function returns a void* pointer to the nearest object, or + NULL if none is found. */ + + +void* lqFindNearestNeighborWithinRadius (lqInternalDB* lq, + float x, float y, float z, + float radius, + void* ignoreObject) +{ + /* initialize search state */ + lqFindNearestState lqFNS; + lqFNS.nearestObject = NULL; + lqFNS.ignoreObject = ignoreObject; + lqFNS.minDistanceSquared = FLT_MAX; + + /* map search helper function over all objects within radius */ + lqMapOverAllObjectsInLocality (lq, + x, y, z, + radius, + lqFindNearestHelper, + &lqFNS); + + /* return nearest object found, if any */ + return lqFNS.nearestObject; +} + + +/* ------------------------------------------------------------------ */ +/* internal helper function */ + +void lqMapOverAllObjectsInBin (lqClientProxy* binProxyList, + lqCallBackFunction func, + void* clientQueryState); + +void lqMapOverAllObjectsInBin (lqClientProxy* binProxyList, + lqCallBackFunction func, + void* clientQueryState) +{ + /* walk down proxy list, applying call-back function to each one */ + while (binProxyList != NULL) + { + (*func) (binProxyList->object, 0, clientQueryState); + binProxyList = binProxyList->next; + } +} + + +/* ------------------------------------------------------------------ */ +/* Apply a user-supplied function to all objects in the database, + regardless of locality (cf lqMapOverAllObjectsInLocality) */ + +void lqMapOverAllObjects (lqInternalDB* lq, + lqCallBackFunction func, + void* clientQueryState) +{ + int i; + int bincount = lq->divx * lq->divy * lq->divz; + for (i=0; ibins[i], func, clientQueryState); + } + lqMapOverAllObjectsInBin (lq->other, func, clientQueryState); +} + +/* ------------------------------------------------------------------ */ +/* looks at all bins (except "other") finding the min and max bin + populations and the average of NON-EMPTY bin populations. (The + average over all bins is a constant (population/bincount)) */ + +#ifndef NO_LQ_BIN_STATS + +void lqgbpsCounter (void* clientObject USUSED_PARAM, + float distanceSquared USUSED_PARAM, + void* clientQueryState); + +void lqgbpsCounter (void* clientObject USUSED_PARAM, + float distanceSquared USUSED_PARAM, + void* clientQueryState) +{ + (*(int*)clientQueryState)++; +} + +void lqGetBinPopulationStats (lqInternalDB* lq, + int* min, + int* max, + float* average) +{ + int minPop = INT_MAX; + int maxPop = 0; + int totalCount = 0; + int nonEmptyBinCount = 0; + int bincount = lq->divx * lq->divy * lq->divz; + int i; + + for (i=0; ibins[i], lqgbpsCounter, &objectCount); + + /* collect data: max and min population, count objects and non-empty bins */ + if (objectCount > 0) + { + nonEmptyBinCount++; + if (maxPop < objectCount) maxPop = objectCount; + if (minPop > objectCount) minPop = objectCount; + totalCount += objectCount; + } + } + + /* set return values */ + *min = minPop; + *max = maxPop; + *average = ((float) totalCount) / ((float) nonEmptyBinCount); +} + +#endif /* NO_LQ_BIN_STATS */ + + +/* ------------------------------------------------------------------ */ +/* internal helper function */ + + +#define lqRemoveAllObjectsInBin(bin) \ + while ((bin) != NULL) lqRemoveFromBin ((bin)); + + +/* ------------------------------------------------------------------ */ +/* Removes (all proxies for) all objects from all bins */ + + +void lqRemoveAllObjects (lqInternalDB* lq) +{ + int i; + int bincount = lq->divx * lq->divy * lq->divz; + for (i=0; ibins[i]); + } + lqRemoveAllObjectsInBin (lq->other); +} + + +/* ------------------------------------------------------------------ */ diff --git a/pedestrian.h b/pedestrian.h deleted file mode 100644 index 2b2d69b..0000000 --- a/pedestrian.h +++ /dev/null @@ -1,134 +0,0 @@ -/************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * -* * -* This software is provided as-is, without any express or implied * -* warranty. In no event will the authors be held liable for any * -* damages arising from the use of this software. * -* * -* Permission is granted to anyone to use this software for any purpose, * -* including commercial applications, and to alter it and redistribute * -* it freely, subject to the following restrictions: * -* * -* 1. The origin of this software must not be misrepresented; you must * -* not claim that you wrote the original software. If you use this * -* software in a product, an acknowledgment in the product documentation * -* would be appreciated but is not required. * -* * -* 2. Altered source versions must be plainly marked as such, and must * -* not be misrepresented as being the original software. * -* * -* 3. This notice may not be removed or altered from any source * -* distribution. * -************************************************************************/ -#ifndef OGTA_PEDESTRIAN_H -#define OGTA_PEDESTRIAN_H - -#include -#include "math3d.h" -#include "obox.h" -#include "animation.h" -#include "opengta.h" - -namespace OpenGTA { - struct Projectile { - Projectile(uint8_t, float, Vector3D, Vector3D, Uint32); - uint8_t typeId; - float rot; - Vector3D pos; - Vector3D delta; - Uint32 endsAtTick; - }; - class SpriteObject { - public: - SpriteObject(const Vector3D & p); - SpriteObject(const SpriteObject & other); - struct Animation : public Util::Animation { - Animation(); - Animation(const Animation & other); - Animation(Uint16 foff, Uint8 num); - Animation(Uint16 foff, Uint8 num, float speed); - Uint16 firstFrameOffset; - //Uint8 numFrames; - float moveSpeed; - }; - Vector3D pos; - //Uint8 curFrame; - Uint16 sprNum; - Sint16 remap; - //Animation * animRef; - Animation anim; - bool animActive; - void update(Uint32 ticks); - Uint32 lastFrameUpdateAt; - Uint32 lastUpdateAt; - float rot; - GraphicsBase::SpriteNumbers::SpriteTypes sprType; - void setAnimation(Animation & otherAnim); - protected: - Uint8 calcCurrentFrame(Uint32 ticks); - float heightOverTerrain(const Vector3D & v); - private: - void copyValues(const SpriteObject & other); - SpriteObject & operator = (const SpriteObject & other) { return *this; } - }; - - class Pedestrian : public SpriteObject, public OBox { - public: - struct Controller { - // turn, move, - // run/walk/swim/crawl - // jump, shoot/punch, - Sint8 turn; - Sint8 move; - }; - Pedestrian(const Vector3D & e, const Vector3D & pos); - Pedestrian(const Vector3D & e, const Vector3D & pos, const Uint32 & asId); - Pedestrian(const Pedestrian & other); - Uint32 pedId; - Controller* m_control; - Uint32 animId; - Vector3D speedForces; - void switchToAnim(const Uint32 & newId); - - void update(Uint32 ticks); - void equip(uint8_t eq_id); - void giveItem(uint8_t id, uint32_t amount); - void fireWeapon(Uint32 ticks); - private: - typedef std::map InventoryType; - InventoryType inventory; - uint8_t activeWeapon; - bool inGroundContact; - void tryMove(Vector3D nPos); - void copyValues(const Pedestrian & other); - Uint32 weaponReloadedAt; - //Uint8 calcCurrentFrame(Uint32 ticks); - Pedestrian & operator = (const Pedestrian & other) { return *this; } - }; - - class Car : public SpriteObject, public OBox { - public: - Car(const OpenGTA::Map::ObjectPosition & op); - Car(const Car & other); - Uint32 delta; - Uint32 carId; - Uint8 type; - private: - GraphicsBase::CarInfo & c_info; - void copyValues(const Car & other); - Car & operator = (const Car & other) { return *this; } - - }; - - class GameObject : public SpriteObject, public OBox { - public: - GameObject(const OpenGTA::Map::ObjectPosition & op); - GameObject(const GameObject & other); - Uint32 objId; - private: - void copyValues(const GameObject & other); - GameObject & operator = (const GameObject & o) { return *this; } - }; -} - -#endif diff --git a/prepare_build.sh b/prepare_build.sh index fc61a60..f019126 100755 --- a/prepare_build.sh +++ b/prepare_build.sh @@ -13,11 +13,11 @@ function program_exists() { function print_make_file_list() { FOO=GL_SRC FOOO=GL_OBJ -( grep -l "^namespace OpenGL" *.cpp ; echo "gl_frustum.cpp";echo "math/obox.cpp coldet/math3d.cpp" ) | sort | xargs echo "$FOO =" +( grep -l "^namespace OpenGL" *.cpp ;echo "gl_frustum.cpp";echo "math/obox.cpp coldet/math3d.cpp util/physfsrwops.c" ) | sort | xargs echo "$FOO =" echo "$FOOO = \${$FOO:.cpp=.o}" FOO=OGTA_SRC FOOO=OGTA_OBJ -( grep -l "^namespace OpenGTA" *.cpp ; echo "slope_height_func.cpp" ) | sort | xargs echo "$FOO =" +( grep -l "^namespace OpenGTA" *.cpp ; echo "slope_height_func.cpp" )|grep -v viewer.cpp |grep -v sprite_anim_player.cpp| sort | xargs echo "$FOO =" echo "$FOOO = \${$FOO:.cpp=.o}" UTIL_SRC=$(ls util/*.cpp | grep -v color.cpp | grep -v sound | xargs echo) @@ -35,6 +35,13 @@ LUA_OBJ = \${LUA_SRC:.cpp=.o} SOUND_SRC = $SOUND_SRC SOUND_OBJ = \${SOUND_SRC:.cpp=.o} +OSTEER_SRC = opensteer/src/Clock.cpp +OSTEER_OBJ = \${OSTEER_SRC:.cpp=.o} + +SOUND_SRC = util/sound_device.cpp util/sound_fx_cache.cpp util/sound_music_player.cpp \ +util/sound_resample2.cpp util/sound_system.cpp +SOUND_OBJ = \$(SOUND_SRC:.cpp=.p) + EOF } @@ -58,13 +65,13 @@ gfxextract${EXE_PFIX}: gfx_extract.cpp read_gry.o read_g24.o read_cmp.o navdata. -o \$@ \$+ \\ \$(SDL_LIB) \$(SDL_GL_LIB) \$(SDL_IMG_LIB) \$(PHYSFS_LIB) \$(LOKI_LIB) -viewer${EXE_PFIX}: main2.cpp viewer.o \$(OGTA_OBJ) \$(GL_OBJ) \$(UTIL_OBJ) +viewer${EXE_PFIX}: main2.cpp viewer.o \$(OGTA_OBJ) \$(GL_OBJ) \$(UTIL_OBJ) \$(OSTEER_OBJ) \$(CXX) \$(CATCH_E) \$(FLAGS) \$(DEFS) \\ \$(INC) \\ -o \$@ \$+ \\ \$(SDL_LIB) \$(SDL_GL_LIB) \$(PHYSFS_LIB) \$(LOKI_LIB) \$(COLDET_LIB) -luaviewer${EXE_PFIX}: main2.cpp viewer.cpp \$(OGTA_OBJ) \$(GL_OBJ) \$(UTIL_OBJ) \ +luaviewer${EXE_PFIX}: main2.cpp viewer.cpp \$(OGTA_OBJ) \$(GL_OBJ) \$(UTIL_OBJ) \$(OSTEER_OBJ) \ \$(LUA_OBJ) \$(CXX) \$(CATCH_E) -DWITH_LUA \$(FLAGS) \$(DEFS) \\ \$(INC) \\ @@ -72,7 +79,7 @@ luaviewer${EXE_PFIX}: main2.cpp viewer.cpp \$(OGTA_OBJ) \$(GL_OBJ) \$(UTIL_OBJ) \$(SDL_LIB) \$(SDL_GL_LIB) \$(PHYSFS_LIB) \$(LOKI_LIB) \$(COLDET_LIB) \$(LUA_LIB) -spriteplayer${EXE_PFIX}: sprite_anim_player.o \$(OGTA_OBJ) \$(GL_OBJ) \$(UTIL_OBJ) main2.cpp +spriteplayer${EXE_PFIX}: sprite_anim_player.o \$(OGTA_OBJ) \$(GL_OBJ) \$(UTIL_OBJ) \$(OSTEER_OBJ) main2.cpp \$(CXX) \$(CATCH_E) \$(FLAGS) \$(DEFS) \\ \$(INC) \\ -o \$@ \$+ \\ @@ -91,6 +98,26 @@ objdump: tools/obj_dump.cpp read_gry.o \$(UTIL_OBJ) main2.o objdump_map: tools/obj_dump.cpp read_gry.o \$(UTIL_OBJ) main2.o read_cmp.o navdata.o \$(CXX) \$(CXXFLAGS) -DDUMP_OBJ_IN_MAP -o \$@ \$+ \$(SDL_LIB) \$(PHYSFS_LIB) +car_dump: tools/car_dump.cpp dataholder.o read_gry.o read_cmp.o read_g24.o navdata.o \ +main2.o read_fxt.o util/set.o util/buffercache.o util/log.o util/m_exceptions.o + \$(CXX) \$(CXXFLAGS) -o \$@ \$+ \$(SDL_LIB) \$(PHYSFS_LIB) \$(LOKI_LIB) + +plane_test: tests/test_plane.cpp math/line_intersect.o util/log.o \ +util/m_exceptions.o util/cell_iterator.o util/set.o util/buffercache.o \ +read_cmp.o datahelper.o navdata.o read_fxt.o read_gry.o read_g24.o \ +dataholder.o + \$(CXX) \$(CXXFLAGS) -o \$@ \$+ \$(SDL_LIB) \$(PHYSFS_LIB) \$(LOKI_LIB) + +lua_map_test: tests/lua_map_test.o util/file_helper.o util/log.o \ +util/m_exceptions.o util/buffercache.o util/set.o navdata.o \ +dataholder.o read_cmp.o read_gry.o read_g24.o read_fxt.o datahelper.o \ +main2.o lua_addon/lua_map.o lua_addon/lua_vm.o lua_addon/lua_stackguard.o + \$(CXX) \$(CXXFLAGS) -o \$@ \$+ \$(SDL_LIB) \$(PHYSFS_LIB) \$(LOKI_LIB) \$(LUA_LIB) + +sound_test: read_sdt.o util/m_exceptions.o util/sound_resample2.o \ +util/sound_device.o util/sound_system.cpp util/sound_fx_cache.o \ +util/sound_music_player.o util/physfsrwops.c util/log.o + \$(CXX) -DSOUND_TEST \$(CXXFLAGS) -o \$@ \$+ \$(SDL_LIB) \$(PHYSFS_LIB) \$(LOKI_LIB) \$(AUDIO_LIB) EOF } @@ -116,6 +143,19 @@ function check_sdl () { pkg_config_try_multiple SDL SDL sdl fi fi + cat <_out_$$.cpp +#include +int main(int argc, char* argv[]) { + SDL_GL_SWAP_CONTROL; +} +EOF + g++ $SDL_INC _out_$$.cpp 2>/dev/null + if [ $? -eq 0 ]; then + SDL_GL_SWAP_CONTROL='#define HAVE_SDL_VSYNC' + else + SDL_GL_SWAP_CONTROL='#undef HAVE_SDL_VSYNC' + fi + rm -f _out_$$.cpp a.out } function pkg_config_try_multiple () { @@ -145,6 +185,38 @@ function check_lua () { fi } +function check_sdl_audio () { +local good=0 +cat <_out_$$.cpp +#include +int main(int argc, char* argv[]) { +} +EOF +g++ $SDL_INC _out_$$.cpp 2>/dev/null +if [ $? -eq 0 ]; then + let good=$good+1 +fi +rm -f _out_$$.cpp + +cat <_out_$$.cpp +#include +int main(int argc, char* argv[]) { +} +EOF +g++ $SDL_INC _out_$$.cpp 2>/dev/null +if [ $? -eq 0 ]; then + let good=$good+1 +fi +rm -f _out_$$.cpp a.out + +if [ $good -eq 2 ]; then + AUDIO_LD="-lSDL_mixer -lSDL_sound" + SDL_SOUND_MIXER='#define WITH_SOUND' +else + SDL_SOUND_MIXER='#undef WITH_SOUND' +fi +} + function check_physfs () { program_exists pkg-config if [ $? -eq 1 ]; then @@ -153,18 +225,26 @@ function check_physfs () { } function check_compiler () { - g++ 1>/dev/null 2>&1 + if [ "$OGTA_PLATFORM" == "WIN32" ]; then + _CXX=i586-mingw32msvc-g++ + _CC=i586-mingw32msvc-gcc + else + _CXX=g++ + _CC=gcc + fi + $_CXX 1>/dev/null 2>&1 if [ $? -eq 1 ]; then - CXX=g++ + CXX=$_CXX else CXX= fi - gcc 1>/dev/null 2>&1 + $_CC 1>/dev/null 2>&1 if [ $? -eq 1 ]; then - CC=gcc + CC=$_CC else CC= fi + GCC_VERSION=$($CXX --version | head -n 1) } # defaults @@ -172,11 +252,6 @@ function check_compiler () { DEBUG=-ggdb WARN=-Wall OPT=-O2 -if [ "$1" == "LINUX" ]; then - DEFS="-DLINUX -DDO_SCALEX" -else - DEFS="-DWIN32 -DDO_SCALEX" -fi PHYSFS_LIB=-lphysfs SDL_LIB=-lSDL LUA_LIB=-llua51 @@ -190,7 +265,7 @@ CC = $CC DEBUG = $DEBUG OPT = $OPT WARN = $WARN -DEFS = $DEFS -DGCC +DEFS = $DEFS # def only for 'main' programs to let gdb handle the exception #CATCH_E = -DDONT_CATCH @@ -211,6 +286,9 @@ SDL_IMG_LIB = -lSDL_image LUA_INC = $LUA_INC LUA_LIB = $LUA_LIB +AUDIO_INC = +AUDIO_LIB = $AUDIO_LD + LINK_LAZY = -Xlinker --unresolved-symbols -Xlinker ignore-all EOF @@ -225,7 +303,7 @@ CC = i586-mingw32msvc-gcc #DEBUG = $DEBUG OPT = $OPT WARN = $WARN -DEFS = $DEFS -DGCC +DEFS = $DEFS # def only for 'main' programs to let gdb handle the exception #CATCH_E = -DDONT_CATCH @@ -256,7 +334,7 @@ function print_all() { check_sdl check_lua check_physfs -check_compiler +check_sdl_audio print_detected print_make_file_list print_target_list @@ -266,12 +344,68 @@ include depend EOF } -if [ "$1" == "LINUX" ]; then - echo "*** LINUX ***" - print_all > src_list.make -else +function print_config_h() { + if [ -e ogta_version ]; then + LAST_TOUCHED=$(cat ogta_version) + else + LAST_TOUCHED=$(find . -type f -exec ls -tl {} \; | grep -v CVS | tail -1 | awk '{print $6}') + echo $LAST_TOUCHED > ogta_version + fi + + cat < src_list.make print_make_file_list >> src_list.make print_target_list >> src_list.make +else + OGTA_PLATFORM="LINUX" + echo "*** LINUX ***" + check_compiler + DEFS="-include config.h" + print_all > src_list.make fi +print_config_h > config.h diff --git a/read_cmp.cpp b/read_cmp.cpp index 33fb05a..659d101 100644 --- a/read_cmp.cpp +++ b/read_cmp.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This file contains code derived from information copyrighted by * * DMA Design. It may not be used in a commercial product. * @@ -15,6 +15,7 @@ #include "navdata.h" #include "log.h" #include "m_exceptions.h" +#include "datahelper.h" /* see http://members.aol.com/form1/fixed.htm for fixed point floats: * int_var = (long) fixed_var >> 8; // for 8 bits after point @@ -35,6 +36,7 @@ namespace OpenGTA { o << filename << " with error: " << SDL_GetError(); throw E_FILENOTFOUND(o.str()); } + size_t level_as_num = Helper::mapFileName2Number(filename); loadHeader(); loadBase(); loadColumn(); @@ -42,7 +44,7 @@ namespace OpenGTA { loadObjects(); loadRoutes(); loadLocations(); - loadNavData(); + loadNavData(level_as_num); //dump(); } Map::~Map() { @@ -217,11 +219,11 @@ namespace OpenGTA { } } - void Map::loadNavData() { + void Map::loadNavData(const size_t levelNum) { PHYSFS_uint32 _si = _baseSize + columnSize + _topHeaderSize + objectPosSize + routeSize + 3 * 6 * 6 + blockSize; PHYSFS_seek(fd, _si); - nav = new NavData(navDataSize, fd); + nav = new NavData(navDataSize, fd, levelNum); assert(nav); } PHYSFS_uint16 Map::getNumBlocksAt(PHYSFS_uint8 x, PHYSFS_uint8 y) { diff --git a/read_fnt.cpp b/read_fnt.cpp index 124ce72..8b69586 100644 --- a/read_fnt.cpp +++ b/read_fnt.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This file contains code derived from information copyrighted by * * DMA Design. It may not be used in a commercial product. * diff --git a/read_fxt.cpp b/read_fxt.cpp index 3013c57..b0a1196 100644 --- a/read_fxt.cpp +++ b/read_fxt.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This file contains code derived from information copyrighted by * * DMA Design. It may not be used in a commercial product. * @@ -11,6 +11,8 @@ #include #include #include "opengta.h" +#include "m_exceptions.h" +#include "log.h" namespace OpenGTA { MessageDB::MessageDB() { @@ -31,8 +33,7 @@ namespace OpenGTA { f = PHYSFS_openRead(f2.c_str()); } if (f == NULL) { - std::cerr << "Error: could not open " << file << " for reading" << std::endl; - return; + throw E_FILENOTFOUND(file); } messages.clear(); @@ -92,7 +93,7 @@ namespace OpenGTA { const std::string& MessageDB::getText(const char* id) { std::map::iterator i = messages.find(std::string(id)); if (i == messages.end()) { - std::cerr << "Error: string lookup failed for key: " << id << std::endl; + ERROR << "string lookup failed for key: " << id << std::endl; return _error; } return i->second; @@ -101,7 +102,7 @@ namespace OpenGTA { const std::string& MessageDB::getText(const std::string &id) { std::map::iterator i = messages.find(id); if (i == messages.end()) { - std::cerr << "Error: string lookup failed for key: " << id << std::endl; + ERROR << "string lookup failed for key: " << id << std::endl; return _error; } return i->second; @@ -112,7 +113,7 @@ namespace OpenGTA { snprintf(reinterpret_cast(&tmp), 10, "%i", id); std::map::iterator i = messages.find(std::string(tmp)); if (i == messages.end()) { - std::cerr << "Error: string lookup failed for key: " << id << std::endl; + ERROR << "string lookup failed for key: " << id << std::endl; return _error; } return i->second; diff --git a/read_g24.cpp b/read_g24.cpp index 20c41af..b9f8282 100644 --- a/read_g24.cpp +++ b/read_g24.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This file contains code derived from information copyrighted by * * DMA Design. It may not be used in a commercial product. * @@ -29,6 +29,23 @@ namespace OpenGTA { palIndex = NULL; loadHeader(); setupBlocking(style); + // actually the next two are style003.g24, but at least somewhere close + firstValidPedRemap = 60; + lastValidPedRemap = 116; + if (style.find("001") != std::string::npos) { + firstValidPedRemap = 75; + lastValidPedRemap = 131; + } + else if (style.find("002") != std::string::npos) { + firstValidPedRemap = 79; + lastValidPedRemap = 135; + } + else if (style.find("003") != std::string::npos) { + // already set + } + else { + WARN << "Unknown g24 style - ped remaps most likely broken!" << std::endl; + } } Graphics24Bit::~Graphics24Bit() { @@ -143,6 +160,7 @@ namespace OpenGTA { PHYSFS_uint64 st = static_cast(_topHeaderSize) + sideSize + lidSize + auxSize + auxBlockTrailSize + animSize + pagedClutSize + paletteIndexSize + objectInfoSize; + //INFO << "seek for " << st << std::endl; loadCarInfo_shared(st); } diff --git a/read_gry.cpp b/read_gry.cpp index b706b35..67c08df 100644 --- a/read_gry.cpp +++ b/read_gry.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This file contains code derived from information copyrighted by * * DMA Design. It may not be used in a commercial product. * @@ -268,6 +268,17 @@ namespace OpenGTA { return NULL; } + unsigned int GraphicsBase::getRandomPedRemapNumber() { + return int(rand() * (1.0f / (1.0f + RAND_MAX)) * + (lastValidPedRemap - firstValidPedRemap) + + firstValidPedRemap); + } + + unsigned int GraphicsBase::getPedRemapNumberType(unsigned int _type) { + ERROR << "not implemented"<< std::endl; + return _type; + } + Graphics8Bit::Graphics8Bit(const std::string& style) : GraphicsBase() { fd = PHYSFS_openRead(style.c_str()); if (fd == NULL) { @@ -288,6 +299,8 @@ namespace OpenGTA { auxBlockTrailSize = 0; loadHeader(); setupBlocking(style); + firstValidPedRemap = 131; + lastValidPedRemap = 187; } Graphics8Bit::~Graphics8Bit() { @@ -423,7 +436,7 @@ namespace OpenGTA { for (int j=0; jframeCount; j++) { uint8_t val; PHYSFS_read(fd, static_cast(&val), 1, 1); - animation->frame.push_back(val); + animation->frame[j] = val; //PHYSFS_read(fd, static_cast(&animations[i].frame[j]), 1, 1); } animations.push_back(animation); @@ -498,8 +511,10 @@ namespace OpenGTA { void GraphicsBase::loadCarInfo_shared(PHYSFS_uint64 offset) { PHYSFS_seek(fd, offset); + //INFO << "starting at offset " << offset << std::endl; PHYSFS_uint32 bytes_read = 0; while (bytes_read < carInfoSize) { + //INFO << bytes_read << ": " << carInfoSize << std::endl; CarInfo * car = new CarInfo(); PHYSFS_readSLE16(fd, &car->width); @@ -579,6 +594,10 @@ namespace OpenGTA { PHYSFS_readSLE16(fd, &car->numDoors); bytes_read += 2; + if (car->numDoors > 2) { + WARN << "num-doors: " << car->numDoors << " > 2 ???" << std::endl; + car->numDoors = 0; + } for (int i=0; i < car->numDoors; i++) { PHYSFS_readSLE16(fd, &car->door[i].rpx); diff --git a/read_ini.cpp b/read_ini.cpp index 0d9f8b9..864b1d8 100644 --- a/read_ini.cpp +++ b/read_ini.cpp @@ -1,5 +1,5 @@ /************************************************************************ - * Copyright (c) 2005-2006 tok@openlinux.org.uk * + * Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This file contains code derived from information copyrighted by * * DMA Design. It may not be used in a commercial product. * @@ -9,31 +9,19 @@ * This notice may not be removed or altered. * ************************************************************************/ #include -#include -#include -#include -#include +#include "log.h" +#include "read_ini.h" namespace OpenGTA { - class ScriptParser { - public: - ScriptParser(const std::string &file); - ~ScriptParser(); - void loadLevel(PHYSFS_uint32 level); - private: - typedef std::map LevelMapType; - LevelMapType levels; - PHYSFS_file* fd; - }; - - ScriptParser::ScriptParser(const std::string &file) { + ScriptParser::ScriptParser(const std::string &file) : section_info(""), section_vars("") { fd = PHYSFS_openRead(file.c_str()); if (!fd) { std::cerr << "Error: could not open file " << file << " for reading!" << std::endl; } else { std::cout << "* Loading script " << file << " ... "; +/* unsigned char v; unsigned char m = 0; char buffer[10]; @@ -50,15 +38,67 @@ namespace OpenGTA { *b = 0x00; b = reinterpret_cast(&buffer); levels[static_cast(atoi(buffer))] = PHYSFS_tell(fd) + 1; + std::cout << buffer << " " << PHYSFS_tell(fd) + 1 << std::endl; } } if (v == '[') { m = 1; } } - std::cout << int(levels.size()) << " sections indexed" << std::endl; +*/ + const size_t buflen = 1024; + char buffer[buflen+1]; + char numbuf[10]; + PHYSFS_sint64 fd_off = 0; + while(!PHYSFS_eof(fd)) { + memset(buffer, 0, buflen+1); + PHYSFS_sint64 fd_off_add = PHYSFS_read(fd, static_cast(buffer), 1, buflen); + + char * buf_ptr = buffer; + while (buf_ptr) { + char * found_str = strchr(buf_ptr, '['); + char * found_str_end = strchr(buf_ptr, ']'); + if (found_str && found_str_end) { + memset(numbuf, 0, 10); + strncpy(numbuf, found_str + 1, found_str_end - found_str - 1); + //std::cout << numbuf << ": " << fd_off + found_str_end - buf_ptr + 2 << std::endl; + levels[static_cast(atoi(numbuf))] = fd_off + found_str_end - buf_ptr + 2; + } + if ((found_str) && (!found_str_end)) { + PHYSFS_seek(fd, PHYSFS_tell(fd) - 10); + break; + } + if (found_str) + buf_ptr = found_str + 1; + else + break; + } + fd_off += fd_off_add; + } } + std::cout << int(levels.size()) << " sections indexed" << std::endl; } + /* + * * Loading script MISSION.INI ... 1 4 +2 84961 +1001 195409 +1002 224532 +1003 256339 +1004 288768 +102 323745 +103 446555 +1101 568117 +1102 607842 +1103 648562 +1104 690150 +202 732582 +203 910588 +1201 1107740 +1202 1147497 +1203 1188235 +1204 1229847 +18 sections indexed +*/ ScriptParser::~ScriptParser() { if (fd != NULL) @@ -66,26 +106,65 @@ namespace OpenGTA { levels.clear(); } + PHYSFS_sint64 ScriptParser::sectionEndOffset(PHYSFS_sint64 start) { + PHYSFS_sint64 offset = PHYSFS_fileLength(fd); + LevelMapType::iterator i = levels.begin(); + while (i != levels.end()) { + if (i->second > start) + if (i->second < offset) + offset = i->second; + ++i; + } + return offset; + } + void ScriptParser::loadLevel(PHYSFS_uint32 level) { LevelMapType::iterator i = levels.find(level); if (i == levels.end()) { std::cerr << "not a valid level: " << level << std::endl; return; } + PHYSFS_sint64 end_of_section = sectionEndOffset(i->second); PHYSFS_seek(fd, i->second); - char buffer[256]; + + const size_t buf_len = 255; // +1 + char buffer[buf_len+1]; PHYSFS_uint16 read_bytes = 255; PHYSFS_uint16 offset = 0; - while(!PHYSFS_eof(fd)) { + size_t num_lines_read = 0; + bool first_part_of_section = true; + while(PHYSFS_tell(fd) < end_of_section) { memset(buffer+offset, 0, read_bytes+1); PHYSFS_read(fd, buffer + offset, 1, read_bytes); char* line_start = buffer; while (1) { char* line_end = strchr(line_start, '\r'); if (line_start && line_end) { + if (*(line_end - 1) == ' ') + line_end--; *line_end = 0; + while (*line_start == '\n' || *line_start == '\r' || *line_start == ' ') + line_start++; if (strlen(line_start) > 0) { - std::cout <<"["<< line_start << "]" << strlen(line_start)< end_of_section) + read_bytes = end_of_section - PHYSFS_tell(fd); //std::cout << buffer << std::endl; } } + void ScriptParser::acceptDefinition(const char* str) { + INFO << "def: " << str << std::endl; + } + + void ScriptParser::acceptCommand(const char* str) { + INFO << "cmd: " << str << std::endl; + } + } #if 0 diff --git a/read_ini.h b/read_ini.h new file mode 100644 index 0000000..8788829 --- /dev/null +++ b/read_ini.h @@ -0,0 +1,28 @@ +#ifndef READ_INI_H +#define READ_INI_H +#include +#include +#include +#include + +namespace OpenGTA { + + class ScriptParser { + public: + ScriptParser(const std::string &file); + virtual ~ScriptParser(); + void loadLevel(PHYSFS_uint32 level); + private: + typedef std::map LevelMapType; + LevelMapType levels; + PHYSFS_file* fd; + PHYSFS_sint64 sectionEndOffset(PHYSFS_sint64 start); + protected: + std::string section_info; + std::string section_vars; + virtual void acceptDefinition(const char*); + virtual void acceptCommand(const char*); + }; + +} +#endif diff --git a/read_sdt.cpp b/read_sdt.cpp index e3428f7..53ec51f 100644 --- a/read_sdt.cpp +++ b/read_sdt.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * diff --git a/readme.txt b/readme.txt index 4a0150f..9f3dae2 100644 --- a/readme.txt +++ b/readme.txt @@ -24,6 +24,11 @@ Just run 'make' or specifically 'make viewer'. The other programs are/were used for development or debugging. +The distributed win32 binaries are created with a cross-compiler. + +The file doc/compiling.txt in the source code release contains +information on the build process. + = Installing the data-files = You can download the game from http://www.rockstargames.com/classics/ . @@ -40,6 +45,13 @@ Needed: STYLE*.GRY (for 8-bit graphics) STYLE*.G24 (for 24-bit graphics) +Will be needed (in the future): +MISSION.INI +*.RAT ( 8 bit menu graphics) +*.RAW (24 bit menu graphics) +AUDIO/*.RAW AUDIO/*.SDT (sound effects) +AUDIO/*.WAV (cutscene text; in legacy format) + = Running = == gfxextract == @@ -61,6 +73,13 @@ The optional param loads the respective city; default is 0: 2 - MIAMI.CMP flags are: + +-V show version and compile time switches +-h show usage + +( The compiled-in usage information is more recent than the + following. ) + * screen dimensions (have to specify neither or both) -w width -h height @@ -92,17 +111,15 @@ furthermore: f : toggle fullscreen/windowed PRINT : save 'screenshot.bmp' in current directory p : dump coords (in lua syntax) to stdout - i,j,k,l : move player-char F2 : toggle drawing of sprite bounding-boxes F3 : toggle marking of sprite tex-border-boxes F4 : toggle free-move vs. follow-player - F5 : toggle drawing of road heading arrows + F5 : toggle drawing of road heading arrows (& normals) F6 : city map mode (ESC to exit, +, -, cursor keys) - 1 - 8 : choose a specific player-sprite animation - 9, 0 : set the player-sprite to a specific frame + F9 : toggle city blocks drawn textured + F10 : toggle blocks wireframe lines in 3d view: - F1 : demo-flight over the city w : forward s : backward space : stop @@ -112,6 +129,14 @@ in 3d view: You can move the view with the mouse; when you switch to 3d and the screen is black: move the mouse down. +in follow-player mode: + i,j,k,l : move player-char + l-shift : toggle walking/running + 0 : unselect weapon / unarmed + 1,2,3,4 : select weapon (only switches graphic) + F7 : draw explosion at player pos (graphical effect) + F8 : create random-walker ped at player-pos + == luaviewer: viewer + Lua (optional target) == Also needs Lua (only 5.1 tried) in path; run: 'make luaviewer' diff --git a/release_files_sorted b/release_files_sorted new file mode 100644 index 0000000..de687ea --- /dev/null +++ b/release_files_sorted @@ -0,0 +1,205 @@ +ogta/blockanim.cpp +ogta/blockanim.h +ogta/blockdata.cpp +ogta/blockdata.h +ogta/bugs.rec +ogta/coldet/box_bld.cpp +ogta/coldet/box.cpp +ogta/coldet/box.h +ogta/coldet/coldet_bld.cpp +ogta/coldet/coldet.cpp +ogta/coldet/coldet.dsp +ogta/coldet/coldet.h +ogta/coldet/coldetimpl.h +ogta/coldet/makefile.g++ +ogta/coldet/math3d.cpp +ogta/coldet/math3d.h +ogta/coldet/mytritri.cpp +ogta/coldet/mytritri.h +ogta/coldet/quickstart.html +ogta/coldet/readme.txt +ogta/coldet/sysdep.cpp +ogta/coldet/sysdep.h +ogta/coldet/transform.txt +ogta/coldet/tritri.c +ogta/common_sdl_gl.cpp +ogta/common_sdl_gl.h +ogta/datahelper.cpp +ogta/datahelper.h +ogta/dataholder.cpp +ogta/dataholder.h +ogta/doc/doc_links.txt +ogta/doc/gouranga.txt +ogta/doc/gta1_winex.txt +ogta/doc/hacking.txt +ogta/doc/more_hints_delfi.txt +ogta/doc/more_info.txt +ogta/doc/slopes1.txt +ogta/Doxyfile +ogta/entity_controller.cpp +ogta/entity_controller.h +ogta/font_cache.cpp +ogta/font_cache.h +ogta/fx_sdt.h +ogta/game_objects.cpp +ogta/game_objects.h +ogta/gfx_extract.cpp +ogta/gl_base.cpp +ogta/gl_base.h +ogta/gl_camera.cpp +ogta/gl_camera.h +ogta/gl_cityview.cpp +ogta/gl_cityview.h +ogta/gl_font.cpp +ogta/gl_font.h +ogta/gl_frustum.cpp +ogta/gl_frustum.h +ogta/gl_pagedtexture.h +ogta/gl_screen.cpp +ogta/gl_screen.h +ogta/gl_spritecache.cpp +ogta/gl_spritecache.h +ogta/gl_texturecache.cpp +ogta/gl_texturecache.h +ogta/id_sys.cpp +ogta/id_sys.h +ogta/licenses/LGPL-2.1.gz +ogta/licenses/LGPL-2.gz +ogta/licenses/mit.txt +ogta/licenses/readme.txt +ogta/licenses/zlib.txt +ogta/license.txt +ogta/lid_normal_data.h +ogta/localplayer.h +ogta/loki.make +ogta/loki.make.w32_cross +ogta/lua_addon/lua_camera.cpp +ogta/lua_addon/lua_camera.h +ogta/lua_addon/lua_cityview.cpp +ogta/lua_addon/lua_cityview.h +ogta/lua_addon/lua.hpp +ogta/lua_addon/lua_ini_bridge.cpp +ogta/lua_addon/lua_ini_bridge.h +ogta/lua_addon/lua_screen.cpp +ogta/lua_addon/lua_screen.h +ogta/lua_addon/lua_spritecache.cpp +ogta/lua_addon/lua_spritecache.h +ogta/lua_addon/lua_stackguard.cpp +ogta/lua_addon/lua_stackguard.h +ogta/lua_addon/lua_vm.cpp +ogta/lua_addon/lua_vm.h +ogta/lua_addon/lunar.h +ogta/main2.cpp +ogta/main.cpp +ogta/makefile +ogta/math/basis.hpp +ogta/math/coord_frame.hpp +ogta/math/interpolate.hpp +ogta/math/makefile +ogta/math/matrix.hpp +ogta/math/obb.cpp +ogta/math/obb.hpp +ogta/math/obox.cpp +ogta/math/obox.h +ogta/math/quaternion.h +ogta/math/rectangle.hpp +ogta/math/vector.hpp +ogta/math/weighted_set.cpp +ogta/math/weighted_set.h +ogta/navdata.cpp +ogta/navdata.h +ogta/ogta_version +ogta/opengta.h +ogta/opensteer/COPYING.OPENSTEER +ogta/opensteer/include/OpenSteer/Clock.h +ogta/opensteer/include/OpenSteer/lq.h +ogta/opensteer/include/OpenSteer/Proximity.h +ogta/opensteer/include/OpenSteer/Utilities.h +ogta/opensteer/include/OpenSteer/Vec3.h +ogta/opensteer/include/OpenSteer/Vec3Utilities.h +ogta/opensteer/ogta_opensteer.txt +ogta/opensteer/src/Clock.cpp +ogta/opensteer/src/lq.c +ogta/opensteer/src/Vec3.cpp +ogta/opensteer/src/Vec3Utilities.cpp +ogta/prepare_build.sh +ogta/read_cmp.cpp +ogta/read_fnt.cpp +ogta/read_fxt.cpp +ogta/read_g24.cpp +ogta/read_gry.cpp +ogta/read_ini.cpp +ogta/read_ini.h +ogta/readme.txt +ogta/read_sdt.cpp +ogta/release_files_sorted +ogta/scripts/demo1.lua +ogta/scripts/demo2.lua +ogta/scripts/demo3.lua +ogta/slope1_data.h +ogta/slope1_tcoords.h +ogta/slope_height_func.cpp +ogta/sprite_anim_player.cpp +ogta/spritemanager.cpp +ogta/spritemanager.h +ogta/tests/interpolate_test.cpp +ogta/tests/menudemo.cpp +ogta/tests/new_obj_test.cpp +ogta/tests/sound_test1.cpp +ogta/tools/analyse_lids_2.c +ogta/tools/analyse_lids.c +ogta/tools/blockview.cpp +ogta/tools/create_normals.cpp +ogta/tools/display_font.cpp +ogta/tools/display_slopes.cpp +ogta/tools/doxy_doc.sh +ogta/tools/gen_texcoords.c +ogta/tools/insert_copyright.sh +ogta/tools/mapinfo.cpp +ogta/tools/minimap.cpp +ogta/tools/obj_dump.cpp +ogta/tools/replace_in_files.sh +ogta/tools/resort_quads.c +ogta/tools/slope_conv.awk +ogta/tools/slope_exchange.sh +ogta/tools/style_demo.sh +ogta/train_system.cpp +ogta/train_system.h +ogta/util/abstract_container.h +ogta/util/animation.cpp +ogta/util/animation.h +ogta/util/buffercache.cpp +ogta/util/buffercache.h +ogta/util/cell_iterator.cpp +ogta/util/cell_iterator.h +ogta/util/cistring.h +ogta/util/file_helper.cpp +ogta/util/file_helper.h +ogta/util/gui.h +ogta/util/image_loader.cpp +ogta/util/image_loader.h +ogta/util/log.cpp +ogta/util/log.h +ogta/util/map_helper.cpp +ogta/util/map_helper.h +ogta/util/m_exceptions.cpp +ogta/util/m_exceptions.h +ogta/util/physfsrwops.c +ogta/util/physfsrwops.h +ogta/util/sample_cache.h +ogta/util/set.cpp +ogta/util/set.h +ogta/util/sound_device.cpp +ogta/util/sound_device.h +ogta/util/sound_fx_cache.cpp +ogta/util/sound_fx_cache.h +ogta/util/sound_mixer.h +ogta/util/sound_music_player.cpp +ogta/util/sound_music_player.h +ogta/util/sound_resample2.cpp +ogta/util/sound_resample2.h +ogta/util/sound_system.cpp +ogta/util/sound_system.h +ogta/util/timer.cpp +ogta/util/timer.h +ogta/viewer.cpp diff --git a/sprite_anim_player.cpp b/sprite_anim_player.cpp index f26d539..e1cbd78 100644 --- a/sprite_anim_player.cpp +++ b/sprite_anim_player.cpp @@ -1,3 +1,25 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ #include #include #include @@ -29,13 +51,17 @@ int bbox_toggle = 0; int texsprite_toggle = 0; int spr_type = (int)ped.sprType; +namespace OpenGTA { +void ai_step_fake(OpenGTA::Pedestrian*) { +} +} void on_exit() { SDL_Quit(); PHYSFS_deinit(); } -void run_init() { +void run_init(const char*) { PHYSFS_init("mapview"); PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1); PHYSFS_addToSearchPath("gtadata.zip", 1); @@ -106,7 +132,7 @@ void drawScene(Uint32 ticks) { if (play_anim) { pedAnim.firstFrameOffset = now_frame; } - OpenGTA::SpriteManagerHolder::Instance().drawPed(ped); + OpenGTA::SpriteManagerHolder::Instance().draw(ped); OpenGL::ScreenHolder::Instance().setFlatProjection(); @@ -188,7 +214,7 @@ void handleKeyPress( SDL_keysym *keysym ) { } if (update_anim) { pedAnim.firstFrameOffset = frame_offset; - ped.setAnimation(pedAnim); + ped.anim = pedAnim; } } diff --git a/spritemanager.cpp b/spritemanager.cpp index e560c59..a3a5f3a 100644 --- a/spritemanager.cpp +++ b/spritemanager.cpp @@ -1,33 +1,35 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * -* * -* This software is provided as-is, without any express or implied * -* warranty. In no event will the authors be held liable for any * -* damages arising from the use of this software. * -* * -* Permission is granted to anyone to use this software for any purpose, * -* including commercial applications, and to alter it and redistribute * -* it freely, subject to the following restrictions: * -* * -* 1. The origin of this software must not be misrepresented; you must * -* not claim that you wrote the original software. If you use this * -* software in a product, an acknowledgment in the product documentation * -* would be appreciated but is not required. * -* * -* 2. Altered source versions must be plainly marked as such, and must * -* not be misrepresented as being the original software. * -* * -* 3. This notice may not be removed or altered from any source * -* distribution. * -************************************************************************/ + * Copyright (c) 2005-2007 tok@openlinux.org.uk * + * * + * This software is provided as-is, without any express or implied * + * warranty. In no event will the authors be held liable for any * + * damages arising from the use of this software. * + * * + * Permission is granted to anyone to use this software for any purpose, * + * including commercial applications, and to alter it and redistribute * + * it freely, subject to the following restrictions: * + * * + * 1. The origin of this software must not be misrepresented; you must * + * not claim that you wrote the original software. If you use this * + * software in a product, an acknowledgment in the product documentation * + * would be appreciated but is not required. * + * * + * 2. Altered source versions must be plainly marked as such, and must * + * not be misrepresented as being the original software. * + * * + * 3. This notice may not be removed or altered from any source * + * distribution. * + ************************************************************************/ #include #include "gl_spritecache.h" #include "dataholder.h" #include "spritemanager.h" #include "log.h" #include "timer.h" +#include "id_sys.h" namespace OpenGTA { + //SpriteManager::SpriteManager() : trainSystem(AbstractContainer::objs){ SpriteManager::SpriteManager() { drawMode = (1); @@ -37,33 +39,55 @@ namespace OpenGTA { registerAnimation(2, SpriteObject::Animation(0, 7, 0.001f)); // walking registerAnimation(3, SpriteObject::Animation(8, 7, 0.0015f)); // running -// registerAnimation(3, SpriteObject::Animation(16, 0)); // sitting in car -// registerAnimation(4, SpriteObject::Animation(17, 7)); // car-exit -// registerAnimation(5, SpriteObject::Animation(25, 7)); // car-enter + // registerAnimation(3, SpriteObject::Animation(16, 0)); // sitting in car + // registerAnimation(4, SpriteObject::Animation(17, 7)); // car-exit + // registerAnimation(5, SpriteObject::Animation(25, 7)); // car-enter //registerAnimation(3, SpriteObject::Animation(107, 7, 0.002f)); //registerAnimation(4, SpriteObject::Animation(99, 7, 0.001f)); //registerAnimation(5, SpriteObject::Animation(28, 7)); -// registerAnimation(6, SpriteObject::Animation(38, 2)); // falling - registerAnimation(7, SpriteObject::Animation(41, 0)); // sliding under - registerAnimation(8, SpriteObject::Animation(42, 1)); // death pose; maybe just 1? - registerAnimation(9, SpriteObject::Animation(44, 0)); // death-back pose - registerAnimation(10, SpriteObject::Animation(45, 1)); // shot-in-front - registerAnimation(11, SpriteObject::Animation(47, 1)); // swimming - registerAnimation(12, SpriteObject::Animation(98, 0)); // standing still + // registerAnimation(6, SpriteObject::Animation(38, 2)); // falling + //registerAnimation(7, SpriteObject::Animation(41, 0)); // sliding under + //registerAnimation(9, SpriteObject::Animation(44, 0)); // death-back pose + //registerAnimation(11, SpriteObject::Animation(47, 1)); // swimming + //registerAnimation(12, SpriteObject::Animation(98, 0)); // standing still registerAnimation(4, SpriteObject::Animation(89, 0)); // standing, gun registerAnimation(5, SpriteObject::Animation(99, 7, 0.001f)); // walking, gun registerAnimation(6, SpriteObject::Animation(107, 7, 0.002f)); // running, gun + + registerAnimation(7, SpriteObject::Animation(134, 0)); //standing, flamethrower + registerAnimation(8, SpriteObject::Animation(118, 7, 0.001f)); // walking, flamethrower + registerAnimation(9, SpriteObject::Animation(126, 7, 0.002f)); // running, flamethrower + + registerAnimation(10, SpriteObject::Animation(152, 0)); //standing, uzi + registerAnimation(11, SpriteObject::Animation(136, 7, 0.001f)); // walking, uzi + registerAnimation(12, SpriteObject::Animation(144, 7, 0.002f)); // running, uzi + + registerAnimation(13, SpriteObject::Animation(170, 0)); //standing, rocket-launcher + registerAnimation(14, SpriteObject::Animation(154, 7, 0.001f)); // walking, rocket-launcher + registerAnimation(15, SpriteObject::Animation(162, 7, 0.002f)); // running, rocket-launcher + + + + registerAnimation(42, SpriteObject::Animation(42, 1)); // death pose; maybe just 1? + registerAnimation(45, SpriteObject::Animation(45, 1)); // shot-in-front + + registerAnimation(46, SpriteObject::Animation(354, 12)); + + + /* - registerAnimation(12, SpriteObject::Animation( - registerAnimation(13, SpriteObject::Animation( - registerAnimation(14, SpriteObject::Animation( - registerAnimation(15, SpriteObject::Animation( - registerAnimation(16, SpriteObject::Animation( - registerAnimation(17, SpriteObject::Animation( - registerAnimation(18, SpriteObject::Animation( - registerAnimation(19, SpriteObject::Animation( -*/ + registerAnimation(12, SpriteObject::Animation( + registerAnimation(13, SpriteObject::Animation( + registerAnimation(14, SpriteObject::Animation( + registerAnimation(15, SpriteObject::Animation( + registerAnimation(16, SpriteObject::Animation( + registerAnimation(17, SpriteObject::Animation( + registerAnimation(18, SpriteObject::Animation( + registerAnimation(19, SpriteObject::Animation( + */ + registerAnimation(99, SpriteObject::Animation(0, 12)); + registerAnimation(100, SpriteObject::Animation(12, 12)); } SpriteManager::~SpriteManager() { clear(); @@ -71,359 +95,594 @@ namespace OpenGTA { } void SpriteManager::update(Uint32 ticks) { - for (PedListType::iterator i = activePeds.begin(); i != activePeds.end(); ++i) { - for (ObjectListType::iterator j = activeObjects.begin(); j != activeObjects.end(); ++j) { - Pedestrian & ped = *i; - GameObject & obj = *j; - Vector3D d(ped.GetCenterPoint() - obj.GetCenterPoint()); - if (d.SquareMagnitude() < 25) { - INFO << "obj: " << obj.pos.x << ", " << obj.pos.y << "[" << obj.m_Extent.y << "], " << obj.pos.z << std::endl; - INFO << "ped: " << ped.pos.x << ", " << ped.pos.y <<", " << ped.pos.z << std::endl; - INFO << "ped in obj: " << ped.IsBoxInBox(obj) << std::endl; - INFO << "obj in ped: " << obj.IsBoxInBox(ped) << std::endl; - } - } + /* + for (PedListType::iterator i = activePeds.begin(); i != activePeds.end(); ++i) { + for (ObjectListType::iterator j = activeObjects.begin(); j != activeObjects.end(); ++j) { + Pedestrian & ped = *i; + GameObject & obj = *j; + Vector3D d(ped.GetCenterPoint() - obj.GetCenterPoint()); + if (d.SquareMagnitude() < 25) { + INFO << "obj: " << obj.pos.x << ", " << obj.pos.y << "[" << obj.m_Extent.y << "], " << obj.pos.z << std::endl; + INFO << "ped: " << ped.pos.x << ", " << ped.pos.y <<", " << ped.pos.z << std::endl; + INFO << "ped in obj: " << ped.IsBoxInBox(obj) << std::endl; + INFO << "obj in ped: " << obj.IsBoxInBox(ped) << std::endl; + } + } + } + for (PedListType::iterator i = activePeds.begin(); i != activePeds.end(); ++i) { + i->update(ticks); + } + for (ObjectListType::iterator i = activeObjects.begin(); i != activeObjects.end(); ++i) { + i->update(ticks); + }*/ + + size_t num_peds, num_cars, num_obj; + num_peds = 0; + for (AbstractContainer::Storage_T_Iterator i = AbstractContainer::objs.begin(); + i != AbstractContainer::objs.end(); ++i) { + Pedestrian & ped = (*i); + ped.update(ticks); + num_peds++; } - for (PedListType::iterator i = activePeds.begin(); i != activePeds.end(); ++i) { - i->update(ticks); + num_cars = 0; + for (AbstractContainer::Storage_T_Iterator i = AbstractContainer::objs.begin(); + i != AbstractContainer::objs.end(); ++i) { + Car & car = (*i); + car.update(ticks); + num_cars++; + } + for (AbstractContainer::Storage_T_Iterator i = AbstractContainer::objs.begin(); + i != AbstractContainer::objs.end(); ++i) { + SpriteObject & obj = (*i); + obj.update(ticks); + num_obj++; + if (obj.isActive == false) + AbstractContainer::toBeRemoved.push_back(i); + } + for (ProjectileListType::iterator i = activeProjectiles.begin(); i != activeProjectiles.end();) { + Projectile & pr = (*i); + pr.update(ticks); + if (pr.lastUpdateAt >= pr.endsAtTick) { + ProjectileListType::iterator j = i++; + activeProjectiles.erase(j); + //INFO << "deleting old projectile; now " << activeProjectiles.size() << std::endl; + } + else + ++i; + + } + removeDeadStuff(); + if (num_peds < 10 && num_peds > 0) { + //MapHelper::createPeds(5); + Map & map = OpenGTA::MapHolder::Instance().get(); + while (1) { + Util::TupleOfUint8 tu8 = creationArea.getValidCoord(); + int k = -1; + for (int i = 0; i < map.getNumBlocksAtNew(tu8.first, tu8.second); ++i) { + Map::BlockInfo * bi = map.getBlockAtNew(tu8.first, tu8.second, i); + if (bi->blockType() == 3) { + k = i; + break; + } + } + if (k == -1) + continue; + + INFO << int(tu8.first) << " " << int(tu8.second) << " " << k << std::endl; + + Vector3D pos(tu8.first + 0.5f, k+1, tu8.second+0.5f); + int id = OpenGTA::TypeIdBlackBox::requestId(); + Sint16 remap = OpenGTA::StyleHolder::Instance().get().getRandomPedRemapNumber(); + OpenGTA::Pedestrian p(Vector3D(0.3f, 0.5f, 0.3f), pos, id, remap); + OpenGTA::SpriteManagerHolder::Instance().add(p); + break; + } } } void SpriteManager::drawInRect(SDL_Rect & r) { - for (PedListType::iterator i = activePeds.begin(); i != activePeds.end(); ++i) { + for (AbstractContainer::Storage_T_Iterator i = AbstractContainer::objs.begin(); + i != AbstractContainer::objs.end(); ++i) { Pedestrian & ped = (*i); if ((ped.pos.x >= r.x) && (ped.pos.x <= r.x + r.w) && - (ped.pos.z >= r.y) && (ped.pos.z <= r.y + r.h)) { - drawPed(ped); - } + (ped.pos.z >= r.y) && (ped.pos.z <= r.y + r.h)) + draw(ped); } - for (ObjectListType::iterator i = activeObjects.begin(); i != activeObjects.end(); ++i) { - GameObject & obj = (*i); + for (AbstractContainer::Storage_T_Iterator i = AbstractContainer::objs.begin(); + i != AbstractContainer::objs.end(); ++i) { + SpriteObject & obj = (*i); if ((obj.pos.x >= r.x) && (obj.pos.x <= r.x + r.w) && - (obj.pos.z >= r.y) && (obj.pos.z <= r.y + r.h)) { - drawObject(obj); - } + (obj.pos.z >= r.y) && (obj.pos.z <= r.y + r.h)) + draw(obj); } - for (CarListType::iterator i = activeCars.begin(); i != activeCars.end(); ++i) { - Car & car = *i; + for (AbstractContainer::Storage_T_Iterator i = AbstractContainer::objs.begin(); + i != AbstractContainer::objs.end(); ++i) { + Car & car = (*i); if ((car.pos.x >= r.x) && (car.pos.x <= r.x + r.w) && - (car.pos.z >= r.y) && (car.pos.z <= r.y + r.h)) { - drawCar(car); - } + (car.pos.z >= r.y) && (car.pos.z <= r.y + r.h)) + draw(car); } + + glColor3f(0.2f, 0.2f, 0.2f); + typedef ProjectileListType::iterator ProjectileIterator; + for (ProjectileIterator i = activeProjectiles.begin(); i != activeProjectiles.end(); ++i) { + Projectile & prj = (*i); + if ((prj.pos.x >= r.x) && (prj.pos.x <= r.x + r.w) && + (prj.pos.z >= r.y) && (prj.pos.z <= r.y + r.h)) + draw(prj); + } + glColor3f(1, 1, 1); + } void SpriteManager::clear() { - activePeds.clear(); - activeObjects.clear(); - activeCars.clear(); +#define TYPED_CLEANUP(T) { \ + AbstractContainer::objs.clear(); \ + AbstractContainer::toBeRemoved.clear(); \ +} + TYPED_CLEANUP(Pedestrian); + TYPED_CLEANUP(Car); + TYPED_CLEANUP(SpriteObject); + //TYPED_CLEANUP(TrainSegment); + activeProjectiles.clear(); + +#undef TYPED_CLEANUP } -/* - void SpriteManager::drawCar(Car & car) { - GraphicsBase & style = StyleHolder::Instance().get(); - - GraphicsBase::SpriteInfo * info = style.getSprite(sprNum); - - OpenGL::PagedTexture t; - GLfloat w, h; - - drawGL(t, w, h); - - } - */ - #define GL_OBJ_COMMON(o) GL_CHECKERROR; \ - glPushMatrix(); \ - glTranslatef(o.pos.x, o.pos.y, o.pos.z); \ - glRotatef(o.rot, 0, 1, 0); \ - glGetFloatv(GL_MODELVIEW_MATRIX, *o.m_M.m) +glPushMatrix(); \ +glTranslatef(o.pos.x, o.pos.y, o.pos.z); \ +glRotatef(o.rot, 0, 1, 0); \ +//glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)o.m_M.m) + +#define DRAW_TEX_QUADS_OBJ(t, w, h) glBindTexture(GL_TEXTURE_2D, t.inPage); \ +glBegin(GL_QUADS); \ +glTexCoord2f(t.coords[0].u, t.coords[1].v); \ +glVertex3f(-w/2, 0.0f, h/2); \ +glTexCoord2f(t.coords[1].u, t.coords[1].v); \ +glVertex3f(w/2, 0.0f, h/2); \ +glTexCoord2f(t.coords[1].u, t.coords[0].v); \ +glVertex3f(w/2, 0.0f, -h/2); \ +glTexCoord2f(t.coords[0].u, t.coords[0].v); \ +glVertex3f(-w/2, 0.0f, -h/2); \ +glEnd() - void SpriteManager::drawCar(Car & car) { - GL_OBJ_COMMON(car); - GraphicsBase & style = StyleHolder::Instance().get(); - OpenGL::PagedTexture t; - PHYSFS_uint16 sprNum = style.spriteNumbers.reIndex(car.sprNum + +void SpriteManager::draw(Car & car) { + GL_OBJ_COMMON(car); + GraphicsBase & style = StyleHolder::Instance().get(); + OpenGL::PagedTexture t; + PHYSFS_uint16 sprNum = style.spriteNumbers.reIndex(car.sprNum + car.anim.firstFrameOffset + car.anim.currentFrame, car.sprType); - - GraphicsBase::SpriteInfo * info = style.getSprite(sprNum); - assert(info); - float w = float(info->w) / 64.0f; - float h = float(info->h) / 64.0f; - if (OpenGL::SpriteCacheHolder::Instance().has(sprNum, car.remap)) - t = OpenGL::SpriteCacheHolder::Instance().get(sprNum, car.remap); - else { - t = OpenGL::SpriteCacheHolder::Instance().create(car.sprNum + + + GraphicsBase::SpriteInfo * info = style.getSprite(sprNum); + assert(info); + float w = float(info->w) / 64.0f; + float h = float(info->h) / 64.0f; + if (OpenGL::SpriteCacheHolder::Instance().has(sprNum, car.remap)) + t = OpenGL::SpriteCacheHolder::Instance().get(sprNum, car.remap); + else { + t = OpenGL::SpriteCacheHolder::Instance().create(car.sprNum + car.anim.firstFrameOffset + car.anim.currentFrame, car.sprType, car.remap); - } - glBindTexture(GL_TEXTURE_2D, t.inPage); - - glBegin(GL_QUADS); - glTexCoord2f(t.coords[0].u, t.coords[1].v); - glVertex3f(-w/2, 0.0f, h/2); - glTexCoord2f(t.coords[1].u, t.coords[1].v); - glVertex3f(w/2, 0.0f, h/2); - glTexCoord2f(t.coords[1].u, t.coords[0].v); - glVertex3f(w/2, 0.0f, -h/2); - glTexCoord2f(t.coords[0].u, t.coords[0].v); - glVertex3f(-w/2, 0.0f, -h/2); - - glEnd(); - glDisable(GL_TEXTURE_2D); - if (getDrawBBox()) { - glBegin(GL_LINE_STRIP); - glVertex3f(-car.m_Extent.x, 0.0f, car.m_Extent.z); - glVertex3f(car.m_Extent.x, 0.0f, car.m_Extent.z); - glVertex3f(car.m_Extent.x, 0.0f, -car.m_Extent.z); - glVertex3f(-car.m_Extent.x, 0.0f, -car.m_Extent.z); - glVertex3f(-car.m_Extent.x, 0.0f, car.m_Extent.z); - glEnd(); - glBegin(GL_LINE_STRIP); - glVertex3f(-car.m_Extent.x, car.m_Extent.y, car.m_Extent.z); - glVertex3f(car.m_Extent.x, car.m_Extent.y, car.m_Extent.z); - glVertex3f(car.m_Extent.x, car.m_Extent.y, -car.m_Extent.z); - glVertex3f(-car.m_Extent.x, car.m_Extent.y, -car.m_Extent.z); - glVertex3f(-car.m_Extent.x, car.m_Extent.y, car.m_Extent.z); - glEnd(); - } - if (getDrawTexBorder()) { - glDisable(GL_TEXTURE_2D); - glBegin(GL_LINE_STRIP); - glColor3f(float(202)/255.0f, float(31)/255.0f, float(123)/255.0f); - glVertex3f(-w/2, 0.0f, h/2); - glVertex3f(w/2, 0.0f, h/2); - glVertex3f(w/2, 0.0f, -h/2); - glVertex3f(-w/2, 0.0f, -h/2); - glVertex3f(-w/2, 0.0f, h/2); - glEnd(); - glColor3f(1.0f, 1.0f, 1.0f); - } - glEnable(GL_TEXTURE_2D); - - glPopMatrix(); - GL_CHECKERROR; } - void SpriteManager::drawObject(GameObject & obj) { - GL_OBJ_COMMON(obj); - GraphicsBase & style = StyleHolder::Instance().get(); - OpenGL::PagedTexture t; - PHYSFS_uint16 sprNum = style.spriteNumbers.reIndex(obj.sprNum + + DRAW_TEX_QUADS_OBJ(t, w, h); + + if (getDrawBBox() || getDrawTexBorder()) + glDisable(GL_TEXTURE_2D); + + if (getDrawBBox()) + drawBBoxOutline(car); + if (getDrawTexBorder()) + drawTextureOutline(w, h); + + if (getDrawBBox() || getDrawTexBorder()) + glEnable(GL_TEXTURE_2D); + + glPopMatrix(); + GL_CHECKERROR; +} + +void SpriteManager::drawBBoxOutline(const OBox & box) { + glBegin(GL_LINE_STRIP); + glVertex3f(-box.m_Extent.x, 0.0f, box.m_Extent.z); + glVertex3f(box.m_Extent.x, 0.0f, box.m_Extent.z); + glVertex3f(box.m_Extent.x, 0.0f, -box.m_Extent.z); + glVertex3f(-box.m_Extent.x, 0.0f, -box.m_Extent.z); + glVertex3f(-box.m_Extent.x, 0.0f, box.m_Extent.z); + glEnd(); + glBegin(GL_LINE_STRIP); + glVertex3f(-box.m_Extent.x, box.m_Extent.y, box.m_Extent.z); + glVertex3f(box.m_Extent.x, box.m_Extent.y, box.m_Extent.z); + glVertex3f(box.m_Extent.x, box.m_Extent.y, -box.m_Extent.z); + glVertex3f(-box.m_Extent.x, box.m_Extent.y, -box.m_Extent.z); + glVertex3f(-box.m_Extent.x, box.m_Extent.y, box.m_Extent.z); + glEnd(); +} + +void SpriteManager::drawTextureOutline(const float & w, const float & h) { + glBegin(GL_LINE_STRIP); + glColor3f(float(202)/255.0f, float(31)/255.0f, float(123)/255.0f); + glVertex3f(-w/2, 0.0f, h/2); + glVertex3f(w/2, 0.0f, h/2); + glVertex3f(w/2, 0.0f, -h/2); + glVertex3f(-w/2, 0.0f, -h/2); + glVertex3f(-w/2, 0.0f, h/2); + glEnd(); + glColor3f(1.0f, 1.0f, 1.0f); +} + +void SpriteManager::draw(SpriteObject & obj) { + if (obj.sprType == GraphicsBase::SpriteNumbers::EX) { + return drawExplosion(obj); + } + GL_OBJ_COMMON(obj); + GraphicsBase & style = StyleHolder::Instance().get(); + OpenGL::PagedTexture t; + PHYSFS_uint16 sprNum = style.spriteNumbers.reIndex(obj.sprNum + obj.anim.firstFrameOffset + obj.anim.currentFrame, obj.sprType); - - GraphicsBase::SpriteInfo * info = style.getSprite(sprNum); - assert(info); - float w = float(info->w) / 64.0f; - float h = float(info->h) / 64.0f; - if (OpenGL::SpriteCacheHolder::Instance().has(sprNum, obj.remap)) - t = OpenGL::SpriteCacheHolder::Instance().get(sprNum, obj.remap); - else { - t = OpenGL::SpriteCacheHolder::Instance().create(obj.sprNum + + + GraphicsBase::SpriteInfo * info = style.getSprite(sprNum); + assert(info); + float w = float(info->w) / 64.0f; + float h = float(info->h) / 64.0f; + if (OpenGL::SpriteCacheHolder::Instance().has(sprNum, obj.remap)) + t = OpenGL::SpriteCacheHolder::Instance().get(sprNum, obj.remap); + else { + t = OpenGL::SpriteCacheHolder::Instance().create(obj.sprNum + obj.anim.firstFrameOffset + obj.anim.currentFrame, obj.sprType, obj.remap); - } - glBindTexture(GL_TEXTURE_2D, t.inPage); - - glBegin(GL_QUADS); - glTexCoord2f(t.coords[0].u, t.coords[1].v); - glVertex3f(-w/2, 0.0f, h/2); - glTexCoord2f(t.coords[1].u, t.coords[1].v); - glVertex3f(w/2, 0.0f, h/2); - glTexCoord2f(t.coords[1].u, t.coords[0].v); - glVertex3f(w/2, 0.0f, -h/2); - glTexCoord2f(t.coords[0].u, t.coords[0].v); - glVertex3f(-w/2, 0.0f, -h/2); - - glEnd(); - glDisable(GL_TEXTURE_2D); - if (getDrawBBox()) { - glBegin(GL_LINE_STRIP); - glVertex3f(-obj.m_Extent.x, 0.0f, obj.m_Extent.z); - glVertex3f(obj.m_Extent.x, 0.0f, obj.m_Extent.z); - glVertex3f(obj.m_Extent.x, 0.0f, -obj.m_Extent.z); - glVertex3f(-obj.m_Extent.x, 0.0f, -obj.m_Extent.z); - glVertex3f(-obj.m_Extent.x, 0.0f, obj.m_Extent.z); - glEnd(); - glBegin(GL_LINE_STRIP); - glVertex3f(-obj.m_Extent.x, obj.m_Extent.y, obj.m_Extent.z); - glVertex3f(obj.m_Extent.x, obj.m_Extent.y, obj.m_Extent.z); - glVertex3f(obj.m_Extent.x, obj.m_Extent.y, -obj.m_Extent.z); - glVertex3f(-obj.m_Extent.x, obj.m_Extent.y, -obj.m_Extent.z); - glVertex3f(-obj.m_Extent.x, obj.m_Extent.y, obj.m_Extent.z); - glEnd(); - } - if (getDrawTexBorder()) { - glDisable(GL_TEXTURE_2D); - glBegin(GL_LINE_STRIP); - glColor3f(float(202)/255.0f, float(31)/255.0f, float(123)/255.0f); - glVertex3f(-w/2, 0.0f, h/2); - glVertex3f(w/2, 0.0f, h/2); - glVertex3f(w/2, 0.0f, -h/2); - glVertex3f(-w/2, 0.0f, -h/2); - glVertex3f(-w/2, 0.0f, h/2); - glEnd(); - glColor3f(1.0f, 1.0f, 1.0f); - } - glEnable(GL_TEXTURE_2D); - - glPopMatrix(); - GL_CHECKERROR; - } - void SpriteManager::drawPed(Pedestrian & ped) { - GL_OBJ_COMMON(ped); - /* - GL_CHECKERROR; - glPushMatrix(); - glTranslatef(ped.pos.x, ped.pos.y, ped.pos.z); - glRotatef(ped.rot, 0, 1, 0); - glGetFloatv(GL_MODELVIEW_MATRIX, *ped.m_M.m); + DRAW_TEX_QUADS_OBJ(t, w, h); + + if (getDrawBBox() || getDrawTexBorder()) + glDisable(GL_TEXTURE_2D); + + if (getDrawBBox()) + drawBBoxOutline(obj); + if (getDrawTexBorder()) + drawTextureOutline(w, h); + + if (getDrawBBox() || getDrawTexBorder()) + glEnable(GL_TEXTURE_2D); + glPopMatrix(); + GL_CHECKERROR; - for (int i=0; i < 4; i++) { - for (int j=0; j <4 ;j++) { - std::cout << ped.m_M.m[i][j] << " "; - } - std::cout << std::endl; - } - std::cout << std::endl; - */ +} - GraphicsBase & style = StyleHolder::Instance().get(); - - - OpenGL::PagedTexture t; - PHYSFS_uint16 sprNum = style.spriteNumbers.reIndex(ped.sprNum + +void SpriteManager::draw(Pedestrian & ped) { + GL_OBJ_COMMON(ped); + + GraphicsBase & style = StyleHolder::Instance().get(); + OpenGL::PagedTexture t; + PHYSFS_uint16 sprNum = style.spriteNumbers.reIndex(ped.sprNum + ped.anim.firstFrameOffset + ped.anim.currentFrame, ped.sprType); - - GraphicsBase::SpriteInfo * info = style.getSprite(sprNum); - assert(info); - float w = float(info->w) / 64.0f; - float h = float(info->h) / 64.0f; + GraphicsBase::SpriteInfo * info = style.getSprite(sprNum); + assert(info); + float w = float(info->w) / 64.0f; + float h = float(info->h) / 64.0f; - if (OpenGL::SpriteCacheHolder::Instance().has(sprNum, ped.remap)) - t = OpenGL::SpriteCacheHolder::Instance().get(sprNum, ped.remap); - else { - t = OpenGL::SpriteCacheHolder::Instance().create(ped.sprNum + + if (OpenGL::SpriteCacheHolder::Instance().has(sprNum, ped.remap)) + t = OpenGL::SpriteCacheHolder::Instance().get(sprNum, ped.remap); + else { + t = OpenGL::SpriteCacheHolder::Instance().create(ped.sprNum + ped.anim.firstFrameOffset + ped.anim.currentFrame, ped.sprType, ped.remap); - } - glBindTexture(GL_TEXTURE_2D, t.inPage); - - glBegin(GL_QUADS); - glTexCoord2f(t.coords[0].u, t.coords[1].v); - glVertex3f(-w/2, 0.0f, h/2); - glTexCoord2f(t.coords[1].u, t.coords[1].v); - glVertex3f(w/2, 0.0f, h/2); - glTexCoord2f(t.coords[1].u, t.coords[0].v); - glVertex3f(w/2, 0.0f, -h/2); - glTexCoord2f(t.coords[0].u, t.coords[0].v); - glVertex3f(-w/2, 0.0f, -h/2); - - glEnd(); - glDisable(GL_TEXTURE_2D); - if (getDrawBBox()) { - glBegin(GL_LINE_STRIP); - glVertex3f(-ped.m_Extent.x, 0.0f, ped.m_Extent.z); - glVertex3f(ped.m_Extent.x, 0.0f, ped.m_Extent.z); - glVertex3f(ped.m_Extent.x, 0.0f, -ped.m_Extent.z); - glVertex3f(-ped.m_Extent.x, 0.0f, -ped.m_Extent.z); - glVertex3f(-ped.m_Extent.x, 0.0f, ped.m_Extent.z); - glEnd(); - } - if (getDrawTexBorder()) { - glDisable(GL_TEXTURE_2D); - glBegin(GL_LINE_STRIP); - glColor3f(float(202)/255.0f, float(31)/255.0f, float(123)/255.0f); - glVertex3f(-w/2, 0.0f, h/2); - glVertex3f(w/2, 0.0f, h/2); - glVertex3f(w/2, 0.0f, -h/2); - glVertex3f(-w/2, 0.0f, -h/2); - glVertex3f(-w/2, 0.0f, h/2); - glEnd(); - glColor3f(1.0f, 1.0f, 1.0f); - } - glEnable(GL_TEXTURE_2D); - - glPopMatrix(); - GL_CHECKERROR; - } - - void SpriteManager::addPed(Pedestrian & ped) { - activePeds.push_back(ped); - } - - Pedestrian & SpriteManager::getPedById(const Uint32 & id) { - PedListType::iterator i = activePeds.begin(); - while (i != activePeds.end()) { - if (i->pedId == id) - return *i; - ++i; - } - assert(0); - return *activePeds.begin(); - } - - void SpriteManager::removePedById(const Uint32 & id) { - PedListType::iterator i = activePeds.begin(); - while (i != activePeds.end()) { - if (i->pedId == id) { - activePeds.erase(i); - return; - } - ++i; - } - WARN << "didn't find ped id " << id << " -- cannot remove"<carId == id) { - return *i; - } - ++i; - } - assert(0); - return *activeCars.begin(); } - void SpriteManager::addObject(GameObject & go) { - activeObjects.push_back(go); - } + DRAW_TEX_QUADS_OBJ(t, w, h); - GameObject & SpriteManager::getObjectById(const Uint32 & id) { - ObjectListType::iterator i = activeObjects.begin(); - while (i != activeObjects.end()) { - if (i->objId == id) { - return *i; - } - ++i; - } - assert(0); - return *activeObjects.begin(); - } + if (getDrawBBox() || getDrawTexBorder()) + glDisable(GL_TEXTURE_2D); - SpriteObject::Animation & SpriteManager::getAnimationById(const Uint32 & id) { - AnimLookupType::iterator i = animations.find(id); - assert(i != animations.end()); - return i->second; - } + if (getDrawBBox()) + drawBBoxOutline(ped); + if (getDrawTexBorder()) + drawTextureOutline(w, h); - void SpriteManager::registerAnimation(const Uint32 & id, + if (getDrawBBox() || getDrawTexBorder()) + glEnable(GL_TEXTURE_2D); + + + glPopMatrix(); + GL_CHECKERROR; +} + +void SpriteManager::drawExplosion(SpriteObject & obj) { + + if (obj.anim.get() == Util::Animation::STOPPED) { + obj.isActive = false; + return; + } + glPushMatrix(); + glTranslatef(obj.pos.x, obj.pos.y, obj.pos.z); + //glRotatef(obj.rot, 0, 1, 0); + glGetFloatv(GL_MODELVIEW_MATRIX, *obj.m_M.m); + + GraphicsBase & style = StyleHolder::Instance().get(); + + PHYSFS_uint16 sprNum = style.spriteNumbers.reIndex(obj.sprNum + + obj.anim.firstFrameOffset + obj.anim.currentFrame, obj.sprType); + + GraphicsBase::SpriteInfo * info = style.getSprite(sprNum); + assert(info); + float w = float(info->w) / 64.0f; + float h = float(info->h) / 64.0f; + OpenGL::PagedTexture t; + if (OpenGL::SpriteCacheHolder::Instance().has(sprNum)) + t = OpenGL::SpriteCacheHolder::Instance().get(sprNum); + else + t = OpenGL::SpriteCacheHolder::Instance().create(obj.sprNum + + obj.anim.firstFrameOffset + obj.anim.currentFrame, obj.sprType, -1); + + glBindTexture(GL_TEXTURE_2D, t.inPage); + + glBegin(GL_QUADS); + glTexCoord2f(t.coords[0].u, t.coords[1].v); + glVertex3f(-w, 0.0f, 0.0f); + glTexCoord2f(t.coords[1].u, t.coords[1].v); + glVertex3f(0.0f, 0.0f, 0.0f); + glTexCoord2f(t.coords[1].u, t.coords[0].v); + glVertex3f(0.0f, 0.0f, -h); + glTexCoord2f(t.coords[0].u, t.coords[0].v); + glVertex3f(-w, 0.0f, -h); + + glEnd(); + + sprNum = style.spriteNumbers.reIndex(obj.sprNum + + obj.anim.firstFrameOffset + obj.anim.currentFrame + 12, obj.sprType); + info = style.getSprite(sprNum); + assert(info); + w = float(info->w) / 64.0f; + h = float(info->h) / 64.0f; + if (OpenGL::SpriteCacheHolder::Instance().has(sprNum)) + t = OpenGL::SpriteCacheHolder::Instance().get(sprNum); + else + t = OpenGL::SpriteCacheHolder::Instance().create(obj.sprNum + + obj.anim.firstFrameOffset + obj.anim.currentFrame+12, obj.sprType, -1); + + glBindTexture(GL_TEXTURE_2D, t.inPage); + + glBegin(GL_QUADS); + glTexCoord2f(t.coords[0].u, t.coords[1].v); + glVertex3f(0.0f, 0.0f, 0.0f); + glTexCoord2f(t.coords[1].u, t.coords[1].v); + glVertex3f(w, 0.0f, 0.0f); + glTexCoord2f(t.coords[1].u, t.coords[0].v); + glVertex3f(w, 0.0f, -h); + glTexCoord2f(t.coords[0].u, t.coords[0].v); + glVertex3f(0.0f, 0.0f, -h); + + glEnd(); + + sprNum = style.spriteNumbers.reIndex(obj.sprNum + + obj.anim.firstFrameOffset + obj.anim.currentFrame + 24, obj.sprType); + info = style.getSprite(sprNum); + assert(info); + w = float(info->w) / 64.0f; + h = float(info->h) / 64.0f; + if (OpenGL::SpriteCacheHolder::Instance().has(sprNum)) + t = OpenGL::SpriteCacheHolder::Instance().get(sprNum); + else + t = OpenGL::SpriteCacheHolder::Instance().create(obj.sprNum + + obj.anim.firstFrameOffset + obj.anim.currentFrame+24, obj.sprType, -1); + + glBindTexture(GL_TEXTURE_2D, t.inPage); + + glBegin(GL_QUADS); + glTexCoord2f(t.coords[0].u, t.coords[1].v); + glVertex3f(-w, 0.0f, 0.0f+h); + glTexCoord2f(t.coords[1].u, t.coords[1].v); + glVertex3f(0.0f, 0.0f, 0.0f+h); + glTexCoord2f(t.coords[1].u, t.coords[0].v); + glVertex3f(0.0f, 0.0f, -h+h); + glTexCoord2f(t.coords[0].u, t.coords[0].v); + glVertex3f(-w, 0.0f, -h+h); + + glEnd(); + + + sprNum = style.spriteNumbers.reIndex(obj.sprNum + + obj.anim.firstFrameOffset + obj.anim.currentFrame + 36, obj.sprType); + info = style.getSprite(sprNum); + assert(info); + w = float(info->w) / 64.0f; + h = float(info->h) / 64.0f; + if (OpenGL::SpriteCacheHolder::Instance().has(sprNum)) + t = OpenGL::SpriteCacheHolder::Instance().get(sprNum); + else + t = OpenGL::SpriteCacheHolder::Instance().create(obj.sprNum + + obj.anim.firstFrameOffset + obj.anim.currentFrame+36, obj.sprType, -1); + + glBindTexture(GL_TEXTURE_2D, t.inPage); + + glBegin(GL_QUADS); + glTexCoord2f(t.coords[0].u, t.coords[1].v); + glVertex3f(0.0f, 0.0f, 0.0f+h); + glTexCoord2f(t.coords[1].u, t.coords[1].v); + glVertex3f(w, 0.0f, 0.0f+h); + glTexCoord2f(t.coords[1].u, t.coords[0].v); + glVertex3f(w, 0.0f, -h+h); + glTexCoord2f(t.coords[0].u, t.coords[0].v); + glVertex3f(0.0f, 0.0f, -h+h); + + glEnd(); + + + glPopMatrix(); + GL_CHECKERROR; + +} + +/* +void SpriteManager::draw(TrainSegment & train) { + GL_OBJ_COMMON(train); + GraphicsBase & style = StyleHolder::Instance().get(); + + OpenGL::PagedTexture t; + PHYSFS_uint16 sprNum = style.spriteNumbers.reIndex(train.sprNum, train.sprType); + + GraphicsBase::SpriteInfo * info = style.getSprite(sprNum); + assert(info); + float w = float(info->w) / 64.0f; + float h = float(info->h) / 64.0f; + + + if (OpenGL::SpriteCacheHolder::Instance().has(sprNum, train.remap)) + t = OpenGL::SpriteCacheHolder::Instance().get(sprNum, train.remap); + else { + t = OpenGL::SpriteCacheHolder::Instance().create(train.sprNum, train.sprType, -1); + } + glBindTexture(GL_TEXTURE_2D, t.inPage); + + glBegin(GL_QUADS); + glTexCoord2f(t.coords[0].u, t.coords[1].v); + glVertex3f(-w/2, 0.0f, h/2); + glTexCoord2f(t.coords[1].u, t.coords[1].v); + glVertex3f(w/2, 0.0f, h/2); + glTexCoord2f(t.coords[1].u, t.coords[0].v); + glVertex3f(w/2, 0.0f, -h/2); + glTexCoord2f(t.coords[0].u, t.coords[0].v); + glVertex3f(-w/2, 0.0f, -h/2); + + glEnd(); + + + glPopMatrix(); + GL_CHECKERROR; +} +*/ + +void SpriteManager::draw(Projectile & proj) { + //GL_OBJ_COMMON(proj); // can't use; not derived from OBox + const float w = 0.05f; + const float h = 0.05f; + + glPushMatrix(); \ + glTranslatef(proj.pos.x, proj.pos.y, proj.pos.z); \ + glRotatef(proj.rot, 0, 1, 0); + + glDisable(GL_TEXTURE_2D); + glBegin(GL_QUADS); + + glVertex3f(-w/2, 0.0f, h/2); + glVertex3f(w/2, 0.0f, h/2); + glVertex3f(w/2, 0.0f, -h/2); + glVertex3f(-w/2, 0.0f, -h/2); + + glEnd(); + glEnable(GL_TEXTURE_2D); + + glPopMatrix(); + GL_CHECKERROR; +} + +/* + + void SpriteManager::addPed(Pedestrian & ped) { + activePeds.push_back(ped); + } + + Pedestrian & SpriteManager::getPedById(const Uint32 & id) { + PedListType::iterator i = activePeds.begin(); + while (i != activePeds.end()) { + if (i->pedId == id) + return *i; + ++i; + } + assert(0); + return *activePeds.begin(); + } + + TrainSegment & SpriteManager::getTrainById(const Uint32 & id) { + TrainListType::iterator i = activeTrains.begin(); + while (i != activeTrains.end()) { + if (i->trainId == id) + return *i; + ++i; + } + assert(0); + return *activeTrains.begin(); + } + + void SpriteManager::removePedById(const Uint32 & id) { + PedListType::iterator i = activePeds.begin(); + while (i != activePeds.end()) { + if (i->pedId == id) { + activePeds.erase(i); + return; + } + ++i; + } + WARN << "didn't find ped id " << id << " -- cannot remove"<carId == id) { + return *i; + } + ++i; + } + assert(0); + return *activeCars.begin(); + } + + void SpriteManager::addObject(GameObject & go) { + activeObjects.push_back(go); + } + + void SpriteManager::createExplosion(Vector3D center) { + GameObject exp(center, 0, GraphicsBase::SpriteNumbers::EX); + exp.anim = SpriteObject::Animation(getAnimationById(99)); + exp.anim.set(Util::Animation::PLAY_FORWARD, Util::Animation::LOOP); + INFO << exp.anim.currentFrame << " " << exp.anim.numFrames << " " << exp.anim.delay << std::endl; + activeObjects.push_back(exp); + } + + GameObject & SpriteManager::getObjectById(const Uint32 & id) { + ObjectListType::iterator i = activeObjects.begin(); +while (i != activeObjects.end()) { + if (i->objId == id) { + return *i; + } + ++i; +} +assert(0); +return *activeObjects.begin(); +} +*/ + +void SpriteManager::removeDeadStuff() { + AbstractContainer::doRealRemove(); + AbstractContainer::doRealRemove(); + AbstractContainer::doRealRemove(); +} + +SpriteObject::Animation & SpriteManager::getAnimationById(const Uint32 & id) { + AnimLookupType::iterator i = animations.find(id); + if (i == animations.end()) { + ERROR << "Failed to find anim id: " << id << std::endl; + return animations.begin()->second; + } + return i->second; +} + +void SpriteManager::registerAnimation(const Uint32 & id, const SpriteObject::Animation & anim) { - animations.insert(std::make_pair(id, anim)); - } + animations.insert(std::make_pair(id, anim)); +} void SpriteManager::setDrawBBox(bool v) { if (v) @@ -431,7 +690,7 @@ namespace OpenGTA { else drawMode = (drawMode & 4 ? drawMode - 4 : drawMode); } - + void SpriteManager::setDrawTexBorder(bool v) { if (v) drawMode = (drawMode | 2); @@ -439,10 +698,18 @@ namespace OpenGTA { drawMode = (drawMode & 2 ? drawMode - 2 : drawMode); } - void SpriteManager::setDrawTexture(bool v) { - } - - void SpriteManager::createProjectile(uint8_t typeId, float r, Vector3D p, Vector3D d, Uint32 & ticks) { - activeProjectiles.push_back(Projectile(typeId, r, p, d, ticks)); - } +void SpriteManager::setDrawTexture(bool v) { +} + +void SpriteManager::createProjectile(uint8_t typeId, float r, Vector3D p, Vector3D d, Uint32 & ticks, Uint32 & owner) { + activeProjectiles.push_back(Projectile(typeId, r, p, d, ticks, owner)); +} + +void SpriteManager::createExplosion(Vector3D center) { + SpriteObject expl(center, 0, GraphicsBase::SpriteNumbers::EX); + expl.anim = SpriteObject::Animation(getAnimationById(99)); + expl.anim.set(Util::Animation::PLAY_FORWARD, Util::Animation::STOP); + add(expl); +} + } diff --git a/spritemanager.h b/spritemanager.h index f5cdd79..d3270b9 100644 --- a/spritemanager.h +++ b/spritemanager.h @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * @@ -25,10 +25,16 @@ #include #include -#include "pedestrian.h" +#include "abstract_container.h" +//#include "pedestrian.h" +#include "game_objects.h" #include "Singleton.h" +#include "train_system.h" +#include "map_helper.h" namespace OpenGTA { + +#if 0 class SpriteManager { public: SpriteManager(); @@ -62,11 +68,17 @@ namespace OpenGTA { void drawPed(Pedestrian & ped); void drawCar(Car & car); void drawObject(GameObject & obj); + void drawExplosion(GameObject & obj); + + void drawTrain(TrainSegment & train); + TrainSegment & getTrainById(const Uint32 & id); void createProjectile(uint8_t typeId, float, Vector3D p, Vector3D d, Uint32 & ticks); + void createExplosion(Vector3D center); void drawProjectile(Projectile & p); void collideProjectile(Projectile & p); + typedef std::list TrainListType; protected: typedef std::list PedListType; PedListType activePeds; @@ -76,14 +88,105 @@ namespace OpenGTA { ObjectListType activeObjects; typedef std::list ProjectileListType; ProjectileListType activeProjectiles; + TrainListType activeTrains; + public: + TrainSystem trainSystem; + protected: typedef std::map AnimLookupType; AnimLookupType animations; private: Uint32 drawMode; }; +#endif + class SpriteManager : + public AbstractContainer, + public AbstractContainer, + public AbstractContainer { //, + //public AbstractContainer { + public: + + ~SpriteManager(); + void drawInRect(SDL_Rect & r); + void clear(); + void removeDeadStuff(); + + template T & add(const T & t) { + return AbstractContainer::doAdd(t); + } + template size_t getNum() { + return AbstractContainer::objs.size(); + } + inline Pedestrian & getPed(uint32_t id) { + return AbstractContainer::doGet(id); + } + inline Car & getCar(uint32_t id) { + return AbstractContainer::doGet(id); + } + inline SpriteObject & getObject(uint32_t id) { + return AbstractContainer::doGet(id); + } + /* + inline TrainSegment & getTrain(uint32_t id) { + return AbstractContainer::doGet(id); + }*/ + + template inline std::list & getList() { + return AbstractContainer::objs; + } + + inline void removePed(uint32_t id) { + AbstractContainer::doRemove(id); + } + inline void removeCar(uint32_t id) { + AbstractContainer::doRemove(id); + } + void realRemove(); + + inline bool getDrawTexture() { return (drawMode & 1); } + inline bool getDrawTexBorder() { return (drawMode & 2); } + inline bool getDrawBBox() { return (drawMode & 4); } + void setDrawTexture(bool v); + void setDrawTexBorder(bool v); + void setDrawBBox(bool v); + void drawBBoxOutline(const OBox &); + void drawTextureOutline(const float &, const float &); + + void draw(Car &); + void draw(Pedestrian &); + void draw(SpriteObject &); + void draw(Projectile &); + + void drawExplosion(SpriteObject &); + + void update(Uint32 ticks); + + SpriteObject::Animation & getAnimationById(const Uint32 & id); + void registerAnimation(const Uint32 & id, const SpriteObject::Animation & anim); + + void createExplosion(Vector3D center); + void createProjectile(uint8_t typeId, float, Vector3D p, Vector3D d, Uint32 & ticks, Uint32 & owner); + + + public: + //TrainSystem trainSystem; + SpriteManager(); + Util::SpriteCreationArea creationArea; + protected: + typedef std::map AnimLookupType; + AnimLookupType animations; + typedef std::list ProjectileListType; + ProjectileListType activeProjectiles; + + private: + Uint32 drawMode; + + //SpriteManager(const SpriteManager & o) : trainSystem(AbstractContainer::objs) {assert(0);} + SpriteManager(const SpriteManager & o) {assert(0);} + + }; typedef Loki::SingletonHolder SpriteManagerHolder; + Loki::DefaultLifetime, Loki::SingleThreaded> SpriteManagerHolder; } #endif diff --git a/tests/interpolate_test.cpp b/tests/interpolate_test.cpp new file mode 100644 index 0000000..cd4a951 --- /dev/null +++ b/tests/interpolate_test.cpp @@ -0,0 +1,160 @@ +#include +#include +#include "interpolate.hpp" + +using namespace std; + +void run_linear(int numSteps) { + float y1, y2; + cin >> y1; + cin >> y2; + Math::Interpolator::Linear li(y1, y2); + int counter = 0; + for (int i = 0; i < numSteps; ++i) { + cout << counter << " " << li.getAt(float(i) / numSteps) << endl; + ++counter; + } + while (cin >> y2) { + li.shiftAndFeed(y2); + for (int i = 0; i < numSteps; ++i) { + cout << counter << " " << li.getAt(float(i) / numSteps) << endl; + ++counter; + } + } +} + +void run_cubic(int numSteps) { + float y1, y2, y3; + + cin >> y1; + cin >> y2; + cin >> y3; + Math::Interpolator::Cubic ci(y1, y2, y3); + int counter = 0; + for (int i = 0; i < numSteps; ++i) { + cout << counter << " " << ci.getAt(float(i) / numSteps) << endl; + ++counter; + } + while (cin >> y3) { + ci.shiftAndFeed(y3); + for (int i = 0; i < numSteps; ++i) { + cout << counter << " " << ci.getAt(float(i) / numSteps) << endl; + ++counter; + } + } + ci.shift(); + for (int i = 0; i < numSteps; ++i) { + cout << counter << " " << ci.getAt(float(i) / numSteps) << endl; + ++counter; + } +} + +void run_cosine(int numSteps) { + float y1, y2; + + cin >> y1; + cin >> y2; + + Math::Interpolator::Cosine ci(y1, y2); + int counter = 0; + for (int i = 0; i < numSteps; ++i) { + cout << counter << " " << ci.getAt(float(i) / numSteps) << endl; + ++counter; + } + while (cin >> y2) { + ci.shiftAndFeed(y2); + for (int i = 0; i < numSteps; ++i) { + cout << counter << " " << ci.getAt(float(i) / numSteps) << endl; + ++counter; + } + } +} + +void run_hermite(int numSteps, float tension, float bias) { + float y1, y2, y3; + + cin >> y1; + cin >> y2; + cin >> y3; + Math::Interpolator::Hermite hi(y1, y2, y3, tension, bias); + int counter = 0; + for (int i = 0; i < numSteps; ++i) { + cout << counter << " " << hi.getAt(float(i) / numSteps) << endl; + ++counter; + } + while (cin >> y3) { + hi.shiftAndFeed(y3); + for (int i = 0; i < numSteps; ++i) { + cout << counter << " " << hi.getAt(float(i) / numSteps) << endl; + ++counter; + } + } + hi.shift(); + for (int i = 0; i < numSteps; ++i) { + cout << counter << " " << hi.getAt(float(i) / numSteps) << endl; + ++counter; + } +} + + +int main(int argc, char* argv[]) { + + int numSteps = 10; + int run = 2; + + float hermite_bias = 1.0f; + float hermite_tension = 1.0f; + + while (1) { + int option_index = 0; + static struct option long_options[] = { + {"linear", 0, 0, 'l'}, + {"cosine", 0, 0, 'o'}, + {"cubic", 0, 0, 'c'}, + {"hermite", 0, 0, 'h'}, + {"steps", 1, 0, 's'}, + {0, 0, 0, 0} + }; + + int c = getopt_long (argc, argv, "h", + long_options, &option_index); + if (c == -1) + break; + switch (c) { + case 's': + numSteps = atoi(optarg); + break; + case 'o': + run = 1; + break; + case 'c': + run = 2; + break; + case 'l': + run = 0; + break; + case 'h': + run = 3; + break; + default: + exit(1); + break; + } + } + + switch(run) { + case 2: + run_cubic(numSteps); + break; + case 1: + run_cosine(numSteps); + break; + case 0: + run_linear(numSteps); + break; + case 3: + run_hermite(numSteps, hermite_tension, hermite_bias); + break; + } + +} diff --git a/tests/menudemo.cpp b/tests/menudemo.cpp new file mode 100644 index 0000000..1953b7b --- /dev/null +++ b/tests/menudemo.cpp @@ -0,0 +1,542 @@ +#include +#include +#include +#include +#include +#include +#include "gl_screen.h" +#include "gl_pagedtexture.h" +#include "log.h" +#include "buffercache.h" +#include "physfsrwops.h" +#include "m_exceptions.h" +#include "gui.h" +#include "timer.h" +#include "dataholder.h" +#include "gl_spritecache.h" +#include "m_exceptions.h" + +extern int global_EC; +extern int global_Done; + +Uint32 arg_screen_w = 800; +Uint32 arg_screen_h = 600; + +namespace GUI { + Object::Object(const SDL_Rect & r) : + id(0), rect(), color(), + manager(ManagerHolder::Instance()) { + copyRect(r); + color.r = 255; color.g = 255; color.b = 255; color.unused = 255; + } + Object::Object(const size_t Id, const SDL_Rect & r) : + id(Id), rect(), color(), + manager(ManagerHolder::Instance()) { + copyRect(r); + color.r = 255; color.g = 255; color.b = 255; color.unused = 255; + } + Object::Object(const size_t Id, const SDL_Rect & r, const SDL_Color & c) : + id(Id), rect(), color(), + manager(ManagerHolder::Instance()) { + copyRect(r); + copyColor(c); + } + void Object::draw() { + glColor4ub(color.r, color.g, color.b, color.unused); + glDisable(GL_TEXTURE_2D); + glBegin(GL_QUADS); + glVertex2i(rect.x, rect.y); + glVertex2i(rect.x + rect.w, rect.y); + glVertex2i(rect.x + rect.w, rect.y + rect.h); + glVertex2i(rect.x, rect.y + rect.h); + glEnd(); + } + void Object::copyRect(const SDL_Rect & src) { + rect.x = src.x; + rect.y = src.y; + rect.w = src.w; + rect.h = src.h; + } + void Object::copyColor(const SDL_Color & src) { + color.r = src.r; + color.g = src.g; + color.b = src.b; + color.unused = src.unused; + } + + void TexturedObject::draw() { + + const OpenGL::PagedTexture & tex = manager.getCachedImage(texId); + glColor4ub(color.r, color.g, color.b, color.unused); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tex.inPage); + glBegin(GL_QUADS); + glTexCoord2f(tex.coords[0].u, tex.coords[1].v); + glVertex2i(rect.x, rect.y); + glTexCoord2f(tex.coords[1].u, tex.coords[1].v); + glVertex2i(rect.x + rect.w, rect.y); + glTexCoord2f(tex.coords[1].u, tex.coords[0].v); + glVertex2i(rect.x + rect.w, rect.y + rect.h); + glTexCoord2f(tex.coords[0].u, tex.coords[0].v); + glVertex2i(rect.x, rect.y + rect.h); + glEnd(); + glDisable(GL_TEXTURE_2D); + } + + void AnimatedTextureObject::draw() { + if (!animation) + animation = manager.findAnimation(animId); + + assert(animation); + size_t texId = animation->getCurrentFrame(); + const OpenGL::PagedTexture & tex = manager.getCachedImage(texId); + glColor4ub(color.r, color.g, color.b, color.unused); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tex.inPage); + glBegin(GL_QUADS); + glTexCoord2f(tex.coords[0].u, tex.coords[1].v); + glVertex2i(rect.x, rect.y); + glTexCoord2f(tex.coords[1].u, tex.coords[1].v); + glVertex2i(rect.x + rect.w, rect.y); + glTexCoord2f(tex.coords[1].u, tex.coords[0].v); + glVertex2i(rect.x + rect.w, rect.y + rect.h); + glTexCoord2f(tex.coords[0].u, tex.coords[0].v); + glVertex2i(rect.x, rect.y + rect.h); + glEnd(); + glDisable(GL_TEXTURE_2D); + } + + void Label::draw() { + glPushMatrix(); + glColor4ub(color.r, color.g, color.b, color.unused); + glEnable(GL_TEXTURE_2D); + glTranslatef(rect.x, rect.y, 0); + rect.w = uint16_t(font->drawString(text)); + rect.h = font->getHeight(); + glPopMatrix(); + /* + glDisable(GL_TEXTURE_2D); + glBegin(GL_LINE_STRIP); + glVertex2i(rect.x, rect.y); + glVertex2i(rect.x + rect.w, rect.y); + glVertex2i(rect.x + rect.w, rect.y + rect.h); + glVertex2i(rect.x, rect.y + rect.h); + glVertex2i(rect.x, rect.y); + glEnd(); + */ + } + + void Pager::draw() { + + const OpenGL::PagedTexture & tex = manager.getCachedImage(texId); + glColor4ub(color.r, color.g, color.b, color.unused); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tex.inPage); + glBegin(GL_QUADS); + glTexCoord2f(tex.coords[0].u, tex.coords[1].v); + glVertex2i(rect.x, rect.y); + glTexCoord2f(tex.coords[1].u, tex.coords[1].v); + glVertex2i(rect.x + rect.w, rect.y); + glTexCoord2f(tex.coords[1].u, tex.coords[0].v); + glVertex2i(rect.x + rect.w, rect.y + rect.h); + glTexCoord2f(tex.coords[0].u, tex.coords[0].v); + glVertex2i(rect.x, rect.y + rect.h); + glEnd(); + glScissor(rect.x, rect.y, rect.w, rect.h); + glEnable(GL_SCISSOR_TEST); + + glPushMatrix(); + glColor4ub(color.r, color.g, color.b, color.unused); + glTranslatef(rect.x+offset, rect.y+4, 0); + int slen = (int)font->drawString("test - hello world, this is a really long message. it will not end. never... or maybe sometime, but not yet. The end."); + if (slen + offset < -10) { + color.unused = 0; + manager.remove(this); + } + INFO << slen <<" " << offset << std::endl; + glPopMatrix(); + + glDisable(GL_SCISSOR_TEST); + glDisable(GL_TEXTURE_2D); + + } + + void Pager::update(Uint32 ticks) { + offset -= 1; + + //if (offset < -50) + // color.unused = 0; + } + + void Manager::draw() { + GuiObjectListMap::iterator layer_it = guiLayers.begin(); + + while (layer_it != guiLayers.end()) { + GuiObjectList & inThisLayer = layer_it->second; + for (GuiObjectList::iterator obj_it = inThisLayer.begin(); + obj_it != inThisLayer.end(); ++obj_it) { + Object * obj = *obj_it; + obj->draw(); + } + ++layer_it; + } + } + + Manager::~Manager() { + clearObjects(); + clearCache(); + } + + void Manager::clearObjects() { + INFO << "clearing gui objects" << std::endl; + GuiObjectListMap::iterator layer_it = guiLayers.begin(); + while (layer_it != guiLayers.end()) { + GuiObjectList & list = layer_it->second; + for (GuiObjectList::iterator i = list.begin(); i != list.end(); ++i) { + delete *i; + } + list.clear(); + ++layer_it; + } + guiLayers.clear(); + } + + void Manager::clearCache() { + INFO << "clearing gui texture cache" << std::endl; + for (GuiTextureCache::iterator i = texCache.begin(); i != texCache.end(); ++i) { + OpenGL::PagedTexture & p = i->second; + glDeleteTextures(1, &p.inPage); + } + texCache.clear(); + for (AnimationMap::iterator i = guiAnimations.begin(); i != guiAnimations.end(); ++i) { + delete i->second; + } + guiAnimations.clear(); + } + + const OpenGL::PagedTexture & Manager::getCachedImage(size_t Id) { + GuiTextureCache::iterator i = findByCacheId(Id); + if (i == texCache.end()) { + std::ostringstream o; + o << "cached texture id " << int(Id); + throw E_UNKNOWNKEY(o.str()); + } + return i->second; + } + + Manager::GuiTextureCache::iterator Manager::findByCacheId(const size_t & Id) { + return texCache.find(Id); + } + + Manager::GuiObjectListMap::iterator Manager::findLayer(uint8_t l) { + return guiLayers.find(l); + } + + void Manager::cacheImageRAW(const std::string & file, size_t k) { + texCache.insert(std::make_pair(k, ImageUtil::loadImageRAW(file))); + } + + void Manager::cacheImageRAT(const std::string & file, const std::string & palette, size_t k) { + texCache.insert(std::make_pair(k, + ImageUtil::loadImageRATWithPalette(file, palette))); + } + + // FIXME: move stuff to ImageUtil + void Manager::cacheImageSDL(const std::string & file, size_t k) { + SDL_RWops * rwops = PHYSFSRWOPS_openRead(file.c_str()); + //SDL_Surface *surface = IMG_Load(file.c_str()); + SDL_Surface *surface = IMG_Load_RW(rwops, 1); + assert(surface); + + ImageUtil::NextPowerOfTwo npot(surface->w, surface->h); + uint16_t bpp = surface->format->BytesPerPixel; + + uint8_t * buffer = Util::BufferCacheHolder::Instance().requestBuffer(npot.w * npot.h * bpp); + SDL_LockSurface(surface); + ImageUtil::copyImage2Image(buffer, (uint8_t*)surface->pixels, surface->pitch, surface->h, + npot.w * bpp); + SDL_UnlockSurface(surface); + + GLuint texture = ImageUtil::createGLTexture(npot.w, npot.h, (bpp == 4) ? true : false, buffer); + texCache.insert(std::make_pair(k, + OpenGL::PagedTexture(texture, 0, 0, GLfloat(surface->w)/npot.w, GLfloat(surface->h)/npot.h))); + SDL_FreeSurface(surface); + } + + ImageUtil::WidthHeightPair Manager::cacheStyleArrowSprite(const size_t id, int remap) { + OpenGTA::GraphicsBase & graphics = OpenGTA::StyleHolder::Instance().get(); + PHYSFS_uint16 t = graphics.spriteNumbers.reIndex(id, OpenGTA::GraphicsBase::SpriteNumbers::ARROW); + OpenGTA::GraphicsBase::SpriteInfo * info = graphics.getSprite(t); + texCache.insert(std::make_pair( + id, OpenGL::SpriteCacheHolder::Instance().createSprite(size_t(t), remap, 0, info) + )); + return ImageUtil::WidthHeightPair(info->w, info->h); + } + + void Manager::add(Object * obj, uint8_t onLevel) { + GuiObjectListMap::iterator l = findLayer(onLevel); + if (l == guiLayers.end()) { + GuiObjectList list; + list.push_back(obj); + guiLayers.insert(std::make_pair(onLevel, list)); + return; + } + GuiObjectList & list = l->second; + list.push_back(obj); + } + + void Manager::remove(Object * obj) { + for (GuiObjectListMap::iterator l = guiLayers.begin(); l != guiLayers.end(); ++l) { + GuiObjectList & list = l->second; + for (GuiObjectList::iterator m = list.begin(); m != list.end(); ++m) { + Object * o = *m; + if (o == obj) { + delete o; + list.erase(m); + return; + } + } + } + throw E_UNKNOWNKEY("not a managed object-ptr"); + } + + Object* Manager::findObject(const size_t id) { + for (GuiObjectListMap::iterator l = guiLayers.begin(); l != guiLayers.end(); ++l) { + GuiObjectList & list = l->second; + for (GuiObjectList::iterator m = list.begin(); m != list.end(); ++m) { + Object * o = *m; + if (o->id == id) + return o; + } + } + std::ostringstream o; + o << "object by id " << int(id); + throw E_UNKNOWNKEY(o.str()); + + return 0; + } + + void Manager::removeById(const size_t id) { + Object * o = findObject(id); + if (o) + remove(o); + //else + // ERROR << "failed to find object " << id << " - cannot remove it" << std::endl; + } + + bool Manager::isInside(Object & obj, Uint16 x, Uint16 y) const { + if ((obj.rect.x <= x) && (x <= obj.rect.x + obj.rect.w) && + (obj.rect.y <= y) && (y <= obj.rect.y + obj.rect.h)) + return true; + return false; + } + + void Manager::receive(SDL_MouseButtonEvent & mb_event) { + Uint32 sh = OpenGL::ScreenHolder::Instance().getHeight(); + GuiObjectListMap::reverse_iterator l = guiLayers.rbegin(); + while (l != guiLayers.rend()) { + std::cout << int(l->first) << std::endl; + GuiObjectList & list = l->second; + for (GuiObjectList::iterator i = list.begin(); i != list.end(); ++i) { + Object * obj = *i; + if (isInside(*obj, mb_event.x, sh - mb_event.y)) { + std::cout << "mouse inside obj id: " << obj->id << " at " << mb_event.x << "," << mb_event.y << std::endl; + return; + } + } + ++l; + } + } + + void Manager::update(uint32_t nowticks) { + for (AnimationMap::iterator i = guiAnimations.begin(); i != guiAnimations.end(); ++i) { + i->second->update(nowticks); + } + GuiObjectListMap::iterator layer_it = guiLayers.begin(); + while (layer_it != guiLayers.end()) { + GuiObjectList & inThisLayer = layer_it->second; + for (GuiObjectList::iterator obj_it = inThisLayer.begin(); + obj_it != inThisLayer.end(); ++obj_it) { + Object * obj = *obj_it; + obj->update(nowticks); + } + ++layer_it; + } + } + + Animation* Manager::findAnimation(uint16_t id) { + AnimationMap::iterator i = guiAnimations.find(id); + return i->second; + } + + void Manager::createAnimation(const std::vector & indices, uint16_t fps, size_t k) { + Animation * anim = new Animation(indices, fps); + guiAnimations.insert(std::make_pair(k, anim)); + anim->set(Util::Animation::PLAY_FORWARD, Util::Animation::LOOP); + } + + uint16_t Animation::getCurrentFrame() { + return indices[getCurrentFrameNumber()]; + } + +} + + +#ifdef GUI_MENU_DEMO +GUI::Manager guiManager; + +void on_exit() { + SDL_Quit(); + PHYSFS_deinit(); + if (global_EC) + std::cerr << "Exiting after fatal problem - please see output above" << std::endl; + else + std::cout << "Goodbye" << std::endl; +} + +void parse_args(int argc, char* argv[]) { +} + +void turn_anim_off(float) { + GUI::AnimatedTextureObject * obj= (GUI::AnimatedTextureObject *)guiManager.findObject(2); + obj->animation->set(obj->animation->get(), Util::Animation::STOP); + INFO << "stopped animation" << std::endl; +} + +void font_play(float b) { + //INFO << b << std::endl; + GUI::Object * obj = guiManager.findObject(5); + obj->color.r = obj->color.g = obj->color.b = obj->color.unused = Uint8((1.0f - b) * 255); +} + +void run_init() { + PHYSFS_init("ogta"); + PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1); + PHYSFS_addToSearchPath("gtadata.zip", 1); + if (getenv("OGTA_MOD")) + PHYSFS_addToSearchPath(getenv("OGTA_MOD"), 0); + OpenGL::Screen & screen = OpenGL::ScreenHolder::Instance(); + screen.activate(arg_screen_w, arg_screen_h); + screen.setSystemMouseCursor(true); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0); + + OpenGTA::StyleHolder::Instance().load("STYLE001.G24"); + + SDL_EnableKeyRepeat( 100, SDL_DEFAULT_REPEAT_INTERVAL ); + + std::vector frame_nums(8); + for (int i = 0; i < 8; ++i) { + std::stringstream o; + o << "F_LOGO" << i << ".RAW"; + guiManager.cacheImageRAW(o.str(), 100+i); + frame_nums[i] = 100+i; + } + guiManager.createAnimation(frame_nums, 5, 1); + + SDL_Rect r; + r.x = 0; r.y = 0; r.h = 312 * screen.getHeight() / 480; r.w = screen.getWidth(); + std::string rawfile("F_LOWER1.RAW"); + guiManager.cacheImageRAW(rawfile, 99); + GUI::TexturedObject * b2 = new GUI::TexturedObject(1, r, 99); + guiManager.add(b2, 2); + r.y = 312 * screen.getHeight() / 480; + r.h = 168 * screen.getHeight() / 480; + GUI::AnimatedTextureObject * b3 = new GUI::AnimatedTextureObject(2, r, 1); + guiManager.add(b3, 2); + + Timer & t = TimerHolder::Instance(); + + + ImageUtil::WidthHeightPair whp = guiManager.cacheStyleArrowSprite(16, -1); + guiManager.cacheStyleArrowSprite(17, -1); + std::vector anim2frames(2); + anim2frames[0] = 16; + anim2frames[1] = 17; + guiManager.createAnimation(anim2frames, 10, 2); + r.x = 200; + r.y = 200; + r.w = whp.first * 2; r.h = whp.second * 2; + GUI::AnimatedTextureObject * b5 = new GUI::AnimatedTextureObject(1, r, 2); + guiManager.add(b5, 3); + + whp = guiManager.cacheStyleArrowSprite(2, -1); + r.w = whp.first; + r.h = whp.second; + GUI::Pager * pager = new GUI::Pager(3, r, 2, "STREET1.FON", 1); + + guiManager.add(pager, 5); + + /*Timer::CallbackType cmd(turn_anim_off); + t.registerCallback(false, cmd, t.getRealTime() + 2000); + + Timer::CallbackType cmd2(font_play); + t.registerCallback(false, cmd2, t.getRealTime() + 100, t.getRealTime() + 3000); + */ +} + +void handleKeyPress( SDL_keysym *keysym ) { + switch ( keysym->sym ) { + case SDLK_ESCAPE: + global_Done = 1; + break; + default: + break; + } +} + +void draw_menu() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + OpenGL::Screen & screen = OpenGL::ScreenHolder::Instance(); + screen.setFlatProjection(); + glDisable(GL_DEPTH_TEST); + + guiManager.draw(); + + + glEnable(GL_DEPTH_TEST); + + SDL_GL_SwapBuffers(); +} + +void run_main() { + SDL_Event event; + Timer & t = TimerHolder::Instance(); + t.update(); + //Uint32 now_ticks = SDL_GetTicks(); + Uint32 now_ticks = t.getRealTime(); + while(!global_Done && !global_EC) { + while (SDL_PollEvent(&event)) { + switch(event.type) { + case SDL_KEYDOWN: + handleKeyPress(&event.key.keysym); + break; + case SDL_MOUSEBUTTONDOWN: + guiManager.receive(event.button); + break; + /*case SDL_KEYUP: + handleKeyUp(&event.key.keysym); + break;*/ + case SDL_VIDEORESIZE: + OpenGL::ScreenHolder::Instance().resize(event.resize.w, event.resize.h); + break; + case SDL_QUIT: + global_Done = 1; + break; + default: + break; + } + } + draw_menu(); + //now_ticks = SDL_GetTicks(); + t.update(); + now_ticks = t.getRealTime(); + guiManager.update(now_ticks); + SDL_Delay(20); + } + // otherwise only at exit, which... troubles loki::smallobject + guiManager.clearCache(); + TimerHolder::Instance().clearAllEvents(); +} + +#endif diff --git a/tests/new_obj_test.cpp b/tests/new_obj_test.cpp new file mode 100644 index 0000000..4940445 --- /dev/null +++ b/tests/new_obj_test.cpp @@ -0,0 +1,51 @@ +#include "log.h" +#include "game_objects.h" +#include "abstract_container.h" + +using namespace OpenGTA; + +class ConcreteContainer : + public AbstractContainer, + public AbstractContainer { + public: + template void add(const T & t) { + AbstractContainer::doAdd(t); + } + Car & getCar(uint32_t id) { + return AbstractContainer::doGet(id); + } + Pedestrian & getPed(uint32_t id) { + return AbstractContainer::doGet(id); + } + void removeCar(uint32_t id) { + AbstractContainer::doRemove(id); + } + void removePed(uint32_t id) { + AbstractContainer::doRemove(id); + } + void realRemove() { + AbstractContainer::doRealRemove(); + AbstractContainer::doRealRemove(); + } +}; + +int main(int argc, char* argv[]) { + + Car c1(1); + + Pedestrian p1(20); + Car c2(20); + + ConcreteContainer cc; + cc.add(p1); + cc.add(c1); + cc.add(c2); + + Car & c = cc.getCar(1); + INFO << c.carId << std::endl; + + Pedestrian & p = cc.getPed(20); + cc.removeCar(20); + cc.realRemove(); + c = cc.getCar(20); +} diff --git a/tests/sound_test1.cpp b/tests/sound_test1.cpp index c6ff49b..2d546f8 100644 --- a/tests/sound_test1.cpp +++ b/tests/sound_test1.cpp @@ -1,4 +1,5 @@ #include +#define USE_RWOPS #include #include #include @@ -69,7 +70,15 @@ void SoundDevice::open(int r, Uint16 f, int c, int bs) { open(); } -#if 0 +int music_volume=127; + +bool sound_enabled=false; + +bool playing_music=false; +Sound_Sample *music_sound=0; +int music_loops=1; +int current_music_loop=0; + void myMusicPlayer(void *udata, Uint8 *stream, int len) { int i,act=0; Sint16 *ptr2; @@ -123,15 +132,84 @@ void myMusicPlayer(void *udata, Uint8 *stream, int len) { for(i=0;i o.idx_in_file) + return false; + return src_file < o.src_file; + } + }; + struct ChunkData { + Uint8 * mem_buf; + Mix_Chunk * chunk; + size_t ref; + ChunkData(Uint8 * m, Mix_Chunk * c, size_t r = 1) : + mem_buf(m), chunk(c), ref(r) {} + ChunkData(const ChunkData & o) : + mem_buf(o.mem_buf), chunk(o.chunk), ref(o.ref) {} + }; + typedef std::map< ChunkId, ChunkData > CacheType; + CacheType cached; + ChunkData & getChunk(std::string & file, size_t idx); + void prepareDB(std::string db_file); + OpenGTA::SoundsDB * getDB(std::string db_file); + private: + ChunkData loadChunk(std::string & file, size_t idx); + typedef std::map< std::string, OpenGTA::SoundsDB* > LookupCache; + LookupCache lookup; + +}; + +AudioChunkCache::ChunkData & AudioChunkCache::getChunk(std::string & file, size_t idx) { + ChunkId id(file, idx); + CacheType::iterator i = cached.find(id); + if (i == cached.end()) { + ChunkData c = loadChunk(file, idx); + cached.insert(std::make_pair(id, c)); + i = cached.find(id); + } + return i->second; +} + +AudioChunkCache::ChunkData AudioChunkCache::loadChunk(std::string & file, size_t idx) { + LookupCache::iterator j = lookup.find(file); + if (j == lookup.end()) { + prepareDB(file); + j = lookup.find(file); + } + OpenGTA::SoundsDB & db = *j->second; + OpenGTA::SoundsDB::Entry & e = db.getEntry(idx); + size_t si; + unsigned char* mem = db.getBuffered(idx); + Uint8 *mem2 = (Uint8*)Audio::resample_new(mem, e.rawSize, si, e.sampleRate, 44100); + Mix_Chunk * music = Mix_QuickLoad_RAW(mem2, si); + return ChunkData(mem2, music, 1); +} + +void AudioChunkCache::prepareDB(std::string db) { + lookup[db] = new OpenGTA::SoundsDB(db); +} int main(int argc, char *argv[]) { PHYSFS_init(argv[0]); PHYSFS_addToSearchPath("gtadata.zip", 1); + PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1); Uint32 sdl_init_flags = SDL_INIT_AUDIO | SDL_INIT_VIDEO; if (SDL_Init(sdl_init_flags) == -1) @@ -143,11 +221,16 @@ int main(int argc, char *argv[]) SoundDevice dev; dev.open(); + if (argc == 3) { + AudioChunkCache acc; + std::string foo(argv[1]); + AudioChunkCache::ChunkData & cd = acc.getChunk(foo, atoi(argv[2])); + /* OpenGTA::SoundsDB db(argv[1]); OpenGTA::SoundsDB::Entry & e = db.getEntry(atoi(argv[2])); unsigned char* mem = db.getBuffered(atoi(argv[2])); size_t si; - Uint8 *mem2 = (Uint8*)resample_new(mem, e.rawSize, si, e.sampleRate, 44100); + Uint8 *mem2 = (Uint8*)Audio::resample_new(mem, e.rawSize, si, e.sampleRate, 44100); //write(1, mem, e.rawSize+ 36 + 8); @@ -161,13 +244,40 @@ int main(int argc, char *argv[]) } delete [] mem; Mix_PlayChannel(0,music,0); + */ - while (Mix_Playing(0)) { + Mix_PlayChannel(0, cd.chunk, 0); + } + else { + /* + SDL_RWops * rw = PHYSFSRWOPS_openRead(argv[1]); + assert(rw); + Mix_Music * music = Mix_LoadMUS_RW(rw); + assert(music); + Mix_PlayMusic(music, 0); + */ + Sound_Init(); + Sound_AudioInfo inf; +#define AUDIO_BUFFER 4096 + inf.format=AUDIO_S16; + inf.channels=2; + inf.rate=44100; + + SDL_RWops * rw = PHYSFSRWOPS_openRead(argv[1]); + + assert(rw); + music_sound = Sound_NewSample(rw, "mp3" ,&inf,AUDIO_BUFFER); + assert(music_sound); + Mix_HookMusic(myMusicPlayer, 0); + playing_music = true; + } + //while (Mix_Playing(0)) { + while (playing_music) { SDL_Delay(1000); } - delete [] mem2; + //delete [] mem2; Mix_HaltMusic(); - Mix_FreeChunk(music); + //Mix_FreeChunk(music); //music = NULL; SDL_Quit(); return(0); diff --git a/tools/insert_copyright.sh b/tools/insert_copyright.sh index 5721a4d..70b0c05 100755 --- a/tools/insert_copyright.sh +++ b/tools/insert_copyright.sh @@ -8,4 +8,5 @@ if [ $# -gt 0 ]; then fi sed '1{h; r $1 D; } -2{x; G; }' $copyright_file $input +2{x; G; }' $copyright_file $input >${input}.copy +mv ${input}.copy $input diff --git a/tools/minimap.cpp b/tools/minimap.cpp index 9e0abeb..307b80d 100644 --- a/tools/minimap.cpp +++ b/tools/minimap.cpp @@ -62,10 +62,11 @@ int main(int argc, char* argv[]) { for (int i = 0; i < 256; i++) { for (int j = 0; j < 256; j++) { - PHYSFS_uint16 emptycount = map.getNumBlocksAt(j,i); + PHYSFS_uint16 emptycount = map.getNumBlocksAtNew(j,i); int found_type = 0; - for (int c=6-emptycount; c > 0; c--) { - OpenGTA::Map::BlockInfo* bi = map.getBlockAt(j, i, c); + //for (int c=6-emptycount; c > 0; c--) { + for (int c = 0; c < emptycount ; ++c) { + OpenGTA::Map::BlockInfo* bi = map.getBlockAtNew(j, i, c); /* if (bi->blockType() > 0) found_type = bi->blockType(); @@ -83,10 +84,12 @@ int main(int argc, char* argv[]) { if (bi->railEndTurn()) std::cout << " end: " << i << ", " << j << std::endl; */ + /* if (bi->blockType() > 0) found_type = bi->blockType(); if (bi->trafficLights()) found_type = 0; + */ if (bi->railway()) found_type = 7; } diff --git a/train_system.cpp b/train_system.cpp new file mode 100644 index 0000000..fe1a6d3 --- /dev/null +++ b/train_system.cpp @@ -0,0 +1,70 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#include "train_system.h" +#include "log.h" + +namespace OpenGTA { +/* +using Util::CellIterator; + TrainSystem::TrainSystem(std::list & list) : + stations(), + segments(list) { + numTrains = 0; + } + + TrainSystem::~TrainSystem() { + stations.clear(); + } + + void TrainSystem::update(Uint32 now_ticks) { + } + + void TrainSystem::loadStations(Map & map) { + std::list stationsWithTrain; + for (int y = 0; y < 256; ++y) { + for (int x = 0; x < 256; ++x) { + PHYSFS_uint16 num_blocks = map.getNumBlocksAtNew(x, y); + for (int c=0; c < num_blocks; ++c) { + OpenGTA::Map::BlockInfo* bi = map.getBlockAtNew(x, y, c); + assert(bi); + if (bi->railway() && bi->railStation()) { + stations.push_back(Util::CellIterator(map, x, y, c)); + if (bi->railStationTrain()) + stationsWithTrain.push_back(CellIterator(map, x, y, c)); + } + } + } + } + INFO << "should create " << stationsWithTrain.size() << " / " << stations.size() + << " trains" << std::endl; + while (stationsWithTrain.size() > 0) { + CellIterator & i = stationsWithTrain.front(); + stationsWithTrain.pop_front(); + INFO << "at " << i.x << " " << i.y << " " << i.z << std::endl; + TrainSegment ts(i); + ts.trainId = numTrains++; + segments.push_back(ts); + } + } + */ +} diff --git a/train_system.h b/train_system.h new file mode 100644 index 0000000..f41abee --- /dev/null +++ b/train_system.h @@ -0,0 +1,50 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#ifndef OGTA_TRAINSYSTEM_H +#define OGTA_TRAINSYSTEM_H + +#include "opengta.h" +//#include "pedestrian.h" +#include "game_objects.h" +#include "cell_iterator.h" + +namespace OpenGTA { +/* + class TrainSystem { + public: + TrainSystem(std::list & list); + ~TrainSystem(); + void update(Uint32 now_ticks); + void loadStations(Map & map); + const size_t getNumStations() const { return stations.size(); } + const int getNumTrains() const { return numTrains; } + private: + int numTrains; + std::list stations; + std::list & segments; + + }; +*/ +} + +#endif diff --git a/util/abstract_container.h b/util/abstract_container.h new file mode 100644 index 0000000..49b3ecf --- /dev/null +++ b/util/abstract_container.h @@ -0,0 +1,88 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#ifndef ABSTRACT_CONTAINER_H +#define ABSTRACT_CONTAINER_H + +#include +#include +#include +#include "m_exceptions.h" + +template +class AbstractContainer { + public: + T & doGet(uint32_t); + void doRemove(uint32_t); + inline T & doAdd(const T & t) { + objs.push_back(t); + return *objs.rbegin(); + } + void doRealRemove(); + protected: + typedef typename std::list Storage_T; + Storage_T objs; + typedef typename std::list::iterator Storage_T_Iterator; + typedef typename std::list< Storage_T_Iterator > Iterator_Storage; + Iterator_Storage toBeRemoved; + private: + Storage_T_Iterator findById(uint32_t & id); +}; + +template +void AbstractContainer::doRealRemove() { + typename Iterator_Storage::iterator i = toBeRemoved.begin(); + while (i != toBeRemoved.end()) { + typename Iterator_Storage::iterator j = i++; + typename Storage_T::iterator ii = *j; + // remove the pointed-to object + objs.erase(ii); + // remove from list of lists + toBeRemoved.erase(j); + } +} + +template +void AbstractContainer::doRemove(uint32_t id) { + typename Storage_T::iterator i = findById(id); + toBeRemoved.push_back(i); +} + +template +T & AbstractContainer::doGet(uint32_t id) { + typename Storage_T::iterator i = findById(id); + return *i; +} + +template +typename std::list::iterator AbstractContainer::findById(uint32_t & id) { + typename Storage_T::iterator i; + for (i = objs.begin(); i != objs.end(); ++i) { + if (i->id() == id) + return i; + } + std::ostringstream ostr; + ostr << id; + throw E_UNKNOWNKEY(ostr.str()); +} + +#endif diff --git a/util/animation.cpp b/util/animation.cpp index fa96970..82c6f3d 100644 --- a/util/animation.cpp +++ b/util/animation.cpp @@ -1,3 +1,25 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ #include #include "animation.h" #include "m_exceptions.h" diff --git a/util/animation.h b/util/animation.h index 089bf48..1fc3675 100644 --- a/util/animation.h +++ b/util/animation.h @@ -1,3 +1,25 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ #ifndef UTIL_ANIMATION_H #define UTIL_ANIMATION_H #include @@ -5,8 +27,15 @@ #include "log.h" namespace Util { - - class Animation { + + /** Capsules play-frames-in-sequence logic. + * + * This class only knows about the number of frames + * and the fps; it does have multiple flags that + * switch the behaviour whenever the 'last' frame is + * finished. + */ + class Animation { public: typedef enum { STOPPED = 0, @@ -23,7 +52,8 @@ namespace Util { Animation(const Animation & o); inline const uint16_t & getCurrentFrameNumber() { return currentFrame; } inline void set(const Status doThis, const OnDone done = STOP) { status = doThis; onDone = done; } - inline const Status & get() { return status; } + inline const Status & get() const { return status; } + inline const OnDone & getDone() const { return onDone; } void jumpToFrame(const uint16_t num, const Status andDo); void update(const uint32_t & nowTicks); typedef Loki::Functor CallbackType; @@ -33,7 +63,7 @@ namespace Util { uint16_t numFrames; uint32_t delay; protected: - + void flipFrame(bool forward); void isDone(); Status status; diff --git a/util/cell_iterator.cpp b/util/cell_iterator.cpp new file mode 100644 index 0000000..a5081c1 --- /dev/null +++ b/util/cell_iterator.cpp @@ -0,0 +1,64 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#include "cell_iterator.h" +#include "log.h" + +namespace Util { + float distance(const Vector3D & p1, const Vector3D & p2) { + float dx = p1.x - p2.x; + float dy = p1.y - p2.y; + float dz = p1.z - p2.z; + return sqrt(dx * dx + dy * dy + dz * dz); + } + float xz_angle(const Vector3D & from, const Vector3D & to) { + Vector3D rel_to(to); + rel_to = rel_to - from; + double res = atan(rel_to.x / rel_to.z) * 180.0f / M_PI; + if (rel_to.z < 0) + return 180.0f + res; + if (rel_to.z >= 0 && rel_to.x < 0) + return 360.0f + res; + return res; + } + + bool CellIterator::isValid() const { + if (x < 0 || x > 255) + return false; + if (y < 0 || y > 255) + return false; + if (z < 0) + return false; + return (z < mapRef.getNumBlocksAtNew(x, y)); + } + + OpenGTA::Map::BlockInfo & CellIterator::getBlock() { + assert(isValid()); + return *mapRef.getBlockAtNew(x, y, z); + } + +#define IABS(v) ((v > 0) ? v : -v) + int CellIterator::distance(const CellIterator & o) const { + return (IABS(x - o.x) + IABS(y - o.y) + IABS(z - o.z)); + } + +} diff --git a/util/cell_iterator.h b/util/cell_iterator.h new file mode 100644 index 0000000..38ca56d --- /dev/null +++ b/util/cell_iterator.h @@ -0,0 +1,100 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#ifndef UTIL_CELLITERATOR_H +#define UTIL_CELLITERATOR_H +#include +#include "opengta.h" +#include "dataholder.h" +#include "math3d.h" +#include "SDL_video.h" + +namespace Util { + float distance(const Vector3D & p1, const Vector3D & p2); + float xz_angle(const Vector3D & from, const Vector3D & to); + + class CellIterator { + public: + CellIterator(const Vector3D & p) : + x(int(floor(p.x))), y(int(floor(p.z))), z(int(floor(p.y))), + mapRef(OpenGTA::MapHolder::Instance().get()) {} + + CellIterator(OpenGTA::Map & map, int _x, int _y, int _z) : + x(_x), y(_y), z(_z), mapRef(map) {} + + CellIterator(const CellIterator & o) : + x(o.x), y(o.y), z(o.z), mapRef(o.mapRef) {} + + bool isValid() const; + int distance(const CellIterator & o) const; + + bool operator == (const CellIterator & o) const { + return (x == o.x && y == o.y && z == o.z); + } + + CellIterator operator = (const CellIterator & o) { + mapRef = o.mapRef; + x = o.x; + y = o.y; + z = o.z; + return *this; + } + + CellIterator left() const { + CellIterator p(*this); + p.x -= 1; + return p; + } + CellIterator right() const { + CellIterator p(*this); + p.x += 1; + return p; + } + CellIterator top() const { + CellIterator p(*this); + p.y += 1; + return p; + } + CellIterator bottom() const { + CellIterator p(*this); + p.y -= 1; + return p; + } + CellIterator up() const { + CellIterator p(*this); + p.z += 1; + return p; + } + CellIterator down() const { + CellIterator p(*this); + p.z -= 1; + return p; + } + int x, y, z; + OpenGTA::Map::BlockInfo & getBlock(); + private: + OpenGTA::Map & mapRef; + }; + +} + +#endif diff --git a/util/file_helper.cpp b/util/file_helper.cpp index f2aed71..fce88ba 100644 --- a/util/file_helper.cpp +++ b/util/file_helper.cpp @@ -1,8 +1,31 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ #include #include #include #include "m_exceptions.h" #include "file_helper.h" +#include "buffercache.h" #ifndef OGTA_DEFAULT_DATA_PATH #define OGTA_DEFAULT_DATA_PATH "gtadata.zip" @@ -10,12 +33,14 @@ #ifndef OGTA_DEFAULT_MOD_PATH #define OGTA_DEFAULT_MOD_PATH "" #endif + #ifndef OGTA_DEFAULT_HOME_PATH -#ifdef LINUX -#define OGTA_DEFAULT_HOME_PATH PHYSFS_getUserDir() -#elif WIN32 -#define OGTA_DEFAULT_HOME_PATH "config" -#endif +//#ifdef LINUX +//#define OGTA_DEFAULT_HOME_PATH PHYSFS_getUserDir() +//#elif WIN32 +//#define OGTA_DEFAULT_HOME_PATH "config" +//#endif +#define OGTA_DEFAULT_HOME_PATH PHYSFS_getBaseDir() #endif namespace Util { @@ -83,4 +108,13 @@ namespace Util { // take this one instead return fd; } + + unsigned char* FileHelper::bufferFromVFS(PHYSFS_file *fd) const { + assert(fd); + unsigned int size = PHYSFS_fileLength(fd); + unsigned char* buffer = BufferCacheHolder::Instance().requestBuffer(size+1); + size = PHYSFS_read(fd, buffer, 1, size); + PHYSFS_close(fd); + return buffer; + } } diff --git a/util/file_helper.h b/util/file_helper.h index f5f0866..f12f16a 100644 --- a/util/file_helper.h +++ b/util/file_helper.h @@ -1,3 +1,25 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ #ifndef UTIL_FILEHELPER_H #define UTIL_FILEHELPER_H @@ -17,6 +39,7 @@ namespace Util { bool existsInSystemFS(const std::string & file) const; bool existsInVFS(const std::string & file) const; PHYSFS_file* openReadVFS(const std::string & file) const; + unsigned char* bufferFromVFS(PHYSFS_file*) const; private: std::string baseDataPath; std::string modDataPath; diff --git a/util/gui.h b/util/gui.h index c5cebc0..9ef142a 100644 --- a/util/gui.h +++ b/util/gui.h @@ -1,9 +1,32 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ #ifndef UTIL_GUI_H #define UTIL_GUI_H #include #include #include #include +#include "Singleton.h" #include "animation.h" #include "gl_pagedtexture.h" #include "image_loader.h" @@ -48,6 +71,9 @@ namespace GUI { }; + typedef Loki::SingletonHolder ManagerHolder; + class Animation : public Util::Animation { public: Animation(const std::vector & _indices, const uint16_t fps) : @@ -65,20 +91,11 @@ namespace GUI { size_t id; SDL_Rect rect; SDL_Color color; - inline void copyRect(const SDL_Rect & src) { - rect.x = src.x; - rect.y = src.y; - rect.w = src.w; - rect.h = src.h; - } - inline void copyColor(const SDL_Color & src) { - color.r = src.r; - color.g = src.g; - color.b = src.b; - color.unused = src.unused; - } + void copyRect(const SDL_Rect & src); + void copyColor(const SDL_Color & src); virtual void draw(); - Manager * manager; + virtual void update(Uint32 ticks) {} + Manager & manager; }; struct TexturedObject : public Object { @@ -121,5 +138,21 @@ namespace GUI { std::string text; void draw(); }; + + struct Pager : public Object { + Pager(const size_t Id, const SDL_Rect & r, const size_t texid, + const std::string & fontFile, const size_t fontScale) : Object(Id, r) { + OpenGL::DrawableFont & fnt = OpenGTA::FontCacheHolder::Instance().getFont(fontFile, fontScale); + font = &fnt; + texId = texid; + offset = r.w-5; + } + OpenGL::DrawableFont * font; + size_t texId; + void update(Uint32 ticks); + void draw(); + std::string lastMsg; + int offset; + }; } #endif diff --git a/util/image_loader.cpp b/util/image_loader.cpp index d86f831..5ff0b66 100644 --- a/util/image_loader.cpp +++ b/util/image_loader.cpp @@ -1,3 +1,25 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ #include #include #include "image_loader.h" diff --git a/util/image_loader.h b/util/image_loader.h index dfa3331..e77d9eb 100644 --- a/util/image_loader.h +++ b/util/image_loader.h @@ -1,3 +1,25 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ #ifndef UTIL_IMAGE_LOADER_H #define UTIL_IMAGE_LOADER_H diff --git a/util/map_helper.cpp b/util/map_helper.cpp new file mode 100644 index 0000000..fc68ce2 --- /dev/null +++ b/util/map_helper.cpp @@ -0,0 +1,14 @@ +#include "map_helper.h" +#include "log.h" + +namespace Util { + void SpriteCreationArea::setRects(const SDL_Rect & allowed, const SDL_Rect & denied) { + validRects = std::make_pair(allowed, denied); + } + + TupleOfUint8 SpriteCreationArea::getValidCoord() { + uint32_t x = rnd.nextUint(validRects.first.w) + validRects.first.x; + uint32_t y = rnd.nextUint(validRects.first.h) + validRects.first.y; + return std::make_pair(x, y); + } +} diff --git a/util/map_helper.h b/util/map_helper.h new file mode 100644 index 0000000..879cc0e --- /dev/null +++ b/util/map_helper.h @@ -0,0 +1,22 @@ +#ifndef MAP_HELPER_H +#define MAP_HELPER_H + +#include +#include +#include "yasli/random.h" + +namespace Util { + typedef std::pair TupleOfRects; + typedef std::pair TupleOfUint8; + typedef std::list< TupleOfRects > ListOfTupleOfRects; + + class SpriteCreationArea { + public: + //ListOfTupleOfRects validTuple; + TupleOfRects validRects; + void setRects(const SDL_Rect & allowed, const SDL_Rect & denied); + TupleOfUint8 getValidCoord(); + Random rnd; + }; +} +#endif diff --git a/util/physfsrwops.c b/util/physfsrwops.c new file mode 100644 index 0000000..c899da1 --- /dev/null +++ b/util/physfsrwops.c @@ -0,0 +1,191 @@ +/* + * This code provides a glue layer between PhysicsFS and Simple Directmedia + * Layer's (SDL) RWops i/o abstraction. + * + * License: this code is public domain. I make no warranty that it is useful, + * correct, harmless, or environmentally safe. + * + * This particular file may be used however you like, including copying it + * verbatim into a closed-source project, exploiting it commercially, and + * removing any trace of my name from the source (although I hope you won't + * do that). I welcome enhancements and corrections to this file, but I do + * not require you to send me patches if you make changes. + * + * Unless otherwise stated, the rest of PhysicsFS falls under the GNU Lesser + * General Public License: http://www.gnu.org/licenses/lgpl.txt + * + * SDL falls under the LGPL, too. You can get SDL at http://www.libsdl.org/ + * + * This file was written by Ryan C. Gordon. (icculus@clutteredmind.org). + */ + +#include /* used for SEEK_SET, SEEK_CUR, SEEK_END ... */ +#include "physfsrwops.h" + +static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence) +{ + PHYSFS_file *handle = (PHYSFS_file *) rw->hidden.unknown.data1; + int pos = 0; + + if (whence == SEEK_SET) + { + pos = offset; + } /* if */ + + else if (whence == SEEK_CUR) + { + PHYSFS_sint64 current = PHYSFS_tell(handle); + if (current == -1) + { + SDL_SetError("Can't find position in file: %s", + PHYSFS_getLastError()); + return(-1); + } /* if */ + + pos = (int) current; + if ( ((PHYSFS_sint64) pos) != current ) + { + SDL_SetError("Can't fit current file position in an int!"); + return(-1); + } /* if */ + + if (offset == 0) /* this is a "tell" call. We're done. */ + return(pos); + + pos += offset; + } /* else if */ + + else if (whence == SEEK_END) + { + PHYSFS_sint64 len = PHYSFS_fileLength(handle); + if (len == -1) + { + SDL_SetError("Can't find end of file: %s", PHYSFS_getLastError()); + return(-1); + } /* if */ + + pos = (int) len; + if ( ((PHYSFS_sint64) pos) != len ) + { + SDL_SetError("Can't fit end-of-file position in an int!"); + return(-1); + } /* if */ + + pos += offset; + } /* else if */ + + else + { + SDL_SetError("Invalid 'whence' parameter."); + return(-1); + } /* else */ + + if ( pos < 0 ) + { + SDL_SetError("Attempt to seek past start of file."); + return(-1); + } /* if */ + + if (!PHYSFS_seek(handle, (PHYSFS_uint64) pos)) + { + SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); + return(-1); + } /* if */ + + return(pos); +} /* physfsrwops_seek */ + + +static int physfsrwops_read(SDL_RWops *rw, void *ptr, int size, int maxnum) +{ + PHYSFS_file *handle = (PHYSFS_file *) rw->hidden.unknown.data1; + PHYSFS_sint64 rc = PHYSFS_read(handle, ptr, size, maxnum); + if (rc != maxnum) + { + if (!PHYSFS_eof(handle)) /* not EOF? Must be an error. */ + SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); + } /* if */ + + return((int) rc); +} /* physfsrwops_read */ + + +static int physfsrwops_write(SDL_RWops *rw, const void *ptr, int size, int num) +{ + PHYSFS_file *handle = (PHYSFS_file *) rw->hidden.unknown.data1; + PHYSFS_sint64 rc = PHYSFS_write(handle, ptr, size, num); + if (rc != num) + SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); + + return((int) rc); +} /* physfsrwops_write */ + + +static int physfsrwops_close(SDL_RWops *rw) +{ + PHYSFS_file *handle = (PHYSFS_file *) rw->hidden.unknown.data1; + if (!PHYSFS_close(handle)) + { + SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); + return(-1); + } /* if */ + + SDL_FreeRW(rw); + return(0); +} /* physfsrwops_close */ + + +static SDL_RWops *create_rwops(PHYSFS_file *handle) +{ + SDL_RWops *retval = NULL; + + if (handle == NULL) + SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); + else + { + retval = SDL_AllocRW(); + if (retval != NULL) + { + retval->seek = physfsrwops_seek; + retval->read = physfsrwops_read; + retval->write = physfsrwops_write; + retval->close = physfsrwops_close; + retval->hidden.unknown.data1 = handle; + } /* if */ + } /* else */ + + return(retval); +} /* create_rwops */ + + +SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_file *handle) +{ + SDL_RWops *retval = NULL; + if (handle == NULL) + SDL_SetError("NULL pointer passed to PHYSFSRWOPS_makeRWops()."); + else + retval = create_rwops(handle); + + return(retval); +} /* PHYSFSRWOPS_makeRWops */ + + +SDL_RWops *PHYSFSRWOPS_openRead(const char *fname) +{ + return(create_rwops(PHYSFS_openRead(fname))); +} /* PHYSFSRWOPS_openRead */ + + +SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname) +{ + return(create_rwops(PHYSFS_openWrite(fname))); +} /* PHYSFSRWOPS_openWrite */ + + +SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname) +{ + return(create_rwops(PHYSFS_openAppend(fname))); +} /* PHYSFSRWOPS_openAppend */ + +/* end of physfsrwops.c ... */ + diff --git a/util/physfsrwops.h b/util/physfsrwops.h new file mode 100644 index 0000000..91ff2eb --- /dev/null +++ b/util/physfsrwops.h @@ -0,0 +1,87 @@ +/* + * This code provides a glue layer between PhysicsFS and Simple Directmedia + * Layer's (SDL) RWops i/o abstraction. + * + * License: this code is public domain. I make no warranty that it is useful, + * correct, harmless, or environmentally safe. + * + * This particular file may be used however you like, including copying it + * verbatim into a closed-source project, exploiting it commercially, and + * removing any trace of my name from the source (although I hope you won't + * do that). I welcome enhancements and corrections to this file, but I do + * not require you to send me patches if you make changes. + * + * Unless otherwise stated, the rest of PhysicsFS falls under the GNU Lesser + * General Public License: http://www.gnu.org/licenses/lgpl.txt + * + * SDL falls under the LGPL, too. You can get SDL at http://www.libsdl.org/ + * + * This file was written by Ryan C. Gordon. (icculus@clutteredmind.org). + */ + +#ifndef _INCLUDE_PHYSFSRWOPS_H_ +#define _INCLUDE_PHYSFSRWOPS_H_ + +#include "physfs.h" +#include "SDL.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Open a platform-independent filename for reading, and make it accessible + * via an SDL_RWops structure. The file will be closed in PhysicsFS when the + * RWops is closed. PhysicsFS should be configured to your liking before + * opening files through this method. + * + * @param filename File to open in platform-independent notation. + * @return A valid SDL_RWops structure on success, NULL on error. Specifics + * of the error can be gleaned from PHYSFS_getLastError(). + */ +__EXPORT__ SDL_RWops *PHYSFSRWOPS_openRead(const char *fname); + +/** + * Open a platform-independent filename for writing, and make it accessible + * via an SDL_RWops structure. The file will be closed in PhysicsFS when the + * RWops is closed. PhysicsFS should be configured to your liking before + * opening files through this method. + * + * @param filename File to open in platform-independent notation. + * @return A valid SDL_RWops structure on success, NULL on error. Specifics + * of the error can be gleaned from PHYSFS_getLastError(). + */ +__EXPORT__ SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname); + +/** + * Open a platform-independent filename for appending, and make it accessible + * via an SDL_RWops structure. The file will be closed in PhysicsFS when the + * RWops is closed. PhysicsFS should be configured to your liking before + * opening files through this method. + * + * @param filename File to open in platform-independent notation. + * @return A valid SDL_RWops structure on success, NULL on error. Specifics + * of the error can be gleaned from PHYSFS_getLastError(). + */ +__EXPORT__ SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname); + +/** + * Make a SDL_RWops from an existing PhysicsFS file handle. You should + * dispose of any references to the handle after successful creation of + * the RWops. The actual PhysicsFS handle will be destroyed when the + * RWops is closed. + * + * @param handle a valid PhysicsFS file handle. + * @return A valid SDL_RWops structure on success, NULL on error. Specifics + * of the error can be gleaned from PHYSFS_getLastError(). + */ +__EXPORT__ SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_file *handle); + +#ifdef __cplusplus +} +#endif + +#endif /* include-once blocker */ + +/* end of physfsrwops.h ... */ + diff --git a/util/sound_device.cpp b/util/sound_device.cpp index a6d48ad..8e06246 100644 --- a/util/sound_device.cpp +++ b/util/sound_device.cpp @@ -1,3 +1,26 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#ifdef WITH_SOUND #include #include #include "sound_device.h" @@ -15,14 +38,13 @@ namespace Audio { } SoundDevice::~SoundDevice() { - Mix_HaltGroup(-1); - Mix_HaltMusic(); close(); } void SoundDevice::close() { if (!status) return; + Mix_HaltMusic(); Mix_CloseAudio(); status = CLOSED; } @@ -35,9 +57,10 @@ namespace Audio { SDL_AudioDriverName (cardName, sizeof (cardName)); if (!Mix_QuerySpec(&rate, &format, &channels)) throw E_NOTSUPPORTED(SDL_GetError()); - INFO << "Sound-device [" << cardName << "] opened at " << rate << " Hz " << - (format & 0xff) << " bit " << channels << " channels " << bufSize << - " buffer size" << std::endl; + INFO << + "Sound-device [" << cardName << "], rate " << rate << " Hz, " << + (format & 0xff) << " bit, " << std::endl << " " << + channels << " channels, " << bufSize << " buffer size" << std::endl; status = OPEN; } @@ -50,3 +73,4 @@ namespace Audio { open(); } } +#endif diff --git a/util/sound_device.h b/util/sound_device.h index b38f4e4..2a90631 100644 --- a/util/sound_device.h +++ b/util/sound_device.h @@ -1,6 +1,30 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ #ifndef UTIL_SOUND_DEVICE_H #define UTIL_SOUND_DEVICE_H +#ifdef WITH_SOUND + #include namespace Audio { @@ -15,6 +39,7 @@ namespace Audio { inline const int getRate() { return rate; } inline const int getNumChannels() { return channels; } inline const int getBufferSize() { return bufSize; } + inline const Uint16 getFormat() { return format; } enum Status { CLOSED = 0, OPEN, @@ -30,5 +55,6 @@ namespace Audio { Status status; }; } +#endif #endif diff --git a/util/sound_fx_cache.cpp b/util/sound_fx_cache.cpp new file mode 100644 index 0000000..3e68067 --- /dev/null +++ b/util/sound_fx_cache.cpp @@ -0,0 +1,59 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#ifdef WITH_SOUND +#include "sound_fx_cache.h" +#include "sound_resample2.h" + +namespace Audio { + ChunkData & AudioChunkCache::getChunk(std::string & file, size_t idx) { + ChunkId id(file, idx); + CacheType::iterator i = cached.find(id); + if (i == cached.end()) { + ChunkData c = loadChunk(file, idx); + cached.insert(std::make_pair(id, c)); + i = cached.find(id); + } + return i->second; + } + + ChunkData AudioChunkCache::loadChunk(std::string & file, size_t idx) { + LookupCache::iterator j = lookup.find(file); + if (j == lookup.end()) { + prepareDB(file); + j = lookup.find(file); + } + OpenGTA::SoundsDB & db = *j->second; + OpenGTA::SoundsDB::Entry & e = db.getEntry(idx); + size_t si; + unsigned char* mem = db.getBuffered(idx); + Uint8 *mem2 = (Uint8*)Audio::resample_new(mem, e.rawSize, si, e.sampleRate, 44100); + Mix_Chunk * music = Mix_QuickLoad_RAW(mem2, si); + return ChunkData(mem2, music, 1); + } + + void AudioChunkCache::prepareDB(std::string db) { + lookup[db] = new OpenGTA::SoundsDB(db); + } + +} +#endif diff --git a/util/sound_fx_cache.h b/util/sound_fx_cache.h new file mode 100644 index 0000000..93f8298 --- /dev/null +++ b/util/sound_fx_cache.h @@ -0,0 +1,76 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#ifndef SOUND_FX_CACHE_H +#define SOUND_FX_CACHE_H +#ifdef WITH_SOUND + +#include +#include +#include +#include "fx_sdt.h" + +namespace Audio { + + struct ChunkId { + std::string src_file; + size_t idx_in_file; + ChunkId(const std::string & file, const size_t idx) : + src_file(file), idx_in_file(idx) {} + bool operator == (const ChunkId & o) const { + return (idx_in_file == o.idx_in_file && src_file == o.src_file); + } + bool operator < (const ChunkId & o) const { + if (idx_in_file < o.idx_in_file) + return true; + if (idx_in_file > o.idx_in_file) + return false; + return src_file < o.src_file; + } + }; + + struct ChunkData { + Uint8 * mem_buf; + Mix_Chunk * chunk; + size_t ref; + ChunkData(Uint8 * m, Mix_Chunk * c, size_t r = 1) : + mem_buf(m), chunk(c), ref(r) {} + ChunkData(const ChunkData & o) : + mem_buf(o.mem_buf), chunk(o.chunk), ref(o.ref) {} + }; + + class AudioChunkCache { + public: + typedef std::map< ChunkId, ChunkData > CacheType; + CacheType cached; + ChunkData & getChunk(std::string & file, size_t idx); + OpenGTA::SoundsDB * getDB(std::string db_file); + private: + void prepareDB(std::string db_file); + ChunkData loadChunk(std::string & file, size_t idx); + typedef std::map< std::string, OpenGTA::SoundsDB* > LookupCache; + LookupCache lookup; + }; +} +#endif + +#endif diff --git a/util/sound_music_player.cpp b/util/sound_music_player.cpp new file mode 100644 index 0000000..a397a51 --- /dev/null +++ b/util/sound_music_player.cpp @@ -0,0 +1,88 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#ifdef WITH_SOUND +#include +#include "m_exceptions.h" +#include "sound_music_player.h" + +namespace Audio { + bool MusicPlayerCtrl::isPlaying = false; + Sound_Sample * MusicPlayerCtrl::music = 0; + MusicFinishedCallbackType MusicPlayerCtrl::musicFinishedCB; + + void MusicPlayerCtrl::clear() { + if (MusicPlayerCtrl::isPlaying) + MusicPlayerCtrl::isPlaying = false; + if (MusicPlayerCtrl::music) { + Sound_FreeSample(MusicPlayerCtrl::music); + MusicPlayerCtrl::music = 0; + } + if (MusicPlayerCtrl::musicFinishedCB) + MusicPlayerCtrl::musicFinishedCB(); + } + + // taken from an example on the web, can't remember where... + // slightly simplified: removed looping + void musicPlayerFunc(void *udata, Uint8 *stream, int len) { + int i,act=0; + Sint16 *ptr2; + + if (stream == 0) + throw E_INVALIDFORMAT("Encountered a zero music stream while playing :-("); + + ptr2=(Sint16 *)stream; + if (MusicPlayerCtrl::isPlaying) { + while (act < len) { + if (MusicPlayerCtrl::music != 0) { + if ((MusicPlayerCtrl::music->flags&SOUND_SAMPLEFLAG_EOF)) { + MusicPlayerCtrl::clear(); + } + else { + /* In the middle of the file: */ + int decoded=0; + Sint16 *ptr; + + Sound_SetBufferSize(MusicPlayerCtrl::music, len-act); + + decoded=Sound_Decode(MusicPlayerCtrl::music); + ptr=(Sint16 *)MusicPlayerCtrl::music->buffer; + for(i=0;i +#include "Functor.h" + +namespace Audio { + static int music_volume = 127; + typedef Loki::Functor MusicFinishedCallbackType; + + struct MusicPlayerCtrl { + static bool isPlaying; + static Sound_Sample *music; + static void clear(); + static MusicFinishedCallbackType musicFinishedCB; + }; + void musicPlayerFunc(void *udata, Uint8 *stream, int len); +} +#endif + +#endif diff --git a/util/sound_resample2.cpp b/util/sound_resample2.cpp new file mode 100644 index 0000000..38192bd --- /dev/null +++ b/util/sound_resample2.cpp @@ -0,0 +1,92 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#include "sound_resample2.h" +#include "interpolate.hpp" + +namespace Audio { + // resample uint8 mono to Sint16 stereo + // assumption: src_rate < wanted_rate + + // derived from some sweet code found in the exult repository, + // now rewritten to avoid license trouble... + // yes, it is (still) similiar - who would have guessed? + Sint16 *resample_new (Uint8 * src, size_t sourcelen, size_t & size, + int rate, int wanted_rate) { + int fp_pos = 0; + int fp_speed = (1 << 16) * rate / wanted_rate; + size = sourcelen; + // adjust the magnitudes of size and rate to prevent division error + while (size & 0xFFFF0000) + size >>= 1, rate = (rate >> 1) + 1; + // Compute the output size (times 4 since it is 16 stereo) + size = (size * wanted_rate / rate) << 2; + + Sint16 *stereo_data = new Sint16[size]; + Sint16 *data = stereo_data; + Uint8 *src_end = src + sourcelen; + + int result; + + // Compute the initial data feed for the interpolator. We don't simply + // shift by 8, but rather duplicate the byte, this way we cover the full + // range. Probably doesn't make a big difference, listening wise :-) + int a = *(src + 0); + a = (a | (a << 8)) - 32768; + int b = *(src + 1); + b = (a | (b << 8)) - 32768; + int c = *(src + 2); + c = (a | (c << 8)) - 32768; + + // scale down by 0.8333 to avoid oversampling + Math::Interpolator::Cubic inter(a * 0.8333f, b * 0.8333f, c * 0.8333f); + do + { + do + { + result = int(inter.getAt(fp_pos / float(0x0000FFFF))); + // limit the range + if (result < -32768) + result = -32768; + else if (result > 32767) + result = 32767; + *data++ = result; + *data++ = result; + + fp_pos += fp_speed; + } + while (!(fp_pos & 0xFFFF0000)); // need more input data + src++; + fp_pos &= 0x0000FFFF; + if (src + 2 < src_end) // still data to fetch + { + c = *(src + 2); + c = (c | (c << 8)) - 32768; + inter.shiftAndFeed (c * 0.8333f); + } + else // guess & interpolate... this the end, my only friend the end + inter.shift (); + } + while (src < src_end); + return stereo_data; + } +} diff --git a/util/sound_resample2.h b/util/sound_resample2.h new file mode 100644 index 0000000..f4c9c66 --- /dev/null +++ b/util/sound_resample2.h @@ -0,0 +1,35 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#ifndef SOUND_RESAMPLE_H2 +#define SOUND_RESAMPLE_H2 + +#include +namespace Audio +{ + Sint16 *resample_new (Uint8 * sourcedata, size_t sourcelen, + size_t & destlen, int current_rate, int wanted_rate); + Sint16 *resample_new_mono (Uint8 * sourcedata, size_t sourcelen, + size_t & destlen, int current_rate, + int wanted_rate); +} +#endif diff --git a/util/sound_system.cpp b/util/sound_system.cpp new file mode 100644 index 0000000..436e944 --- /dev/null +++ b/util/sound_system.cpp @@ -0,0 +1,100 @@ +#include +#include +#include "sound_system.h" +#include "physfsrwops.h" +#include "m_exceptions.h" +#include "log.h" + +namespace Audio { + +#ifdef WITH_SOUND + SoundSystem::SoundSystem() : device(), chunkCache() { + SDL_InitSubSystem(SDL_INIT_AUDIO); + device.open(); + enabled = true; + if (device.getStatus() == SoundDevice::OPEN) + Sound_Init(); + else { + WARN << "Could not open audio-device - disabling sound!" << std::endl; + enabled = false; + } + } + + SoundSystem::~SoundSystem() { + device.close(); + Sound_Quit(); + } + + void SoundSystem::playFx(std::string file, size_t idx) { + if (!enabled) + return; + ChunkData & cd = chunkCache.getChunk(file, idx); + Mix_PlayChannel(0, cd.chunk, 0); + } + + void SoundSystem::playMusic(std::string file) { + if (!enabled) + return; + Sound_AudioInfo inf; + inf.format = device.getFormat(); + inf.channels = device.getNumChannels(); + inf.rate = device.getRate(); + + MusicPlayerCtrl::clear(); + + SDL_RWops * rw = PHYSFSRWOPS_openRead(file.c_str()); + if (!rw) + throw E_FILENOTFOUND(file); + + size_t pos = file.rfind('.'); + std::string ext(file.substr(pos + 1, pos - 1)); + + MusicPlayerCtrl::music = Sound_NewSample(rw, ext.c_str(), &inf, device.getBufferSize()); + + if (!MusicPlayerCtrl::music) + throw E_NOTSUPPORTED("file: " + file + " - " + Sound_GetError()); + + Mix_HookMusic(musicPlayerFunc, 0); + MusicPlayerCtrl::isPlaying = true; + } + + void SoundSystem::listMusicDecoders() { + std::cout << "* Supported music decoders *" << std::endl; + const Sound_DecoderInfo **i; + for (i = Sound_AvailableDecoders(); *i != NULL; i++) { + std::cout << std::setfill(' ') << std::setw(5) << + (*i)->extensions[0] << " : " << (*i)->description << std::endl; + } + } +#else + SoundSystem::SoundSystem() : enabled(false) { + } + + SoundSystem::~SoundSystem() {} + + void SoundSystem::playFx(std::string file, size_t idx) {} + void SoundSystem::playMusic(std::string file) {} + void SoundSystem::listMusicDecoders() {} +#endif + + void CB_MusicDone() { + std::cout << "music finished" << std::endl; + } +} + +#ifdef SOUND_TEST +using namespace Audio; +int main(int argc, char* argv[]) { + PHYSFS_init(argv[0]); + PHYSFS_addToSearchPath("gtadata.zip", 1); + PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1); + + SoundSystem noisemaker; + noisemaker.listMusicDecoders(); + noisemaker.playMusic(argv[1]); + MusicPlayerCtrl::musicFinishedCB = CB_MusicDone; + while (MusicPlayerCtrl::isPlaying) { + SDL_Delay(1000); + } +} +#endif diff --git a/util/sound_system.h b/util/sound_system.h new file mode 100644 index 0000000..b3dc8cc --- /dev/null +++ b/util/sound_system.h @@ -0,0 +1,27 @@ +#ifndef SOUND_SYSTEM_H +#define SOUND_SYSTEM_H + +#ifdef WITH_SOUND +#include "sound_device.h" +#include "sound_music_player.h" +#include "sound_fx_cache.h" +#endif + +namespace Audio { + class SoundSystem { +#ifdef WITH_SOUND + private: + SoundDevice device; + AudioChunkCache chunkCache; +#endif + public: + SoundSystem(); + ~SoundSystem(); + void playFx(std::string file, size_t idx); + void SoundSystem::playMusic(std::string file); + void SoundSystem::listMusicDecoders(); + bool enabled; + }; +} + +#endif diff --git a/util/timer.cpp b/util/timer.cpp index 335ee1d..1f81c2e 100644 --- a/util/timer.cpp +++ b/util/timer.cpp @@ -1,6 +1,28 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ #include -#include "timer.h" #include +#include "timer.h" Timer::TimeEvent::TimeEvent(const uint32_t & b, const uint32_t e, CallbackType & c) : begin(b), end(e), callback(c) {} @@ -12,18 +34,30 @@ Timer::TimeEvent::TimeEvent(const TimeEvent & o) : begin(o.begin), end(o.end), callback(o.callback) {} Timer::Timer() { + simIsRunning = false; +#ifdef TIMER_OPENSTEER_CLOCK + sdlTicks = uint32_t(floor(clock.realTimeSinceFirstClockUpdate()*1000)); + clock.setPausedState(simIsRunning); +#else sdlTicks = SDL_GetTicks(); +#endif simTicks = 0; delta = 0; - simIsRunning = false; } Timer::~Timer() { clearAllEvents(); } + void Timer::update() { +#ifdef TIMER_OPENSTEER_CLOCK + if (simIsRunning) + clock.update(); + uint32_t nowTicks = uint32_t(floor(clock.realTimeSinceFirstClockUpdate()*1000)); +#else uint32_t nowTicks = SDL_GetTicks(); +#endif delta = nowTicks - sdlTicks; sdlTicks = nowTicks; if (simIsRunning) @@ -36,6 +70,13 @@ void Timer::update() { checkSimEvents(); } +void Timer::setSimulationRunning(bool yes) { + simIsRunning = yes; +#ifdef TIMER_OPENSTEER_CLOCK + clock.setPausedState(!yes); +#endif +} + void Timer::checkRTEvents() { RealTimeMap::iterator i = realTimeEvents.begin(); while (i != realTimeEvents.end() && i->first <= sdlTicks) { diff --git a/util/timer.h b/util/timer.h index 5ae6af1..37cc5f9 100644 --- a/util/timer.h +++ b/util/timer.h @@ -1,9 +1,38 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ #ifndef OGTA_TIMER_H #define OGTA_TIMER_H #include #include "Singleton.h" #include "Functor.h" +// instead of SDL_GetTicks() +#define TIMER_OPENSTEER_CLOCK + +#ifdef TIMER_OPENSTEER_CLOCK +#include "OpenSteer/Clock.h" +#endif + class Timer { public: typedef Loki::Functor CallbackType; @@ -22,11 +51,14 @@ class Timer { // time since SDL_Init inline const uint32_t & getRealTime() const { return sdlTicks; } void update(); - inline void setSimulationRunning(bool yes) { simIsRunning = yes; } + void setSimulationRunning(bool yes); inline bool getSimulationRunning() const { return simIsRunning; } void registerCallback(bool simTime, CallbackType & c, const uint32_t & b, const uint32_t & e); void registerCallback(bool simTime, CallbackType & c, const uint32_t & b); void clearAllEvents(); +#ifdef TIMER_OPENSTEER_CLOCK + OpenSteer::Clock clock; +#endif private: void checkRTEvents(); void checkSimEvents(); diff --git a/viewer.cpp b/viewer.cpp index dbc7ec6..48625b3 100644 --- a/viewer.cpp +++ b/viewer.cpp @@ -1,5 +1,5 @@ /************************************************************************ -* Copyright (c) 2005-2006 tok@openlinux.org.uk * +* Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * @@ -21,27 +21,36 @@ * distribution. * ************************************************************************/ #include -#include +#include #include +#include #include -//#include "common_sdl_gl.h" -#include "gl_screen.h" -#include "opengta.h" -#include "gl_texturecache.h" +#include "blockanim.h" +#include "dataholder.h" +#include "entity_controller.h" +#include "file_helper.h" +#include "gl_camera.h" #include "gl_cityview.h" #include "gl_font.h" -#include "gl_camera.h" -#include "navdata.h" -#include "log.h" -#include "spritemanager.h" -#include "localplayer.h" -#include "m_exceptions.h" -#include "file_helper.h" +#include "gl_screen.h" #include "gl_spritecache.h" +#include "gl_texturecache.h" +#include "id_sys.h" +#include "localplayer.h" +#include "log.h" +#include "m_exceptions.h" +#include "navdata.h" +#include "opengta.h" +#include "spritemanager.h" +#include "timer.h" #ifdef WITH_LUA #include "lua_addon/lua_vm.h" #endif +#define getPedById getPed +#define removePedById removePed +#define addPed add + extern SDL_Surface* screen; extern int global_EC; extern int global_Done; @@ -73,12 +82,17 @@ int bbox_toggle = 0; int texsprite_toggle = 0; int follow_toggle = 0; OpenGTA::SpriteObject::Animation pedAnim(0, 0); +#ifdef OGTA_DEFAULT_GRAPHICS_G24 +bool highcolor_data = true; +#else bool highcolor_data = false; +#endif bool full_screen = false; bool player_toggle_run = false; const char* script_file = NULL; int paused = 0; +int next_station_zoom = 0; /* void ERROR(const char* s) { @@ -101,6 +115,224 @@ void on_exit() { std::cout << "Goodbye" << std::endl; } +void print_usage(const char* argv0) { + std::cout << "USAGE: " << argv0 << " [options] [city-num]" << std::endl << + std::endl << + "Options: " << std::endl << + " -l k : log-level (default: 0; 1, 2)" << std::endl << + " -c k : 0 = 8bit GRY, 1 = 24bit G24" << std::endl << + " -f : fullscreen on program-start" << std::endl << + " -V : show version & compile-time switches" << std::endl << + std::endl << + " -m map_file -g style_file : load specified files" << std::endl << + " -w width -h height : screen dimension" << std::endl << + std::endl << + "City-num: 0 (default), 1, 2" << std::endl << + std::endl << + "The following environment variables are used when defined:" << std::endl << + " OGTA_DATA : PhysicsFS source for main data file lookup" << std::endl << + " OGTA_HOME : unused - will be config/save dir" << std::endl << + " OGTA_MOD : PhysicsFS source to override main data files" << std::endl; +} + +void print_version_info() { +#define PRINT_FORMATED(spaces) std::setw(spaces) << std::left << +#define PRINT_OFFSET PRINT_FORMATED(18) + std::cout << PRINT_OFFSET "OpenGTA version:" << OGTA_VERSION_INFO << std::endl << + PRINT_OFFSET "platform:" << OGTA_PLATFORM_INFO << std::endl << + + PRINT_OFFSET "Lua support:" << +#ifdef WITH_LUA + "yes [" << LUA_RELEASE << "]" << +#else + "no" << +#endif + std::endl << + PRINT_OFFSET "sound support:" << +#ifdef WITH_SOUND + "yes" << +#else + "no" << +#endif + std::endl << + PRINT_OFFSET "vsync support:" << +#ifdef HAVE_SDL_VSYNC + "yes" << +#else + "no" << +#endif + std::endl << + +#ifdef OGTA_DEFAULT_DATA_PATH + PRINT_OFFSET "data-path:" << "[" << OGTA_DEFAULT_DATA_PATH << "]" << std::endl << +#endif +#ifdef OGTA_DEFAULT_MOD_PATH + PRINT_OFFSET "mod-path:" << "[" << OGTA_DEFAULT_MOD_PATH << "]" << std::endl << +#endif + PRINT_OFFSET "default graphics:" << +#ifdef OGTA_DEFAULT_GRAPHICS_G24 + "G24 - 24 bit" << +#else + "GRY - 8 bit" << +#endif + std::endl << + + PRINT_OFFSET "compiler: " << USED_GCC_VERSION + << std::endl; +} + +void parse_args(int argc, char* argv[]) { + int index; + int c; + + opterr = 0; + +#ifdef WITH_LUA +#define VIEWER_FLAGS "s:w:h:c:m:g:l:fV" +#else +#define VIEWER_FLAGS "w:h:c:m:g:l:fV" +#endif + while ((c = getopt (argc, argv, VIEWER_FLAGS)) != -1) + switch (c) + { +#ifdef WITH_LUA + case 's': + script_file = std::string(optarg); + break; +#endif + case 'c': + highcolor_data = atoi(optarg); + break; + case 'm': + specific_map = std::string(optarg); + break; + case 'g': + specific_style = std::string(optarg); + break; + case 'w': + arg_screen_w = atoi(optarg); + break; + case 'h': + arg_screen_h = atoi(optarg); + break; + case 'l': + Util::Log::setOutputLevel(atoi(optarg)); + break; + case 'f': + full_screen = true; + break; + case 'V': + print_version_info(); + exit(0); + break; + default: + if (optopt == '?') { + print_usage(argv[0]); + exit(0); + } + else if (isprint (optopt)) + ERROR << "Unknown option `-" << char(optopt) << "'" << std::endl; + else + ERROR << "Unknown option character `" << optopt << "'" << std::endl; + print_usage(argv[0]); + exit(1); + } + + for (index = optind; index < argc; index++) + city_num = atoi(argv[index]); + + if (city_num > 2) { + ERROR << "Invalid city number: " << city_num << std::endl; + exit(1); + } +} + +void run_init(const char* prg_name) { + // physfs + PHYSFS_init(prg_name); + + // physfs-ogta + Util::FileHelper & fh = GET_FILE_HELPER; + if (fh.existsInSystemFS(fh.getBaseDataPath())) { + PHYSFS_addToSearchPath(GET_FILE_HELPER.getBaseDataPath().c_str(), 1); + } + else { + WARN << "Could not load data-source: " << fh.getBaseDataPath() << std::endl; + } + + PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1); + + if (fh.existsInSystemFS(fh.getModDataPath())) + PHYSFS_addToSearchPath(GET_FILE_HELPER.getModDataPath().c_str(), 0); + + + OpenGL::Screen & screen = OpenGL::ScreenHolder::Instance(); +#ifdef WITH_LUA + if (fh.existsInVFS("config")) { + char* config_as_string = (char*)fh.bufferFromVFS( + fh.openReadVFS("config")); + + OpenGTA::Script::LuaVM & vm = OpenGTA::Script::LuaVMHolder::Instance(); + try { + vm.runString(config_as_string); + } + catch (const Util::ScriptError & e) { + std::cerr << "Error in config-file: " << e.what() << std::endl; + global_EC = 1; + exit(1); + } + + try { + Uint32 sw = vm.getGlobalInt("screen_width"); + if (!arg_screen_w) + arg_screen_w = sw; + } + catch (const Util::ScriptError & e) {} + try { + Uint32 sh = vm.getGlobalInt("screen_height"); + if (!arg_screen_h) + arg_screen_h = sh; + } + catch (const Util::ScriptError & e) {} + try { + Uint32 sh = vm.getGlobalInt("full_screen"); + if (!full_screen) + full_screen = sh; + } + catch (const Util::ScriptError & e) {} + + float fov = screen.getFieldOfView(); + float np = screen.getNearPlane(); + float fp = screen.getFarPlane(); + try { + fov = vm.getGlobalFloat("field_of_view"); + } + catch (const Util::ScriptError & e) {} + try { + np = vm.getGlobalFloat("near_plane"); + } + catch (const Util::ScriptError & e) {} + try { + fp = vm.getGlobalFloat("far_plane"); + } + catch (const Util::ScriptError & e) {} + screen.setupGlVars(fov, np, fp); + + } +#endif + + if ((arg_screen_h && !arg_screen_w) || (!arg_screen_h && arg_screen_w)) { + WARN << "Invalid screen specified: " << arg_screen_w << "x" << + arg_screen_h << " - using default" << std::endl; + arg_screen_h = 0; arg_screen_w = 0; + } + + screen.setFullScreenFlag(full_screen); + screen.activate(arg_screen_w, arg_screen_h); + SDL_EnableKeyRepeat( 100, SDL_DEFAULT_REPEAT_INTERVAL ); +} + + void print_position() { Vector3D & v = OpenGL::CameraHolder::Instance().getCenter(); Vector3D & e = OpenGL::CameraHolder::Instance().getEye(); @@ -127,16 +359,27 @@ void print_position() { void handleKeyUp( SDL_keysym *keysym) { switch ( keysym->sym ) { case 'j': - OpenGTA::LocalPlayer::Instance().turn = 0; + OpenGTA::LocalPlayer::Instance().getCtrl().releaseTurnLeft(); + //OpenGTA::LocalPlayer::Instance().turn = 0; + //OpenGTA::LocalPlayer::Instance().setTurn(0); break; case 'l': - OpenGTA::LocalPlayer::Instance().turn = 0; + OpenGTA::LocalPlayer::Instance().getCtrl().releaseTurnRight(); + //OpenGTA::LocalPlayer::Instance().turn = 0; + //OpenGTA::LocalPlayer::Instance().setTurn(0); break; case 'i': - OpenGTA::LocalPlayer::Instance().move = 0; + OpenGTA::LocalPlayer::Instance().getCtrl().releaseMoveForward(); + //OpenGTA::LocalPlayer::Instance().move = 0; + //OpenGTA::LocalPlayer::Instance().setMove(0); break; case 'k': - OpenGTA::LocalPlayer::Instance().move = 0; + OpenGTA::LocalPlayer::Instance().getCtrl().releaseMoveBack(); + //OpenGTA::LocalPlayer::Instance().move = 0; + //OpenGTA::LocalPlayer::Instance().setMove(0); + break; + case SDLK_LCTRL: + OpenGTA::LocalPlayer::Instance().getCtrl().setFireWeapon(false); break; default: break; @@ -147,10 +390,111 @@ void draw_mapmode(); void create_ped_at(const Vector3D v) { OpenGTA::Pedestrian p(Vector3D(0.3f, 0.5f, 0.3f), v, 0xffffffff); - p.m_control = &OpenGTA::LocalPlayer::Instance(); + p.remap = OpenGTA::StyleHolder::Instance().get().getRandomPedRemapNumber(); + INFO << "using remap: " << p.remap << std::endl; + OpenGTA::Pedestrian & pr = OpenGTA::SpriteManagerHolder::Instance().addPed(p); + pr.switchToAnim(1); + OpenGTA::LocalPlayer::Instance().setCtrl(pr.m_control); + //pr.m_control = &OpenGTA::LocalPlayer::Instance(); + //OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).giveItem(1, 255); +} + +void explode_ped() { + try { + OpenGTA::Pedestrian & ped = OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff); + Vector3D p(ped.pos); + p.y += 0.2f; + OpenGTA::SpriteManagerHolder::Instance().createExplosion(p); + } + catch (Util::UnknownKey & e) { + WARN << "Cannot place explosion - press F4 to switch to player-mode first!" << std::endl; + } +} + +void zoomToTrain(int k) { +/* + OpenGTA::TrainSegment & ts = OpenGTA::SpriteManagerHolder::Instance().getTrainById(k); + Vector3D p(ts.pos); + p.y += 9; + OpenGL::CameraHolder::Instance().interpolate(p, 1, 30000); +*/ + +} + +#include "cell_iterator.h" + +namespace OpenGTA { + void ai_step_fake(OpenGTA::Pedestrian *p) { + try { + OpenGTA::Pedestrian & pr = OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff); + float t_angle = Util::xz_angle(p->pos, pr.pos); + //INFO << "dist " << Util::distance(p->pos, pr.pos) << std::endl; + //INFO << "angle " << t_angle << std::endl; + //INFO << "myrot: " << p->rot << std::endl; + if (Util::distance(p->pos, pr.pos) > 3) { + p->m_control.setTurnLeft(false); + p->m_control.setTurnRight(false); + if (t_angle > p->rot) + p->m_control.setTurnLeft(true); + else + p->m_control.setTurnRight(true); + } + else { + p->m_control.setMoveForward(true); + int k = rand() % 5; + if (k == 0) { + p->m_control.setTurnLeft(false); + p->m_control.setTurnRight(false); + } + else if (k == 1) { + p->m_control.setTurnLeft(true); + p->m_control.setTurnRight(false); + } + else if (k == 2) { + p->m_control.setTurnLeft(false); + p->m_control.setTurnRight(true); + } + } + } + catch (Util::UnknownKey & e) { + } + + } +} + +#include "id_sys.h" +void add_auto_ped() { + try { + OpenGTA::Pedestrian & pr = OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff); + int id = OpenGTA::TypeIdBlackBox::requestId(); + Vector3D v(pr.pos); + v.y += 0.9f; + //INFO << v.x << " " << v.y << " " << v.z << std::endl; + Sint16 remap = OpenGTA::StyleHolder::Instance().get().getRandomPedRemapNumber(); + OpenGTA::Pedestrian p(Vector3D(0.3f, 0.5f, 0.3f), v, id, remap); OpenGTA::SpriteManagerHolder::Instance().addPed(p); - OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).switchToAnim(1); - OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).giveItem(1, 255); + OpenGTA::Pedestrian & pr2 = OpenGTA::SpriteManagerHolder::Instance().getPedById(id); + pr2.switchToAnim(1); + INFO << "now " << OpenGTA::SpriteManagerHolder::Instance().getNum() << " peds " << std::endl; + + //pr2.m_control = &OpenGTA::nullAI; + } + catch (Util::UnknownKey & e) { + WARN << "Cannot place peds now - press F4 to switch to player-mode first!" << std::endl; + } +} + +void toggle_player_run() { + OpenGTA::PedController * pc = &OpenGTA::LocalPlayer::Instance().getCtrl(); + + if (!pc) { + WARN << "no player yet!" << std::endl; + return; + } + if (!pc->getRunning()) + pc->setRunning(true); + else + pc->setRunning(false); } void handleKeyPress( SDL_keysym *keysym ) { @@ -181,7 +525,11 @@ void handleKeyPress( SDL_keysym *keysym ) { cam.setSpeed(0.0f); break; case SDLK_F1: - cam.interpolate(Vector3D(254, 9, 254), 1, 20000); + //cam.interpolate(Vector3D(254, 9, 254), 1, 20000); + + //zoomToTrain(next_station_zoom++); + //if (next_station_zoom >= OpenGTA::SpriteManagerHolder::Instance().trainSystem.getNumTrains()) + // next_station_zoom = 0; break; case SDLK_F2: bbox_toggle = (bbox_toggle ? 0 : 1); @@ -194,17 +542,22 @@ void handleKeyPress( SDL_keysym *keysym ) { case SDLK_F4: follow_toggle = (follow_toggle ? 0 : 1); if (follow_toggle) { + SDL_EnableKeyRepeat( 0, SDL_DEFAULT_REPEAT_INTERVAL ); city->setViewMode(false); Vector3D p(cam.getEye()); create_ped_at(p); - cam.setVectors( Vector3D(p.x, 10, p.z), Vector3D(p.x, 0.0f, p.z), Vector3D(0, 0, -1) ); + cam.setVectors( Vector3D(p.x, 10, p.z), Vector3D(p.x, 9.0f, p.z), Vector3D(0, 0, -1) ); cam.setFollowMode(OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).pos); + cam.setCamGravity(true); } else { + SDL_EnableKeyRepeat( 100, SDL_DEFAULT_REPEAT_INTERVAL ); cam.setVectors(cam.getEye(), Vector3D(cam.getEye() + Vector3D(1, -1, 1)), Vector3D(0, 1, 0)); + cam.setCamGravity(false); cam.releaseFollowMode(); OpenGTA::SpriteManagerHolder::Instance().removePedById(0xffffffff); + OpenGTA::SpriteManagerHolder::Instance().removeDeadStuff(); } break; case SDLK_F5: @@ -214,12 +567,21 @@ void handleKeyPress( SDL_keysym *keysym ) { case SDLK_F6: draw_mapmode(); break; + case SDLK_F7: + explode_ped(); + break; + case SDLK_F8: + add_auto_ped(); + break; case SDLK_F9: city->setDrawTextured(city->getDrawTextured() ? 0 : 1); break; case SDLK_F10: city->setDrawLines(city->getDrawLines() ? 0 : 1); break; + case SDLK_LSHIFT: + toggle_player_run(); + break; /* case SDLK_F6: tex_flip = (tex_flip ? 0 : 1); @@ -227,32 +589,39 @@ void handleKeyPress( SDL_keysym *keysym ) { city->setTexFlipTest(tex_flip); break; */ + case SDLK_LCTRL: + OpenGTA::LocalPlayer::Instance().getCtrl().setFireWeapon(); + break; case '1': - OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(1); + //OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(1); + OpenGTA::LocalPlayer::Instance().getCtrl().setActiveWeapon(1); break; case '2': - OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(2); + //OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(2); + OpenGTA::LocalPlayer::Instance().getCtrl().setActiveWeapon(2); break; case '3': - OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(3); + //OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(3); + OpenGTA::LocalPlayer::Instance().getCtrl().setActiveWeapon(3); break; case '4': - OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(4); + //OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(4); + OpenGTA::LocalPlayer::Instance().getCtrl().setActiveWeapon(4); break; case '5': - OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(5); + //OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(5); break; case '6': - OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(6); + //OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(6); break; case '7': - OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(7); + //OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(7); break; case '8': - OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(8); + //OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(8); break; case '9': - OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(9); + //OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(9); /* ped_anim -= 1; if (ped_anim < 0) ped_anim = 0; pedAnim.firstFrameOffset = ped_anim; @@ -261,13 +630,14 @@ void handleKeyPress( SDL_keysym *keysym ) { */ break; case '0': + OpenGTA::LocalPlayer::Instance().getCtrl().setActiveWeapon(0); /* ped_anim += 1; if (ped_anim > 200) ped_anim = 200; pedAnim.firstFrameOffset = ped_anim; INFO << "switching to sprite: " << ped_anim << std::endl; OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).setAnimation(pedAnim); */ - OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(0); + //OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).equip(0); break; case 'w': cam.setSpeed(0.2f); @@ -276,20 +646,16 @@ void handleKeyPress( SDL_keysym *keysym ) { cam.setSpeed(-0.2f); break; case 'j': - OpenGTA::LocalPlayer::Instance().turn = 1; + OpenGTA::LocalPlayer::Instance().getCtrl().setTurnLeft(); break; case 'l': - OpenGTA::LocalPlayer::Instance().turn = -1; + OpenGTA::LocalPlayer::Instance().getCtrl().setTurnRight(); break; case 'i': - OpenGTA::LocalPlayer::Instance().move = (player_toggle_run) ? 2 : 1; + OpenGTA::LocalPlayer::Instance().getCtrl().setMoveForward(); break; case 'k': - OpenGTA::LocalPlayer::Instance().move = -1; - break; - case SDLK_LSHIFT: - player_toggle_run = (player_toggle_run) ? false : true; - INFO << player_toggle_run << std::endl; + OpenGTA::LocalPlayer::Instance().getCtrl().setMoveBack(); break; case 'f': OpenGL::ScreenHolder::Instance().toggleFullscreen(); @@ -363,10 +729,12 @@ void drawScene(Uint32 ticks) { glTranslatef(10, 10, 0); m_font->drawString(city->getCurrentSector()->getFullName()); glPopMatrix(); + glPushMatrix(); glTranslatef(5, 50, 0); std::ostringstream strstr; strstr << fps << " fps"; m_font->drawString(strstr.str()); + glPopMatrix(); num_frames_drawn += 1; @@ -455,6 +823,7 @@ void draw_mapmode() { glDeleteTextures(1, &map_tex.inPage); } +#if 0 void parse_args(int argc, char* argv[]) { int index; int c; @@ -513,7 +882,7 @@ void parse_args(int argc, char* argv[]) { } } -void run_init() { +void run_init(const char* prgname) { PHYSFS_init("mapview"); //PHYSFS_addToSearchPath("gtadata.zip", 1); Util::FileHelper & fh = GET_FILE_HELPER; @@ -529,11 +898,13 @@ void run_init() { OpenGL::Screen & screen = OpenGL::ScreenHolder::Instance(); screen.setFullScreenFlag(full_screen); screen.activate(arg_screen_w, arg_screen_h); - SDL_EnableKeyRepeat( 100, SDL_DEFAULT_REPEAT_INTERVAL ); + //SDL_EnableKeyRepeat( 100, SDL_DEFAULT_REPEAT_INTERVAL ); } +#endif void run_main() { SDL_Event event; + OpenGTA::MainMsgHolder::Instance().load("ENGLISH.FXT"); m_font = new OpenGL::DrawableFont(); m_font->loadFont("F_MTEXT.FON"); @@ -564,7 +935,16 @@ void run_main() { //cam.setVectors( Vector3D(4, 10, 4), Vector3D(4, 0.0f, 4.0f), Vector3D(0, 0, -1) ); cam.setVectors( Vector3D(12, 20, 12), Vector3D(13.0f, 19.0f, 13.0f), Vector3D(0, 1, 0) ); + +#ifdef TIMER_OPENSTEER_CLOCK + Timer & timer = TimerHolder::Instance(); + timer.update(); + last_tick = timer.getRealTime(); + //timer.setSimulationRunning(true); +#else last_tick = SDL_GetTicks(); +#endif + #ifdef WITH_LUA OpenGTA::Script::LuaVM & vm = OpenGTA::Script::LuaVMHolder::Instance(); vm.setCityView(*city); @@ -604,8 +984,14 @@ void run_main() { break; } } +#ifdef TIMER_OPENSTEER_CLOCK + timer.update(); + Uint32 now_ticks = timer.getRealTime(); +#else Uint32 now_ticks = SDL_GetTicks(); +#endif OpenGTA::SpriteManagerHolder::Instance().update(now_ticks); + city->blockAnims->update(now_ticks); if (!paused) { drawScene(now_ticks - last_tick); last_tick = now_ticks; @@ -622,11 +1008,19 @@ void run_main() { } #endif } + OpenGTA::SpriteManagerHolder::Instance().creationArea.setRects( + city->getActiveRect(), city->getOnScreenRect()); + +//#ifdef TIMER_OPENSTEER_CLOCK +// fps = int(timer.clock.getSmoothedFPS()); +//#else if (now_ticks - fps_last_tick > 2000) { fps = num_frames_drawn / 2; num_frames_drawn = 0; fps_last_tick = now_ticks; } +//#endif // SDL_Delay(10); } + }