2007-04-16

This commit is contained in:
Anonymous Maarten 2015-12-03 01:37:37 +01:00
parent 78c27f03c8
commit e20673c2cd
120 changed files with 9578 additions and 1036 deletions

59
blockanim.cpp Normal file
View File

@ -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();
}
}

59
blockanim.h Normal file
View File

@ -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<GraphicsBase::LoadedAnim*> DataAnimVector;
typedef std::vector<BlockAnim*> BlockAnimVector;
BlockAnimCtrl(const DataAnimVector & v);
~BlockAnimCtrl();
void update(uint32_t ticks);
BlockAnim * getAnim(uint8_t area, uint8_t id);
private:
BlockAnimVector anims;
};
}

View File

@ -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] = {

View File

@ -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 <cstddef>

19
bugs.rec Normal file
View File

@ -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.
%%

View File

@ -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);
}

View File

@ -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

27
datahelper.cpp Normal file
View File

@ -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;
}
}
}

7
datahelper.h Normal file
View File

@ -0,0 +1,7 @@
#include <string>
namespace OpenGTA {
namespace Helper {
size_t mapFileName2Number(const std::string & file);
}
}

View File

@ -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);
}
}

View File

@ -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,17 +28,10 @@
#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 T>
class ActiveData {
@ -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

View File

@ -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

View File

@ -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.

198
entity_controller.cpp Normal file
View File

@ -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 <SDL_events.h>
#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 <SDL_events.h>
#include "localplayer.h"
template <class ENTITY>
class ClassicKeyConsumer {
public:
bool handle(const SDL_keysym & ks, bool press);
};
template <> bool ClassicKeyConsumer<PedController>::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
}

102
entity_controller.h Normal file
View File

@ -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 <stdint.h>
#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

View File

@ -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,

View File

@ -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 <string>

View File

@ -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 *

View File

@ -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,72 +85,181 @@ 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) {}
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 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(Uint16 foff, Uint8 num) :
Util::Animation(num, 7),
firstFrameOffset(foff), moveSpeed(0.0f) {}
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) {
}
Pedestrian::Pedestrian(const Pedestrian & other) : SpriteObject(other),
OBox(other.m_M, other.m_Extent) {
//animRef(SpriteManagerHolder::Instance().getAnimationById(other.animId)) {
copyValues(other);
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 Pedestrian::switchToAnim(const Uint32 & newId) {
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;
}
void Pedestrian::copyValues(const Pedestrian & other) {
Pedestrian::Pedestrian(const Pedestrian & other) :
GameObject_common(other), Sprite(other), OBox(other),
m_control = other.m_control;
animId = other.animId;
pedId = other.pedId;
pedId(other.pedId),
m_control(),
speedForces(other.speedForces) {
lastUpdateAt = other.lastUpdateAt;
inGroundContact = other.inGroundContact;
sprType = other.sprType;
speedForces = other.speedForces;
activeWeapon = other.activeWeapon;
inventory = other.inventory;
weaponReloadedAt = other.weaponReloadedAt;
animId = other.animId;
isDead = other.isDead;
m_M = TranslateMatrix3D(other.pos);
m_M.RotZ(other.rot);
}
void Pedestrian::giveItem(uint8_t id, uint32_t amount) {
InventoryType::iterator i = inventory.find(id);
if (i == inventory.end())
inventory[id] = amount;
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
i->second += amount;
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::tryMove(Vector3D nPos) {
@ -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<void> 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<Pedestrian> & list = SpriteManagerHolder::Instance().getList<Pedestrian>();
for (std::list<Pedestrian>::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 <<std::endl;
*/
pos = new_pos;
lastUpdateAt = ticks;
}
}

146
game_objects.h Normal file
View File

@ -0,0 +1,146 @@
/************************************************************************
* 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 GAME_OBJECTS_H
#define GAME_OBJECTS_H
#include "math3d.h"
#include "obox.h"
#include "animation.h"
#include "opengta.h"
#include "cell_iterator.h"
#include "entity_controller.h"
#include "OpenSteer/Proximity.h"
namespace OpenGTA {
struct GameObject_common;
typedef OpenSteer::AbstractTokenForProximityDatabase<GameObject_common*> ProximityToken;
typedef OpenSteer::AbstractProximityDatabase<GameObject_common*> 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

View File

@ -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:

View File

@ -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 *

View File

@ -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 *

View File

@ -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,

View File

@ -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<uint8_t>("SideCache");
lidCache = new OpenGL::TextureCache<uint8_t>("LidCache");
auxCache = new OpenGL::TextureCache<uint8_t>("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 << "," <<r.y << " - " << r.x + r.w << "," << r.y+r.h<<std::endl;
GL_CHECKERROR;
SpriteManagerHolder::Instance().drawInRect(r);
SpriteManagerHolder::Instance().drawInRect(activeRect);
lastCacheEmptyTicks += ticks;
if (lastCacheEmptyTicks > 4000) {
@ -540,6 +578,12 @@ namespace OpenGTA {
// FIXME: no remaps used!
if (bi->lid) {
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<unsigned int>(bi->lid), 0, is_flat));
@ -548,7 +592,24 @@ namespace OpenGTA {
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<unsigned int>(aux_id), 0, is_flat));
auxCache->addTexture(aux_id, lid_tex);
}
else
lid_tex = auxCache->getTextureWithId(aux_id);
}
}
if (bi->left) {
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<unsigned int>(bi->left), 0, is_flat));
@ -557,7 +618,25 @@ namespace OpenGTA {
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<unsigned int>(aux_id), 0, is_flat));
auxCache->addTexture(aux_id, left_tex);
}
else
left_tex = auxCache->getTextureWithId(aux_id);
}
}
if (bi->right) {
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<unsigned int>(bi->right), 0, is_flat));
@ -566,7 +645,25 @@ namespace OpenGTA {
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<unsigned int>(aux_id), 0, is_flat));
auxCache->addTexture(aux_id, right_tex);
}
else
right_tex = auxCache->getTextureWithId(aux_id);
}
}
if (bi->top) {
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<unsigned int>(bi->top), 0, is_flat));
@ -575,7 +672,25 @@ namespace OpenGTA {
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<unsigned int>(aux_id), 0, is_flat));
auxCache->addTexture(aux_id, top_tex);
}
else
top_tex = auxCache->getTextureWithId(aux_id);
}
}
if (bi->bottom) {
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<unsigned int>(bi->bottom), 0, is_flat));
@ -584,6 +699,18 @@ namespace OpenGTA {
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<unsigned int>(aux_id), 0, is_flat));
auxCache->addTexture(aux_id, bottom_tex);
}
else
bottom_tex = auxCache->getTextureWithId(aux_id);
}
}
// handle flat/transparent case
if (is_flat) {
@ -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;
}

View File

@ -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<uint8_t>* sideCache;
OpenGL::TextureCache<uint8_t>* lidCache;
OpenGL::TextureCache<uint8_t>* 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;

View File

@ -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 *

View File

@ -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 *

View File

@ -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 *

View File

@ -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() {

View File

@ -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;
};

View File

@ -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 <map>
#include <cassert>
#include <SDL_image.h>
#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;

View File

@ -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 *

View File

@ -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 *

View File

@ -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 *

8
id_sys.cpp Normal file
View File

@ -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;
}

29
id_sys.h Normal file
View File

@ -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

View File

@ -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 <craig_reynolds@playstation.sony.com>
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.

View File

@ -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<PlayerController, Loki::CreateUsingNew,

View File

@ -0,0 +1,87 @@
#include "lua_ini_bridge.h"
#include "log.h"
namespace OpenGTA { namespace Script {
#define GLOBAL_TABLE(name) lua_newtable(L); lua_setglobal(L, name)
IniScriptBridge::IniScriptBridge(const std::string & file) :
ScriptParser(file) {
L = lua_open();
luaL_openlibs(L);
}
IniScriptBridge::~IniScriptBridge() {
lua_close(L);
}
void IniScriptBridge::reset() {
lua_settop(L, 0);
GLOBAL_TABLE("commands");
GLOBAL_TABLE("definitions");
lua_gc(L, LUA_GCCOLLECT, 0);
lua_settop(L, 0);
}
void IniScriptBridge::loadLevel(PHYSFS_uint32 level) {
reset();
ScriptParser::loadLevel(level);
}
void IniScriptBridge::acceptCommand(const char* cmd) {
char *skip_idx = strchr(cmd, ' ');
assert(skip_idx);
*skip_idx = 0;
int idx = atoi(cmd);
++skip_idx;
//INFO << idx << " " << skip_idx << std::endl;
lua_settop(L, 0);
lua_getglobal(L, "commands");
lua_pushinteger(L, idx);
lua_pushstring(L, skip_idx);
lua_settable(L, -3);
lua_settop(L, 0);
}
void IniScriptBridge::acceptDefinition(const char* def) {
char *skip_idx = strchr(def, ' ');
assert(skip_idx);
*skip_idx = 0;
int idx = atoi(def);
skip_idx++;
if (*skip_idx == '1' && *(skip_idx+1) == ' ')
skip_idx += 2;
//INFO << idx << " " << skip_idx << std::endl;
lua_settop(L, 0);
lua_getglobal(L, "definitions");
lua_pushinteger(L, idx);
lua_pushstring(L, skip_idx);
lua_settable(L, -3);
lua_settop(L, 0);
}
}}
#if 0
void on_exit() {
PHYSFS_deinit();
}
int main(int argc, char* argv[]) {
PHYSFS_init(argv[0]);
PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1);
atexit(on_exit);
OpenGTA::Script::IniScriptBridge p(argv[1]);
p.loadLevel(atoi(argv[2]));
if (luaL_loadfile(p.L, argv[3]) || lua_pcall(p.L, 0, 0, 0))
ERROR << lua_tostring(p.L, -1);
return 0;
}
#endif

View File

@ -0,0 +1,25 @@
#ifndef LUA_INI_BRIDGE_H
#define LUA_INI_BRIDGE_H
#include <string>
#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

View File

@ -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}
};
}
}

View File

@ -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

View File

@ -1,6 +1,7 @@
#include <string>
#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<Block>::Register2(L);
Lunar<LMap>::Register2(L);
/*
Lunar<CityView>::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<LMap*>(&map);
lua_gettable(L, LUA_GLOBALSINDEX);
int scv_ref = Lunar<LMap>::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<CityView*>(&cv);
lua_gettable(L, LUA_GLOBALSINDEX);
int scv_ref = Lunar<CityView>::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) {

View File

@ -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<LuaVM, Loki::CreateUsingNew, Loki::DefaultLifetime,
Loki::SingleThreaded> LuaVMHolder;

View File

@ -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;

View File

@ -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

218
math/interpolate.hpp Normal file
View File

@ -0,0 +1,218 @@
#ifndef MMATH_INTERPOLATE_H
#define MMATH_INTERPOLATE_H
#include <cmath>
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 <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
Linear<T>::Linear(const T & y1, const T & y2) : v1(y1), v2(y2) {}
template <typename T>
T Linear<T>::getAt(const T & mu) const {
return v1 * (1 - mu) + v2 * mu;
}
template <typename T>
void Linear<T>::shiftAndFeed(const T & y_i) {
v1 = v2;
v2 = y_i;
}
// Cubic
template <typename T>
Cubic<T>::Cubic(const T & y0,
const T & y1, const T & y2, const T & y3) {
setCoefficients(y0, y1, y2, y3);
}
template <typename T>
Cubic<T>::Cubic(const T & y1,
const T & y2, const T & y3) {
setCoefficients(2 * y1 - y2, y1, y2, y3);
}
template <typename T>
void Cubic<T>::shiftAndFeed(const T & y_i) {
setCoefficients(a3, v2, v3, y_i);
}
template <typename T>
void Cubic<T>::shift() {
setCoefficients(a3, v2, v3, 2 * v2 - a3);
}
template <typename T>
void Cubic<T>::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 <typename T>
T Cubic<T>::getAt(const T & mu) const {
const T mu_sq = mu * mu;
return(a0 * mu * mu_sq + a1 * mu_sq + a2 * mu + a3);
}
// Cosine
template <typename T>
Cosine<T>::Cosine(const T & y1, const T & y2) : v1(y1), v2(y2) {}
template <typename T>
T Cosine<T>::getAt(const T & mu) const {
T mu2 = (1 - cos(mu * M_PI)) / 2;
return v1 * (1 - mu2) + v2 * mu2;
}
template <typename T>
void Cosine<T>::shiftAndFeed(const T & y_i) {
v1 = v2;
v2 = y_i;
}
// Hermite
template <typename T>
Hermite<T>::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 <typename T>
T Hermite<T>::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 <typename T>
void Hermite<T>::setCoefficients(const T y0, const T y1, const T y2,
const T y3) {
v0 = y0; v1 = y1; v2 = y2; v3 = y3;
updateCoefficients();
}
template <typename T>
void Hermite<T>::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 <typename T>
void Hermite<T>::setTension(const T & _tension) {
tension = _tension;
updateCoefficients();
}
template <typename T>
void Hermite<T>::setBias(const T & _bias) {
bias = _bias;
updateCoefficients();
}
template <typename T>
void Hermite<T>::shiftAndFeed(const T & y_i) {
setCoefficients(v1, v2, v3, y_i);
}
template <typename T>
void Hermite<T>::shift() {
setCoefficients(v1, v2, v3, 2 * v2 - v1);
}
}
}
#endif

View File

@ -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;

View File

@ -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;

108
math/rectangle.hpp Normal file
View File

@ -0,0 +1,108 @@
#ifndef RECTANGLE_2D_H
#define RECTANGLE_2D_H
#include <list>
namespace Math {
template <typename U> 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<U> & o) :
x(o.x), y(o.y), w(o.w), h(o.h) {}
inline bool operator == (const Rectangle<U> & 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 <typename U> bool rectangle_test_inside (
const Rectangle<U> & larger,
const Rectangle<U> & 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 <typename U> bool rectangle_test_leftborder (
const Rectangle<U> & larger,
const Rectangle<U> & smaller ) {
return (larger.x == smaller.x);
}
template <typename U> bool rectangle_test_rightborder (
const Rectangle<U> & larger,
const Rectangle<U> & smaller ) {
return (larger.x + larger.w == smaller.x + smaller.w);
}
template <typename U> bool rectangle_test_bottomborder (
const Rectangle<U> & larger,
const Rectangle<U> & smaller ) {
return (larger.y == smaller.y);
}
template <typename U> bool rectangle_test_topborder (
const Rectangle<U> & larger,
const Rectangle<U> & smaller ) {
return (larger.y + larger.h == smaller.y + smaller.h);
}
template <typename U> 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 <typename U> void RectangleGeometry<U>::difference(ListOfRectangleU & list,
const Rectangle< U > & first, const Rectangle< U > & second) {
// assume first is larger, second is smaller
if (! rectangle_test_leftborder<U>(first, second)) {
/*
### #
#x# split off the left col #
### #
*/
list.push_back( Rectangle<U>( first.x, first.y, second.x - first.x, first.h ) );
}
if (! rectangle_test_rightborder<U>(first, second)) {
// split of the right column
list.push_back( Rectangle<U>( second.x + second.w, first.y,
first.x + first.w - (second.x + second.w), first.h));
}
if (! rectangle_test_topborder<U>(first, second)) {
// remainder of the top row
list.push_back( Rectangle<U>( second.x, second.y + second.h,
second.w, first.y + first.h - (second.y + second.h)));
}
if (! rectangle_test_bottomborder<U>(first, second)) {
// remainder of the bottom row
list.push_back( Rectangle<U>(second.x, first.y,
second.w, second.y - first.y));
}
}
}
#endif

View File

@ -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

34
math/weighted_set.cpp Normal file
View File

@ -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 <iostream>
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;
}*/

20
math/weighted_set.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef WEIGHTED_SET_H
#define WEIGHTED_SET_H
#include <vector>
#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<unsigned int> elements;
Random rng;
};
}
#endif

View File

@ -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 <cassert>
#include <iostream>
#include <sstream>
#include <iomanip>
#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<void*>(&x), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&y), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&w), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&h), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&sam), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&name), 30, 1);
// seek over the name embedded in the mapfile; use sample-num to
// lookup in msg-db
//PHYSFS_read(fd, static_cast<void*>(&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<PHYSFS_uint16, Sector*>(sec->getSize(), sec));
}
}
// dummy catch-all sector for gta london maps
areas.insert(std::pair<PHYSFS_uint16, Sector*>(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;

View File

@ -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 <map>
#include <string>
#include <physfs.h>
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:

1
ogta_version Normal file
View File

@ -0,0 +1 @@
2007-04-16

View File

@ -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;
};

View File

@ -0,0 +1,30 @@
OpenSteer -- Steering Behaviors for Autonomous Characters
Copyright (c) 2002-2005, Sony Computer Entertainment America
Original author: Craig Reynolds <craig_reynolds@playstation.sony.com>
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.

View File

@ -0,0 +1,205 @@
// ----------------------------------------------------------------------------
//
//
// OpenSteer -- Steering Behaviors for Autonomous Characters
//
// Copyright (c) 2002-2005, Sony Computer Entertainment America
// Original author: Craig Reynolds <craig_reynolds@playstation.sony.com>
//
// 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 <xtl.h>
#elif defined (_WIN32)
#include <windows.h>
#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

View File

@ -0,0 +1,337 @@
// ----------------------------------------------------------------------------
//
//
// OpenSteer -- Steering Behaviors for Autonomous Characters
//
// Copyright (c) 2002-2005, Sony Computer Entertainment America
// Original author: Craig Reynolds <craig_reynolds@playstation.sony.com>
//
// 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 <algorithm>
#include <vector>
#include "OpenSteer/Vec3.h"
#include "OpenSteer/lq.h" // XXX temp?
namespace OpenSteer {
// ----------------------------------------------------------------------------
// "tokens" are the objects manipulated by the spatial database
template <class ContentType>
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<ContentType>& 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 ContentType>
class AbstractProximityDatabase
{
public:
// type for the "tokens" manipulated by this spatial database
typedef AbstractTokenForProximityDatabase<ContentType> 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 ContentType>
class BruteForceProximityDatabase
: public AbstractProximityDatabase<ContentType>
{
public:
// constructor
BruteForceProximityDatabase (void)
{
}
// destructor
virtual ~BruteForceProximityDatabase ()
{
}
// "token" to represent objects stored in the database
class tokenType : public AbstractTokenForProximityDatabase<ContentType>
{
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<ContentType>& 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<tokenType*> 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 ContentType>
class LQProximityDatabase : public AbstractProximityDatabase<ContentType>
{
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<ContentType>
{
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<ContentType>& 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<ContentType> 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

View File

@ -0,0 +1,514 @@
// ----------------------------------------------------------------------------
//
//
// OpenSteer -- Steering Behaviors for Autonomous Characters
//
// Copyright (c) 2002-2005, Sony Computer Entertainment America
// Original author: Craig Reynolds <craig_reynolds@playstation.sony.com>
//
// 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 <iostream> // for ostream, <<, etc.
#include <cstdlib> // for rand, etc.
#include <cfloat> // for FLT_MAX, etc.
#include <cmath> // for sqrt, etc.
#include <vector> // for std::vector
#include <cassert> // for assert
#include <limits> // 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<class T> 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<class T>
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 <cmath>
// 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 <code>value</code> if <code>value >= 0 </code>, otherwise
* <code>-value</code>.
*/
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 <code>abs( lhs - rhs ) <= tolerance</code>
*
* @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 <code>abs( lhs - rhs ) <= tolerance * max( abs( lhs ), abs( rhs ), 1 )</code>
*
* @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 <code>abs( lhs - rhs ) <= tolerance * ( abs( lhs ) + abs( rhs ) + 1 )</code>
*
* @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

View File

@ -0,0 +1,382 @@
// ----------------------------------------------------------------------------
//
//
// OpenSteer -- Steering Behaviors for Autonomous Characters
//
// Copyright (c) 2002-2005, Sony Computer Entertainment America
// Original author: Craig Reynolds <craig_reynolds@playstation.sony.com>
//
// 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

View File

@ -0,0 +1,96 @@
// ----------------------------------------------------------------------------
//
//
// OpenSteer -- Steering Behaviors for Autonomous Characters
//
// Copyright (c) 2002-2005, Sony Computer Entertainment America
// Original author: Craig Reynolds <craig_reynolds@playstation.sony.com>
//
// 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

View File

@ -0,0 +1,323 @@
/*
// ----------------------------------------------------------------------------
//
//
// OpenSteer -- Steering Behaviors for Autonomous Characters
//
// Copyright (c) 2002-2005, Sony Computer Entertainment America
// Original author: Craig Reynolds <craig_reynolds@playstation.sony.com>
//
// 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 */

View File

@ -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.

310
opensteer/src/Clock.cpp Normal file
View File

@ -0,0 +1,310 @@
// ----------------------------------------------------------------------------
//
//
// OpenSteer -- Steering Behaviors for Autonomous Characters
//
// Copyright (c) 2002-2005, Sony Computer Entertainment America
// Original author: Craig Reynolds <craig_reynolds@playstation.sony.com>
//
// 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 <xtl.h>
#elif defined (_WIN32)
#include <windows.h>
#else
#include <sys/time.h>
#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
// ----------------------------------------------------------------------------

213
opensteer/src/Vec3.cpp Normal file
View File

@ -0,0 +1,213 @@
// ----------------------------------------------------------------------------
//
//
// OpenSteer -- Steering Behaviors for Autonomous Characters
//
// Copyright (c) 2002-2005, Sony Computer Entertainment America
// Original author: Craig Reynolds <craig_reynolds@playstation.sony.com>
//
// 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;
}
// ----------------------------------------------------------------------------

View File

@ -0,0 +1,88 @@
/**
* OpenSteer -- Steering Behaviors for Autonomous Characters
*
* Copyright (c) 2002-2005, Sony Computer Entertainment America
* Original author: Craig Reynolds <craig_reynolds@playstation.sony.com>
*
* 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 <bknafla@uni-kassel.de>
*/
#include "OpenSteer/Vec3Utilities.h"
// Include assert
#include <cassert>
// 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 ) );
}

712
opensteer/src/lq.c Normal file
View File

@ -0,0 +1,712 @@
/*
// ----------------------------------------------------------------------------
//
//
// OpenSteer -- Steering Behaviors for Autonomous Characters
//
// Copyright (c) 2002-2005, Sony Computer Entertainment America
// Original author: Craig Reynolds <craig_reynolds@playstation.sony.com>
//
// 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 <stdlib.h>
#include <float.h>
#include <limits.h> /* 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; i<bincount; i++) lq->bins[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; i<bincount; i++)
{
lqMapOverAllObjectsInBin (lq->bins[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; i<bincount; i++)
{
/* clear the counter */
int objectCount = 0;
/* apply counting function to each object in bin[i] */
lqMapOverAllObjectsInBin (lq->bins[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; i<bincount; i++)
{
lqRemoveAllObjectsInBin (lq->bins[i]);
}
lqRemoveAllObjectsInBin (lq->other);
}
/* ------------------------------------------------------------------ */

View File

@ -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 <SDL.h>
#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<uint8_t, uint32_t> 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

View File

@ -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 <<EOF >_out_$$.cpp
#include <SDL.h>
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 <<EOF >_out_$$.cpp
#include <SDL_mixer.h>
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 <<EOF >_out_$$.cpp
#include <SDL_sound.h>
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
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 <<EOF
// WIN32 already defined when cross-compiling...
#ifndef $OGTA_PLATFORM
#define $OGTA_PLATFORM
#endif
// to avoid some errors on prg-exit
#define LOKI_FUNCTOR_IS_NOT_A_SMALLOBJECT
// platform specific switches
#ifdef LINUX
#define OGTA_PLATFORM_INFO "linux"
// for coldet; FIXME: really only for linux?
#define GCC
#elif WIN32
#define OGTA_PLATFORM_INFO "win32"
#else
#error(No platform defined)
#endif
// global compile-time vars
#define OGTA_VERSION_INFO "$LAST_TOUCHED"
#define DEFAULT_SCREEN_WIDTH 640
#define DEFAULT_SCREEN_HEIGHT 480
#define OGTA_DEFAULT_DATA_PATH "gtadata.zip"
#define OGTA_DEFAULT_MOD_PATH ""
#define OGTA_DEFAULT_HOME_PATH PHYSFS_getBaseDir()
#define USED_GCC_VERSION "$GCC_VERSION"
// enable features
#define DO_SCALEX
#undef WITH_LUA
$SDL_SOUND_MIXER
$SDL_GL_SWAP_CONTROL
EOF
}
if [[ -n "$1" && "$1" != "LINUX" ]]; then
OGTA_PLATFORM=WIN32
echo "*** WIN32 ***"
DEFS="-include config.h"
check_compiler
print_w32settings > 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

View File

@ -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) {

View File

@ -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. *

View File

@ -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 <stdio.h>
#include <iostream>
#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<std::string, std::string>::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<std::string, std::string>::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<char*>(&tmp), 10, "%i", id);
std::map<std::string, std::string>::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;

View File

@ -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<PHYSFS_uint64>(_topHeaderSize) +
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize +
pagedClutSize + paletteIndexSize + objectInfoSize;
//INFO << "seek for " << st << std::endl;
loadCarInfo_shared(st);
}

View File

@ -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; j<animation->frameCount; j++) {
uint8_t val;
PHYSFS_read(fd, static_cast<void*>(&val), 1, 1);
animation->frame.push_back(val);
animation->frame[j] = val;
//PHYSFS_read(fd, static_cast<void*>(&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);

View File

@ -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 <iostream>
#include <string>
#include <map>
#include <stdlib.h>
#include <physfs.h>
#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<PHYSFS_uint32, PHYSFS_sint64> 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<char*>(&buffer);
levels[static_cast<PHYSFS_uint32>(atoi(buffer))] = PHYSFS_tell(fd) + 1;
std::cout << buffer << " " << PHYSFS_tell(fd) + 1 << std::endl;
}
}
if (v == '[') {
m = 1;
}
}
*/
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<void*>(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<PHYSFS_uint32>(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)<<std::endl;
//std::cout <<"["<< line_start << "]" << strlen(line_start)<<std::endl;
if (num_lines_read == 0)
//std::cout << "level: " << line_start << std::endl;
section_info = line_start;
else if (num_lines_read == 1)
//std::cout << "vars: " << line_start << std::endl;
section_vars = line_start;
else {
if (strncmp(line_start, "-1", 2) == 0)
first_part_of_section = false;
else {
if (first_part_of_section)
acceptDefinition(line_start);
else
acceptCommand(line_start);
}
}
++num_lines_read;
}
line_start = line_end + 1;
if (*line_start == '\n')
@ -94,16 +173,25 @@ namespace OpenGTA {
else
break;
}
typedef unsigned int uint32;
//std::cout << uint32(line_start) - uint32(buffer) << std::endl;
PHYSFS_uint32 begin_rest = PHYSFS_uint32(line_start) - PHYSFS_uint32(buffer);
offset = 255 - begin_rest;
memmove(buffer, &buffer[begin_rest], 255 - begin_rest);
read_bytes = 255 - offset;
offset = buf_len - begin_rest;
memmove(buffer, &buffer[begin_rest], buf_len - begin_rest);
read_bytes = buf_len - offset;
if (PHYSFS_tell(fd) + read_bytes > 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

28
read_ini.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef READ_INI_H
#define READ_INI_H
#include <string>
#include <map>
#include <stdlib.h>
#include <physfs.h>
namespace OpenGTA {
class ScriptParser {
public:
ScriptParser(const std::string &file);
virtual ~ScriptParser();
void loadLevel(PHYSFS_uint32 level);
private:
typedef std::map<PHYSFS_uint32, PHYSFS_sint64> 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

View File

@ -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 *

View File

@ -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'

205
release_files_sorted Normal file
View File

@ -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

View File

@ -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 <iostream>
#include <sstream>
#include <SDL_opengl.h>
@ -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;
}
}

View File

@ -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 *
@ -26,8 +26,10 @@
#include "spritemanager.h"
#include "log.h"
#include "timer.h"
#include "id_sys.h"
namespace OpenGTA {
//SpriteManager::SpriteManager() : trainSystem(AbstractContainer<TrainSegment>::objs){
SpriteManager::SpriteManager() {
drawMode = (1);
@ -44,16 +46,36 @@ namespace OpenGTA {
//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(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(
@ -64,6 +86,8 @@ namespace OpenGTA {
registerAnimation(18, SpriteObject::Animation(
registerAnimation(19, SpriteObject::Animation(
*/
registerAnimation(99, SpriteObject::Animation(0, 12));
registerAnimation(100, SpriteObject::Animation(12, 12));
}
SpriteManager::~SpriteManager() {
clear();
@ -71,6 +95,7 @@ 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;
@ -87,60 +112,143 @@ namespace OpenGTA {
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<Pedestrian>::Storage_T_Iterator i = AbstractContainer<Pedestrian>::objs.begin();
i != AbstractContainer<Pedestrian>::objs.end(); ++i) {
Pedestrian & ped = (*i);
ped.update(ticks);
num_peds++;
}
num_cars = 0;
for (AbstractContainer<Car>::Storage_T_Iterator i = AbstractContainer<Car>::objs.begin();
i != AbstractContainer<Car>::objs.end(); ++i) {
Car & car = (*i);
car.update(ticks);
num_cars++;
}
for (AbstractContainer<SpriteObject>::Storage_T_Iterator i = AbstractContainer<SpriteObject>::objs.begin();
i != AbstractContainer<SpriteObject>::objs.end(); ++i) {
SpriteObject & obj = (*i);
obj.update(ticks);
num_obj++;
if (obj.isActive == false)
AbstractContainer<SpriteObject>::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<Pedestrian>(p);
break;
}
}
}
void SpriteManager::drawInRect(SDL_Rect & r) {
for (PedListType::iterator i = activePeds.begin(); i != activePeds.end(); ++i) {
for (AbstractContainer<Pedestrian>::Storage_T_Iterator i = AbstractContainer<Pedestrian>::objs.begin();
i != AbstractContainer<Pedestrian>::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<SpriteObject>::Storage_T_Iterator i = AbstractContainer<SpriteObject>::objs.begin();
i != AbstractContainer<SpriteObject>::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<Car>::Storage_T_Iterator i = AbstractContainer<Car>::objs.begin();
i != AbstractContainer<Car>::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<T>::objs.clear(); \
AbstractContainer<T>::toBeRemoved.clear(); \
}
TYPED_CLEANUP(Pedestrian);
TYPED_CLEANUP(Car);
TYPED_CLEANUP(SpriteObject);
//TYPED_CLEANUP(TrainSegment);
activeProjectiles.clear();
/*
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);
#undef TYPED_CLEANUP
}
*/
#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)
//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) {
void SpriteManager::draw(Car & car) {
GL_OBJ_COMMON(car);
GraphicsBase & style = StyleHolder::Instance().get();
OpenGL::PagedTexture t;
@ -158,38 +266,42 @@ namespace OpenGTA {
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);
DRAW_TEX_QUADS_OBJ(t, w, h);
glEnd();
if (getDrawBBox() || getDrawTexBorder())
glDisable(GL_TEXTURE_2D);
if (getDrawBBox()) {
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(-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);
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(-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);
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();
}
if (getDrawTexBorder()) {
glDisable(GL_TEXTURE_2D);
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);
@ -200,13 +312,11 @@ namespace OpenGTA {
glEnd();
glColor3f(1.0f, 1.0f, 1.0f);
}
glEnable(GL_TEXTURE_2D);
glPopMatrix();
GL_CHECKERROR;
void SpriteManager::draw(SpriteObject & obj) {
if (obj.sprType == GraphicsBase::SpriteNumbers::EX) {
return drawExplosion(obj);
}
void SpriteManager::drawObject(GameObject & obj) {
GL_OBJ_COMMON(obj);
GraphicsBase & style = StyleHolder::Instance().get();
OpenGL::PagedTexture t;
@ -224,78 +334,30 @@ namespace OpenGTA {
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);
DRAW_TEX_QUADS_OBJ(t, w, h);
glEnd();
if (getDrawBBox() || getDrawTexBorder())
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);
}
if (getDrawBBox())
drawBBoxOutline(obj);
if (getDrawTexBorder())
drawTextureOutline(w, h);
if (getDrawBBox() || getDrawTexBorder())
glEnable(GL_TEXTURE_2D);
glPopMatrix();
GL_CHECKERROR;
}
void SpriteManager::drawPed(Pedestrian & ped) {
void SpriteManager::draw(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);
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 +
ped.anim.firstFrameOffset + ped.anim.currentFrame, ped.sprType);
@ -305,7 +367,6 @@ namespace OpenGTA {
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 {
@ -313,6 +374,170 @@ namespace OpenGTA {
ped.anim.firstFrameOffset + ped.anim.currentFrame,
ped.sprType, ped.remap);
}
DRAW_TEX_QUADS_OBJ(t, w, h);
if (getDrawBBox() || getDrawTexBorder())
glDisable(GL_TEXTURE_2D);
if (getDrawBBox())
drawBBoxOutline(ped);
if (getDrawTexBorder())
drawTextureOutline(w, h);
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);
@ -326,34 +551,39 @@ namespace OpenGTA {
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();
glPopMatrix();
GL_CHECKERROR;
}
if (getDrawTexBorder()) {
*/
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_LINE_STRIP);
glColor3f(float(202)/255.0f, float(31)/255.0f, float(123)/255.0f);
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);
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);
}
@ -369,6 +599,17 @@ namespace OpenGTA {
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()) {
@ -402,6 +643,14 @@ namespace OpenGTA {
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()) {
@ -413,10 +662,20 @@ namespace OpenGTA {
assert(0);
return *activeObjects.begin();
}
*/
void SpriteManager::removeDeadStuff() {
AbstractContainer<Pedestrian>::doRealRemove();
AbstractContainer<Car>::doRealRemove();
AbstractContainer<SpriteObject>::doRealRemove();
}
SpriteObject::Animation & SpriteManager::getAnimationById(const Uint32 & id) {
AnimLookupType::iterator i = animations.find(id);
assert(i != animations.end());
if (i == animations.end()) {
ERROR << "Failed to find anim id: " << id << std::endl;
return animations.begin()->second;
}
return i->second;
}
@ -442,7 +701,15 @@ namespace OpenGTA {
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::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);
}
}

View File

@ -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 <list>
#include <map>
#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<TrainSegment> TrainListType;
protected:
typedef std::list<Pedestrian> PedListType;
PedListType activePeds;
@ -76,11 +88,102 @@ namespace OpenGTA {
ObjectListType activeObjects;
typedef std::list<Projectile> ProjectileListType;
ProjectileListType activeProjectiles;
TrainListType activeTrains;
public:
TrainSystem trainSystem;
protected:
typedef std::map<Uint32, SpriteObject::Animation> AnimLookupType;
AnimLookupType animations;
private:
Uint32 drawMode;
};
#endif
class SpriteManager :
public AbstractContainer<Pedestrian>,
public AbstractContainer<Car>,
public AbstractContainer<SpriteObject> { //,
//public AbstractContainer<TrainSegment> {
public:
~SpriteManager();
void drawInRect(SDL_Rect & r);
void clear();
void removeDeadStuff();
template <typename T> T & add(const T & t) {
return AbstractContainer<T>::doAdd(t);
}
template <typename T> size_t getNum() {
return AbstractContainer<T>::objs.size();
}
inline Pedestrian & getPed(uint32_t id) {
return AbstractContainer<Pedestrian>::doGet(id);
}
inline Car & getCar(uint32_t id) {
return AbstractContainer<Car>::doGet(id);
}
inline SpriteObject & getObject(uint32_t id) {
return AbstractContainer<SpriteObject>::doGet(id);
}
/*
inline TrainSegment & getTrain(uint32_t id) {
return AbstractContainer<TrainSegment>::doGet(id);
}*/
template <typename T> inline std::list<T> & getList() {
return AbstractContainer<T>::objs;
}
inline void removePed(uint32_t id) {
AbstractContainer<Pedestrian>::doRemove(id);
}
inline void removeCar(uint32_t id) {
AbstractContainer<Car>::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<Uint32, SpriteObject::Animation> AnimLookupType;
AnimLookupType animations;
typedef std::list<Projectile> ProjectileListType;
ProjectileListType activeProjectiles;
private:
Uint32 drawMode;
//SpriteManager(const SpriteManager & o) : trainSystem(AbstractContainer<TrainSegment>::objs) {assert(0);}
SpriteManager(const SpriteManager & o) {assert(0);}
};
typedef Loki::SingletonHolder<SpriteManager, Loki::CreateUsingNew,
Loki::DefaultLifetime, Loki::SingleThreaded> SpriteManagerHolder;

160
tests/interpolate_test.cpp Normal file
View File

@ -0,0 +1,160 @@
#include <iostream>
#include <getopt.h>
#include "interpolate.hpp"
using namespace std;
void run_linear(int numSteps) {
float y1, y2;
cin >> y1;
cin >> y2;
Math::Interpolator::Linear<float> 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<float> 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<float> 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<float> 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;
}
}

542
tests/menudemo.cpp Normal file
View File

@ -0,0 +1,542 @@
#include <iostream>
#include <sstream>
#include <SDL_image.h>
#include <SDL_opengl.h>
#include <unistd.h>
#include <physfs.h>
#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<size_t, OpenGL::PagedTexture>(k, ImageUtil::loadImageRAW(file)));
}
void Manager::cacheImageRAT(const std::string & file, const std::string & palette, size_t k) {
texCache.insert(std::make_pair<size_t, OpenGL::PagedTexture>(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<size_t, OpenGL::PagedTexture>(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<size_t, OpenGL::PagedTexture>(
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<uint8_t, GuiObjectList>(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<uint16_t> & indices, uint16_t fps, size_t k) {
Animation * anim = new Animation(indices, fps);
guiAnimations.insert(std::make_pair<size_t, Animation*>(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<uint16_t> 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<uint16_t> 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

51
tests/new_obj_test.cpp Normal file
View File

@ -0,0 +1,51 @@
#include "log.h"
#include "game_objects.h"
#include "abstract_container.h"
using namespace OpenGTA;
class ConcreteContainer :
public AbstractContainer<Pedestrian>,
public AbstractContainer<Car> {
public:
template <typename T> void add(const T & t) {
AbstractContainer<T>::doAdd(t);
}
Car & getCar(uint32_t id) {
return AbstractContainer<Car>::doGet(id);
}
Pedestrian & getPed(uint32_t id) {
return AbstractContainer<Pedestrian>::doGet(id);
}
void removeCar(uint32_t id) {
AbstractContainer<Car>::doRemove(id);
}
void removePed(uint32_t id) {
AbstractContainer<Pedestrian>::doRemove(id);
}
void realRemove() {
AbstractContainer<Car>::doRealRemove();
AbstractContainer<Pedestrian>::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);
}

View File

@ -1,4 +1,5 @@
#include <SDL.h>
#define USE_RWOPS
#include <SDL_sound.h>
#include <SDL_mixer.h>
#include <string>
@ -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<len;i++) stream[i]=0;
} /* if */
} /* myMusicPlayer */
#endif
#include "fx_sdt.h"
#include "sound_resample.h"
#include "sound_resample2.h"
class AudioChunkCache {
public:
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) {}
};
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<ChunkId, ChunkData>(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);

View File

@ -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

View File

@ -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;
}

70
train_system.cpp Normal file
View File

@ -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<TrainSegment> & list) :
stations(),
segments(list) {
numTrains = 0;
}
TrainSystem::~TrainSystem() {
stations.clear();
}
void TrainSystem::update(Uint32 now_ticks) {
}
void TrainSystem::loadStations(Map & map) {
std::list<CellIterator> 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);
}
}
*/
}

50
train_system.h Normal file
View File

@ -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<TrainSegment> & 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<Util::CellIterator> stations;
std::list<TrainSegment> & segments;
};
*/
}
#endif

88
util/abstract_container.h Normal file
View File

@ -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 <string>
#include <list>
#include <sstream>
#include "m_exceptions.h"
template <class T>
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<T> Storage_T;
Storage_T objs;
typedef typename std::list<T>::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 <class T>
void AbstractContainer<T>::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 <class T>
void AbstractContainer<T>::doRemove(uint32_t id) {
typename Storage_T::iterator i = findById(id);
toBeRemoved.push_back(i);
}
template <class T>
T & AbstractContainer<T>::doGet(uint32_t id) {
typename Storage_T::iterator i = findById(id);
return *i;
}
template <class T>
typename std::list<T>::iterator AbstractContainer<T>::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

View File

@ -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 <sstream>
#include "animation.h"
#include "m_exceptions.h"

View File

@ -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 <vector>
@ -6,6 +28,13 @@
namespace Util {
/** 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 {
@ -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<void> CallbackType;

64
util/cell_iterator.cpp Normal file
View File

@ -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));
}
}

100
util/cell_iterator.h Normal file
View File

@ -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 <cassert>
#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

View File

@ -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 <cstdlib>
#include <physfs.h>
#include <sstream>
#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;
}
}

View File

@ -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;

Some files were not shown because too many files have changed in this diff Show More