diff --git a/ai.cpp b/ai.cpp new file mode 100644 index 0000000..75432dd --- /dev/null +++ b/ai.cpp @@ -0,0 +1,52 @@ +#include +#include "ai.h" +#include "opengta.h" +#include "game_objects.h" +#include "cell_iterator.h" +#include "log.h" + +namespace OpenGTA { + namespace AI { + namespace Pedestrian { + void walk_pavement(OpenGTA::Pedestrian* ped) { + assert(ped); + Util::CellIterator ci(ped->pos); + if (!ci.isValid()) + return; + OpenGTA::Map::BlockInfo & bi = ci.getBlock(); + //INFO << " ped in bt: " << int(bi.blockType()) << std::endl; + //INFO << ped->pos.x << " " << ped->pos.z << std::endl; + std::pair f = ci.findNeighbourWithType(3, ped->rot); + if (f.first) { + //INFO << "next: " << f.second.x << " " << f.second.y << std::endl; + ped->aiData.pos1 = Vector3D(f.second.x+0.5f, ped->pos.y, f.second.y+0.5f); + ped->aiMode = 1; + } + } + + void moveto_shortrange(OpenGTA::Pedestrian *ped) { + assert(ped); + float d = Util::distance(ped->pos, ped->aiData.pos1); + //INFO << "dist: " << d << std::endl; + float a = Util::xz_turn_angle(ped->pos, ped->aiData.pos1); + float da = Util::xz_angle(ped->pos, ped->aiData.pos1); + //INFO << a << std::endl; + //INFO << "rot " << ped->rot << std::endl; + ped->m_control.setMoveForward(false); + ped->m_control.setTurnLeft(false); + ped->m_control.setTurnRight(false); + //INFO << ped->rot + a << std::endl; + if (fabs(ped->rot - da) > 5) { + if (a > 0) + ped->m_control.setTurnLeft(true); + else + ped->m_control.setTurnRight(true); + } + if (fabs(ped->rot - da) < 120 && d > 0.19f) + ped->m_control.setMoveForward(true); + if (d <= 0.19f) + ped->aiMode = 0; + } + } + } +} diff --git a/ai.h b/ai.h new file mode 100644 index 0000000..5370895 --- /dev/null +++ b/ai.h @@ -0,0 +1,16 @@ +#ifndef OGTA_AI_H +#define OGTA_AI_H + +namespace OpenGTA { + class Pedestrian; + + namespace AI { + namespace Pedestrian { + void walk_pavement(OpenGTA::Pedestrian*); + void moveto_shortrange(OpenGTA::Pedestrian*); + void move_away(OpenGTA::Pedestrian*); + } + } +} + +#endif diff --git a/blockdata.h b/blockdata.h index a29e07e..acb80ec 100644 --- a/blockdata.h +++ b/blockdata.h @@ -39,9 +39,9 @@ namespace OpenGTA { Loki::DefaultLifetime, Loki::SingleThreaded> BlockDataHolder; } -#define SLOPE_RAW_DATA BlockDataHolder::Instance().slope_raw_data -#define SLOPE_TEX_DATA BlockDataHolder::Instance().slope_tex_data -#define LID_NORMAL_DATA BlockDataHolder::Instance().lid_normal_data +#define SLOPE_RAW_DATA OpenGTA::BlockDataHolder::Instance().slope_raw_data +#define SLOPE_TEX_DATA OpenGTA::BlockDataHolder::Instance().slope_tex_data +#define LID_NORMAL_DATA OpenGTA::BlockDataHolder::Instance().lid_normal_data #endif diff --git a/bugs.rec b/bugs.rec index 407e6d0..2bfcb6e 100644 --- a/bugs.rec +++ b/bugs.rec @@ -1,19 +1,72 @@ Bug: style001.gry bridge texture artifacts -Image: http://skybound.portland.co.uk/ogta/bugs_in_transparent_texture_2006-10-03.jpg +Image: http://picasaweb.google.com/under.northern.sky/OpenGTAScreenshots/photo#5015284379944604402 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 +Image: http://picasaweb.google.com/under.northern.sky/OpenGTAScreenshots/photo#5015284384239571746 +Status: maybe-closed Most likely the side that is a triangle and not a quad. Needs research if 'flipping' the texture is related. + +Update: fixed for the case shown in the screenshot; may lurk on north/south sides of +blocks, flipping/rotation influence remains unknown. %% 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 +Image: http://picasaweb.google.com/under.northern.sky/OpenGTAScreenshots/photo#5052612481245901378 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 +Image: http://picasaweb.google.com/under.northern.sky/OpenGTAScreenshots/photo#5052612481245901394 Simply doesn't look good, especially with g24 graphics. %% +Bug: wrong-player position in viewer.exe when switching from free mode (F4) +A position somewhat ~north~ is actually used; if you are at the north-border of the +city this can cause the player to be spawned outside 0->255 ^2 range, which exits +the program. +%% +Bug: wrong walk/run animations when armed +Switching between forward/backward/run often changes the weapon as well; walking +forward with the gun doesn't work at all. +%% +Bug: scale2x disabled in all previous releases +The script prepare_build.sh defines -DDO_SCALEX while the code actually is +activated by -DDO_SCALE2X; errare humanum est. + +This bug will be closed when the next release includes this feature; otherwise +see cvs. +%% +Bug: switching to/from fullscreen (at runtime) is broken on Windows (again?) +Most polygons are plain white, some strange rendering errors appear as well; +aka. oh gl-context, where did all my textures go? + +Does this affect switching the screen resolution as well? Probably :-( +%% +Bug: vertical sync - SDL_GL_SWAP_CONTROL +Does not work in the Win32 binaries, the SDL version I used is too old. + +Stopped doing anything on at least my Linux system (after an update) as well. +%% +Bug: Data _or_ interpretation - block type +Image: http://picasaweb.google.com/under.northern.sky/OpenGTAScreenshots/photo#5060057403938727394 +Several problems may stem from the 'flags stored in block above the one with the graphic' gta- +legacy. The symptom is: you can fall through some floor blocks! + +Probably several cases exist; either a bug in my code or some quirk of the map format. +%% +Bug: Collision with 'flat' blocks +Partially transparent blocks (sign posts, fence, etc.) need special rules to handle +blocking of peds/projectiles/car; implemented only for peds. + +Furthermore only works on nyc.cmp, need to research the tile-ids for the other style +files. +FIXME: which blocks should _not_ block projectiles? +%% +Bug: Pedestrian movement physics + +1) Moving up/down on a slope should influence speed + +2) You can walk up a single vertical wall (can be seen when walking on roofs; +probably also teleports to the upper road when under the bridges in nyc.cmp. +%% diff --git a/coldet/math3d.cpp b/coldet/math3d.cpp index fcc4fb9..7a0fb35 100644 --- a/coldet/math3d.cpp +++ b/coldet/math3d.cpp @@ -93,9 +93,17 @@ void Matrix3D::Translate(const Vector3D & v) } void Matrix3D::RotZ(float angle) { - const float TO_RAD = M_PI / 180.0f; + const float c = cosf(angle * M_PI / 180.0f); + const float s = sinf(angle * 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); +*/ + m[0][0] = c; + m[2][2] = c; + m[0][2] = s; + m[2][0] = -s; + } diff --git a/coldet/math3d.h b/coldet/math3d.h index a31d6c3..47d9a73 100644 --- a/coldet/math3d.h +++ b/coldet/math3d.h @@ -93,11 +93,14 @@ struct Matrix3 }; static const Matrix3 Identity; - Vector3D& baseRow(int i) { return *((Vector3D*)m[i]); } + //Vector3D& baseRow(int i) { return *((Vector3D*)m[i]); } float operator() (int i, int j) const { return m[i][j]; } float& operator() (int i, int j) { return m[i][j]; } }; +Matrix3D PitchMatrix3D(const float theta); +Matrix3D YawMatrix3D(const float theta); +Matrix3D RollMatrix3D(const float theta); struct Matrix3D { union { @@ -127,9 +130,11 @@ struct Matrix3D return *this = *this * m; } +/* friend Matrix3D PitchMatrix3D(const float theta); friend Matrix3D YawMatrix3D(const float theta); friend Matrix3D RollMatrix3D(const float theta); +*/ void rotate(const Vector3D& v); Matrix3D Inverse() const; diff --git a/cvs_changelog.txt b/cvs_changelog.txt new file mode 100644 index 0000000..927925e --- /dev/null +++ b/cvs_changelog.txt @@ -0,0 +1,134 @@ +2007-06-14 skyb + +* fixes for win32 build + +* updated bugs, documentation, build system +* preparing to change key input handling + +2007-05-30 skyb + +* added WGL swap interval feature +* spriteplayer: try anim feature; updated docs +* luaviewer: read config file +* experimental parts of in-game gui +* playing around with basic ped ai +* environment variable influences language file +* updated docs; added author of code fragment to license + +2007-05-17 skyb + +* derived EntityController registers state change +* rotation fixes +* fixes concerning weapons + moving +* car deltas: damage, doors, lights +* more about "shooting" (hit, damage, explode cars); +col-det tries to find angle for peds (still always the same anim) +* fix: choose correct sprType for non-CAR types (bike, bus, train) +* gui: drawing a string right-to-left +* Map::BlockInfo partial setXXX() functionality +* choose fxt language file (not hardcoded to english anymore) +* 'viewer' screen-gamma in game +* updated usage & version info +* code cleanup + +2007-04-30 skyb + +* updated bugs list; fixed image links +* vsync options: none, sdl, glx +* uses anisotropic texture filtering if extension is supported +* viewer config options for above (and mipmap & scale2x) +* playing around with car-data +* cars block ped movement + +2007-04-25 skyb + +A number of helpers: +* project housekeeping +* data dumper tool for cars +* fxt <-> txt converter (txt -> fxt partially working) +* build_svg_rect: visually verify Rectangle operations +* raw_image: generate information about gui 2d art + +* projectile-wall collisions should now work on all tiles; minus: z-info, +non-blocking ids +* test code for block-type; minimap nows exports several bmps, viewer +shows colored lines + +2007-04-23 skyb + +* main feature: projectile hits walls; flat case not working correctly +* (partially?) fixed the triangle-slope texture bug; top/bottom sides? +* gui.h/cpp is included, moved code into image_loader for reuse + +2007-04-16 skyb + +fix: allowing 24 bit color depth + +really unimportant fixes + +contains the code release date; may not be accurate in cvs but will serve +as a kind of version-number for actual releases. + +removing dependency on unused code + +* feature: animated block textures +* switching from GL matrix to calculations for obj position +* collision: projectile + pedestrian +* unique id generator +* other helpers (not really used so far) + +2007-04-12 skyb + +Fixes, cleanup and new helpers... little new features: +* prototype sounds: play fx, play music +* many peds on map, running randomly around player + +2007-02-25 skyb + +* screen: try to guess color depth from bpp +(fixes hang on < 32 bit x11 displays) +* missing code from last commit + +fix: lookup now gets level number; should work for all gta1 maps + +* build script should detect if SDL_GL_SWAP_CONTROL is defined (by SDL +>= 1.2.10) +* sdl_init & videomode: check for errors + +* sector name from message db +* initial projectile support +* minor game_object updates + +2007-02-17 skyb + +* abstract_container: return (reference to copy of) added T +* enable weapons selection/animation +* more screen config options +* gui-object cleanup +* file_helper: load vfs into mem (for Lua) +* spriteplayer: update to new version (compiles again) + camera hack +(gravity doubles +as y-scroll switch) +* build-system: config.h instead of -D defines; related changes +* coldet/opensteer in license.txt + +2007-02-16 skyb + +* each explosion plays once and gets removed +* FIXME: at high framerates there is a visible delay when the textures +aren't loaded + +* rewrote spritemanager & game objects +* some other fixes +* assorted helpers; sometimes even with testcase, generally not used at +this time + +A first halfway working version; some older features are broken, +it may even compile (right now). + +2007-01-09 skyb + +Importing src release 2006-12-10 + +Initial revision + diff --git a/dataholder.cpp b/dataholder.cpp index e0e73c8..c1bf89e 100644 --- a/dataholder.cpp +++ b/dataholder.cpp @@ -116,6 +116,7 @@ namespace OpenGTA { template<> void MainMsgLookup::load(const std::string & file) { unload(); try { + INFO << "Trying to load: " << file << std::endl; m_data = new MessageDB(file); } catch (const Exception & e) { diff --git a/doc/compiling.txt b/doc/compiling.txt new file mode 100644 index 0000000..ad1817c --- /dev/null +++ b/doc/compiling.txt @@ -0,0 +1,53 @@ += What happens when you call 'make' = + +The main makefile checks the env-variable 'HOST'; +which is assumed to be "LINUX" or "WIN32", the latter actually being +used to indicate cross-compiling using a mingw-toolchain. + +The main makefile checks if the 'Loki'-library is already there; +if not 'wget's it and calls loki.make(.w32_cross) to build it. + +It then looks for a file named src_list.make; if that does not exist +it calls "prepare_build.sh $HOST" which generates both src_list.make +and config.h. + +The script will only work on Linux where it will use pkg-config to +find the libraries; I hardcoded many Win32 values pointing to my +toolchain and library pathes. + +Make now includes src_list.make and builds the default targets; +there are more programs that can be build with an explicit +"make $program_name"; look at src_list.make. + +If you need to setup compiler/library paths src_list.make is the +place to do it. Then run make again. + + += Features in config.h = + +DO_SCALE2X +Enable scale2x algorithm; so far only used for sprites, on if enabled. + +HAVE_SDL_VSYNC +Does the SDL header define SDL_GL_SWAP_CONTROL? Must be #undef-ined if +not, may be undefined anyway (turn feature off) and it really depends +whether the driver supports it (at runtime). + +In the future a number of WITH_* defines will be used to enable +support for library-dependent features (Lua, SDL_sound + SDL_mixer, +SDL_image). For the moment only the Lua related flag changes 'viewer', +the other features are only used in testcases. + +DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT +The initial screen size (unless otherwise defined); defaults to 640x480 +if not defined. + +DEFAULT_SCREEN_VSYNC +Default setting for vsync;can be one of 0, 1, 2 + +On Linux you can colorify the log-output by defining LOG_USE_ANSI_COLORS. + += If you modify the code yourself = + +Note: the dependency system is somewhat broken, sometimes changes in +header files are ignored; either "make clean" or "touch config.h". diff --git a/doc/ped_remaps.txt b/doc/ped_remaps.txt new file mode 100644 index 0000000..4ed3fa5 --- /dev/null +++ b/doc/ped_remaps.txt @@ -0,0 +1,26 @@ +style001.g24 +231 - 293 + +style002.g24 +238 - 300 + +style003.g24 +219 - 281 +------------- +1.g24 +75 - 131 +HK 93 +PRIESTS 94 +idx: 660 + +2.g24 +79 - 135 +HARE KRISHNAS 97 +DOCTOR/PRIESTS 98 +idx: 662 + +3.g24 +60 - 116 +HK 78 +PRIESTS 79 +idx: 675 diff --git a/doc/sprites.txt b/doc/sprites.txt new file mode 100644 index 0000000..efae5e9 --- /dev/null +++ b/doc/sprites.txt @@ -0,0 +1,173 @@ +style001.gry + +604 - 611 : rotating "x" +612 - 619 : rotating coin + +620 - 627 : player, walking +628 - 635 : player, running? +658 - 661 : player, falling? +678 - 689 : player, walking 2? +738 - 745 : player, flame-thrower, standing +746 - 753 : player, flame-thrower, walking +754 - 755 : player, flame-thrower, standing? +756 - 763 : player, gun, standing +764 - 771 : player, gun, running? +772 - 773 : player, gun, standing? +774 - 781 : player, big-gun, standing +782 - 789 : player, big-gun, running? +790 - 791 : player, big-gun, standing? +792 - 796 : player, electro-death + +797 - 800 : player, swimming? +801 - 808 : player, punching? + + +style002.gry + +99 - 105 : cone, tumbling +106 - 111 : ring? +112 - 124 : plant? +125 - 129 : road barrier +130 - 136 : road barrier, broken + +622 - 629 : player, walking + +811 - 818 : cop, walking +819 - 826 : cop, moving? +827 - 844 : cop, driving? +845 - 848 : ??? + +style001.g24 + +117 - 127 : smoke, circle, small +128 - 131 : grey bar | dissolving +132 - 135 : red bar | dissolving +136 - 140 : small water splash +141 - 146 : blood dissolving +147 - 150 : brown bar | dissolving +151 - 166 : fire +167 - 173 : big water dissolving + +174 : tree +175 - 176: green/grey blob? + +188 : box, top open, cross +189 : closed box; x? +190 : box, top open, rockets? +191 : telephone +192 : telephone, arrow +193 : telephone, arrow, highlight +194 : white circle, pickup package + +247 - 257 : smoke, right->left, dissolving +258 - 265 : small flames +266 - 273 : water, fire truck +274 - 281 : water hits fire + +282 : fire truck part? +283 - 294 : grey smoke, cirle, growing, gets darker +296 - 306 : smoke?, at bottom +307 - 313 : train door open? +315 - 326 : big water splash + +327 - 330/331? : fire truck parts + +332 - 342 : small smoke (again) +342 - 352 : like above??? +354 - 365 : blood grow + dissolve? +366 : big blood splash + +367 - 377 : smoke, cone from bottom +393 - 403 : flames, from bottom, flame-thrower? +404 - 411 : rotating canister +412 - 419 : rotating gun +420 - 432 : crate; breaking after first frame +434 - 441 : race finish flag +442 - 454 : crate + stuff; breaking +455 : green blob +456 : red blob +457 - 464 : helicopter blades +465 - 472 : uzi, rotating +473 - 480 : rocket-launcher rotating +481 - 488 : flame-thrower rotating +489 - 496 : red canister rotating +497 - 504 : red ? rotating +506 - 513 : info-sign-post rotating +514 - 521 : blue shield? +522 - 529 : car speed up +530 - 537 : jail free +538 - 545 : extra life +546 - 553 : multiplier up +554 - 561 : police bribe + + +ped1 + +second col: (#frames - 1) + +0|7|walk +8|7|running forward +16|0|sitting in car +17|7|car exit +25|7|car enter +33|0|sitting in car +34|3|unused junk +38|2|frames, looped while falling +41|0|frame, sliding UNDER car +42|1|frames, usual death pose +44|0|special death pose when shot in back +45|1|played when you get shot in front +47|1|swimming, you CAN swim, but just for 1 cube long +49|0|unknown, most likely not used +50|5|punching while standing animation +56|11|unknown, repeating unused animations +68|9|seems like player strafing? unused. +80|3|jumping onto motorbike +84|0|sitting on a motorbike +85|3|exitting motorbike +89|0|shooting handgun while standing still +91|2|played when you jump onto car +94|0|played while you slide on cars +95|1|played when you drop off a car sliding +97|0|repeated sitting in car +98|0|STANDING COMPLETELY STILL +99|7|walking shooting handgun +107|7|running shooting handgun +115|2|riding a skateboard? unused. +118|7|walking shooting flamethrower +126|7|running shooting flamethrower +134|1|identical standing shooting flamethrower +136|7|walking shooting UZI +144|7|running shooting UZI +152|1|identical standing shooting uzi +154|7|walking shooting rocket launcher +162|7|running shooting rocket launcher +170|1|identical standing shooting rocket launcher +172|4|electrocution by electrified rail +177|3|crawling on floor - unused +181|7|running & punching + +police ped + +189 - 196 : walking +197 - 204 : running +205 : sitting +206 - 213 : exit car +214 - 221 : enter car +222 : sitting +227 - 228 : falling +229 : slide under +230 : shot front? +231 - 233 : dead? (3 identical frames; lying) +234 : ??? +235 : same as 230? +236 - 237 : drowning? different ped colour?? +238 : shot in back +239 - 243 : arrest? +269/270? - 272 : enter bike +273 : sitting on bike +274 - 277 : exit bike +278 : standing, gun +278 - 279 : shoot gun? +288 - 292 : electro-death +293 - 294 : shoot uzi diff --git a/doc/using_mods.txt b/doc/using_mods.txt new file mode 100644 index 0000000..65e62be --- /dev/null +++ b/doc/using_mods.txt @@ -0,0 +1,27 @@ +Mods can (in theory) be downloaded and used directly +as the ZIP file. + +The install procedure in readme.txt is slightly dated, +'viewer' actually does the following: + +* look for environment variable "OGTA_DATA"; if it exists + this is used as the base-data source. + By default this is the file 'gtadata.zip' searched in + the current directory (at viewer runtime). + + If this source is not valid the directory where viewer + is installed is checked before giving up. + +* look for environment variable "OGTA_MOD"; if it exists + and is a valid data-source all files contained within + will overlay files in the base data source. + This is not used by default. + +To load a mod I use something like this: +OGTA_MOD=mods/a_mod.zip ./viewer [...] -m map_filename -g style_filename + +In this case you have to use -m & -g and use the filenames +contained in the zip (note upper/lower case). + +Similiar to gtadata.zip the files have to be in the 'root' of +the ZIP file, not in sub-directory. diff --git a/entity_controller.cpp b/entity_controller.cpp index 6f66809..ab2e97b 100644 --- a/entity_controller.cpp +++ b/entity_controller.cpp @@ -41,6 +41,13 @@ namespace OpenGTA { rawData = v; } + bool ControllerWithMemory::statusChanged() { + bool res = (rawData != lastRawData); + if (res) + lastRawData = rawData; + return res; + } + void PedController::setTurnLeft(bool press) { dataSet.set_item(0, press); } diff --git a/entity_controller.h b/entity_controller.h index ab2f9ca..d61a753 100644 --- a/entity_controller.h +++ b/entity_controller.h @@ -34,17 +34,31 @@ namespace OpenGTA { void zero(); typedef uint32_t Storage_T; void setRaw(Storage_T v); + inline const Storage_T & getRaw() { return rawData; } protected: EntityController(const EntityController & other); Storage_T rawData; Util::Set dataSet; }; + class ControllerWithMemory : public EntityController { + public: + ControllerWithMemory() : EntityController(), + lastRawData(rawData) {} + ControllerWithMemory(const ControllerWithMemory & o) : + EntityController(o), lastRawData(o.lastRawData) {} + bool statusChanged(); + protected: + Storage_T lastRawData; + }; + class Pedestrian; - class PedController : public EntityController { +// class PedController : public EntityController { + class PedController : public ControllerWithMemory { public: PedController() {} - PedController(const PedController & other) : EntityController(other) {} +// PedController(const PedController & other) : EntityController(other) {} + PedController(const PedController & other) : ControllerWithMemory(other) {} void setTurnLeft(bool press = true); inline void releaseTurnLeft() { setTurnLeft(false); } void setTurnRight(bool press = true); diff --git a/game_objects.cpp b/game_objects.cpp index 8685ab8..37d2878 100644 --- a/game_objects.cpp +++ b/game_objects.cpp @@ -1,31 +1,40 @@ /************************************************************************ -* 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. * -************************************************************************/ + * 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 "game_objects.h" #include "spritemanager.h" #include "dataholder.h" #include "cell_iterator.h" #include "timer.h" #include "Functor.h" +#include "plane.h" +#include "ai.h" +#include "localplayer.h" + +// ugly fix for win32 +#ifdef WIN32 +#undef ERROR +#define ERROR Util::Log::error(__FILE__, __LINE__) +#endif #define INT2FLOAT_WRLD(c) (float(c >> 6) + float(c % 64) / 64.0f) #define INT2F_DIV64(v) (float(v) / 64.0f) @@ -63,8 +72,10 @@ namespace OpenGTA { assert(block); if (block->blockType() > 0) { float bz = slope_height_offset(block->slopeType(), v.x - x, v.z - z); - if (block->slopeType() == 0 && block->blockType() != 5) + if (block->slopeType() == 0 && (block->blockType() != 5 && + block->blockType() != 6)) bz -= 1.0f; + //INFO << "hit " << int(block->blockType()) << " at " << int(y) << std::endl; return v.y - (y + bz); } y -= 1.0f; @@ -75,8 +86,10 @@ namespace OpenGTA { assert(block); if (block->blockType() > 0) { float bz = slope_height_offset(block->slopeType(), v.x - x, v.z - z); - if (block->slopeType() == 0 && block->blockType() != 5) + if (block->slopeType() == 0 && (block->blockType() != 5 + && block->blockType() != 6)) bz -= 1.0f; + //INFO << "hit " << int(block->blockType()) << " at " << int(y) << std::endl; return v.y - (y + bz); } y += 1.0f; @@ -130,14 +143,18 @@ namespace OpenGTA { animId = newId; } + uint32_t Pedestrian::fistAmmo = 0; + 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) { + speedForces(0, 0, 0), + inventory(), activeWeapon(0), activeAmmo(&fistAmmo), + aiData() { m_M = TranslateMatrix3D(p); - m_M.RotZ(rot); + m_M.RotZ(-rot); pedId = id; animId = 0; isDead = 0; @@ -150,13 +167,17 @@ namespace OpenGTA { pedId(other.pedId), m_control(), - speedForces(other.speedForces) { + speedForces(other.speedForces), + inventory(other.inventory), + activeWeapon(other.activeWeapon), + activeAmmo(&inventory.find(activeWeapon)->second), + aiData(other.aiData) { lastUpdateAt = other.lastUpdateAt; inGroundContact = other.inGroundContact; animId = other.animId; isDead = other.isDead; m_M = TranslateMatrix3D(other.pos); - m_M.RotZ(other.rot); + m_M.RotZ(-other.rot); } extern void ai_step_fake(Pedestrian*); @@ -168,26 +189,36 @@ namespace OpenGTA { } if (pedId < 0xffffffff) ai_step_fake(this); - uint8_t activeWeapon = m_control.getActiveWeapon(); + //AI::Pedestrian::walk_pavement(this); + if (aiMode) { + AI::Pedestrian::moveto_shortrange(this); + } + uint8_t chooseWeapon = m_control.getActiveWeapon(); + if (chooseWeapon != activeWeapon) { + if (chooseWeapon == 0) { + activeWeapon = 0; + activeAmmo = &fistAmmo; + } + else { + InventoryMap::iterator i = inventory.find(chooseWeapon); + if (i != inventory.end()) { + activeWeapon = chooseWeapon; + activeAmmo = &i->second; + } + } + } +activeWeapon = chooseWeapon; 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); + 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); @@ -201,7 +232,7 @@ namespace OpenGTA { anim.update(ticks); Uint32 delta = ticks - lastUpdateAt; //INFO << "delta = " << delta << " t: " << ticks << " lt: " << lastUpdateAt << std::endl; - Vector3D moveDelta(0, 0, 0); + moveDelta = Vector3D(0, 0, 0); switch(m_control.getTurn()) { case -1: rot -= 0.2f * delta; @@ -234,6 +265,8 @@ namespace OpenGTA { case 0: break; } + if (pedId == 0xffffffff) { + } tryMove(pos + moveDelta); if (!inGroundContact) { speedForces.y += 0.0005f *delta; @@ -252,17 +285,23 @@ namespace OpenGTA { 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 - ); + //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; } + /* + if (m_control.statusChanged()) { + INFO << "Ped-event id: " << pedId << " control: " << m_control.getRaw() << + " time: " << ticks << std::endl; + }*/ + //INFO << pos.x << " " << pos.y << " " << pos.z << std::endl; lastUpdateAt = ticks; } - void Pedestrian::tryMove(Vector3D nPos) { + void Pedestrian::tryMove(Vector3D nPos) { float x, y, z; x = floor(nPos.x); y = floor(nPos.y); @@ -271,12 +310,13 @@ namespace OpenGTA { OpenGTA::GraphicsBase & graphics = OpenGTA::StyleHolder::Instance().get(); //INFO << heightOverTerrain(nPos) << std::endl; float hot = heightOverTerrain(nPos); - if (hot > 0.1f) + if (hot > 0.3f) inGroundContact = 0; else if (hot < 0.0) { - INFO << "gone below: " << hot << " at " << nPos.x << ", " << nPos.y << ", " << nPos.z << std::endl; + WARN << "gone below: " << hot << " at " << nPos.x << ", " << nPos.y << ", " << nPos.z << std::endl; nPos.y -= (hot - 0.3f); - INFO << nPos.y << std::endl; + //nPos.y += 1; + //INFO << nPos.y << std::endl; inGroundContact = 1; } else { @@ -287,34 +327,10 @@ namespace OpenGTA { 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; OpenGTA::Map::BlockInfo * block = map.getBlockAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z), PHYSFS_uint8(y)); - assert(block);/* - if (block->blockType() > 0) { - float bz = slope_height_offset(block->slopeType(), nPos.x - x, nPos.z - z); - if (block->slopeType() == 0) - bz -= 1.0f; - if (inGroundContact) { - nPos.y = y + bz + 0.3f; - //pos = nPos; - } - else if (nPos.y - y - bz < 0.3f) { - INFO << "ped near ground (type: " << int(block->blockType()) << " float-pos: " - << nPos.x << ", " << nPos.y << ", " << nPos.z << std::endl; - inGroundContact = 1; - nPos.y = y + bz + 0.3f; - INFO << "height rewritten to: " << nPos.y << std::endl; - //pos = nPos; - - } - } - else { - inGroundContact = 0; - INFO << "lost footing: " << x << ", " << y << ", " << z << std::endl; - }*/ - if (block->left && graphics.isBlockingSide(block->left)) { // && block->isFlat() == false) { + assert(block); + if (block->left && graphics.isBlockingSide(block->left)) { if (block->isFlat()) { - //INFO << "xblock left: " << x - pos.x << std::endl; if (x - pos.x < 0 && x - pos.x > -0.2f) { nPos.x = (nPos.x < pos.x) ? pos.x : nPos.x; } @@ -323,7 +339,7 @@ namespace OpenGTA { } else { #ifdef DEBUG_OLD_PED_BLOCK - INFO << "xblock left: " << x - pos.x << " tex: " << int(block->left) << std::endl; + 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; @@ -341,10 +357,10 @@ namespace OpenGTA { else if (pos.x - x - 1 < 0 && pos.x - x - 1 > -0.2f) nPos.x = (nPos.x > pos.x) ? pos.x : nPos.x; } - if (block->top && graphics.isBlockingSide(block->top)) { // && block->isFlat() == false) { + if (block->top && graphics.isBlockingSide(block->top)) { if (block->isFlat()) { #ifdef DEBUG_OLD_PED_BLOCK - INFO << "zblock top: " << z - pos.z << " tex: " << int(block->top) << std::endl; + 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; @@ -353,7 +369,7 @@ namespace OpenGTA { } else { #ifdef DEBUG_OLD_PED_BLOCK - INFO << "zblock top: " << z - pos.z << " tex: " << int(block->top)<< std::endl; + 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; @@ -384,7 +400,7 @@ 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) { + if (block->left && graphics.isBlockingSide(block->left)) { #ifdef DEBUG_OLD_PED_BLOCK INFO << "xblock left: " << x + 1 - pos.x << " tex: " << int(block->left)<< std::endl; #endif @@ -411,7 +427,7 @@ 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) { + if (block->top && graphics.isBlockingSide(block->top)) { #ifdef DEBUG_OLD_PED_BLOCK INFO << "zblock top: " << z + 1 - pos.z<< " tex: " << int(block->top) << std::endl; #endif @@ -428,7 +444,15 @@ namespace OpenGTA { //if (inGroundContact) // pos = nPos; } - if (inGroundContact) + bool obj_blocked = false; + std::list & list = SpriteManagerHolder::Instance().getList(); + for (std::list::iterator i = list.begin(); i != list.end(); i++) { + if (isBoxInBox(*i)) { + if (Util::distance(pos, i->pos) > Util::distance(nPos, i->pos)) + obj_blocked = true; + } + } + if ((inGroundContact) && (obj_blocked == false)) pos = nPos; //else // inGroundContact = 0; @@ -438,9 +462,17 @@ namespace OpenGTA { void Pedestrian::die() { INFO << "DIE!!!" << std::endl; switchToAnim(42); + if (isDead == 3) { + anim.set(Util::Animation::STOPPED, Util::Animation::STOP); + return; + } + anim.set(Util::Animation::PLAY_FORWARD, Util::Animation::FCALLBACK); + Loki::Functor cmd(this, &Pedestrian::die); + anim.setCallback(cmd); + isDead++; } - void Pedestrian::getShot(bool front) { + void Pedestrian::getShot(uint32_t shooterId, uint32_t dmg, bool front) { isDead = 1; switchToAnim(45); anim.set(Util::Animation::PLAY_FORWARD, Util::Animation::FCALLBACK); @@ -448,66 +480,311 @@ namespace OpenGTA { anim.setCallback(cmd); } + CarSprite::CarSprite() : sprNum(0), remap(-1), + sprType(GraphicsBase::SpriteNumbers::CAR), delta(0), + deltaSet(sizeof(delta) * 8, (unsigned char*)&delta), + animState() {} + + CarSprite::CarSprite(const CarSprite & o) : + sprNum(o.sprNum), remap(o.remap), sprType(o.sprType), delta(o.delta), + deltaSet(sizeof(delta) * 8, (unsigned char*)&delta), + animState(o.animState) {} + + CarSprite::CarSprite(Uint16 sprN, Sint16 rem, + GraphicsBase::SpriteNumbers::SpriteTypes sprT) : sprNum(sprN), + remap(rem), sprType(sprT), delta(0), + deltaSet(sizeof(delta) * 8, (unsigned char*)&delta), + animState() {} + + void CarSprite::setDamage(uint8_t k) { + deltaSet.set_item(k, true); + } + + bool CarSprite::assertDeltaById(uint8_t k) { + GraphicsBase & style = StyleHolder::Instance().get(); + PHYSFS_uint16 absNum = style.spriteNumbers.reIndex(sprNum, sprType); + GraphicsBase::SpriteInfo * info = style.getSprite(absNum); + if (k >= info->deltaCount) + return false; + return true; + } + + void CarSprite::openDoor(uint8_t k) { + DoorDeltaAnimation dda(k, true); + doorAnims.push_back(dda); + } + + void CarSprite::closeDoor(uint8_t k) { + doorAnims.push_back(DoorDeltaAnimation(k, false)); + } + + void CarSprite::setSirenAnim(bool on) { + if (!(assertDeltaById(15) && assertDeltaById(16))) { + ERROR << "Trying to set siren anim on car-sprite that has no such delta!" << std::endl; + return; + } + animState.set_item(10, on); + } + + void CarSprite::update(Uint32 ticks) { + +// siren anim indices +#define DSI_1 15 +#define DSI_2 16 + +#define D_A_THEN_B(d, a, b) (d.get_item(a)) { d.set_item(a, false); d.set_item(b, true); } + + // drive-anim + if (animState.get_item(0)) {} + /* + if (ticks - lt_door > 500) { + // 1-4 door-opening + if (animState.get_item(1)) { + deltaSet.set_item(6, true); + } + // 5-8 door-closing + lt_door = ticks; + }*/ + DoorAnimList::iterator i = doorAnims.begin(); + while (i != doorAnims.end()) { + i->update(ticks); + if (i->opening) { + if (i->doorId == 0) { + for (int k=6; k < 10; k++) + deltaSet.set_item(k, false); + deltaSet.set_item(i->getCurrentFrameNumber() + 6, true); + } + else if (i->doorId == 1) { + for (int k=11; k < 15; k++) + deltaSet.set_item(k, false); + deltaSet.set_item(i->getCurrentFrameNumber() + 11, true); + } + else if (i->doorId == 2) { + for (int k=20; k < 24; k++) + deltaSet.set_item(k, false); + deltaSet.set_item(i->getCurrentFrameNumber() + 20, true); + } + else if (i->doorId == 3) { + for (int k=24; k < 28; k++) + deltaSet.set_item(k, false); + deltaSet.set_item(i->getCurrentFrameNumber() + 24, true); + } + } + else { + if (i->doorId == 0) { + for (int k=6; k < 10; k++) + deltaSet.set_item(k, false); + if (i->getCurrentFrameNumber() > 0) + deltaSet.set_item(i->getCurrentFrameNumber() + 5, true); + } + else if (i->doorId == 1) { + for (int k=11; k < 15; k++) + deltaSet.set_item(k, false); + if (i->getCurrentFrameNumber() > 0) + deltaSet.set_item(i->getCurrentFrameNumber() + 10, true); + } + else if (i->doorId == 2) { + for (int k=20; k < 24; k++) + deltaSet.set_item(k, false); + if (i->getCurrentFrameNumber() > 0) + deltaSet.set_item(i->getCurrentFrameNumber() + 19, true); + } + else if (i->doorId == 3) { + for (int k=24; k < 28; k++) + deltaSet.set_item(k, false); + if (i->getCurrentFrameNumber() > 0) + deltaSet.set_item(i->getCurrentFrameNumber() + 23, true); + } + } + if (i->get() == Util::Animation::STOPPED) { + DoorAnimList::iterator j = i; + i++; + animState.set_item(j->doorId + 1, j->opening); + doorAnims.erase(j); + } + else + i++; + } + if (animState.get_item(10)) { + if (ticks - lt_siren > 500) { + if D_A_THEN_B(deltaSet, DSI_1, DSI_2) + else if D_A_THEN_B(deltaSet, DSI_2, DSI_1) + else { deltaSet.set_item(DSI_1, true); deltaSet.set_item(DSI_2, false); } + lt_siren = ticks; + } + } + } + + CarSprite::DoorDeltaAnimation::DoorDeltaAnimation(uint8_t dId, bool dOpen) : + Util::Animation(4 + (dOpen ? 0 : 1), 5), doorId(dId), opening(dOpen) { + if (!opening) { + set(Util::Animation::PLAY_BACKWARD, Util::Animation::STOP); + jumpToFrame(4, Util::Animation::PLAY_BACKWARD); + } + else { + set(Util::Animation::PLAY_FORWARD, Util::Animation::STOP); + } + } + + Car::Car(Vector3D & _pos, float _rot, uint32_t id, uint8_t _type, int16_t _remap) : + GameObject_common(_pos, _rot), + CarSprite(0, -1, GraphicsBase::SpriteNumbers::CAR), OBox(), + carInfo(*StyleHolder::Instance().get().findCarByModel(_type)) { + type = _type; + carId = id; + sprNum = carInfo.sprNum; + if ((_remap > -1) && (StyleHolder::Instance().get().getFormat() == 0)) + remap = carInfo.remap8[_remap]; + fixSpriteType(); + m_Extent = Vector3D(INT2F_DIV128(carInfo.width), + INT2F_DIV128(carInfo.depth), + INT2F_DIV128(carInfo.height)); + m_M = TranslateMatrix3D(pos); + m_M.RotZ(-rot); + hitPoints = carInfo.damagable; + } + + void Car::fixSpriteType() { + if (carInfo.vtype == 3) + sprType = GraphicsBase::SpriteNumbers::BIKE; + else if (carInfo.vtype == 0) + sprType = GraphicsBase::SpriteNumbers::BUS; + else if (carInfo.vtype == 8) + sprType = GraphicsBase::SpriteNumbers::TRAIN; + } + 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(), + CarSprite(0, -1, GraphicsBase::SpriteNumbers::CAR), OBox(), carInfo(*StyleHolder::Instance().get().findCarByModel(op.type)){ - carId = id; - type = op.type; - 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); + carId = id; + type = op.type; + if (op.remap - 128 > 0) { + if (StyleHolder::Instance().get().getFormat() == 0) + remap = carInfo.remap8[op.remap-129]; + else + WARN << "remap " << int(op.remap-129) << + " requested but not implemented for G24" << std::endl; + } + sprNum = carInfo.sprNum; + fixSpriteType(); + m_Extent = Vector3D(INT2F_DIV128(carInfo.width), + INT2F_DIV128(carInfo.depth) , + INT2F_DIV128(carInfo.height)); + m_M = TranslateMatrix3D(pos); - rot = op.rotation * 360 / 1024; - } + rot = op.rotation * 360 / 1024; + m_M.RotZ(-rot); + hitPoints = carInfo.damagable; + } Car::Car(const Car & other) : - GameObject_common(other), Sprite(other), OBox(other), + GameObject_common(other), CarSprite(other), OBox(other), carInfo(*StyleHolder::Instance().get().findCarByModel(other.type)) { - type = other.type; - m_M = TranslateMatrix3D(pos); - m_M.RotZ(rot); + type = other.type; + m_M = TranslateMatrix3D(pos); + m_M.RotZ(-rot); + hitPoints = other.hitPoints; - carId = other.carId; - } + carId = other.carId; + } void Car::update(Uint32 ticks) { + //m_M = TranslateMatrix3D(pos); + //m_M.RotZ(rot+90); + CarSprite::update(ticks); + } + + void Car::damageAt(const Vector3D & hit, uint32_t dmg) { + float angle = Util::xz_angle(Vector3D(0, 0, 0), hit); + INFO << "hit angle: " << angle << std::endl; + + /* + * front rear + * 270 + * 0 _|o---o| _ 180 + * |o---o| + * 45 90 + */ +#define A1 60 +#define A2 (180 - A1) +#define A3 (180 + A1) +#define A4 (360 - A1) + + uint8_t k = 0; + if (angle <= A1) { + // front left + k = 3; + } + else if (angle <= A2) { + // left side + k = 2; + } + else if (angle < 180.0f) { + // rear left + k = 1; + } + else if (angle <= A3) { + // rear right + k = 4; + } + else if (angle <= A4) { + // right side + k = 5; + } + else { + // right front + k = 0; + } + setDamage(k); + hitPoints -= dmg; + if (hitPoints <= 0) + explode(); + } + + void Car::explode() { + //SpriteManagerHolder::Instance().removeCar(carId); + //return; + Vector3D exp_pos(pos); + exp_pos.y += 0.1f; + SpriteManagerHolder::Instance().createExplosion(exp_pos); + sprNum = 0; + remap = -1; + sprType = GraphicsBase::SpriteNumbers::WCAR; + delta = 0; } 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 = TranslateMatrix3D(pos); - m_M.RotZ(rot); - rot = op.rotation * 360 / 1024; - isActive = true; - } + 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 = TranslateMatrix3D(pos); + m_M.RotZ(-rot); + rot = op.rotation * 360 / 1024; + isActive = true; + } 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); - } + isActive = true; + m_M = TranslateMatrix3D(pos); + m_M.RotZ(-rot); + } 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; - } + objId(other.objId) { + m_M = TranslateMatrix3D(pos); + m_M.RotZ(-rot); + + isActive = other.isActive; + } void SpriteObject::update(Uint32 ticks) { anim.update(ticks); @@ -517,20 +794,100 @@ namespace OpenGTA { GameObject_common(p, r), typeId(t), delta(d), endsAtTick(ticks), owner(o), lastUpdateAt(ticks) { - endsAtTick = lastUpdateAt + 1000; - } + 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) {} + bool Projectile::testCollideBlock_flat(Util::CellIterator & ci, Vector3D & newp) { + Map::BlockInfo & bi = ci.getBlock(); + if (bi.top) { + Math::Plane plane(Vector3D(ci.x, ci.z, ci.y), Vector3D(0, 0, -1)); + Vector3D hit_pos; + if (plane.segmentIntersect(pos, newp, hit_pos)) { + INFO << "intersect flat-t: " << hit_pos.x << " " << hit_pos.y << " " <= ci.x && hit_pos.x <= ci.x + 1) { + newp = hit_pos; + return true; + } + } + } + if (bi.left) { + Math::Plane plane(Vector3D(ci.x, ci.z, ci.y), Vector3D(-1, 0, 0)); + Vector3D hit_pos; + if (plane.segmentIntersect(pos, newp, hit_pos)) { + INFO << "intersect flat-l: " << hit_pos.x << " " << hit_pos.y << " " <= ci.y && hit_pos.z <= ci.y + 1) { + newp = hit_pos; + return true; + } + } + } + return false; + } + + bool Projectile::testCollideBlock(Util::CellIterator & ci, Vector3D & newp) { + Map::BlockInfo & bi = ci.getBlock(); + //INFO << "pos: " << ci.x << " " << ci.y << " " << ci.z << std::endl; + //if (bi.isFlat()) + // return false; + if (bi.left) { + Math::Plane plane(Vector3D(ci.x, ci.z, ci.y), Vector3D(-1, 0, 0)); + Vector3D hit_pos; + if (plane.segmentIntersect(pos, newp, hit_pos)) { + INFO << "intersect left: " << hit_pos.x << " " << hit_pos.y << " " <= ci.y && hit_pos.z <= ci.y + 1) { + newp = hit_pos; + return true; + } + } + } + if (bi.right && !bi.isFlat()) { + Math::Plane plane(Vector3D(ci.x+1, ci.z, ci.y), Vector3D(1, 0, 0)); + Vector3D hit_pos; + if (plane.segmentIntersect(pos, newp, hit_pos)) { + INFO << "intersect right: " << hit_pos.x << " " << hit_pos.y << " " <= ci.y && hit_pos.z <= ci.y + 1) { + newp = hit_pos; + return true; + } + } + } + if (bi.top) { + Math::Plane plane(Vector3D(ci.x, ci.z, ci.y), Vector3D(0, 0, -1)); + Vector3D hit_pos; + if (plane.segmentIntersect(pos, newp, hit_pos)) { + INFO << "intersect top: " << hit_pos.x << " " << hit_pos.y << " " <= ci.x && hit_pos.x <= ci.x + 1) { + newp = hit_pos; + return true; + } + } + } + if (bi.bottom && !bi.isFlat()) { + Math::Plane plane(Vector3D(ci.x, ci.z, ci.y+1), Vector3D(0, 0, 1)); + Vector3D hit_pos; + if (plane.segmentIntersect(pos, newp, hit_pos)) { + INFO << "intersect bottom: " << hit_pos.x << " " << hit_pos.y << " " <= ci.x && hit_pos.x <= ci.x + 1) { + newp = hit_pos; + return true; + } + } + + } + return false; + } + 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; - */ + " to " << new_pos.x << " " << new_pos.y << " " << new_pos.z << std::endl; + */ std::list & list = SpriteManagerHolder::Instance().getList(); for (std::list::iterator i = list.begin(); i != list.end(); ++i) { Pedestrian & ped = *i; @@ -538,49 +895,77 @@ namespace OpenGTA { 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); + if (ped.isLineInBox( pos, new_pos ) ) { + Vector3D p; + ped.lineCrossBox(pos, new_pos, p); + float angle = Util::xz_angle(Vector3D(0,0,0), p); + INFO << angle << std::endl; + if (angle <= 90.0f || angle > 270.0f) + INFO << "FRONT" << std::endl; + else + INFO << "BACK" << std::endl; + ped.getShot(owner, Projectile::damageByType(typeId), true); + PlayerController & pc = LocalPlayer::Instance(); + if (owner == pc.getId()) { + pc.addCash(10); + pc.addWanted(1); + } endsAtTick = 0; } } - - /* - Util::CellIterator oi(pos); + std::list & clist = SpriteManagerHolder::Instance().getList(); + for (std::list::iterator i = clist.begin(); i != clist.end(); i++) { + Car & car = *i; - 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()); + if (car.isLineInBox(pos, new_pos)) { + INFO << "CAR HIT" << std::endl; + Vector3D p; + car.lineCrossBox(pos, new_pos, p); + car.damageAt(p, 5); + //INFO << Util::xz_angle(Vector3D(0,0,0), p) << std::endl; + delta = Vector3D(0, 0, 0); + p = Transform(p, car.m_M); + new_pos.x = p.x; + new_pos.z = p.z; + new_pos.y += 0.1f; } } - else - INFO << "NEITHER VALID!"<< oi.x << " " << oi.y << " " << oi.z < InventoryMap; + InventoryMap inventory; + uint8_t activeWeapon; + uint32_t * activeAmmo; + uint32_t aiMode; + static uint32_t fistAmmo; + struct AiData { + AiData() : id1(0), id2(0), pos1() {} + AiData(const AiData & o) : id1(o.id1), id2(o.id2), pos1(o.pos1) {} + uint32_t id1; + uint32_t id2; + Vector3D pos1; + }; + AiData aiData; + Vector3D moveDelta; }; - class Car : public GameObject_common, public Sprite, public OBox { + class CarSprite { + public: + class DoorDeltaAnimation : public Util::Animation { + public: + DoorDeltaAnimation(uint8_t dId, bool dOpen); + uint8_t doorId; + bool opening; + }; + CarSprite(); + CarSprite(Uint16 sprN, Sint16 rem, GraphicsBase::SpriteNumbers::SpriteTypes sprT); + CarSprite(const CarSprite & o); + Uint16 sprNum; + Sint16 remap; + GraphicsBase::SpriteNumbers::SpriteTypes sprType; + uint32_t delta; + Util::Set deltaSet; + Util::Set animState; + void setDamage(uint8_t k); + void openDoor(uint8_t k); + void closeDoor(uint8_t k); + void setSirenAnim(bool on); + bool assertDeltaById(uint8_t k); + void update(Uint32 ticks); + private: + typedef std::list DoorAnimList; + DoorAnimList doorAnims; + Uint32 lt_siren; + }; + + class Car : public GameObject_common, public CarSprite, public OBox { public: Car(const Car & o); Car(OpenGTA::Map::ObjectPosition&, uint32_t id); + Car(Vector3D & _pos, float _rot, uint32_t id, uint8_t _type, int16_t _remap = -1); uint32_t carId; inline uint32_t id() const { return carId; } GraphicsBase::CarInfo & carInfo; uint8_t type; void update(Uint32 ticks); Uint32 lastUpdateAt; + void damageAt(const Vector3D & hit, uint32_t dmg); + void explode(); + private: + void fixSpriteType(); + int32_t hitPoints; }; class SpriteObject : public GameObject_common, public Sprite, public OBox { @@ -139,6 +190,9 @@ namespace OpenGTA { uint32_t owner; void update(Uint32 ticks); Uint32 lastUpdateAt; + bool testCollideBlock(Util::CellIterator &, Vector3D & newp); + bool testCollideBlock_flat(Util::CellIterator &, Vector3D & newp); + static uint32_t damageByType(const uint8_t & k); }; } diff --git a/gl_camera.cpp b/gl_camera.cpp index 038ee44..f77b4c2 100644 --- a/gl_camera.cpp +++ b/gl_camera.cpp @@ -78,12 +78,12 @@ namespace OpenGL { OpenGTA::Map::BlockInfo * block = map.getBlockAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z), PHYSFS_uint8(y)); if (block->blockType() > 0 && block->blockType() <= 5) { float bz = slope_height_offset(block->slopeType(), eye.x - x, eye.z - z); - if (block->slopeType() == 0 && block->blockType() != 5) + if (block->slopeType() == 0 && (block->blockType() != 5 && block->blockType() != 6)) bz -= 1; //INFO << int(block->blockType()) << ", " << eye.y << ", " << // eye.y - y << ", " << eye.y - y - bz << ", " << bz << std::endl; float react_delta = 0.3f; - if (block->blockType() == 5) + if (block->blockType() == 5 || block->blockType() == 6) react_delta = 0.0f; if (eye.y - y - bz < react_delta) { //do_grav = 0; @@ -109,7 +109,7 @@ namespace OpenGL { y -= 1; if (y < map.getNumBlocksAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z)) && y > 0.0f) { OpenGTA::Map::BlockInfo * block = map.getBlockAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z), PHYSFS_uint8(y)); - if (block->blockType() == 5) { + if (block->blockType() == 5 || block->blockType() == 6) { float bz = slope_height_offset(block->slopeType(), eye.x - x, eye.z - z); //INFO << eye.y << ", " << y << " bz " << bz << std::endl; if (eye.y - y - bz < 0.4f) { diff --git a/gl_cityview.cpp b/gl_cityview.cpp index b3fd76f..fef3c96 100644 --- a/gl_cityview.cpp +++ b/gl_cityview.cpp @@ -35,6 +35,8 @@ #include "blockdata.h" #include "image_loader.h" #include "blockanim.h" +#include "id_sys.h" +#include "map_helper.h" float slope_height_offset(unsigned char slope_type, float dx, float dz); namespace OpenGTA { @@ -72,6 +74,33 @@ namespace OpenGTA { return tex; } */ + struct GLColor { + GLfloat rgb[3]; + GLColor() { rgb[0] = rgb[1] = rgb[2] = 0; } + GLColor(GLfloat i) { rgb[0] = rgb[1] = rgb[2] = i; } + GLColor(GLfloat r, GLfloat g, GLfloat b) { rgb[0] = r; rgb[1] = g; rgb[2] = b; } + }; + + GLColor block_colors[8] = { + GLColor(1), // air + GLColor(0, 0, 1), // water + GLColor(0, 1, 1), // road + GLColor(1, 0, 0), // pavement + GLColor(0, 1, 0), // field + GLColor(1, 1, 0), // building + GLColor(1), // unused + GLColor(1) // unused + }; + + GLfloat* map_block_type_color(uint8_t k) { + // k = 6 now used to fix pavement cols + if (k == 7) + WARN << "block-type: " << int(k) << " should be unused!" << std::endl; + if (k < 8) + return block_colors[k].rgb; + ERROR << "Invalid block-type: " << int(k) << std::endl; + return block_colors[0].rgb; + } CityView::CityView() { setNull(); @@ -95,6 +124,7 @@ namespace OpenGTA { topDownView = true; drawTextured = true; drawLines = false; + drawLinesBlockType = true; setPosition(0.0f, 0.0f, 20.0f); scene_display_list = 0; @@ -119,8 +149,10 @@ namespace OpenGTA { } bool CityView::getDrawTextured() { return drawTextured; } bool CityView::getDrawLines() { return drawLines; } + bool CityView::getDrawLinesBlockColor() { return drawLinesBlockType; } void CityView::setDrawTextured(bool v) { drawTextured = v; } void CityView::setDrawLines(bool v) { drawLines= v; } + void CityView::setDrawLinesBlockColor(bool v) { drawLinesBlockType= v; } void CityView::cleanup() { //if (loadedMap) // delete loadedMap; @@ -146,6 +178,7 @@ namespace OpenGTA { loadedMap = &MapHolder::Instance().get(); StyleHolder::Instance().load(style_f); style = &StyleHolder::Instance().get(); + style->setDeltaHandling(true); /* for (size_t i = 0; i < style->carInfos.size(); ++i) { OpenGTA::GraphicsBase::CarInfo * cinfo = style->carInfos[i]; @@ -166,23 +199,33 @@ namespace OpenGTA { scene_display_list = glGenLists(1); SpriteManagerHolder::Instance().clear(); + + // safeguard against double car entries (in nyc.cmp) + Util::MapOfPair2Int d_car_map; for (PHYSFS_uint16 oc = 0; oc < loadedMap->numObjects; oc++) { + OpenGTA::Map::ObjectPosition & op = loadedMap->objects[oc]; + if (op.remap >= 128) { + if (Util::item_count(d_car_map, op.x, op.y) == 0) + Util::register_item1(d_car_map, op.x, op.y); + else + continue; + } createLevelObject(&loadedMap->objects[oc]); } //SpriteManagerHolder::Instance().trainSystem.loadStations(*loadedMap); + activeRect.x = activeRect.y = 0; + activeRect.w = activeRect.h = 0; } void CityView::createLevelObject(OpenGTA::Map::ObjectPosition *obj) { SpriteManager & s_man = SpriteManagerHolder::Instance(); + uint32_t id = TypeIdBlackBox::requestId(); if (obj->remap >= 128) { - Car car(*obj, 0); + Car car(*obj, id); s_man.add(car); - //s_man.addCar(car); } else { - //GameObject gobj(*obj); - SpriteObject gobj(*obj, 0); + SpriteObject gobj(*obj, id); s_man.add(gobj); - //s_man.addObject(gobj); } } void CityView::setZoom(const GLfloat zoom) { @@ -232,6 +275,7 @@ namespace OpenGTA { int yi = int(z); //int zi = int(z); float h = 0.5f; + WARN << "THIS FUNCTION SHOULD NOT BE USED!" << std::endl; PHYSFS_uint16 emptycount = loadedMap->getNumBlocksAt(xi, yi); for (int c=6-emptycount; c >= 1; c--) { OpenGTA::Map::BlockInfo* bi = loadedMap->getBlockAt(xi, yi, c); @@ -250,14 +294,56 @@ namespace OpenGTA { } OpenGL::PagedTexture CityView::renderMap2Texture() { - uint32_t width = OpenGL::ScreenHolder::Instance().getWidth(); - uint32_t height = OpenGL::ScreenHolder::Instance().getHeight(); + OpenGL::Screen & screen = OpenGL::ScreenHolder::Instance(); + uint32_t width = screen.getWidth(); + uint32_t height = screen.getHeight(); + + uint32_t gl_h = 1; + while (gl_h < height) + gl_h <<= 1; + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - OpenGL::ScreenHolder::Instance().set3DProjection(); - glRotatef(180, 0, 0, 1); - gluLookAt(128, 230, 128, 128, 0, 128, 0.0f, 0.0f, 1.0f); - glTranslatef(-42, 0, 0); + glFinish(); + Vector3D v_off(0,0,0); + int persp_find_done = 0; + int break_loop_safe = 500; + while (persp_find_done != 3) { + OpenGL::ScreenHolder::Instance().set3DProjection(); + glRotatef(180, 0, 0, 1); + + gluLookAt(128+v_off.x, 230, 128+v_off.y, 128+v_off.x, 0, 128+v_off.y, 0.0f, 0.0f, 1.0f); + + GLint viewport[4]; + GLdouble mvmatrix[16], projmatrix[16]; + GLdouble winx, winy, winz; + glGetIntegerv (GL_VIEWPORT, viewport); + glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix); + glGetDoublev (GL_PROJECTION_MATRIX, projmatrix); + gluProject(0, 0, 0, mvmatrix, projmatrix, viewport, &winx, &winy, &winz); + if (winx > 0.5f) + v_off.x += 0.2f; + else if (winx < -0.5f) + v_off.x -= 0.2f; + else + persp_find_done |= 1; + INFO << winx << " " << winy << std::endl; + gluProject(256, 0, 256, mvmatrix, projmatrix, viewport, &winx, &winy, &winz); + if (winy < -0.5f) + v_off.y += 0.2f; + else if (winy > 0.5f) + v_off.y -= 0.2f; + else + persp_find_done |= 2; + break_loop_safe--; + if (break_loop_safe == 0) { + WARN << "breaking out of loop - NOT GOOD!" << std::endl; + persp_find_done = 3; + } + INFO << winx << " " << winy << std::endl; + } + + //glTranslatef(-35, 0, 0); for (int i = 0; i <= 255; i++) { for (int j= 0; j <= 255; j++) { glPushMatrix(); @@ -273,17 +359,28 @@ namespace OpenGTA { } } GL_CHECKERROR; - - uint32_t gl_h = 1; - while (gl_h < height) - gl_h <<= 1; + + glFinish(); +/* + GLuint txtnumber; + glGenTextures(1, &txtnumber); // Create 1 Texture + glBindTexture(GL_TEXTURE_2D, txtnumber); // Bind The Texture + GL_CHECKERROR; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, gl_h, gl_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + GL_CHECKERROR; + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width/2, height/2); + GL_CHECKERROR; + //glViewport(0, 0, width, height); + return OpenGL::PagedTexture(txtnumber, 0, 0, 1, 1); +*/ uint32_t img_size = gl_h * gl_h * 3; uint8_t *img_buf = Util::BufferCacheHolder::Instance().requestBuffer(img_size); glReadBuffer(GL_BACK); - for (uint32_t i = 0; i < gl_h; i++) { - glReadPixels(0, i, gl_h, 1, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)(img_buf + gl_h * 3 * i)); - } + //for (uint32_t i = 0; i < gl_h; i++) { + // glReadPixels(0, i, gl_h, 1, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)(img_buf + gl_h * 3 * i)); + //} + glReadPixels(0, 0, gl_h, gl_h, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)img_buf); GL_CHECKERROR; sideCache->sink(); @@ -295,12 +392,26 @@ namespace OpenGTA { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + uint32_t y_off = 100; + uint32_t x = 0; + while (*(img_buf + y_off * gl_h * 3 + x) == 0 && *(img_buf + y_off * gl_h * 3 + x+1) == 0 && + *(img_buf + y_off * gl_h * 3 + x + 2) == 0) + x += 3; + INFO << "color after x = " << x/3 << std::endl; + x = gl_h-3; + while (*(img_buf + y_off * gl_h * 3 + x) == 0 && *(img_buf + y_off * gl_h * 3 + x+1) == 0 && + *(img_buf + y_off * gl_h * 3 + x+2) == 0) + x -= 3; + INFO << "color after x = " << x/3 << std::endl; + + GLuint tex = ImageUtil::createGLTexture(gl_h, gl_h, false, img_buf); float f_h = float(height) / gl_h; float f_w = float(width) / gl_h; //float horiz_corr = (1.0f - f_w) / 2.0f; //return OpenGL::PagedTexture(tex, 0+horiz_corr, 0, f_w+horiz_corr, f_h); - return OpenGL::PagedTexture(tex, 0, 0, f_w, f_h); + + return OpenGL::PagedTexture(tex, 0, 0, f_h, f_h); } void CityView::draw(Uint32 ticks) { @@ -363,6 +474,8 @@ namespace OpenGTA { if (y2 > 255) y2 = 255; + //INFO << activeRect.x << ", " << activeRect.y << " -> " << + // activeRect.x+activeRect.w << ", " << activeRect.y + activeRect.h << std::endl; activeRect.x = x1; activeRect.y = y1; activeRect.w = x2 - x1; @@ -405,6 +518,12 @@ namespace OpenGTA { for (int c=0; c < maxcount; ++c) { ++scene_rendered_blocks; glPushMatrix(); + if (c < maxcount - 1) { + Map::BlockInfo * bi = loadedMap->getBlockAtNew(j, i, c + 1); + aboveBlockType = bi->blockType(); + } + else + aboveBlockType = loadedMap->getBlockAtNew(j, i, c)->blockType(); drawBlock(loadedMap->getBlockAtNew(j, i, c)); glPopMatrix(); glTranslatef(0.0f, 1.0f, 0.0f); @@ -711,6 +830,14 @@ namespace OpenGTA { } } + +#define RESET_COLOR glColor3f(1, 1, 1) +#define COLOR_OFF if (drawLinesBlockType) RESET_COLOR +#define COLOR_BY_BLOCK(idx) { GLfloat *_c = map_block_type_color(idx); glColor3f(_c[0], _c[1], _c[2]); } +#define COLOR_ON if (drawLinesBlockType) COLOR_BY_BLOCK(aboveBlockType) +//#define COLOR_ON if (drawLinesBlockType) COLOR_BY_BLOCK(bi->blockType()) + +if (drawLinesBlockType) // handle flat/transparent case if (is_flat) { @@ -738,6 +865,7 @@ namespace OpenGTA { // lines if (drawLines) { glDisable(GL_TEXTURE_2D); + COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][0][j][0], @@ -750,6 +878,7 @@ namespace OpenGTA { glEnd(); glEnable(GL_TEXTURE_2D); // end-of-lines + COLOR_OFF; } } #undef MSWAP @@ -790,6 +919,7 @@ namespace OpenGTA { // lines if (drawLines) { glDisable(GL_TEXTURE_2D); + COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][2][j][0], @@ -810,6 +940,7 @@ namespace OpenGTA { glEnd(); glEnable(GL_TEXTURE_2D); // end-of-lines + COLOR_OFF; } } jj = 0; @@ -848,6 +979,7 @@ namespace OpenGTA { // lines if (drawLines) { glDisable(GL_TEXTURE_2D); + COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][3][j][0], @@ -866,6 +998,7 @@ namespace OpenGTA { SLOPE_RAW_DATA[which][4][0][1], SLOPE_RAW_DATA[which][4][0][2]); glEnd(); + COLOR_OFF; glEnable(GL_TEXTURE_2D); // end-of-lines } @@ -896,6 +1029,7 @@ namespace OpenGTA { // lines if (drawLines) { glDisable(GL_TEXTURE_2D); + COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][0][j][0], @@ -908,6 +1042,7 @@ namespace OpenGTA { glEnd(); glEnable(GL_TEXTURE_2D); // end-of-lines + COLOR_OFF; } } jj = 0; // only 'lid' rotated @@ -947,6 +1082,7 @@ namespace OpenGTA { // lines if (drawLines) { glDisable(GL_TEXTURE_2D); + COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][2][j][0], @@ -959,6 +1095,7 @@ namespace OpenGTA { glEnd(); glEnable(GL_TEXTURE_2D); // end-of-lines + COLOR_OFF; } } jj = 0; @@ -989,6 +1126,7 @@ namespace OpenGTA { // lines if (drawLines) { glDisable(GL_TEXTURE_2D); + COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][1][j][0], @@ -1001,6 +1139,7 @@ namespace OpenGTA { glEnd(); glEnable(GL_TEXTURE_2D); // end-of-lines + COLOR_OFF; } } /*memcpy(sideTex1, sideTex1_bak, 8 * sizeof(GLfloat)); @@ -1037,6 +1176,7 @@ namespace OpenGTA { // lines if (drawLines) { glDisable(GL_TEXTURE_2D); + COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][3][j][0], @@ -1049,6 +1189,7 @@ namespace OpenGTA { glEnd(); glEnable(GL_TEXTURE_2D); // end-of-lines + COLOR_OFF; } } jj = 0; @@ -1079,6 +1220,7 @@ namespace OpenGTA { // lines if (drawLines) { glDisable(GL_TEXTURE_2D); + COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][4][j][0], @@ -1091,6 +1233,7 @@ namespace OpenGTA { glEnd(); glEnable(GL_TEXTURE_2D); // end-of-lines + COLOR_OFF; } } diff --git a/gl_cityview.h b/gl_cityview.h index abd90a2..cdc006e 100644 --- a/gl_cityview.h +++ b/gl_cityview.h @@ -54,10 +54,12 @@ namespace OpenGTA { NavData::Sector* getCurrentSector(); OpenGL::PagedTexture renderMap2Texture(); - bool CityView::getDrawTextured(); - bool CityView::getDrawLines(); - void CityView::setDrawTextured(bool v); - void CityView::setDrawLines(bool v); + bool getDrawTextured(); + bool getDrawLines(); + bool getDrawLinesBlockColor(); + void setDrawTextured(bool v); + void setDrawLines(bool v); + void setDrawLinesBlockColor(bool v); void resetTextures(); const SDL_Rect & getActiveRect() { return activeRect; } @@ -83,6 +85,9 @@ namespace OpenGTA { bool topDownView; bool drawTextured; bool drawLines; + bool drawLinesBlockType; + bool drawHeadingMarkers; + uint8_t aboveBlockType; SDL_Rect activeRect; SDL_Rect drawnRect; @@ -92,7 +97,6 @@ namespace OpenGTA { GLuint scene_display_list; bool scene_is_dirty; - bool drawHeadingMarkers; int texFlipTest; Uint32 lastCacheEmptyTicks; diff --git a/gl_font.cpp b/gl_font.cpp index bf67bf5..510c4dc 100644 --- a/gl_font.cpp +++ b/gl_font.cpp @@ -95,6 +95,34 @@ namespace OpenGL { return move; } + GLfloat DrawableFont::drawString_r2l(const std::string & text) { + assert(texCache != NULL); + assert(fontSource != NULL); + std::string::const_reverse_iterator i = text.rbegin(); + std::string::const_reverse_iterator e = text.rend(); + GLfloat move = 0.0f; + while (i != e) { + + if (*i != ' ') { + FontQuad* character = NULL; + std::map::const_iterator j = drawables.find(*i); + if (j == drawables.end()) { + character = createDrawableCharacter(*i); + drawables[*i] = character; + } + else { + GLfloat mm = float(fontSource->getMoveWidth(*i)) * 1.1f * scale; + glTranslatef(-mm, 0.0f, 0.0f); + character = j->second; + move += mm; + } + Renderer::draw(*character); + } + i++; + } + return move; + } + uint16_t DrawableFont::getHeight() { return scale * fontSource->getCharHeight(); } diff --git a/gl_font.h b/gl_font.h index 3be6d9d..7b691bd 100644 --- a/gl_font.h +++ b/gl_font.h @@ -36,6 +36,7 @@ namespace OpenGL { ~DrawableFont(); void loadFont(const std::string & filename); GLfloat drawString(const std::string & text) ; + GLfloat drawString_r2l(const std::string & text) ; void setScale(unsigned int newScale); uint16_t getHeight(); void resetTextures(); diff --git a/gl_screen.cpp b/gl_screen.cpp index 4352242..0d3e7ae 100644 --- a/gl_screen.cpp +++ b/gl_screen.cpp @@ -25,6 +25,7 @@ #include "log.h" #include "buffercache.h" #include "m_exceptions.h" +#include "image_loader.h" namespace OpenGL { #ifndef DEFAULT_SCREEN_WIDTH @@ -32,6 +33,9 @@ namespace OpenGL { #endif #ifndef DEFAULT_SCREEN_HEIGHT #define DEFAULT_SCREEN_HEIGHT 480 +#endif +#ifndef DEFAULT_SCREEN_VSYNC +#define DEFAULT_SCREEN_VSYNC 0 #endif Screen::Screen() { @@ -43,6 +47,8 @@ namespace OpenGL { fieldOfView = 60.0f; nearPlane = 0.1f; farPlane = 250.0f; + // 0: no vsync, 1: sdl, 2 native + useVsync = DEFAULT_SCREEN_VSYNC; } void Screen::activate(Uint32 w, Uint32 h) { @@ -52,6 +58,7 @@ namespace OpenGL { height = h; initSDL(); resize(width, height); + INFO << "activating screen: " << width << "x" << height << std::endl; initGL(); setSystemMouseCursor(false); } @@ -62,6 +69,10 @@ namespace OpenGL { farPlane = far_p; } + void Screen::setupVsync(size_t mode) { + useVsync = mode; + } + void Screen::setSystemMouseCursor(bool visible) { SDL_ShowCursor((visible ? SDL_ENABLE : SDL_DISABLE)); } @@ -112,7 +123,7 @@ namespace OpenGL { const char* sdl_err = SDL_GetError(); if (strlen(sdl_err) > 0) - INFO << "sdl_init complained: " << sdl_err << std::endl; + WARN << "SDL_Init complained: " << sdl_err << std::endl; SDL_ClearError(); const SDL_VideoInfo *vInfo = SDL_GetVideoInfo(); @@ -166,33 +177,75 @@ namespace OpenGL { 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); + if (useVsync == 1) { + SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 1); + INFO << "enabling vertical sync:" << " SDL" << std::endl; + } +#else + if (useVsync == 1) + WARN << "Cannot use SDL vsync - option disabled while compiling" << std::endl; #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 }; - + if (useVsync == 2) { +#ifdef LINUX + int (*fp)(int) = (int(*)(int)) SDL_GL_GetProcAddress("glXSwapIntervalMESA"); + if (fp) { + fp(1); + INFO << "enabling vertical sync:" << " GLX" << std::endl; + } + else + ERROR << "No symbol 'glXSwapIntervalMESA' found - cannot use GLX vsync" << std::endl; +#else + typedef void (APIENTRY * WGLSWAPINTERVALEXT) (int); + WGLSWAPINTERVALEXT wglSwapIntervalEXT = + (WGLSWAPINTERVALEXT) wglGetProcAddress("wglSwapIntervalEXT"); + if (wglSwapIntervalEXT) + { + wglSwapIntervalEXT(1); // set vertical synchronisation + INFO << "enabling vertical sync:" << " WGL" << std::endl; + } + else + ERROR << "No symbol 'wglSwapIntervalEXT' found - cannot use WGL vsync" << std::endl; +#endif + } + /* + GLfloat LightAmbient[] = { 0.1f, 0.1f, 0.1f, 1.0f }; + GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + GLfloat LightPosition[] = { 1.0f, 1.0f, 0.0f, 0.0f }; + */ //glShadeModel( GL_SMOOTH ); glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); glEnable( GL_DEPTH_TEST ); - //glEnable( GL_LIGHTING ); + /* + glEnable( GL_LIGHTING ); glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); - //glLightfv( GL_LIGHT0, GL_AMBIENT, LightAmbient ); - //glLightfv( GL_LIGHT0, GL_DIFFUSE, LightDiffuse ); - //glLightfv( GL_LIGHT0, GL_POSITION, LightPosition ); - //glEnable( GL_LIGHT0 ); + glLightfv( GL_LIGHT0, GL_AMBIENT, LightAmbient ); + glLightfv( GL_LIGHT0, GL_DIFFUSE, LightDiffuse ); + glLightfv( GL_LIGHT0, GL_POSITION, LightPosition ); + glEnable( GL_LIGHT0 ); + */ glEnable( GL_COLOR_MATERIAL); glCullFace(GL_BACK); //glPolygonMode(GL_FRONT, GL_FILL); //glPolygonMode(GL_BACK, GL_LINE); + glEnable(GL_TEXTURE_2D); + + if (queryExtension("GL_EXT_texture_filter_anisotropic")) { + GLfloat maxAniso = 1.0f; + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAniso); + //if (maxAniso >= 2.0f) + ImageUtil::supportedMaxAnisoDegree = maxAniso; + INFO << "GL supports anisotropic filtering with degree: " << maxAniso << std::endl; + } + GL_CHECKERROR; } @@ -256,4 +309,18 @@ namespace OpenGL { SDL_SaveBMP(image, filename); SDL_FreeSurface( image ); } + + GLboolean Screen::queryExtension(const char *extName) { + // from the 'Red Book' + char *p = (char *) glGetString(GL_EXTENSIONS); + char *end = p + strlen(p); + while (p < end) { + size_t n = strcspn(p, " "); + if ((strlen(extName)==n) && (strncmp(extName,p,n)==0)) { + return GL_TRUE; + } + p += (n + 1); + } + return GL_FALSE; + } } diff --git a/gl_screen.h b/gl_screen.h index 0a81a13..630f95b 100644 --- a/gl_screen.h +++ b/gl_screen.h @@ -48,6 +48,9 @@ namespace OpenGL { inline float getNearPlane() { return nearPlane; } inline float getFarPlane() { return farPlane; } void setupGlVars( float fov, float near_p, float far_p); + void setupVsync( size_t enabled ); + + static GLboolean queryExtension(const char *extName); private: void initGL(); @@ -55,6 +58,7 @@ namespace OpenGL { Uint32 width, height; Uint32 bpp; Uint32 videoFlags; + size_t useVsync; float fieldOfView; float nearPlane; float farPlane; diff --git a/gl_spritecache.cpp b/gl_spritecache.cpp index e3c293c..97c4203 100644 --- a/gl_spritecache.cpp +++ b/gl_spritecache.cpp @@ -24,6 +24,7 @@ #include #include #include "gl_spritecache.h" +#include "image_loader.h" #include "opengta.h" #include "dataholder.h" #include "buffercache.h" @@ -188,8 +189,6 @@ namespace OpenGL { INFO << "creating new sprite: " << sprite_num << " remap: " << remap << std::endl; unsigned char* src = OpenGTA::StyleHolder::Instance().get(). getSpriteBitmap(sprite_num, remap , delta); - unsigned int glwidth = 1; - unsigned int glheight = 1; #if 0 if (sprite_num == 257) { info->w = 72; @@ -210,6 +209,9 @@ namespace OpenGL { } #endif +#if 0 + int glwidth = 1; + int glheight = 1; while(glwidth < info->w) glwidth <<= 1; @@ -225,8 +227,21 @@ namespace OpenGL { t += glwidth * 4; r += info->w * 4; } +#endif + ImageUtil::NextPowerOfTwo npot(info->w, info->h); + Util::BufferCache & bc = Util::BufferCacheHolder::Instance(); + uint8_t* dst = bc.requestBuffer(npot.w * npot.h * 4); + + ImageUtil::copyImage2Image(dst, src, info->w * 4, info->h, npot.w * 4); + bc.unlockBuffer(src); + #ifdef DO_SCALE2X if (doScale2x) { + bc.lockBuffer(dst); + uint8_t* dst_scalex = ImageUtil::scale2x_32bit(dst, npot.w, npot.h); + bc.unlockBuffer(dst); + dst = dst_scalex; +#if 0 #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -236,9 +251,9 @@ namespace OpenGL { Util::BufferCacheHolder::Instance().lockBuffer(dst); Uint8* dstpix = Util::BufferCacheHolder::Instance().requestBuffer(glwidth * glheight * 4 * 4); Uint32 E0, E1, E2, E3, B, D, E, F, H; - for(unsigned int looph = 0; looph < glheight; ++looph) + for(int looph = 0; looph < glheight; ++looph) { - for(unsigned int loopw = 0; loopw < glwidth; ++ loopw) + for(int loopw = 0; loopw < glwidth; ++ loopw) { B = *(Uint32*)(srcpix + (MAX(0,looph-1)*srcpitch) + (4*loopw)); D = *(Uint32*)(srcpix + (looph*srcpitch) + (4*MAX(0,loopw-1))); @@ -259,10 +274,14 @@ namespace OpenGL { } Util::BufferCacheHolder::Instance().unlockBuffer(dst); dst = dstpix; +#endif } #endif - GLuint texid; + GLuint texid = (doScale2x) ? + ImageUtil::createGLTexture(npot.w * 2, npot.h * 2, true, dst) + : ImageUtil::createGLTexture(npot.w, npot.h, true, dst); +#if 0 glGenTextures(1, &texid); glBindTexture(GL_TEXTURE_2D, texid); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -276,9 +295,11 @@ namespace OpenGL { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glwidth, glheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, dst); #else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glwidth, glheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, dst); +#endif + #endif return OpenGL::PagedTexture(texid, 0, 0, - float(info->w)/float(glwidth), float(info->h)/float(glheight)); + float(info->w)/float(npot.w), float(info->h)/float(npot.h)); } } diff --git a/gl_spritecache.h b/gl_spritecache.h index 1840e78..35d1753 100644 --- a/gl_spritecache.h +++ b/gl_spritecache.h @@ -22,6 +22,7 @@ ************************************************************************/ #ifndef SPRITE_CACHE_H #define SPRITE_CACHE_H +#include #include #include "Singleton.h" #include "gl_pagedtexture.h" @@ -65,7 +66,7 @@ namespace OpenGL { OpenGTA::GraphicsBase::SpriteNumbers::SpriteTypes, PHYSFS_sint16 remap, PHYSFS_uint32 delta); - OpenGL::PagedTexture SpriteCache::createSprite(size_t sprite_num, PHYSFS_sint16 remap, + OpenGL::PagedTexture createSprite(size_t sprite_num, PHYSFS_sint16 remap, PHYSFS_uint32 delta, OpenGTA::GraphicsBase::SpriteInfo* info); private: diff --git a/license.txt b/license.txt index 1909e3a..a3faa81 100644 --- a/license.txt +++ b/license.txt @@ -63,6 +63,11 @@ these remain under their respective licenses. Copyright (C) 2000 Amir Geva GNU Library General Public License +* Oriented bounding box derived from code originally written by + Jonathan Kreuzer + http://www.3dkingdoms.com/ + No license given by original author; derived code under zlib license. + *************************************************************************** Please do not redistribute the data files of the original game together with this software. diff --git a/localplayer.cpp b/localplayer.cpp new file mode 100644 index 0000000..8521743 --- /dev/null +++ b/localplayer.cpp @@ -0,0 +1,69 @@ +#include "localplayer.h" +#include "spritemanager.h" + +namespace OpenGTA { + Pedestrian & PlayerController::getPed() { + return SpriteManagerHolder::Instance().getPed(playerId); + } + + bool PlayerController::up(const uint32_t & key) { + if (!pc_ptr) + return false; + bool handled = false; + switch (key) { + case SDLK_LEFT: + pc_ptr->releaseTurnLeft(); + handled = true; + break; + case SDLK_RIGHT: + pc_ptr->releaseTurnRight(); + handled = true; + break; + case SDLK_UP: + pc_ptr->releaseMoveForward(); + handled = true; + break; + case SDLK_DOWN: + pc_ptr->releaseMoveBack(); + handled = true; + break; + case SDLK_LCTRL: + pc_ptr->releaseFireWeapon(); + handled = true; + break; + default: + break; + } + return handled; + } + + bool PlayerController::down(const uint32_t & key) { + if (!pc_ptr) + return false; + bool handled = false; + switch(key) { + case SDLK_LEFT: + handled = true; + break; + case SDLK_RIGHT: + handled = true; + break; + case SDLK_UP: + handled = true; + break; + case SDLK_DOWN: + handled = true; + break; + case SDLK_LCTRL: + handled = true; + break; + case SDLK_LSHIFT: + handled = true; + break; + default: + break; + } + return handled; + } + +} diff --git a/localplayer.h b/localplayer.h index 14a503f..5e78d8c 100644 --- a/localplayer.h +++ b/localplayer.h @@ -4,13 +4,21 @@ #include "game_objects.h" #include "entity_controller.h" #include "id_sys.h" +#include "key_handler.h" namespace OpenGTA { - class PlayerController { // : public PedController { //public Pedestrian::Controller { + class PlayerController : public Util::KeyHandler { public: PlayerController() { + reset(); + } + void reset() { playerId = TypeIdBlackBox::getPlayerId(); + cash = 0; + wantedLevel = 0; + modifier = 0; + numLives = 0; pc_ptr = NULL; } PedController & getCtrl() { @@ -20,8 +28,27 @@ namespace OpenGTA { void setCtrl(PedController & pc) { pc_ptr = &pc; } + void giveLives(uint16_t k) { + numLives += k; + } + void disableCtrl(bool soft); + void enableCtrl(); + Pedestrian & getPed(); + int32_t getNumLives() { return numLives; } + int32_t getWantedLevel() { return wantedLevel; } + uint32_t getCash() { return cash; } + bool up(const uint32_t & key); + bool down(const uint32_t & key); + uint32_t getId() { return playerId; } + void addCash(uint32_t v) { cash += v; } + void setWanted(int32_t v) { wantedLevel = v; } + void addWanted(uint32_t v) { wantedLevel += v; if (wantedLevel > 5) wantedLevel = 5; } private: uint32_t playerId; + uint32_t cash; + int32_t wantedLevel; + uint32_t modifier; + int32_t numLives; PedController * pc_ptr; }; diff --git a/lua_addon/lua_ini_bridge.cpp b/lua_addon/lua_ini_bridge.cpp index 015ec86..1808455 100644 --- a/lua_addon/lua_ini_bridge.cpp +++ b/lua_addon/lua_ini_bridge.cpp @@ -1,3 +1,4 @@ +#include #include "lua_ini_bridge.h" #include "log.h" diff --git a/lua_addon/lua_map.cpp b/lua_addon/lua_map.cpp new file mode 100644 index 0000000..61a58f9 --- /dev/null +++ b/lua_addon/lua_map.cpp @@ -0,0 +1,150 @@ +#include +#include +#include "lua_map.h" +#include "m_exceptions.h" + +namespace OpenGTA { + namespace Script { + int Block::l_getBlockType(lua_State *L) { + lua_pushinteger(L, blockType()); + return 1; + } + int Block::l_setBlockType(lua_State *L) { + uint8_t v = luaL_checkinteger(L, 1); + setBlockType(v); + return 0; + } + int Block::l_getSlopeType(lua_State *L) { + lua_pushinteger(L, slopeType()); + return 1; + } + int Block::l_setSlopeType(lua_State *L) { + uint8_t v = luaL_checkinteger(L, 1); + setSlopeType(v); + return 0; + } + int Block::l_getRotation(lua_State *L) { + lua_pushinteger(L, rotation()); + return 1; + } + int Block::l_setRotation(lua_State *L) { + uint8_t v = luaL_checkinteger(L, 1); + setRotation(v); + return 0; + } + int Block::l_getUpOk(lua_State *L) { + lua_pushboolean(L, upOk()); + return 1; + } + int Block::l_getDownOk(lua_State *L) { + lua_pushboolean(L, downOk()); + return 1; + } + int Block::l_getLeftOk(lua_State *L) { + lua_pushboolean(L, leftOk()); + return 1; + } + int Block::l_getRightOk(lua_State *L) { + lua_pushboolean(L, rightOk()); + return 1; + } + int Block::l_getIsFlat(lua_State *L) { + lua_pushboolean(L, isFlat()); + return 1; + } + int Block::l_getRailway(lua_State *L) { + lua_pushboolean(L, railway()); + return 1; + } + int Block::l_getRailStation(lua_State *L) { + lua_pushboolean(L, railStation()); + return 1; + } + int Block::l_getRailStationTrain(lua_State *L) { + lua_pushboolean(L, railStationTrain()); + return 1; + } + int Block::l_getTextureId(lua_State *L) { + int which = luaL_checkinteger(L, 1); + int v = 0; + if ((which < 0) || (which > 4)) { + std::ostringstream ostr; + ostr << "Quad id " << which << " is invalid"; + throw E_OUTOFRANGE(ostr.str()); + } + switch(which) { + case 0: + v = lid; + break; + case 1: + v = top; + break; + case 2: + v = bottom; + break; + case 3: + v = left; + break; + case 4: + v = right; + break; + default: + break; + // handled above + } + lua_pushinteger(L, v); + return 1; + } + + int LMap::l_getBlockAt(lua_State *L) { + int x, y, z; + x = luaL_checkinteger(L, 1); + y = luaL_checkinteger(L, 2); + z = luaL_checkinteger(L, 3); + OpenGTA::Map::BlockInfo* bi = getBlockAtNew(x, y, z); + assert(bi); + Block* b = static_cast(bi); + Lunar::push(L, b, false); + return 1; + } + int LMap::l_getNumBlocksAt(lua_State *L) { + int x, y; + x = luaL_checkinteger(L, 1); + y = luaL_checkinteger(L, 2); + lua_pushinteger(L, getNumBlocksAtNew(x, y)); + return 1; + } + + const char Block::className[] = "Block"; +#define method(name) {#name, &Block::l_##name} + Lunar::RegType Block::methods[] = { + method(getBlockType), + method(getSlopeType), + method(getRotation), + method(getIsFlat), + method(getLeftOk), + method(getRightOk), + method(getUpOk), + method(getDownOk), + method(getRailway), + method(getRailStation), + method(getRailStationTrain), + method(getTextureId), + + method(setBlockType), + method(setRotation), + method(setSlopeType), + {0, 0} + }; +#undef method +#define method(name) {#name, &LMap::l_##name} + const char LMap::className[] = "Map"; + Lunar::RegType LMap::methods[] = { + method(getNumBlocksAt), + method(getBlockAt), + {0, 0} + }; + + + } +} diff --git a/lua_addon/lua_map.h b/lua_addon/lua_map.h new file mode 100644 index 0000000..83c239d --- /dev/null +++ b/lua_addon/lua_map.h @@ -0,0 +1,50 @@ +#ifndef LUA_MAP_H +#define LUA_MAP_H + +#include "lunar.h" +#include "opengta.h" + +namespace OpenGTA { + namespace Script { + class Block : public OpenGTA::Map::BlockInfo { + public: + int l_getBlockType(lua_State *L); + int l_getUpOk(lua_State *L); + int l_getDownOk(lua_State *L); + int l_getLeftOk(lua_State *L); + int l_getRightOk(lua_State *L); + int l_getIsFlat(lua_State *L); + int l_getSlopeType(lua_State *L); + int l_getRotation(lua_State *L); + int l_getRailway(lua_State *L); + int l_getRailStation(lua_State *L); + int l_getRailStationTrain(lua_State *L); + int l_getTextureId(lua_State *L); + + int l_setBlockType(lua_State *L); + int l_setUpOk(lua_State *L); + int l_setDownOk(lua_State *L); + int l_setLeftOk(lua_State *L); + int l_setRightOk(lua_State *L); + int l_setIsFlat(lua_State *L); + int l_setSlopeType(lua_State *L); + int l_setRotation(lua_State *L); + //... + int l_setTextureId(lua_State *L); + + + static const char className[]; + static Lunar::RegType methods[]; + }; + class LMap : public OpenGTA::Map { + public: + LMap() : OpenGTA::Map("") {} + int l_getNumBlocksAt(lua_State *L); + int l_getBlockAt(lua_State *L); + + static const char className[]; + static Lunar::RegType methods[]; + }; + } +} +#endif diff --git a/lua_addon/lua_vm.cpp b/lua_addon/lua_vm.cpp index 3d76936..c458ab0 100644 --- a/lua_addon/lua_vm.cpp +++ b/lua_addon/lua_vm.cpp @@ -11,6 +11,8 @@ using namespace Util; +extern int global_Done; + namespace OpenGTA { namespace Script { LuaVM::LuaVM() : L(NULL) { @@ -20,6 +22,7 @@ namespace OpenGTA { luaopen_base(L); luaopen_math(L); + luaopen_table(L); _registered = false; lua_settop(L, 0); prepare(); @@ -31,17 +34,24 @@ namespace OpenGTA { L = NULL; } + int vm_quit(lua_State *L) { + global_Done = true; + return 0; + } + void LuaVM::prepare() { LGUARD(L); if (!_registered) { Lunar::Register2(L); Lunar::Register2(L); - /* +#ifndef LUA_MAP_ONLY Lunar::Register2(L); luaL_openlib(L, "camera", Camera::methods, 0); luaL_openlib(L, "screen", Screen::methods, 0); luaL_openlib(L, "spritecache", SpriteCache::methods, 0); - */ +#endif + lua_pushcfunction(L, vm_quit); + lua_setglobal(L, "quit"); } _registered = true; } @@ -61,15 +71,15 @@ namespace OpenGTA { } void LuaVM::setCityView(OpenGTA::CityView & cv) { +#ifndef LUA_MAP_ONLY LGUARD(L); - /* CityView *scv = static_cast(&cv); lua_gettable(L, LUA_GLOBALSINDEX); int scv_ref = Lunar::push(L, scv, false); lua_pushliteral(L, "city_view"); lua_pushvalue(L, scv_ref); lua_settable(L, LUA_GLOBALSINDEX); - */ +#endif } void LuaVM::runString(const char* _str) { @@ -103,7 +113,7 @@ namespace OpenGTA { lua_getglobal(L, key); if (!lua_isnumber(L, -1)) throw E_SCRIPTERROR("Expected int value for key: " + std::string(key)); - int v = int(lua_tonumber(L, -1)); + int v = int(lua_tointeger(L, -1)); return v; } @@ -125,9 +135,69 @@ namespace OpenGTA { return v; } + bool LuaVM::getGlobalBool(const char* key) { + LGUARD(L); + lua_getglobal(L, key); + if (!lua_isboolean(L, -1)) + throw E_SCRIPTERROR("Expected boolean value for key: " + std::string(key)); + return lua_toboolean(L, -1); + } + + void LuaVM::setInt(const char* key, int v) { + lua_pushinteger(L, v); + lua_setfield(L, -2, key); + } + + int LuaVM::getInt(const char* key) { + LGUARD(L); + lua_getfield(L, -1, key); + if (!lua_isnumber(L, -1)) + throw E_SCRIPTERROR("Expected int value for key: " + std::string(key)); + return luaL_checkinteger(L, -1); + } + + void LuaVM::setFloat(const char* key, float v) { + lua_pushnumber(L, v); + lua_setfield(L, -2, key); + } + + float LuaVM::getFloat(const char* key) { + LGUARD(L); + lua_getfield(L, -1, key); + if (!lua_isnumber(L, -1)) + throw E_SCRIPTERROR("Expected float value for key: " + std::string(key)); + return luaL_checknumber(L, -1); + } + + void LuaVM::setString(const char* key, const char* v) { + lua_pushstring(L, v); + lua_setfield(L, -2, key); + } + + const char* LuaVM::getString(const char* key) { + LGUARD(L); + lua_getfield(L, -1, key); + if (!lua_isstring(L, -1)) + throw E_SCRIPTERROR("Expected string value for key: " + std::string(key)); + return luaL_checkstring(L, -1); + } + + void LuaVM::setBool(const char* key, bool v) { + lua_pushboolean(L, v); + lua_setfield(L, -2, key); + } + + bool LuaVM::getBool(const char* key) { + LGUARD(L); + lua_getfield(L, -1, key); + if (!lua_isboolean(L, -1)) + throw E_SCRIPTERROR("Expected boolean value for key: " + std::string(key)); + return lua_toboolean(L, -1); + } + void LuaVM::setGlobalInt(const char* key, int v) { LGUARD(L); - lua_pushnumber(L, v); + lua_pushinteger(L, v); lua_setglobal(L, key); } @@ -143,5 +213,11 @@ namespace OpenGTA { lua_setglobal(L, key); } + void LuaVM::setGlobalBool(const char* key, bool v) { + LGUARD(L); + lua_pushboolean(L, v); + lua_setglobal(L, key); + } + } } diff --git a/lua_addon/lua_vm.h b/lua_addon/lua_vm.h index d489086..0700298 100644 --- a/lua_addon/lua_vm.h +++ b/lua_addon/lua_vm.h @@ -11,17 +11,29 @@ namespace OpenGTA { public: LuaVM(); ~LuaVM(); - void runString(const char*); - void runFile(const char*); - void callSimpleFunction(const char*); - void setCityView(OpenGTA::CityView &); - void setMap(OpenGTA::Map &); - int getGlobalInt(const char*); + void runString(const char*); + void runFile(const char*); + void callSimpleFunction(const char*); + 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*); + bool getGlobalBool(const char*); + void setGlobalInt(const char*, int); + void setGlobalFloat(const char*, float); + void setGlobalString(const char*, const char*); + void setGlobalBool(const char*, bool); + + void setInt(const char*, int); + int getInt(const char*); + void setFloat(const char*, float); + float getFloat(const char*); + void setString(const char*, const char*); + const char* getString(const char*); + void setBool(const char*, bool); + bool getBool(const char*); + lua_State *getInternalState(); protected: lua_State *L; diff --git a/main2.cpp b/main2.cpp index 48c4398..9b048e3 100644 --- a/main2.cpp +++ b/main2.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "m_exceptions.h" #include "log.h" @@ -11,6 +12,7 @@ extern void run_main(); int global_EC = 0; int global_Done = 0; +int global_Restart = 0; #ifndef DONT_CATCH bool catch_exceptions = true; @@ -54,5 +56,10 @@ int main(int argc, char* argv[]) { } } + if (global_Restart) { + on_exit(); + execvp(argv[0], argv); + } + std::exit(0); } diff --git a/makefile b/makefile index e547374..f60f57e 100644 --- a/makefile +++ b/makefile @@ -58,7 +58,8 @@ doxy_main.h: doc/hacking.txt tools/doxy_doc.sh doxyclean: $(RM) doxy_main.h -r doc/html -package: +package: release_files_sorted + sh tools/cvslog.sh (cd .. && tar jvcf ogta_src_`date +%F`.tar.bz2 -T ogta/release_files_sorted) @echo "saved as: ogta_src_`date +%F.tar.bz2`" diff --git a/math/obox.cpp b/math/obox.cpp index 57456a6..ce745a7 100644 --- a/math/obox.cpp +++ b/math/obox.cpp @@ -1,4 +1,46 @@ +/* Derived from code written by Jonathan Kreuzer. + * + * See: http://www.3dkingdoms.com/weekly/weekly.php?a=21 + * + * basically the same as bbox.h/.cpp but using coldet math + * + * -- quote from a mail of the author -- + * + * You're free to continue using my CBBox code however you want. + * ... [snip] ... + * The only thing I ask is a note about where it came from ( I think + * you said you added a link to the article, so that's fine. ) + * + */ + +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ + +#include +#include "log.h" #include "obox.h" + +#include "plane.h" // -------------------------- // // Oriented Bounding Box Class @@ -8,7 +50,7 @@ // // Check if a point is in this bounding box // -bool OBox::IsPointInBox(const Vector3D &InP) const +bool OBox::isPointInBox(const Vector3D &InP) const { // Rotate the point into the box's coordinates Vector3D P = Transform(InP, m_M.Inverse()); @@ -23,7 +65,7 @@ bool OBox::IsPointInBox(const Vector3D &InP) const // // Check if a sphere overlaps any part of this bounding box // -bool OBox::IsSphereInBox( const Vector3D &InP, float fRadius) const +bool OBox::isSphereInBox( const Vector3D &InP, float fRadius) const { float fDist; float fDistSq = 0; @@ -44,7 +86,7 @@ bool OBox::IsSphereInBox( const Vector3D &InP, float fRadius) const // // 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 ) const +bool OBox::boxOutsidePlane( const Vector3D &InNorm, const Vector3D &InP ) const { // Plane Normal in Box Space Vector3D Norm = rotateVector(InNorm, m_M.Inverse() ); @@ -52,7 +94,7 @@ bool OBox::BoxOutsidePlane( const Vector3D &InNorm, const Vector3D &InP ) const float Extent = Norm * m_Extent; //Norm.Dot( m_Extent ); // Box Extent along the plane normal //float Distance = InNorm.Dot( GetCenterPoint() - InP ); // Distance from Box Center to the Plane - float Distance = InNorm * (GetCenterPoint() - InP); + float Distance = InNorm * (getCenterPoint() - InP); // If Box Centerpoint is behind the plane further than its extent, the Box is outside the plane if ( Distance < -Extent ) return true; @@ -62,7 +104,7 @@ bool OBox::BoxOutsidePlane( const Vector3D &InNorm, const Vector3D &InP ) const // // Does the Line (L1, L2) intersect the Box? // -bool OBox::IsLineInBox( const Vector3D& L1, const Vector3D& L2 ) const +bool OBox::isLineInBox( const Vector3D& L1, const Vector3D& L2 ) const { // Put line in box space Matrix3D MInv = m_M.Inverse(); @@ -87,10 +129,40 @@ bool OBox::IsLineInBox( const Vector3D& L1, const Vector3D& L2 ) const return true; } +void OBox::lineCrossBox(const Vector3D& L1, const Vector3D& L2, Vector3D & isecLocal) const { + // Put line in box space + Matrix3D MInv = m_M.Inverse(); + Vector3D LB1 = Transform(L1, MInv); + Vector3D LB2 = Transform(L2, MInv); + float small_t = 2.0f; + Vector3D p_copy(0, 0, 0); + + //i = 0: -x,-z <-> -x,z + //i = 1: -x,-z <-> x,-z + //i = 2: x,-z, <-> x,z + //i = 3: -x,z <-> x,z + for (int i = 0; i < 4; i++) { + Vector3D s1((i <= 1 || i == 3 ? -m_Extent.x : m_Extent.x), 0, (i < 3 ? -m_Extent.z : m_Extent.z)); + Vector3D s2((i == 0 ? -m_Extent.x : m_Extent.x), 0, (i == 1 ? -m_Extent.z : m_Extent.z)); + Vector3D p; + float dt = Math::intersection_segments(s1, s2, LB1, LB2, p); + if ((dt >= 0.0f) && (dt < small_t)) { + p_copy = p; + small_t = dt; + } + } + if (small_t >= 0.0f && small_t <= 1.0f) { + isecLocal = p_copy; + return; + } + ERROR << "Did not find intersection when OBB says there is one :-(" << std::endl; + isecLocal = L1; +} + // // Returns a 3x3 rotation matrix as vectors // -inline void OBox::GetInvRot( Vector3D *pvRot ) const +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,13 +173,13 @@ inline void OBox::GetInvRot( Vector3D *pvRot ) const // Check if any part of a box is inside any part of another box // Uses the separating axis test. // -bool OBox::IsBoxInBox( OBox &BBox ) const +bool OBox::isBoxInBox( OBox &BBox ) const { Vector3D SizeA = m_Extent; Vector3D SizeB = BBox.m_Extent; Vector3D RotA[3], RotB[3]; - GetInvRot( RotA ); - BBox.GetInvRot( RotB ); + getInvRot( RotA ); + BBox.getInvRot( RotB ); float R[3][3]; // Rotation from B to A float AR[3][3]; // absolute values of R matrix, to use with box extents @@ -123,7 +195,7 @@ bool OBox::IsBoxInBox( OBox &BBox ) const } // Vector separating the centers of Box B and of Box A - Vector3D vSepWS = BBox.GetCenterPoint() - GetCenterPoint(); + Vector3D vSepWS = BBox.getCenterPoint() - getCenterPoint(); // Rotated into Box A's coordinates Vector3D vSepA( vSepWS * RotA[0], vSepWS * RotA[1], vSepWS * RotA[2] ); diff --git a/math/obox.h b/math/obox.h index 62545a0..7f84ada 100644 --- a/math/obox.h +++ b/math/obox.h @@ -1,43 +1,79 @@ +/* Derived from code written by Jonathan Kreuzer. + * + * See: http://www.3dkingdoms.com/weekly/weekly.php?a=21 + * + * basically the same as bbox.h/.cpp but using coldet math + * + * -- quote from a mail of the author -- + * + * You're free to continue using my CBBox code however you want. + * ... [snip] ... + * The only thing I ask is a note about where it came from ( I think + * you said you added a link to the article, so that's fine. ) + * + */ + +/************************************************************************ +* 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 "math3d.h" -// see: from: http://www.3dkingdoms.com/weekly/weekly.php?a=21 - -// basically the same as bbox.h/.cpp but using coldet math - class OBox { public: OBox() {} OBox( const Matrix3D & m, const Vector3D & extent ) - { Set( m, extent ); } + { set( m, extent ); } OBox( const Matrix3D & m, const Vector3D & low, const Vector3D & high ) - { Set( m, low, high ); } + { set( m, low, high ); } OBox( const OBox & other) - { Set( other.m_M, other.m_Extent ); } + { set( other.m_M, other.m_Extent ); } - void Set( const Matrix3D & m, const Vector3D & extent ) + void set( const Matrix3D & m, const Vector3D & extent ) { m_M = m; m_Extent = extent; } - void Set( const Matrix3D & m, const Vector3D & low, const Vector3D & high ) + void set( const Matrix3D & m, const Vector3D & low, const Vector3D & high ) { m_M = m; m_M.Translate( 0.5f * (low + high) ); m_Extent = 0.5f * (high - low); } - Vector3D GetSize() const + Vector3D getSize() const { return 2.0f * m_Extent; } - Vector3D GetCenterPoint() const + Vector3D getCenterPoint() const { return m_M.GetTranslate(); } - void GetInvRot( Vector3D *pvRot ) const; + void getInvRot( Vector3D *pvRot ) const; - 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 ; + 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 ; + + void lineCrossBox(const Vector3D & l1, const Vector3D & l2, Vector3D & isecLocalSpace) const; // Data Matrix3D m_M; diff --git a/math/plane.cpp b/math/plane.cpp new file mode 100644 index 0000000..6e38968 --- /dev/null +++ b/math/plane.cpp @@ -0,0 +1,74 @@ +#include "plane.h" +#include "log.h" + +namespace Math { + + // see: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/example.cpp + float intersection_segments(const Vector3D & s1, const Vector3D & s2, + const Vector3D & l1, const Vector3D & l2, Vector3D & hit) { + float denom = (l2.z - l1.z) * (s2.x - s1.x) - + (l2.x - l1.x) * (s2.z - s1.z); + + float d_a = (l2.x - l1.x) * (s1.z - l1.z) - + (l2.z - l1.z) * (s1.x - l1.x); + + float d_b = (s2.x - s1.x) * (s1.z - l1.z) - + (s2.z - s1.z) * (s1.x - l1.x); + + float ua = d_a / denom; // ratio on s1 -> s2 + float ub = d_b / denom; // ratio on l1 -> l2 + + if (denom == 0.0f) { + /* + if (d_a == 0.0f && d_b == 0.0f) + INFO << "COINCIDENT" << std::endl; + else + INFO << "PARALLEL" << std::endl; + */ + return -1.0f; + } + + if (ua >= 0.0f && ua <= 1.0f && ub >= 0.0f && ub <= 1.0f) { + hit.x = s1.x + ua * (s2.x - s1.x); + hit.z = s1.z + ua * (s2.z - s1.z); + //INFO << "INTERSECTING " << hit.x << " " << hit.z << std::endl; + //INFO << ua << " | " << ub << std::endl; + return ub; + } + //INFO << "NOT INTERSECTING" << std::endl; + return -1.0f; + } + + int Plane::segmentIntersect(const Vector3D & p1, const Vector3D & p2, Vector3D & p_p) { + float d = - normal.x * pop.x - normal.y * pop.y - normal.z * pop.z; + float denom = normal.x * (p2.x - p1.x) + normal.y * (p2.y - p1.y) + + normal.z * (p2.z - p1.z); + if (fabs(denom) < 0.001f) + return false; + float mu = - (d + normal.x * p1.x + normal.y * p1.y + normal.z * p1.z) / denom; + p_p = Vector3D(p2 - p1) * mu + p1; + if (mu < 0 || mu > 1) + return false; + return true; + } + float Plane::distance(const Vector3D & p) { + float d = normal * p; + d += - normal.x * pop.x - normal.y * pop.y - normal.z * pop.z; + return d; + } +} + +/* +int main() { + Vector3D p(0, 0, 0); + Vector3D n(-1, 0, 0); + Math::Plane plane(p, n); + Vector3D p1(-1, 0, 0); + Vector3D p2(1, 0, 0); + Vector3D col; + if (plane.segmentIntersect(p1, p2, col)) + std::cout << "intersect at: " << col.x << " " << col.y << " " << col.z << std::endl; + std::cout << plane.distance(p1) << std::endl; + std::cout << plane.distance(p2) << std::endl; +} +*/ diff --git a/math/plane.h b/math/plane.h new file mode 100644 index 0000000..58e0e42 --- /dev/null +++ b/math/plane.h @@ -0,0 +1,26 @@ +#ifndef MATH_PLANE_H +#define MATH_PLANE_H + +#include "math3d.h" + +namespace Math { + + float intersection_segments(const Vector3D & s1, const Vector3D & s2, + const Vector3D & l1, const Vector3D & l2, Vector3D & hit); + + struct Plane { + Plane(const Vector3D & p, const Vector3D & n) : + pop(p), normal(n) {} + Plane(const Vector3D & p1, const Vector3D & p2, const Vector3D & p3) : + pop(p1), normal() { + const Vector3D pa(p2 - p1); + const Vector3D pb(p3 - p1); + normal = CrossProduct(pa, pb).Normalized(); + } + Vector3D pop; + Vector3D normal; + int segmentIntersect(const Vector3D & p1, const Vector3D & p2, Vector3D & p_p); + float distance(const Vector3D & p); + }; +} +#endif diff --git a/navdata.cpp b/navdata.cpp index e77203a..4a7999d 100644 --- a/navdata.cpp +++ b/navdata.cpp @@ -100,28 +100,48 @@ namespace OpenGTA { return ""; std::string n; if (lastSubLocation == 0) - n.append("Central "); + //n.append("Central "); + n.append(_c); else if (lastSubLocation == 1) - n.append("North "); + //n.append("North "); + n.append(_n); else if (lastSubLocation == 2) - n.append("South "); + n.append(_s); + //n.append("South "); else if (lastSubLocation == 4) - n.append("East "); + n.append(_e); + //n.append("East "); else if (lastSubLocation == 8) - n.append("West "); + n.append(_w); + //n.append("West "); else if (lastSubLocation == 9) - n.append("Northwest "); + n.append(_nw); + //n.append("Northwest "); else if (lastSubLocation == 10) - n.append("Southwest "); + n.append(_sw); + //n.append("Southwest "); else if (lastSubLocation == 5) - n.append("Northeast "); + n.append(_ne); + //n.append("Northeast "); else if (lastSubLocation == 6) - n.append("Southeast "); - + n.append(_se); + //n.append("Southeast "); + + n.append(" "); n.append(name); return n.c_str(); } + std::string NavData::_c; + std::string NavData::_n; + std::string NavData::_s; + std::string NavData::_w; + std::string NavData::_e; + std::string NavData::_nw; + std::string NavData::_ne; + std::string NavData::_sw; + std::string NavData::_se; + NavData::NavData(PHYSFS_uint32 size, PHYSFS_file *fd, const size_t level_num) { if (size % 35) { std::ostringstream o; @@ -133,6 +153,15 @@ namespace OpenGTA { assert(fd); MessageDB & msg = MainMsgHolder::Instance().get(); + _c =msg.getText("c"); + _n = msg.getText("n"); + _s = msg.getText("s"); + _w = msg.getText("w"); + _e = msg.getText("e"); + _nw = msg.getText("nw"); + _ne = msg.getText("ne"); + _sw = msg.getText("sw"); + _se = msg.getText("se"); for (PHYSFS_uint32 i = 0; i < c; ++i) { Sector *sec = new Sector(fd); if (sec->getSize() == 0) { // workaround for 'NYC.CMP' (empty sectors) diff --git a/navdata.h b/navdata.h index 5380582..18b5f5f 100644 --- a/navdata.h +++ b/navdata.h @@ -89,6 +89,7 @@ namespace OpenGTA { NavData(PHYSFS_uint32 size, PHYSFS_file *fd, const size_t level_num); ~NavData(); Sector* getSectorAt(PHYSFS_uint8, PHYSFS_uint8); + static std::string _c, _n, _s, _w, _e, _nw, _ne, _sw, _se; private: void clear(); typedef std::multimap SectorMapType; diff --git a/ogta_version b/ogta_version index 9c173cf..4aebf08 100644 --- a/ogta_version +++ b/ogta_version @@ -1 +1 @@ -2007-04-16 +2007-06-14 diff --git a/opengta.h b/opengta.h index 412e974..ef1d374 100644 --- a/opengta.h +++ b/opengta.h @@ -27,6 +27,7 @@ namespace OpenGTA { public: GraphicsBase(); virtual ~GraphicsBase(); + uint8_t getFormat(); typedef struct ObjectInfo { PHYSFS_uint32 width, height, depth; @@ -395,15 +396,19 @@ namespace OpenGTA { PHYSFS_uint8 typeMapExt; PHYSFS_uint8 left, right, top, bottom, lid; - inline bool upOk() { return (typeMap & 1); } - inline bool downOk() { return (typeMap & 2); } - inline bool leftOk() { return (typeMap & 4); } - inline bool rightOk() { return (typeMap & 8); } - inline uint8_t blockType() { return ((typeMap & 16 ? 1 : 0) + (typeMap & 32 ? 2 : 0) + (typeMap & 64 ? 4 : 0)); } - inline bool isFlat() { return (typeMap & 128); } - inline uint8_t slopeType() { return ((typeMap & 256 ? 1 : 0) + (typeMap & 512 ? 2 : 0) + - (typeMap & 1024 ? 4 : 0) + (typeMap & 2048 ? 8 : 0) + (typeMap & 4096 ? 16 : 0) + (typeMap & 8192 ? 32 : 0));} - inline uint8_t rotation() { return ((typeMap & 16384 ? 1 : 0) + (typeMap & 32768 ? 2 : 0)); } + inline bool upOk() { return (typeMap & 1); } + inline bool downOk() { return (typeMap & 2); } + inline bool leftOk() { return (typeMap & 4); } + inline bool rightOk() { return (typeMap & 8); } + inline uint8_t blockType() { return ((typeMap & 16 ? 1 : 0) + + (typeMap & 32 ? 2 : 0) + (typeMap & 64 ? 4 : 0)); } + inline bool isFlat() { return (typeMap & 128); } + inline uint8_t slopeType() { return ((typeMap & 256 ? 1 : 0) + + (typeMap & 512 ? 2 : 0) + (typeMap & 1024 ? 4 : 0) + + (typeMap & 2048 ? 8 : 0) + (typeMap & 4096 ? 16 : 0) + + (typeMap & 8192 ? 32 : 0)); } + inline uint8_t rotation() { return ((typeMap & 16384 ? 1 : 0) + + (typeMap & 32768 ? 2 : 0)); } /* m1win seems to indicate: * 000 - Nothing * 001 - traffic lights @@ -414,12 +419,22 @@ namespace OpenGTA { * 110 - railway station * 111 - railway station train */ + + inline void setUpOk(bool v) { if (v) typeMap |= 1; else typeMap &= ~1; } + inline void setDownOk(bool v) { if (v) typeMap |= 2; else typeMap &= ~2; } + inline void setLeftOk(bool v) { if (v) typeMap |= 4; else typeMap &= ~4; } + inline void setRightOk(bool v) { if (v) typeMap |= 8; else typeMap &= ~8; } + inline void setIsFlat(bool v) { if (v) typeMap |= 128; else typeMap &= ~128; } + void setBlockType(uint8_t v); + void setSlopeType(uint8_t v); + void setRotation(uint8_t v); + inline bool trafficLights() { return (typeMapExt & 1); } - inline bool railEndTurn() { return (typeMapExt & 4); } + inline bool railEndTurn() { return (typeMapExt & 4); } inline bool railStartTurn() { return ((typeMapExt & 4) && (typeMapExt &1)); } - inline bool railStation() { return ((typeMapExt & 4) && (typeMapExt & 2));} + inline bool railStation() { return ((typeMapExt & 4) && (typeMapExt & 2));} inline bool railStationTrain() { return ((typeMapExt & 4) && (typeMapExt & 2) && (typeMapExt & 1)); } - inline uint8_t remapIndex() { return ((typeMapExt & 8 ? 1 : 0) + (typeMapExt & 16 ? 2 : 0));} + inline uint8_t remapIndex() { return ((typeMapExt & 8 ? 1 : 0) + (typeMapExt & 16 ? 2 : 0));} inline bool flipTopBottom() { return (typeMapExt & 32); } inline bool flipLeftRight() { return (typeMapExt & 64); } inline bool railway() { return (typeMapExt & 128); } @@ -450,6 +465,8 @@ namespace OpenGTA { NavData *nav; ObjectPosition *objects; PHYSFS_uint16 numObjects; + const Location & getNearestLocationByType(uint8_t t, uint8_t x, uint8_t y); + const LocationMap & getLocationMap() { return locations; } protected: PHYSFS_uint32 base[GTA_MAP_MAXDIMENSION][GTA_MAP_MAXDIMENSION]; diff --git a/prepare_build.sh b/prepare_build.sh index f019126..45a240e 100755 --- a/prepare_build.sh +++ b/prepare_build.sh @@ -13,7 +13,7 @@ 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 util/physfsrwops.c" ) | sort | xargs echo "$FOO =" +( grep -l "^namespace OpenGL" *.cpp ;echo "gl_frustum.cpp";echo "math/obox.cpp math/plane.cpp coldet/math3d.cpp util/physfsrwops.c" ) | sort | xargs echo "$FOO =" echo "$FOOO = \${$FOO:.cpp=.o}" FOO=OGTA_SRC FOOO=OGTA_OBJ @@ -71,9 +71,9 @@ viewer${EXE_PFIX}: main2.cpp viewer.o \$(OGTA_OBJ) \$(GL_OBJ) \$(UTIL_OBJ) \$(OS -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) \$(OSTEER_OBJ) \ +luaviewer${EXE_PFIX}: main2.cpp viewer.o \$(OGTA_OBJ) \$(GL_OBJ) \$(UTIL_OBJ) \$(OSTEER_OBJ) \ \$(LUA_OBJ) - \$(CXX) \$(CATCH_E) -DWITH_LUA \$(FLAGS) \$(DEFS) \\ + \$(CXX) \$(CATCH_E) \$(FLAGS) \$(DEFS) \\ \$(INC) \\ -o \$@ \$+ \\ \$(SDL_LIB) \$(SDL_GL_LIB) \$(PHYSFS_LIB) \$(LOKI_LIB) \$(COLDET_LIB) \$(LUA_LIB) @@ -89,6 +89,11 @@ slopeview: main.o tools/display_slopes.o navdata.o read_cmp.o \ \$(UTIL_OBJ) common_sdl_gl.o \$(CXX) \$(CXXFLAGS) -o \$@ \$+ \$(SDL_LIB) \$(PHYSFS_LIB) -lSDL_image +blockview: main2.o tools/blockview.cpp util/log.o util/m_exceptions.o \ +gl_camera.o gl_screen.o read_cmp.o dataholder.o slope_height_func.o navdata.o \ +datahelper.o read_gry.o read_g24.o util/set.o util/buffercache.o read_fxt.o blockdata.o + \$(CXX) \$(CXXFLAGS) -o \$@ \$+ \$(SDL_LIB) \$(SDL_GL_LIB) \$(PHYSFS_LIB) + g24: read_g24.cpp read_gry.o \$(UTIL_OBJ) \$(CXX) -DG24_DUMPER \$(CXXFLAGS) -o \$@ \$+ \$(SDL_LIB) \$(PHYSFS_LIB) @@ -305,6 +310,8 @@ OPT = $OPT WARN = $WARN DEFS = $DEFS +LIB_RT_PATH = libs + # def only for 'main' programs to let gdb handle the exception #CATCH_E = -DDONT_CATCH @@ -312,7 +319,7 @@ DEFS = $DEFS # the external libraries PHYSFS_INC = -Iinc -PHYSFS_LIB = -Llibs -lphysfs -lz +PHYSFS_LIB = -Llibs -lphysfs-1-1-0 -lzlib1 SDL_INC = -Iinc -D_GNU_SOURCE=1 -D_REENTRANT SDL_LIB = -Llibs -lSDLmain -lSDL @@ -379,17 +386,28 @@ function print_config_h() { #define DEFAULT_SCREEN_WIDTH 640 #define DEFAULT_SCREEN_HEIGHT 480 +// 0 - no vsync (default), 1 - try to use SDL_GL_SWAP_CONTROL, +// 2 - try native call (GLX on linux, unsupported on win32) +//#undef DEFAULT_SCREEN_VSYNC +#define DEFAULT_SCREEN_VSYNC 2 + +// default pathes; env-variables can override #define OGTA_DEFAULT_DATA_PATH "gtadata.zip" #define OGTA_DEFAULT_MOD_PATH "" #define OGTA_DEFAULT_HOME_PATH PHYSFS_getBaseDir() +// just for fun #define USED_GCC_VERSION "$GCC_VERSION" // enable features -#define DO_SCALEX -#undef WITH_LUA +#define DO_SCALE2X $SDL_SOUND_MIXER $SDL_GL_SWAP_CONTROL + +// use escape sequences to mark Log::info/warn/error() +#ifdef LINUX +//#define LOG_USE_ANSI_COLORS +#endif EOF } @@ -401,6 +419,7 @@ if [[ -n "$1" && "$1" != "LINUX" ]]; then print_w32settings > src_list.make print_make_file_list >> src_list.make print_target_list >> src_list.make + SDL_GL_SWAP_CONTROL='#define HAVE_SDL_VSYNC' else OGTA_PLATFORM="LINUX" echo "*** LINUX ***" diff --git a/read_cmp.cpp b/read_cmp.cpp index 659d101..d732041 100644 --- a/read_cmp.cpp +++ b/read_cmp.cpp @@ -22,6 +22,70 @@ */ namespace OpenGTA { + void Map::BlockInfo::setBlockType(uint8_t v) { + switch(v) { + case 0: + typeMap &= ~(16 | 32 | 64); + break; + case 1: + typeMap |= 16; + typeMap &= ~(32 | 64); + break; + case 2: + typeMap |= 32; + typeMap &= ~(16 | 64); + break; + case 3: + typeMap |= (16 | 32); + typeMap &= ~64; + break; + case 4: + typeMap |= 64; + typeMap &= ~(16 | 32); + break; + case 5: + typeMap |= (16 | 64); + typeMap &= ~32; + break; + case 6: + typeMap |= (32 | 64); + typeMap &= ~16; + break; + case 7: + typeMap |= (16 | 32 | 64); + break; + default: + ERROR << "Invalid block-type: " << int(v) << std::endl; + break; + } + } + + void Map::BlockInfo::setSlopeType(uint8_t v) { + WARN << "NOT IMPLEMENTED" << std::endl; + } + + void Map::BlockInfo::setRotation(uint8_t v) { + switch(v) { + case 0: + typeMap &= ~(16384 | 32768); + break; + case 1: + typeMap |= 16384; + typeMap &= ~32768; + break; + case 2: + typeMap |= 32768; + typeMap &= ~16384; + break; + case 3: + typeMap |= (16384 | 32768); + break; + default: + ERROR << "Invalid rotation: " << int(v) << std::endl; + break; + } + } + Map::Map(const std::string& filename) { nav = 0; fd = PHYSFS_openRead(filename.c_str()); @@ -204,6 +268,7 @@ namespace OpenGTA { PHYSFS_read(fd, static_cast(&loc.x), 1, 1); PHYSFS_read(fd, static_cast(&loc.y), 1, 1); PHYSFS_read(fd, static_cast(&loc.z), 1, 1); + // skip dummy entries at 0,0,0 if ((loc.x == 0) && (loc.y == 0) && (loc.z == 0)) continue; if (i < 6) @@ -266,6 +331,32 @@ namespace OpenGTA { } } } + const Map::Location & Map::getNearestLocationByType(uint8_t t, uint8_t x, uint8_t y) { + INFO << int(t) << " at " << int(x) << " " << int(y) << std::endl; + LocationMap::iterator i = locations.find(t); + LocationMap::iterator j; + if (i == locations.end()) { + std::ostringstream o; + o << "location-type " << int(t) << " not found in map"; + throw E_UNKNOWNKEY(o.str()); + } + int _x(x); + int _y(y); + int min_d = 255 * 255; +#define ABS(a) (a > 0 ? a : -a) + + while (i != locations.end()) { + INFO << int(i->first) << ": "<< int(i->second->x) << " " << int(i->second->y) << std::endl; + int d = ABS((_x - i->second->x)) + ABS((_y - i->second->y)); + if (d < min_d) { + min_d = d; + j = i; + } + } +#undef ABS + return *j->second; + } + } #if 0 diff --git a/read_fxt.cpp b/read_fxt.cpp index b0a1196..cf7f18f 100644 --- a/read_fxt.cpp +++ b/read_fxt.cpp @@ -77,6 +77,9 @@ namespace OpenGTA { //std::cout << tmp << " : " << buff << std::endl; /*else std::cout << "Skipping: " << tmp << ": " << buff << std::endl;*/ +#ifdef FXT_TEST + std::cout << tmp << " : " << buff << std::endl; +#endif } else { buff[i] = v; @@ -122,11 +125,19 @@ namespace OpenGTA { } #if FXT_TEST +#include "file_helper.h" int main(int argc, char* argv[]) { PHYSFS_init(argv[0]); PHYSFS_addToSearchPath("gtadata.zip", 1); - OpenGTA::MessageDB* strings = new OpenGTA::MessageDB(); + const char* lang = getenv("OGTA_LANG"); + if (!lang) + lang = getenv("LANG"); + if (!lang) + lang = "en"; + OpenGTA::MessageDB* strings = new OpenGTA::MessageDB( + Util::FileHelper::lang2MsgFilename(lang) + ); std::cout << strings->getText(1001) << std::endl; delete strings; diff --git a/read_gry.cpp b/read_gry.cpp index 67c08df..6a4f02b 100644 --- a/read_gry.cpp +++ b/read_gry.cpp @@ -278,6 +278,15 @@ namespace OpenGTA { ERROR << "not implemented"<< std::endl; return _type; } + + uint8_t GraphicsBase::getFormat() { + if (_topHeaderSize == 52) + return 0; + else if (_topHeaderSize == 64) + return 1; + throw E_INVALIDFORMAT("graphics-base header size"); + return 255; + } Graphics8Bit::Graphics8Bit(const std::string& style) : GraphicsBase() { fd = PHYSFS_openRead(style.c_str()); @@ -344,8 +353,6 @@ namespace OpenGTA { "#object-info: " << objectInfos.size() << " #car-info: " << carInfos.size() << std::endl; } - - void Graphics8Bit::loadHeader() { PHYSFS_uint32 vc; PHYSFS_readULE32(fd, &vc); @@ -600,8 +607,8 @@ namespace OpenGTA { } for (int i=0; i < car->numDoors; i++) { - PHYSFS_readSLE16(fd, &car->door[i].rpx); PHYSFS_readSLE16(fd, &car->door[i].rpy); + PHYSFS_readSLE16(fd, &car->door[i].rpx); PHYSFS_readSLE16(fd, &car->door[i].object); PHYSFS_readSLE16(fd, &car->door[i].delta); bytes_read += 4 * 2; @@ -777,14 +784,26 @@ namespace OpenGTA { const unsigned int b_offset = 256 * info.yoffset + info.xoffset; if (delta_is_a_set) { Util::Set delta_set(32, (unsigned char*)&delta); - for (int i = 0; i < 32; ++i) { + for (int i = 0; i < 20; ++i) { if (delta_set.get_item(i)) { assert(i < info.deltaCount); const DeltaInfo & di = info.delta[i]; applyDelta(info, buffer, b_offset, di); } } - assert(0); + for (int i=20; i < 24; i++) { + if (delta_set.get_item(i)) { + const DeltaInfo & di = info.delta[i - 20 + 6]; + applyDelta(info, buffer, b_offset, di, true); + } + } + for (int i=24; i < 28; i++) { + if (delta_set.get_item(i)) { + const DeltaInfo & di = info.delta[i - 24 + 11]; + applyDelta(info, buffer, b_offset, di, true); + } + } + //assert(0); } else { // delta is only an index; one to big @@ -1006,6 +1025,13 @@ namespace OpenGTA { int Graphics8Bit::RGBPalette::loadFromFile(PHYSFS_file* fd) { PHYSFS_read(fd, static_cast(&data), 1, 256*3); + /* + int max_sum = 0; + for (int i = 1; i < 256; i+=3) { + int sum = int(data[i]) + int(data[i+1]) + int(data[i+2]); + if (sum > max_sum) + max_sum = sum; + }*/ return 0; } diff --git a/read_sdt.cpp b/read_sdt.cpp index 53ec51f..6f83a3f 100644 --- a/read_sdt.cpp +++ b/read_sdt.cpp @@ -21,6 +21,7 @@ * distribution. * ************************************************************************/ #include +#include #include "m_exceptions.h" #include "fx_sdt.h" diff --git a/readme.txt b/readme.txt index 9f3dae2..c60cd4c 100644 --- a/readme.txt +++ b/readme.txt @@ -15,6 +15,14 @@ * GNU Make [ http://www.gnu.org/software/make/ ] += Optional software = +* Lua + [ http://www.lua.org/ ] +* SDL_mixer + [ http://www.libsdl.org/projects/SDL_mixer/ ] +* SDL_sound + [ http://icculus.org/SDL_sound/ ] + = Compiling = Only tested on GNU Linux using gcc & make; I assume that GL, SDL and @@ -27,7 +35,7 @@ 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. +more information about the build process. = Installing the data-files = @@ -37,7 +45,7 @@ These programs expect to find the data in the current directory, either directly in the file-system or in a ZIP file (named 'gtadata.zip'). You want the content of the original game directory GTADATA, but not the directory itself. -See mods/using_mods.txt for a slightly longer description. +See doc/using_mods.txt for a slightly longer description. Needed: *.FXT, *.FON, *.CMP @@ -52,13 +60,28 @@ MISSION.INI AUDIO/*.RAW AUDIO/*.SDT (sound effects) AUDIO/*.WAV (cutscene text; in legacy format) +You may also want to keep the music (even though it isn't used yet). +It is safe to assume that Ogg Vorbis [ http://vorbis.com/ ] will +be supported, so you can encode the music files. + = Running = +Note: Binary releases only contain the 'viewer' application; the other +programs should only be intersting for developers (read: compile +them yourself). + == gfxextract == Export/Display textures and sprites; run ./gfxextract -h (or without any parameters) for usage info. +== spriteplayer == + +Sprite graphics browser; shows internal indices, can display +animations (ped walking, car delta anims). + +run ./spriteplayer -h for usage information. + == viewer == Brain-dead immediate-mode renderer of the city (now with objects); with @@ -72,33 +95,14 @@ The optional param loads the respective city; default is 0: 1 - SANB.CMP 2 - MIAMI.CMP -flags are: +There are several flags; see the compiled-in usage information. -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 - -* log verbosity --l level (0 default; everything, 1 warn + error, 2 only error) - Using "-l 1" will make it easier to see actual error messages; sometimes there is a lot of noise on 'info' level (0). -* style-file --c 0 (default; uses .GRY 8bit styles) --c 1 (uses .G24 24bit styles) - -* other map & graphics files (have to specify neither or both) --m map_filename -g style_filename - -This is for loading non-GTA1 data; like GTA London. - keys: ESC, cursor-keys, + and - do what you might except them to do; @@ -108,7 +112,7 @@ furthermore: . : decrease visible range , : increase visible range t : display entire city (at a crawl) - f : toggle fullscreen/windowed + f : toggle fullscreen/windowed [only works on Linux] PRINT : save 'screenshot.bmp' in current directory p : dump coords (in lua syntax) to stdout F2 : toggle drawing of sprite bounding-boxes @@ -118,6 +122,7 @@ furthermore: F6 : city map mode (ESC to exit, +, -, cursor keys) F9 : toggle city blocks drawn textured F10 : toggle blocks wireframe lines + F12 : show/hide screen-gamma scrollbar in 3d view: w : forward @@ -132,11 +137,15 @@ 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 + l-ctrl : shoot 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 +You can still use + and - to zoom; but the view will try +to return to the old position quickly. + == luaviewer: viewer + Lua (optional target) == Also needs Lua (only 5.1 tried) in path; run: 'make luaviewer' diff --git a/release_files_sorted b/release_files_sorted index de687ea..9ce3464 100644 --- a/release_files_sorted +++ b/release_files_sorted @@ -1,3 +1,5 @@ +ogta/ai.cpp +ogta/ai.h ogta/blockanim.cpp ogta/blockanim.h ogta/blockdata.cpp @@ -24,17 +26,22 @@ ogta/coldet/transform.txt ogta/coldet/tritri.c ogta/common_sdl_gl.cpp ogta/common_sdl_gl.h +ogta/cvs_changelog.txt ogta/datahelper.cpp ogta/datahelper.h ogta/dataholder.cpp ogta/dataholder.h +ogta/doc/compiling.txt 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/ped_remaps.txt ogta/doc/slopes1.txt +ogta/doc/sprites.txt +ogta/doc/using_mods.txt ogta/Doxyfile ogta/entity_controller.cpp ogta/entity_controller.h @@ -70,6 +77,7 @@ ogta/licenses/readme.txt ogta/licenses/zlib.txt ogta/license.txt ogta/lid_normal_data.h +ogta/localplayer.cpp ogta/localplayer.h ogta/loki.make ogta/loki.make.w32_cross @@ -80,6 +88,8 @@ 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_map.cpp +ogta/lua_addon/lua_map.h ogta/lua_addon/lua_screen.cpp ogta/lua_addon/lua_screen.h ogta/lua_addon/lua_spritecache.cpp @@ -101,6 +111,8 @@ ogta/math/obb.cpp ogta/math/obb.hpp ogta/math/obox.cpp ogta/math/obox.h +ogta/math/plane.cpp +ogta/math/plane.h ogta/math/quaternion.h ogta/math/rectangle.hpp ogta/math/vector.hpp @@ -136,6 +148,9 @@ ogta/release_files_sorted ogta/scripts/demo1.lua ogta/scripts/demo2.lua ogta/scripts/demo3.lua +ogta/scripts/dump_config.lua +ogta/scripts/map_test_blocktype.lua +ogta/scripts/parser.lua ogta/slope1_data.h ogta/slope1_tcoords.h ogta/slope_height_func.cpp @@ -143,25 +158,39 @@ ogta/sprite_anim_player.cpp ogta/spritemanager.cpp ogta/spritemanager.h ogta/tests/interpolate_test.cpp +ogta/tests/lua_map_test.cpp ogta/tests/menudemo.cpp ogta/tests/new_obj_test.cpp +ogta/tests/plot_interpolate.sh +ogta/tests/rectangle.cpp ogta/tests/sound_test1.cpp ogta/tools/analyse_lids_2.c ogta/tools/analyse_lids.c ogta/tools/blockview.cpp +ogta/tools/bug_parser.awk +ogta/tools/build_svg_rect.sh +ogta/tools/car_dump.cpp ogta/tools/create_normals.cpp ogta/tools/display_font.cpp ogta/tools/display_slopes.cpp ogta/tools/doxy_doc.sh +ogta/tools/fxt.c ogta/tools/gen_texcoords.c ogta/tools/insert_copyright.sh +ogta/tools/label_screenshot.sh ogta/tools/mapinfo.cpp ogta/tools/minimap.cpp ogta/tools/obj_dump.cpp +ogta/tools/package_binary.sh +ogta/tools/picasa_ls.sh +ogta/tools/plot_stats.sh +ogta/tools/projects_stats.sh +ogta/tools/raw_images.m4 ogta/tools/replace_in_files.sh ogta/tools/resort_quads.c ogta/tools/slope_conv.awk ogta/tools/slope_exchange.sh +ogta/tools/stats_recalc.sh ogta/tools/style_demo.sh ogta/train_system.cpp ogta/train_system.h @@ -175,15 +204,20 @@ ogta/util/cell_iterator.h ogta/util/cistring.h ogta/util/file_helper.cpp ogta/util/file_helper.h +ogta/util/gui.cpp ogta/util/gui.h ogta/util/image_loader.cpp ogta/util/image_loader.h +ogta/util/key_handler.cpp +ogta/util/key_handler.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/pf_tree.cpp +ogta/util/pf_tree.hpp ogta/util/physfsrwops.c ogta/util/physfsrwops.h ogta/util/sample_cache.h diff --git a/scripts/demo1.lua b/scripts/demo1.lua index 54f3944..782de98 100644 --- a/scripts/demo1.lua +++ b/scripts/demo1.lua @@ -20,7 +20,7 @@ tick = 0 -- every 100 ms, but it is pretty pointless at this time. function game_tick() if tick == 1 then - screen.makeScreenShot("test.bmp") + --screen.makeScreenShot("test.bmp") end tick = tick + 1 end diff --git a/scripts/demo2.lua b/scripts/demo2.lua index 7c6845f..95f8997 100644 --- a/scripts/demo2.lua +++ b/scripts/demo2.lua @@ -1,4 +1,5 @@ -screen.setFullscreen(true) + +--screen.setFullscreen(true) camera.setCenter(61.4261, 7.56265, 2.2242) camera.setEye(61.4185, 8.72266, 0.810034) camera.setUp(0, 1, 0) diff --git a/scripts/dump_config.lua b/scripts/dump_config.lua new file mode 100644 index 0000000..1476530 --- /dev/null +++ b/scripts/dump_config.lua @@ -0,0 +1,40 @@ +function pairsByKeys (t, f) + local a = {} + for n in pairs(t) do table.insert(a, n) end + table.sort(a, f) + local i = 0 -- iterator variable + local iter = function () -- iterator function + i = i + 1 + if a[i] == nil then return nil + else return a[i], t[a[i]] + end + end + return iter +end + +function config_as_string() + local conf_str = "" + if type(config) ~= 'table' then return conf_str end + table.sort(config) + for i, j in pairsByKeys(config) do + if type(j) == 'boolean' then + if j == true then + conf_str = conf_str .. i .. ' = true\n' + else + conf_str = conf_str .. i .. ' = false\n' + end + elseif type(j) == 'string' then + conf_str = conf_str .. i .. ' = "' .. j .. '"\n' + else + conf_str = conf_str .. i .. ' = ' .. j .. '\n' + end + end + return conf_str +end + + +print("-- CONFIG DUMP --") +print(config_as_string()) +print("-- END OF CONFIG --") +quit() + diff --git a/scripts/map_test_blocktype.lua b/scripts/map_test_blocktype.lua new file mode 100644 index 0000000..713e176 --- /dev/null +++ b/scripts/map_test_blocktype.lua @@ -0,0 +1,97 @@ +-- run it: +-- ./lua_map_test $map_file scripts/map_test_blocktype.lua +-- +-- may soon also work from within luaviewer + +if rawget(_G, 'map') == nil then + print("No map loaded!") + os.exit() +end + +function block_type_name(t) + if t == 0 then return "air" end + if t == 1 then return "water" end + if t == 2 then return "road" end + if t == 3 then return "pavement" end + if t == 4 then return "field" end + if t == 5 then return "building" end + if t == 6 then return "unused1" end + if t == 7 then return "unused2" end + return "????????" +end + +function find_all_of_type(t) +list = {} +for y = 0, 255 do + for x = 0, 255 do + c = map:getNumBlocksAt(x, y) + for i = 0, c - 1 do + info = map:getBlockAt(x, y, i) + if info:getBlockType() == t then + table.insert(list, { x, y, i }) + end + end + end +end +return list +end + + +function find_air_columns() +for y = 0, 255 do + for x = 0, 255 do + c = map:getNumBlocksAt(x, y) + is_air = true + for i = 0, c - 1 do + info = map:getBlockAt(x, y, i) + if info:getBlockType() ~= 0 then + is_air = false + end + end + if is_air == true then + for i = 0, c - 1 do + info = map:getBlockAt(x, y, i) + lid = info:getTextureId(0) + if lid > 0 and i < 4 then + print("Air-column: " .. x .. ", " .. y) + print("Texture " .. lid .. " set at " .. i) + end + end + end + + end +end +end + +function is_block_of_type(x, y, z, t) + local c = map:getNumBlocksAt(x, y) + assert(c > z) + local info = map:getBlockAt(x, y, z) + return info:getBlockType() == t +end + +--find_air_columns() + +function find_block_holes() +for y = 0, 255 do + for x = 0, 255 do + c = map:getNumBlocksAt(x, y) + info = map:getBlockAt(x, y, c - 1) + if info:getTextureId(0) > 0 and info:getBlockType() == 0 then + print(x .. ", " .. y .. " has texture but no type above; level: " .. c - 1 .. + " lid: " .. info:getTextureId(0)) + end + end +end +end + +find_block_holes() + +--num = map:getNumBlocksAt(25, 17) +--for i = 0, num-1 do +-- info = map:getBlockAt(25, 17, i) +-- info:setBlockType(3) +-- print(i) +-- print("texture: " .. info:getTextureId(0)) +-- print("type: " .. info:getBlockType()) +--end diff --git a/scripts/parser.lua b/scripts/parser.lua new file mode 100644 index 0000000..6de84e7 --- /dev/null +++ b/scripts/parser.lua @@ -0,0 +1,122 @@ +local n +--definition_indices = {} +--for n in pairs(definitions) do table.insert(definition_indices, n) end +--table.sort(definition_indices) + +command_indices = {} +for n in pairs(commands) do table.insert(command_indices, n) end +table.sort(command_indices) + +function idx_by_gtaidx(gta_idx) + local i + for i = 1, #command_indices do + if command_indices[i] == gta_idx then return i end + end + --error("Invalid gta-cmd-idx: " .. gta_idx) + return -1 +end + +-- from: http://lua-users.org/wiki/StringRecipes +-- Compatibility: Lua-5.1 +function split(str, pat) + local t = {} -- NOTE: use {n = 0} in Lua-5.0 + local fpat = "(.-)" .. pat + local last_end = 1 + local s, e, cap = string.find(str, fpat, 1) + while s do + if s ~= 1 or cap ~= "" then + table.insert(t,cap) + end + last_end = e+1 + s, e, cap = string.find(str, fpat, last_end) + end + if last_end <= string.len(str) then + cap = string.sub(str, last_end) + table.insert(t, cap) + end + return t +end + +function run_command(idx, cmd, params) + local res = 0 + if cmd == "KICKSTART" then + -- new_thread(idx, params[1]) + print("\tKICKSTART in " .. idx .. " from " .. params[1] .. " = " ..idx_by_gtaidx(params[1] + 0)) + new_thread(idx, idx_by_gtaidx(params[1] + 0)) + else + print("\t" .. cmd .. " in line " .. idx) + end + return res +end + +function iterate_commands(idx) + local is_sleeping = false + while idx <= #command_indices do + local gta_idx = command_indices[idx] + if is_sleeping == true then + while true do + print(" thread is sleeping in " .. gta_idx) + coroutine.yield() + end + end + --print("LINE " .. gta_idx) + local cmd = commands[gta_idx] + local cmd_split = split(cmd, " ") + local cmd_name = cmd_split[1] + --print(cmd) + table.remove(cmd_split, 1) + local ok_idx = cmd_split[2] + local fail_idx = cmd_split[3] + if idx == 1 then + idx = idx + 1 + elseif idx > 1 then + local next_idx = 0 + --print(" "..gta_idx .. " " .. cmd_name) + if run_command(gta_idx, cmd_name, cmd_split) == 1 then + next_idx = fail_idx + 0 + print(' failed '..fail_idx) + else + next_idx = ok_idx + 0 + print(' ok '..ok_idx) + end + if next_idx == 0 then + idx = idx + 1 + elseif next_idx == -1 then + if cmd_name == "CRANE" then idx = idx + 1 + else + is_sleeping = true + --error("EXIT: " .. next_idx) + end + else + idx = idx_by_gtaidx(next_idx) + end + end + coroutine.yield() + print(' RESUMING2') + end + coroutine.yield() + print(' RESUMING3') +end + +threads = {} +thread_indices = {} +function new_thread(t_id, start_at_idx) + table.insert(threads, coroutine.create(function () iterate_commands(start_at_idx) end)) + print(" "..#threads .. " = " ..t_id) + table.insert(thread_indices, t_id) +end + + +new_thread(0, 1) +while #threads > 0 do + for i, j in pairs(threads) do + print("thread " .. thread_indices[i] .. " [" .. #threads .. "]") + if coroutine.status(j) == "suspended" then + coroutine.resume(j) + elseif coroutine.status(j) == "dead" then + table.remove(threads, i) + table.remove(thread_indices, i) + print("removing dead " .. i) + end + end +end diff --git a/slope1_tcoords.h b/slope1_tcoords.h index b4de454..dc87658 100644 --- a/slope1_tcoords.h +++ b/slope1_tcoords.h @@ -1084,11 +1084,12 @@ { 1.00, 1.00 } }, { // east - { 1.00, 0.00 }, - { 0.00, 1.00 }, - { 0.00, 1.00 }, - { 1.00, 1.00 } + { 0.00, 0.00 }, + { 1.00, 1.00 }, + { 1.00, 1.00 }, + { 0.00, 1.00 } } + }, { // slope: 42 { // north @@ -1110,10 +1111,10 @@ { 1.00, 1.00 } }, { // east - { 1.00, 1.00 }, { 0.00, 0.00 }, - { 0.00, 1.00 }, - { 1.00, 1.00 } + { 1.00, 0.00 }, + { 1.00, 1.00 }, + { 0.00, 1.00 } } }, { // slope: 43 diff --git a/sprite_anim_player.cpp b/sprite_anim_player.cpp index e1cbd78..7774c33 100644 --- a/sprite_anim_player.cpp +++ b/sprite_anim_player.cpp @@ -36,7 +36,10 @@ extern int global_EC; extern int global_Done; std::string style_file("STYLE001.GRY"); +float screen_gamma = 1.0f; +OpenGTA::Car * car = NULL; +Vector3D _p(4, 0.01f, 4); OpenGTA::Pedestrian ped(Vector3D(0.5f, 0.5f, 0.5f), Vector3D(4, 0.01f, 4), 0xffffffff); OpenGTA::SpriteObject::Animation pedAnim(0, 0); @@ -47,19 +50,43 @@ int first_offset = 0; int second_offset = 0; int now_frame = 0; bool play_anim = false; +unsigned int play_anim_time = 0; int bbox_toggle = 0; int texsprite_toggle = 0; +int c_c = 1; +int car_model = 0; +int car_remap = -1; +int car_last_model_ok = 0; +bool playWithCar = false; +uint32_t car_delta = 0; int spr_type = (int)ped.sprType; namespace OpenGTA { -void ai_step_fake(OpenGTA::Pedestrian*) { -} + void ai_step_fake(OpenGTA::Pedestrian*) { + } } -void on_exit() { - SDL_Quit(); - PHYSFS_deinit(); -} + void on_exit() { + if (car) + delete car; + SDL_Quit(); + PHYSFS_deinit(); + } + + void safe_try_model(uint8_t model_id) { + if (car) + delete car; + car = NULL; + try { + car = new OpenGTA::Car(_p, 0, 0, model_id, car_remap); + } + catch (Util::UnknownKey & uk) { + car = NULL; + ERROR << "not a model" << std::endl; + return; + } + car_last_model_ok = model_id; + } void run_init(const char*) { PHYSFS_init("mapview"); @@ -69,9 +96,14 @@ void run_init(const char*) { SDL_EnableKeyRepeat( 100, SDL_DEFAULT_REPEAT_INTERVAL ); OpenGTA::StyleHolder::Instance().load(style_file); + OpenGTA::StyleHolder::Instance().get().setDeltaHandling(true); + OpenGTA::MainMsgHolder::Instance().load("ENGLISH.FXT"); - m_font.loadFont("STREET1.FON"); - m_font.setScale(2); + m_font.loadFont("F_MTEXT.FON"); + m_font.setScale(1); + glClearColor(1, 1, 1, 1); + if (playWithCar) + car = new OpenGTA::Car(_p, 0, 0, car_model); } const char* spr_type_name(int t) { @@ -122,26 +154,69 @@ const char* spr_type_name(int t) { return "???"; } +const char* vtype2name(int vt) { + switch(vt) { + case 0: + return "bus"; + case 3: + return "motorcycle"; + case 4: + return "car"; + case 8: + return "train"; + } + return ""; +} + void drawScene(Uint32 ticks) { GL_CHECKERROR; glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - + OpenGL::ScreenHolder::Instance().set3DProjection(); OpenGL::CameraHolder::Instance().update(ticks); - if (play_anim) { - pedAnim.firstFrameOffset = now_frame; + if (playWithCar) { + if (car) { + car->update(ticks); + OpenGTA::SpriteManagerHolder::Instance().draw(*car); + } + + OpenGL::ScreenHolder::Instance().setFlatProjection(); + + glPushMatrix(); + glTranslatef(10, 10, 0); + std::ostringstream sprite_info_str; + std::ostringstream ostr; + ostr << "car" << int(car_model); + + if (car) { + sprite_info_str << vtype2name(car->carInfo.vtype)<< " model: " << int(car_model) << " name: " << + OpenGTA::MainMsgHolder::Instance().get().getText(ostr.str()); + } + else + sprite_info_str << "not a model: " << int(car_model); + m_font.drawString(sprite_info_str.str()); + glPopMatrix(); } - OpenGTA::SpriteManagerHolder::Instance().draw(ped); + else { + if (play_anim && ticks > play_anim_time + 200) { + now_frame++; + if (now_frame > second_offset) + now_frame = first_offset; + ped.anim.firstFrameOffset = now_frame; + play_anim_time = ticks; + } + OpenGTA::SpriteManagerHolder::Instance().draw(ped); - OpenGL::ScreenHolder::Instance().setFlatProjection(); + OpenGL::ScreenHolder::Instance().setFlatProjection(); - glPushMatrix(); - glTranslatef(10, 10, 0); - std::ostringstream sprite_info_str; - sprite_info_str << spr_type_name(spr_type) << " offset " << frame_offset; - m_font.drawString(sprite_info_str.str()); - glPopMatrix(); + glPushMatrix(); + glTranslatef(10, 10, 0); + std::ostringstream sprite_info_str; + sprite_info_str << spr_type_name(spr_type) << " offset " << frame_offset; + m_font.drawString(sprite_info_str.str()); + glPopMatrix(); + } SDL_GL_SwapBuffers(); GL_CHECKERROR; @@ -155,46 +230,125 @@ void handleKeyPress( SDL_keysym *keysym ) { case SDLK_ESCAPE: global_Done = 1; break; + case SDLK_TAB: + c_c += 1; c_c %= 2; + glClearColor(c_c, c_c, c_c, 0); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + break; + case 'k': + if (car_delta > 0) + car_delta -= 1; + if (car) + car->delta = car_delta; + break; + case 'l': + if (car_delta < 32) + car_delta += 1; + if (car) { + car->delta = car_delta; + } + break; case '+': cam.translateBy(Vector3D(0, -0.5f, 0)); break; case '-': cam.translateBy(Vector3D(0, 0.5f, 0)); break; + case '1': + if (playWithCar) { + if (car->animState.get_item(1)) + car->closeDoor(0); + else + car->openDoor(0); + } + break; + case '2': + if (playWithCar) { + if (car->animState.get_item(2)) + car->closeDoor(1); + else + car->openDoor(1); + } + break; + case '3': + if (playWithCar) { + if (car->animState.get_item(3)) + car->closeDoor(2); + else + car->openDoor(2); + } + break; + case '4': + if (playWithCar) { + if (car->animState.get_item(4)) + car->closeDoor(3); + else + car->openDoor(3); + } + break; + + case ',': + if (playWithCar) { + car_model -= 1; + if (car_model < 0) + car_model = 0; + } frame_offset -= 1; if (frame_offset < 0) frame_offset = 0; update_anim = true; break; case '.': + if (playWithCar) { + car_model += 1; + if (car_model > 88) + car_model = 88; + } frame_offset += 1; if (frame_offset >= style.spriteNumbers.countByType(ped.sprType)) frame_offset -= 1; update_anim = true; break; case 'n': + if (playWithCar) { + car_remap -= 1; + if (car_remap < -1) + car_remap = -1; + INFO << "remap: " << int(car_remap) << std::endl; + } do { spr_type -= 1; if (spr_type < 0) spr_type = 0; } while (style.spriteNumbers.countByType( - (OpenGTA::GraphicsBase::SpriteNumbers::SpriteTypes) spr_type) == 0); + (OpenGTA::GraphicsBase::SpriteNumbers::SpriteTypes) spr_type) == 0); ped.sprType = (OpenGTA::GraphicsBase::SpriteNumbers::SpriteTypes)spr_type; frame_offset = 0; update_anim = 1; break; case 'm': + if (playWithCar) { + car_remap += 1; + if (car_remap > 11) + car_remap = 11; + INFO << "remap: " << int(car_remap) << std::endl; + } do { spr_type += 1; if (spr_type > 20) spr_type = (int)ped.sprType; } while (style.spriteNumbers.countByType( - (OpenGTA::GraphicsBase::SpriteNumbers::SpriteTypes) spr_type) == 0); + (OpenGTA::GraphicsBase::SpriteNumbers::SpriteTypes) spr_type) == 0); ped.sprType = (OpenGTA::GraphicsBase::SpriteNumbers::SpriteTypes)spr_type; frame_offset = 0; update_anim = 1; break; + case 's': + if (playWithCar) { + car->setSirenAnim(true); + } + break; case SDLK_F2: bbox_toggle = (bbox_toggle ? 0 : 1); OpenGTA::SpriteManagerHolder::Instance().setDrawBBox(bbox_toggle); @@ -205,9 +359,21 @@ void handleKeyPress( SDL_keysym *keysym ) { break; case SDLK_F5: first_offset = frame_offset; + std::cout << "First frame: " << first_offset << std::endl; break; case SDLK_F6: second_offset = frame_offset; + std::cout << "Last frame: " << second_offset << std::endl; + break; + case SDLK_F7: + play_anim = (play_anim ? false : true); + if (play_anim) + std::cout << "Playing: " << first_offset << " .. " << second_offset << std::endl; + now_frame = first_offset; + break; + case SDLK_F8: + playWithCar = playWithCar ? false : true; + update_anim = true; break; default: break; @@ -215,18 +381,30 @@ void handleKeyPress( SDL_keysym *keysym ) { if (update_anim) { pedAnim.firstFrameOffset = frame_offset; ped.anim = pedAnim; + if (playWithCar) + safe_try_model(car_model); } } void usage(const char* a0) { std::cout << "USAGE: " << a0 << " [style-filename]" << std::endl; std::cout << std::endl << "Default is: STYLE001.GRY" << std::endl << - "Keys:" << std::endl << - " + - : zoom in/out" << std::endl << - " , . : previous/next frame offset" << std::endl << - " n m : previous/next sprite-type" << std::endl << - " F2 : toggle BBox drawn" << std::endl << - " F3 : toggle tex-border drawn" << std::endl; + "Keys:" << std::endl << + " + - : zoom in/out" << std::endl << + " , . : previous/next frame offset" << std::endl << + " n m : previous/next sprite-type" << std::endl << + " tab : black/white background" << std::endl << + " F2 : toggle BBox drawn" << std::endl << + " F3 : toggle tex-border drawn" << std::endl << + " F5 : prepare animation: first-frame = current frame" << std::endl << + " F6 : prepare animation: last-frame = current frame" << std::endl << + " F7 : toggle: play frames" << std::endl << + " F8 : toggle: special-car-mode" << std::endl << std::endl << + "In car-mode:" << std::endl << + " , . : choose model" << std::endl << + " n m : choose remap" << std::endl << + " 1, 2, 3, 4 : open car door (if exists)" << std::endl << + " s : toggle siren anim (if exists)" << std::endl; } void parse_args(int argc, char* argv[]) { @@ -274,7 +452,7 @@ void run_main() { handleKeyPress(&event.key.keysym); break; case SDL_KEYUP: -// handleKeyUp(&event.key.keysym); + // handleKeyUp(&event.key.keysym); break; case SDL_VIDEORESIZE: OpenGL::ScreenHolder::Instance().resize(event.resize.w, event.resize.h); diff --git a/spritemanager.cpp b/spritemanager.cpp index a3a5f3a..176db9a 100644 --- a/spritemanager.cpp +++ b/spritemanager.cpp @@ -54,7 +54,7 @@ namespace OpenGTA { 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 @@ -66,9 +66,9 @@ namespace OpenGTA { 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 @@ -119,25 +119,26 @@ namespace OpenGTA { size_t num_peds, num_cars, num_obj; num_peds = 0; for (AbstractContainer::Storage_T_Iterator i = AbstractContainer::objs.begin(); - i != AbstractContainer::objs.end(); ++i) { + i != AbstractContainer::objs.end(); ++i) { Pedestrian & ped = (*i); ped.update(ticks); num_peds++; } num_cars = 0; for (AbstractContainer::Storage_T_Iterator i = AbstractContainer::objs.begin(); - i != AbstractContainer::objs.end(); ++i) { + i != AbstractContainer::objs.end(); ++i) { Car & car = (*i); car.update(ticks); num_cars++; } + num_obj = 0; for (AbstractContainer::Storage_T_Iterator i = AbstractContainer::objs.begin(); - i != AbstractContainer::objs.end(); ++i) { + i != AbstractContainer::objs.end(); ++i) { SpriteObject & obj = (*i); obj.update(ticks); num_obj++; if (obj.isActive == false) - AbstractContainer::toBeRemoved.push_back(i); + AbstractContainer::toBeRemoved.push_back(i); } for (ProjectileListType::iterator i = activeProjectiles.begin(); i != activeProjectiles.end();) { Projectile & pr = (*i); @@ -152,64 +153,74 @@ namespace OpenGTA { } 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 (num_peds < 50 && num_peds > 2 && ticks - lastCreateTick > 100) { + //MapHelper::createPeds(5); + Map & map = OpenGTA::MapHolder::Instance().get(); + lastCreateTick = ticks; + while (1) { + Util::TupleOfUint8 tu8 = creationArea.getValidCoord(); + INFO << "testing: " << int(tu8.first) << ", " << int(tu8.second) << std::endl; + 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; + } + 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); + p.rot = 360 * (rand() / (RAND_MAX + 1.0)); OpenGTA::SpriteManagerHolder::Instance().add(p); break; } } } +#define POS_INSIDE_RECT(pos, r) ((pos.x >= r.x) && \ + (pos.x <= r.x + r.w) && (pos.z >= r.y) && (pos.z <= r.y + r.h)) + void SpriteManager::drawInRect(SDL_Rect & r) { for (AbstractContainer::Storage_T_Iterator i = AbstractContainer::objs.begin(); - i != AbstractContainer::objs.end(); ++i) { + i != AbstractContainer::objs.end(); ++i) { Pedestrian & ped = (*i); - if ((ped.pos.x >= r.x) && (ped.pos.x <= r.x + r.w) && - (ped.pos.z >= r.y) && (ped.pos.z <= r.y + r.h)) - draw(ped); + if (POS_INSIDE_RECT(ped.pos, r)) + //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)) + draw(ped); + else + removePed(ped.id()); } for (AbstractContainer::Storage_T_Iterator i = AbstractContainer::objs.begin(); - i != AbstractContainer::objs.end(); ++i) { + i != AbstractContainer::objs.end(); ++i) { SpriteObject & obj = (*i); - if ((obj.pos.x >= r.x) && (obj.pos.x <= r.x + r.w) && - (obj.pos.z >= r.y) && (obj.pos.z <= r.y + r.h)) - draw(obj); + //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)) + if (POS_INSIDE_RECT(obj.pos, r)) + draw(obj); } for (AbstractContainer::Storage_T_Iterator i = AbstractContainer::objs.begin(); - i != AbstractContainer::objs.end(); ++i) { + i != AbstractContainer::objs.end(); ++i) { Car & car = (*i); - if ((car.pos.x >= r.x) && (car.pos.x <= r.x + r.w) && - (car.pos.z >= r.y) && (car.pos.z <= r.y + r.h)) - draw(car); + // 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)) + if (POS_INSIDE_RECT(car.pos, r)) + 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); + if (POS_INSIDE_RECT(prj.pos, r)) + draw(prj); } glColor3f(1, 1, 1); @@ -230,13 +241,13 @@ namespace OpenGTA { } #define GL_OBJ_COMMON(o) GL_CHECKERROR; \ -glPushMatrix(); \ + glPushMatrix(); \ glTranslatef(o.pos.x, o.pos.y, o.pos.z); \ glRotatef(o.rot, 0, 1, 0); \ //glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)o.m_M.m) #define DRAW_TEX_QUADS_OBJ(t, w, h) glBindTexture(GL_TEXTURE_2D, t.inPage); \ -glBegin(GL_QUADS); \ + 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); \ @@ -252,23 +263,30 @@ void SpriteManager::draw(Car & car) { GL_OBJ_COMMON(car); GraphicsBase & style = StyleHolder::Instance().get(); OpenGL::PagedTexture t; - PHYSFS_uint16 sprNum = style.spriteNumbers.reIndex(car.sprNum + - car.anim.firstFrameOffset + car.anim.currentFrame, car.sprType); + PHYSFS_uint16 sprNum = style.spriteNumbers.reIndex(car.sprNum, car.sprType); + //+ car.anim.firstFrameOffset + car.anim.currentFrame, car.sprType); GraphicsBase::SpriteInfo * info = style.getSprite(sprNum); assert(info); float w = float(info->w) / 64.0f; float h = float(info->h) / 64.0f; - if (OpenGL::SpriteCacheHolder::Instance().has(sprNum, car.remap)) - t = OpenGL::SpriteCacheHolder::Instance().get(sprNum, car.remap); + OpenGL::SpriteIdentifier si(sprNum, car.remap, car.delta); + if (OpenGL::SpriteCacheHolder::Instance().has(si)) + t = OpenGL::SpriteCacheHolder::Instance().get(si); else { - t = OpenGL::SpriteCacheHolder::Instance().create(car.sprNum + - car.anim.firstFrameOffset + car.anim.currentFrame, - car.sprType, car.remap); + t = OpenGL::SpriteCacheHolder::Instance().create(car.sprNum,// + + //car.anim.firstFrameOffset + car.anim.currentFrame, + car.sprType, car.remap, car.delta); } DRAW_TEX_QUADS_OBJ(t, w, h); + glDisable(GL_TEXTURE_2D); + glBegin(GL_POINTS); + glVertex3f(car.carInfo.door[0].rpx / 64.0f, 0.1f, car.carInfo.door[0].rpy / 64.0f); + glEnd(); + glEnable(GL_TEXTURE_2D); + if (getDrawBBox() || getDrawTexBorder()) glDisable(GL_TEXTURE_2D); @@ -304,11 +322,11 @@ void SpriteManager::drawBBoxOutline(const OBox & box) { void SpriteManager::drawTextureOutline(const float & w, const float & h) { glBegin(GL_LINE_STRIP); glColor3f(float(202)/255.0f, float(31)/255.0f, float(123)/255.0f); - glVertex3f(-w/2, 0.0f, h/2); - glVertex3f(w/2, 0.0f, h/2); - glVertex3f(w/2, 0.0f, -h/2); + glVertex3f(-w/2, 0.0f, h/2); + glVertex3f( w/2, 0.0f, h/2); + 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); } @@ -374,7 +392,7 @@ void SpriteManager::draw(Pedestrian & ped) { ped.anim.firstFrameOffset + ped.anim.currentFrame, ped.sprType, ped.remap); } - + DRAW_TEX_QUADS_OBJ(t, w, h); if (getDrawBBox() || getDrawTexBorder()) @@ -520,43 +538,43 @@ void SpriteManager::drawExplosion(SpriteObject & obj) { } /* -void SpriteManager::draw(TrainSegment & train) { - GL_OBJ_COMMON(train); - GraphicsBase & style = StyleHolder::Instance().get(); + 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); + 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; + 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); + if (OpenGL::SpriteCacheHolder::Instance().has(sprNum, train.remap)) + t = OpenGL::SpriteCacheHolder::Instance().get(sprNum, train.remap); + else { + t = OpenGL::SpriteCacheHolder::Instance().create(train.sprNum, train.sprType, -1); + } + glBindTexture(GL_TEXTURE_2D, t.inPage); - glBegin(GL_QUADS); - glTexCoord2f(t.coords[0].u, t.coords[1].v); - glVertex3f(-w/2, 0.0f, h/2); - glTexCoord2f(t.coords[1].u, t.coords[1].v); - glVertex3f(w/2, 0.0f, h/2); - glTexCoord2f(t.coords[1].u, t.coords[0].v); - glVertex3f(w/2, 0.0f, -h/2); - glTexCoord2f(t.coords[0].u, t.coords[0].v); - glVertex3f(-w/2, 0.0f, -h/2); + 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(); + glEnd(); - glPopMatrix(); - GL_CHECKERROR; -} -*/ + glPopMatrix(); + GL_CHECKERROR; + } + */ void SpriteManager::draw(Projectile & proj) { //GL_OBJ_COMMON(proj); // can't use; not derived from OBox @@ -564,12 +582,12 @@ void SpriteManager::draw(Projectile & proj) { const float h = 0.05f; glPushMatrix(); \ - glTranslatef(proj.pos.x, proj.pos.y, proj.pos.z); \ - glRotatef(proj.rot, 0, 1, 0); + glTranslatef(proj.pos.x, proj.pos.y, proj.pos.z); \ + glRotatef(proj.rot, 0, 1, 0); glDisable(GL_TEXTURE_2D); glBegin(GL_QUADS); - + glVertex3f(-w/2, 0.0f, h/2); glVertex3f(w/2, 0.0f, h/2); glVertex3f(w/2, 0.0f, -h/2); @@ -582,92 +600,21 @@ void SpriteManager::draw(Projectile & proj) { GL_CHECKERROR; } -/* - - void SpriteManager::addPed(Pedestrian & ped) { - activePeds.push_back(ped); - } - - Pedestrian & SpriteManager::getPedById(const Uint32 & id) { - PedListType::iterator i = activePeds.begin(); - while (i != activePeds.end()) { - if (i->pedId == id) - return *i; - ++i; - } - assert(0); - return *activePeds.begin(); - } - - TrainSegment & SpriteManager::getTrainById(const Uint32 & id) { - TrainListType::iterator i = activeTrains.begin(); - while (i != activeTrains.end()) { - if (i->trainId == id) - return *i; - ++i; - } - assert(0); - return *activeTrains.begin(); - } - - void SpriteManager::removePedById(const Uint32 & id) { - PedListType::iterator i = activePeds.begin(); - while (i != activePeds.end()) { - if (i->pedId == id) { - activePeds.erase(i); - return; - } - ++i; - } - WARN << "didn't find ped id " << id << " -- cannot remove"<carId == id) { - return *i; - } - ++i; - } - assert(0); - return *activeCars.begin(); - } - - void SpriteManager::addObject(GameObject & go) { - activeObjects.push_back(go); - } - - void SpriteManager::createExplosion(Vector3D center) { - GameObject exp(center, 0, GraphicsBase::SpriteNumbers::EX); - exp.anim = SpriteObject::Animation(getAnimationById(99)); - exp.anim.set(Util::Animation::PLAY_FORWARD, Util::Animation::LOOP); - INFO << exp.anim.currentFrame << " " << exp.anim.numFrames << " " << exp.anim.delay << std::endl; - activeObjects.push_back(exp); - } - - GameObject & SpriteManager::getObjectById(const Uint32 & id) { - ObjectListType::iterator i = activeObjects.begin(); -while (i != activeObjects.end()) { - if (i->objId == id) { - return *i; - } - ++i; -} -assert(0); -return *activeObjects.begin(); -} -*/ - void SpriteManager::removeDeadStuff() { AbstractContainer::doRealRemove(); AbstractContainer::doRealRemove(); AbstractContainer::doRealRemove(); + AbstractContainer::Storage_T_Iterator i = AbstractContainer::objs.begin(); + while (i != AbstractContainer::objs.end()) { + Pedestrian & ped = (*i); + if ((ped.isDead == 3) && (creationArea.isOnScreen(ped.pos) == false)) { + AbstractContainer::Storage_T_Iterator j = i; j++; + AbstractContainer::objs.erase(i); + i = j; + } + else + i++; + } } SpriteObject::Animation & SpriteManager::getAnimationById(const Uint32 & id) { diff --git a/spritemanager.h b/spritemanager.h index d3270b9..cb18f54 100644 --- a/spritemanager.h +++ b/spritemanager.h @@ -179,6 +179,7 @@ namespace OpenGTA { private: Uint32 drawMode; + Uint32 lastCreateTick; //SpriteManager(const SpriteManager & o) : trainSystem(AbstractContainer::objs) {assert(0);} SpriteManager(const SpriteManager & o) {assert(0);} diff --git a/tests/lua_map_test.cpp b/tests/lua_map_test.cpp new file mode 100644 index 0000000..11f0a00 --- /dev/null +++ b/tests/lua_map_test.cpp @@ -0,0 +1,49 @@ +#include +#include "lua_vm.h" +#include "opengta.h" +#include "dataholder.h" +#include "file_helper.h" +#include "log.h" + +std::string map_filename; +const char* script_file; + +void on_exit() { + SDL_Quit(); + PHYSFS_deinit(); +} + +void parse_args(int argc, char* argv[]) { + if (argc != 3) { + ERROR << "invalid args" << std::endl; + exit(1); + } + map_filename = std::string(argv[1]); + script_file = argv[2]; +} + +void run_init(const char* prg_name) { + PHYSFS_init(prg_name); + + Util::FileHelper & fh = GET_FILE_HELPER; + if (fh.existsInSystemFS(fh.getBaseDataPath())) { + PHYSFS_addToSearchPath(GET_FILE_HELPER.getBaseDataPath().c_str(), 1); + } + else { + WARN << "Could not load data-source: " << fh.getBaseDataPath() << std::endl; + } + + PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1); + +} + +void run_main() { + OpenGTA::Script::LuaVM & vm = OpenGTA::Script::LuaVMHolder::Instance(); + + OpenGTA::MainMsgHolder::Instance().load("ENGLISH.FXT"); + OpenGTA::MapHolder::Instance().load(map_filename); + OpenGTA::Map & loadedMap = OpenGTA::MapHolder::Instance().get(); + vm.setMap(loadedMap); + + vm.runFile(script_file); +} diff --git a/tests/plot_interpolate.sh b/tests/plot_interpolate.sh new file mode 100644 index 0000000..70c4ca5 --- /dev/null +++ b/tests/plot_interpolate.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +function input_data() { + cat <gnuplot_data.$$ + cat <gnuplot_script.$$ +plot "gnuplot_data.$$" title "$switch" +EOF + gnuplot gnuplot_script.$$ - +} + +if [ ! -f interpolate_test ]; then + g++ -I ../math -o interpolate_test interpolate_test.cpp +fi + +transform linear +transform cubic +transform cosine +transform hermite + +rm -f gnuplot_data.$$ gnuplot_script.$$ diff --git a/tests/rectangle.cpp b/tests/rectangle.cpp new file mode 100644 index 0000000..4472c1b --- /dev/null +++ b/tests/rectangle.cpp @@ -0,0 +1,75 @@ +#include +#include "rectangle.hpp" + +using namespace std; +using namespace Math; + +template bool test_values ( const Rectangle & r, T x, T y, T w, T h ) { + return (r.x == x && r.y == y && r.w == w && r.h == h); +} + +int main(int argc, char* argv[]) { +/* +#define TEST_SET_1 5, 10, 24, 31 + Rectangle a(TEST_SET_1); + if (!test_values(a, TEST_SET_1)) + cerr << "verifying values failed " << __LINE__ << endl; + + Rectangle a_copy(a); + if (!test_values(a_copy, TEST_SET_1)) + cerr << "copy-constructor failed " << __LINE__ << endl; + + if (! (a == a_copy) ) + cerr << "equality failed " << __LINE__ << endl; + + if (! a.isInside(15, 15) ) + cerr << "isInside failed " << __LINE__ << endl; + + + Rectangle b(10, 15, 10, 15); + if (a == b ) + cerr << "equality failed " << __LINE__ << endl; + + if (! rectangle_test_inside(a, b) ) + cerr << "rect-inside-rect test failed " << __LINE__ << endl; + + if (rectangle_test_leftborder(a, b)) + cerr << "rectangle-left-b failed " << __LINE__ << endl; + + if (rectangle_test_rightborder(a, b)) + cerr << "rectangle-right-b failed " << __LINE__ << endl; + + if (rectangle_test_topborder(a, b)) + cerr << "rectangle-top-b failed " << __LINE__ << endl; + + if (rectangle_test_bottomborder(a, b)) + cerr << "rectangle-bottom-b failed " << __LINE__ << endl; + +*/ + + typedef Rectangle IRect; + + int input[4]; + for (int j = 0; j < 4; ++j) { + input[j] = 0; + input[j] = atoi(argv[j+1]); + } + + IRect big(input[0], input[1], input[2], input[3]); + for (int j = 0; j < 4; ++j) { + input[j] = 0; + input[j] = atoi(argv[j+5]); + } + + + IRect small(input[0], input[1], input[2], input[3]); + list< IRect > mlist; + RectangleGeometry::difference(mlist, big, small); + + cout << mlist.size() << " rects returned" << endl; + list< IRect >::iterator i; + for (i = mlist.begin(); i != mlist.end(); ++i) { + cout << "x = " << i->x << " y = " << i->y + << " w = " << i->w << " h = " << i->h << endl; + } +} diff --git a/tools/blockview.cpp b/tools/blockview.cpp index d0eb943..1bd4036 100644 --- a/tools/blockview.cpp +++ b/tools/blockview.cpp @@ -1,62 +1,38 @@ #include #include -#include "common_sdl_gl.h" #include "opengta.h" -#include "gl_texturecache.h" +#include "dataholder.h" +#include "gl_screen.h" +#include "gl_camera.h" +#include "log.h" -namespace OpenGTA { - class MapViewGL { - private: - Map* currentMap; - Graphics8Bit* styleDB; - OpenGL::TextureCache* sideCache; - OpenGL::TextureCache* lidCache; - public: - MapViewGL(); - ~MapViewGL(); - int loadMap(const std::string &map, const std::string &style); - void drawMap(int32_t x, int32_t y, int32_t dx, int32_t dy); - void drawBlock(Map::BlockInfo* bi); - }; -} +Uint32 arg_screen_w = 0; +Uint32 arg_screen_h = 0; +std::string map_file("NYC.CMP"); +Vector3D e(3, 3, 3); +Vector3D c(0.5f, 0.5f, 0.5f); +Vector3D u(0, 1, 0); +uint8_t which = 0; +float r = 0; +bool wireframe = true; -namespace OpenGTA { - MapViewGL::MapViewGL() { - currentMap = NULL; - styleDB = NULL; - sideCache = NULL; - lidCache = NULL; - } - MapViewGL::~MapViewGL() { - if (currentMap) - delete currentMap; - if (styleDB) - delete styleDB; - if (sideCache) - delete sideCache; - if (lidCache) - delete lidCache; - } - int MapViewGL::loadMap(const std::string &map, const std::string &style) { - currentMap = new Map(map); - styleDB = new Graphics8Bit(style); - sideCache = new OpenGL::TextureCache(); - lidCache = new OpenGL::TextureCache(); - //currentMap->dump(); - return 0; - } -} -extern SDL_Surface* screen; -GLfloat mapPos[3] = {12.0f, 12.0f, 20.0f}; -GLfloat camVec[3] = {0.0f, 1.0f, 0.0f}; -OpenGTA::MapViewGL *map = NULL; +extern int global_EC; +extern int global_Done; + + +const size_t numBlockTypes = 53; +const size_t numFaces = 5; + +float slope_raw_data[numBlockTypes][numFaces][4][3] = { +#include "slope2_data.h" +}; + +#define SLOPE_RAW_DATA slope_raw_data + void on_exit() { - SDL_FreeSurface(screen); SDL_Quit(); - if (map) - delete map; PHYSFS_deinit(); if (global_EC) std::cerr << "Exiting after fatal problem - please see output above" << std::endl; @@ -64,255 +40,171 @@ void on_exit() { std::cout << "Goodbye" << std::endl; } +void print_usage(const char*) { +} + +void parse_args(int argc, char* argv[]) { +} + void handleKeyPress( SDL_keysym *keysym ) { switch ( keysym->sym ) { case SDLK_ESCAPE: global_Done = 1; break; case SDLK_LEFT: - mapPos[0] += 1.0f; + r -= 10; break; case SDLK_RIGHT: - mapPos[0] -= 1.0f; - if (mapPos[0] < 0.0f) - mapPos[0] = 0.0f; + r += 10; + break; + case SDLK_SPACE: + wireframe = (wireframe) ? false : true; break; case SDLK_UP: - mapPos[1] += 1.0f; + which++; + if (which >= numBlockTypes) + which = numBlockTypes - 1; + INFO << "slope-type: " << int(which) << std::endl; break; case SDLK_DOWN: - mapPos[1] -= 1.0f; - if (mapPos[1] < 0.0f) - mapPos[1] = 0.0f; - break; - case '+': - mapPos[2] += 1.0f; - break; - case '-': - mapPos[2] -= 1.0f; - break; - case 'x': - camVec[0] = 1.0f; camVec[1] = 0.0f; camVec[2] = 0.0f; - break; - case 'y': - camVec[0] = 0.0f; camVec[1] = 1.0f; camVec[2] = 0.0f; - break; - case 'z': - camVec[0] = 0.0f; camVec[1] = 0.0f; camVec[2] = 1.0f; + if (which > 0) + which--; + INFO << "slope-type: " << int(which) << std::endl; break; + default: break; } } -GLuint createGLTexture(GLsizei w, GLsizei h, const void* pixels) { - GLuint tex; - glGenTextures(1, &tex); - glBindTexture(GL_TEXTURE_2D, tex); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, param); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, param); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - // GL_LINEAR_MIPMAP_LINEAR); - /*gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, w, - h, GL_RGB, GL_UNSIGNED_BYTE, pixels); - */ - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - return tex; -} - -void OpenGTA::MapViewGL::drawBlock(OpenGTA::Map::BlockInfo* bi) { - float size = 0.5f; - int jj = 0; - if (bi == NULL) - return; - glEnable(GL_TEXTURE_2D); - if (bi->left) { - // Left Face - if (!sideCache->hasTexture(bi->left)) { - styleDB->getSide(static_cast(bi->left-1), 0, true); - sideCache->addTexture(bi->left, createGLTexture(64, 64, &styleDB->tileTmpRGBA)); - } - glBindTexture(GL_TEXTURE_2D, sideCache->getTextureWithId(bi->left)); - //} - glBegin(GL_QUADS); - glTexCoord2f(0.0f, 0.0f); - //glNormal3f(-1.0f, 0.0f, 0.0f); - glVertex3f(-size, -size, -size);// Bottom Left Of The Texture and Quad - glTexCoord2f(1.0f, 0.0f); - glVertex3f(-size, -size, size);// Bottom Right Of The Texture and Quad - glTexCoord2f(1.0f, 1.0f); - glVertex3f(-size, size, size);// Top Right Of The Texture and Quad - glTexCoord2f(0.0f, 1.0f); - glVertex3f(-size, size, -size);// Top Left Of The Texture and Quad - glEnd(); - } - if (bi->right) { - // Right face - if (!sideCache->hasTexture(bi->right)) { - styleDB->getSide(static_cast(bi->right-1), 0, true); - sideCache->addTexture(bi->right, createGLTexture(64, 64, &styleDB->tileTmpRGBA)); - } - glBindTexture(GL_TEXTURE_2D, sideCache->getTextureWithId(bi->right)); - //} - glBegin(GL_QUADS); - glTexCoord2f(1.0f, 0.0f); - //glNormal3f(1.0f, 0.0f, 0.0f); - glVertex3f( size, -size, -size);// Bottom Right Of The Texture and Quad - glTexCoord2f(1.0f, 1.0f); - glVertex3f( size, size, -size);// Top Right Of The Texture and Quad - glTexCoord2f(0.0f, 1.0f); - glVertex3f( size, size, size);// Top Left Of The Texture and Quad - glTexCoord2f(0.0f, 0.0f); - glVertex3f( size, -size, size);// Bottom Left Of The Texture and Quad - glEnd(); - } - if (bi->top) { - // Back Face - if (!sideCache->hasTexture(bi->top)) { - styleDB->getSide(static_cast(bi->top-1), 0, true); - sideCache->addTexture(bi->top, createGLTexture(64, 64, &styleDB->tileTmpRGBA)); - } - glBindTexture(GL_TEXTURE_2D, sideCache->getTextureWithId(bi->top)); - //} - glBegin(GL_QUADS); - glTexCoord2f(0.0f, 1.0f); - //glNormal3f(0.0f, 0.0f, 1.0f); - glVertex3f(-size, size, -size);// Top Left Of The Texture and Quad - glTexCoord2f(0.0f, 0.0f); - glVertex3f(-size, size, size);// Bottom Left Of The Texture and Quad - glTexCoord2f(1.0f, 0.0f); - glVertex3f( size, size, size);// Bottom Right Of The Texture and Quad - glTexCoord2f(1.0f, 1.0f); - glVertex3f( size, size, -size);// Top Right Of The Texture and Quad - glEnd(); - } - if (bi->bottom) { - // Front Face - if (!sideCache->hasTexture(bi->bottom)) { - styleDB->getSide(static_cast(bi->bottom-1), 0, true); - sideCache->addTexture(bi->bottom, createGLTexture(64, 64, &styleDB->tileTmpRGBA)); - } - glBindTexture(GL_TEXTURE_2D, sideCache->getTextureWithId(bi->bottom)); - //} - glBegin(GL_QUADS); - //glNormal3f(0.0f, 0.0f, -1.0f); - glTexCoord2f(1.0f, 1.0f); - glVertex3f(-size, -size, -size);// Top Right Of The Texture and Quad - glTexCoord2f(0.0f, 1.0f); - glVertex3f( size, -size, -size);// Top Left Of The Texture and Quad - glTexCoord2f(0.0f, 0.0f); - glVertex3f( size, -size, size);// Bottom Left Of The Texture and Quad - glTexCoord2f(1.0f, 0.0f); - glVertex3f(-size, -size, size);// Bottom Right Of The Texture and Quad - glEnd(); - } - if (bi->lid) { - // Top Face - if (!lidCache->hasTexture(bi->lid)) { - styleDB->getLid(static_cast(bi->lid-1), 0, true); - lidCache->addTexture(bi->lid, createGLTexture(64, 64, &styleDB->tileTmpRGBA)); - } - if (bi->typeMapExt & 128) { - //std::cout << "blending!" << std::endl; - } - jj = 0; - if (bi->typeMap & 16384) { - jj += 2; - } - if (bi->typeMap & 32768) { - jj += 4; - } - GLfloat lidTex[8] = {0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}; -#ifdef GLTEX_HELPER -#undef GLTEX_HELPER -#endif -#define GLTEX_HELPER \ - glTexCoord2f(lidTex[jj], lidTex[jj+1]); jj += 2; if (jj > 6) { jj = 0; } - - glBindTexture(GL_TEXTURE_2D, lidCache->getTextureWithId(bi->lid)); - //} - glBegin(GL_QUADS); - GLTEX_HELPER; - //glNormal3f(0.0f, 1.0f, 0.0f); - glVertex3f(-size, -size, size);// Bottom Left Of The Texture and Quad - GLTEX_HELPER; - glVertex3f( size, -size, size);// Bottom Right Of The Texture and Quad - GLTEX_HELPER; - glVertex3f( size, size, size);// Top Right Of The Texture and Quad - GLTEX_HELPER; - glVertex3f(-size, size, size);// Top Left Of The Texture and Quad - glEnd(); -#undef GLTEX_HELPER - } -} -void OpenGTA::MapViewGL::drawMap(int32_t x1, int32_t y1, int32_t x2, int32_t y2) { - if (x1 < 0) - x1 = 0; - if (y1 < 0) - y1 = 0; - - // FIXME: can't access 255 either x or y... WHY? - if (x2 >= 255) - x2 = 255; - if (y2 >= 255) - y2 = 255; - - //std::cout << "draw: " << x1 << " " << y1 << " - " << x2 << " " << y2 << std::endl; - sideCache->sink(); - lidCache->sink(); - for (int i = y1; i <= y2; i++) { - glPushMatrix(); - glTranslatef(0.0f, -1.0f*i, 0.0f); - for (int j= x1; j <= x2; j++) { - glPushMatrix(); - glTranslatef(1.0f*j, 0.0f, 0.0f); - PHYSFS_uint16 emptycount = currentMap->getNumBlocksAt(j,i); - /*glPushMatrix(); - * for(int c=0; c < 6 - emptycount-1; c++) */ - for (int c=6-emptycount-0; c >= 1; c--) { - drawBlock(currentMap->getBlockAt(j,i, c)); - glTranslatef(0.0f, 0.0f, 1.0f); - } - glPopMatrix(); - } - glPopMatrix(); - } - sideCache->clear(); - lidCache->clear(); -} - void drawScene() { glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glLoadIdentity(); - gluLookAt(mapPos[0], -mapPos[1], mapPos[2], mapPos[0], -mapPos[1], 0.0f, camVec[0], camVec[1], camVec[2]); - //map->drawMap(int(mapPos[0]), int(mapPos[1])); - map->drawMap(int32_t(mapPos[0])-10, int32_t(mapPos[1])-10,int32_t(mapPos[0])+10, int32_t(mapPos[1])+10); + OpenGL::ScreenHolder::Instance().set3DProjection(); + OpenGL::CameraHolder::Instance().update(1); + + glRotatef(r, 0, 1, 0); + glColor3f(0.5f, 1, 0.2f); + // lid + if (wireframe) + glBegin(GL_LINE_STRIP); + else + glBegin(GL_QUADS); + for (int j=0; j < 4; j++) { + glVertex3f(SLOPE_RAW_DATA[which][0][j][0], + SLOPE_RAW_DATA[which][0][j][1], + SLOPE_RAW_DATA[which][0][j][2]); + } + if (wireframe) + glVertex3f(SLOPE_RAW_DATA[which][0][0][0], + SLOPE_RAW_DATA[which][0][0][1], + SLOPE_RAW_DATA[which][0][0][2]); + glEnd(); + + glColor3f(0.1f, 0.5f, 1); + // top + if (which != 42 && which != 45) { + if (wireframe) + glBegin(GL_LINE_STRIP); + else + glBegin(GL_QUADS); + for (int j=0; j < 4; j++) { + glVertex3f(SLOPE_RAW_DATA[which][2][j][0], + SLOPE_RAW_DATA[which][2][j][1], + SLOPE_RAW_DATA[which][2][j][2]); + } + if (wireframe) + glVertex3f(SLOPE_RAW_DATA[which][2][0][0], + SLOPE_RAW_DATA[which][2][0][1], + SLOPE_RAW_DATA[which][2][0][2]); + glEnd(); + } + + glColor3f(1, 0.2f, 0.5f); + // bottom + if (which != 41 && which != 46) { + if (wireframe) + glBegin(GL_LINE_STRIP); + else + glBegin(GL_QUADS); + for (int j=0; j < 4; j++) { + glVertex3f(SLOPE_RAW_DATA[which][1][j][0], + SLOPE_RAW_DATA[which][1][j][1], + SLOPE_RAW_DATA[which][1][j][2]); + } + if (wireframe) + glVertex3f(SLOPE_RAW_DATA[which][1][0][0], + SLOPE_RAW_DATA[which][1][0][1], + SLOPE_RAW_DATA[which][1][0][2]); + glEnd(); + } + + glColor3f(0.4f, 0.1f, 0.6f); + // left + if (which != 44 && which != 48) { + if (wireframe) + glBegin(GL_LINE_STRIP); + else + glBegin(GL_QUADS); + for (int j=0; j < 4; j++) { + glVertex3f(SLOPE_RAW_DATA[which][3][j][0], + SLOPE_RAW_DATA[which][3][j][1], + SLOPE_RAW_DATA[which][3][j][2]); + } + if (wireframe) + glVertex3f(SLOPE_RAW_DATA[which][3][0][0], + SLOPE_RAW_DATA[which][3][0][1], + SLOPE_RAW_DATA[which][3][0][2]); + glEnd(); + } + + glColor3f(0.8f, 0.6f, 0.2f); + // right + if (which != 43 && which != 47) { + if (wireframe) + glBegin(GL_LINE_STRIP); + else + glBegin(GL_QUADS); + for (int j=0; j < 4; j++) { + glVertex3f(SLOPE_RAW_DATA[which][4][j][0], + SLOPE_RAW_DATA[which][4][j][1], + SLOPE_RAW_DATA[which][4][j][2]); + } + if (wireframe) + glVertex3f(SLOPE_RAW_DATA[which][4][0][0], + SLOPE_RAW_DATA[which][4][0][1], + SLOPE_RAW_DATA[which][4][0][2]); + glEnd(); + } SDL_GL_SwapBuffers(); } +void run_init(const char* prg) { + PHYSFS_init("blockview"); + PHYSFS_addToSearchPath("gtadata.zip", 1); + PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1); + + OpenGL::Screen & screen = OpenGL::ScreenHolder::Instance(); + screen.activate(arg_screen_w, arg_screen_h); + SDL_EnableKeyRepeat( 100, SDL_DEFAULT_REPEAT_INTERVAL ); + + OpenGTA::MainMsgHolder::Instance().load("ENGLISH.FXT"); + OpenGTA::MapHolder::Instance().load(map_file); + + OpenGL::CameraHolder::Instance().setVectors(e, c, u); + +} + void run_main() { SDL_Event event; int paused = 0; - PHYSFS_init("mapview"); + PHYSFS_init("blockview"); PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1); - - glEnable(GL_TEXTURE_2D); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glPolygonMode(GL_FRONT, GL_FILL); glEnable(GL_CULL_FACE); - glEnable(GL_BLEND); - glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - //glEnable(GL_ALPHA_TEST); - //glDisable(GL_DEPTH_TEST); - - map = new OpenGTA::MapViewGL(); - map->loadMap("NYC.CMP", "STYLE001.GRY"); - + while(!global_Done && !global_EC) { while (SDL_PollEvent(&event)) { switch(event.type) { @@ -326,17 +218,11 @@ void run_main() { handleKeyPress(&event.key.keysym); break; case SDL_VIDEORESIZE: - screen = SDL_SetVideoMode( event.resize.w, - event.resize.h, 32, videoFlags ); - if (!screen) - ERROR("Failed to set video mode after resize event"); - resize(event.resize.w, event.resize.h); break; case SDL_QUIT: global_Done = 1; break; case SDL_MOUSEMOTION: - std::cout << "Mouse move: x " << float(event.motion.x)/screen->w << " y " << float(event.motion.y)/screen->h << std::endl; break; default: break; diff --git a/tools/bug_parser.awk b/tools/bug_parser.awk new file mode 100644 index 0000000..e3d2bd7 --- /dev/null +++ b/tools/bug_parser.awk @@ -0,0 +1,54 @@ +BEGIN { + in_record = 1 + bug_num = 0 +} +{ + if ($1 ~ /^\%\% *$/) { +# print "RECORD END" + if (length(bug_status) == 0) { + bug_status = "open" + } + if (length(bug_has_image) == 0) { + pr_image_str = "" + } + else { + pr_image_str = "image: " bug_has_image "" + } + print "
" + print " #" bug_num "   " bug_title "
" + print " status: " bug_status "   " pr_image_str "
" + print " " bug_descr "" + print "
" + print "
" + } + if ($1 == "Bug:") { + sub(/^Bug: /, "", $0) + bug_title = $0 + in_record = 2 + bug_has_image = "" + bug_descr = "" + bug_status = "" + bug_num = bug_num + 1 + } + else if ($1 == "Image:") { + bug_has_image = $2 + } + else if ($1 == "Status:") { + bug_status = $2 + } + else { + if (in_record == 2) { + if (length(bug_descr) > 0) { + if (length($0) == 0) { + bug_descr = bug_descr "
" + } + else { + bug_descr = bug_descr " " $0 + } + } + else { + bug_descr = $0 + } + } + } +} diff --git a/tools/build_svg_rect.sh b/tools/build_svg_rect.sh new file mode 100755 index 0000000..b61cc13 --- /dev/null +++ b/tools/build_svg_rect.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +function print_header() { +cat < + + +EOF +} + +function print_rect() { + local x=$1 + local y=$2 + local w=$3 + local h=$4 + local col=$5 +cat < +EOF +} + +WIDTH=200 +HEIGHT=200 + +function print_rnd_col() { + foo=$(echo "$RANDOM % 4" | bc) + case $foo in + 0) + echo "0,0,255";; + 1) + echo "255,0,0";; + 2) + echo "0,255,0";; + 3) + echo "255,255,0";; + esac +} + +if [ $# -gt 0 ]; then + print_header +fi +while [ $# -gt 0 ]; do + col=$(print_rnd_col) + print_rect $1 $2 $3 $4 $col + shift;shift;shift;shift +done + +echo '' diff --git a/tools/car_dump.cpp b/tools/car_dump.cpp new file mode 100644 index 0000000..de6211b --- /dev/null +++ b/tools/car_dump.cpp @@ -0,0 +1,86 @@ +#include +#include +#include +#include "opengta.h" +#include "dataholder.h" + +extern int global_EC; +extern int global_Done; +std::string map_file("undefined_map_file"); +std::string style_file("undefined_style_file"); +std::string msg_file("ENGLISH.FXT"); + +void on_exit() { + PHYSFS_deinit(); + if (global_EC) + std::cerr << "Exiting after fatal problem - please see output above" << std::endl; +} + +void parse_args(int argc, char* argv[]) { +#ifdef DUMP_CARS_IN_MAP + if (argc != 3) { + std::cout << "USAGE: " << argv[0] << " map-file style-file" << std::endl; + exit(1); + } + map_file = argv[1]; + style_file = argv[2]; +#else + if (argc != 2) { + std::cout << "USAGE: " << argv[0] << " style-file" << std::endl; + exit(1); + } + map_file = ""; + style_file = argv[1]; +#endif + +} + +void print_car(OpenGTA::GraphicsBase::CarInfo & ci) { + std::ostringstream ostr; + ostr << "car" << int(ci.model); +#define PRINT(c) << #c << ":" << ci.c << "|" +#define PRINTC(c) << #c << ":" << int(ci.c) << "|" + std::cout PRINT(width) PRINT(height) PRINT(depth) + PRINT(sprNum) PRINT(weightDescriptor) PRINT(maxSpeed) PRINT(minSpeed) + PRINT(acceleration) PRINT(braking) PRINT(grip) PRINT(handling) + // remaps + PRINTC(vtype) PRINTC(model) PRINTC(turning) PRINTC(damagable) << + "model-name:" << OpenGTA::MainMsgHolder::Instance().get().getText(ostr.str()) << "|" + PRINTC(cx) PRINTC(cy) PRINT(moment) + PRINT(rbpMass) PRINT(g1_Thrust) PRINT(tyreAdhesionX) PRINT(tyreAdhesionY) + PRINT(handBrakeFriction) PRINT(footBrakeFriction) PRINT(frontBrakeBias) + PRINT(turnRatio) PRINT(driveWheelOffset) PRINT(steeringWheelOffset) + PRINT(backEndSlideValue) PRINT(handBrakeSlideValue) + PRINTC(convertible) PRINTC(engine) PRINTC(radio) PRINTC(horn) PRINTC(soundFunction) + PRINTC(fastChangeFlag) PRINT(numDoors); +#undef PRINT +#define PRINT(c) << #c << ":" << ci.door[i].c << "|" + for (int i = 0; i < ci.numDoors; i++) { + std::cout PRINT(rpx) PRINT(rpy) PRINT(object) PRINT(delta); + } + std::cout << "remap8:"; + for (int i = 0 ; i < 12; i++) { + std::cout << int(ci.remap8[i]) << (i < 11 ? "," : ""); + } + std::cout << std::endl; +} + +void run_init(const char*) { + PHYSFS_init("mapview"); + PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1); + PHYSFS_addToSearchPath("gtadata.zip", 1); +} + +// dump all cars in style +void run_main() { + OpenGTA::MainMsgHolder::Instance().load(msg_file); + OpenGTA::StyleHolder::Instance().load(style_file); + OpenGTA::GraphicsBase & style = OpenGTA::StyleHolder::Instance().get(); + std::cout << "DUMP_OBJ_INFO BEGIN" << std::endl; + for (size_t i = 0; i < style.carInfos.size(); ++i) { + OpenGTA::GraphicsBase::CarInfo * cinfo = style.carInfos[i]; + assert(cinfo); + print_car(*cinfo); + } + +} diff --git a/tools/fxt.c b/tools/fxt.c new file mode 100644 index 0000000..c891a60 --- /dev/null +++ b/tools/fxt.c @@ -0,0 +1,90 @@ +#include +#include + +void encode(); +void decode(); +int count = 0; + +void usage(const char* prg) { + printf("USAGE: %s [-e | -d] < src_file > target_file\n", prg); + exit(0); +} + +int main(int argc, char* argv[]) { + int mode = 0; + if (argc == 2) { + if (argv[1][1] == 'd') + mode = 1; + if (argv[1][1] == 'e') + mode = 2; + } + else + usage(argv[0]); + + switch (mode) { + case 1: + decode(); + break; + case 2: + encode(); + break; + default: + usage(argv[0]); + break; + } +} + +void decode() { + int c; + int addVal = 0; + while ((c = getchar()) != EOF) { + c--; + if (count <= 7) + c -= (0x63 << count); + if (c == 195) { + addVal = 64; +// fprintf(stderr, "addval after %i bytes\n", count); + } + else { + c += addVal; +/* if (addVal) + fprintf(stderr, "decoding-addval %i %i\n", c, c - addVal); + else + fprintf(stderr, "decoding: %i\n", (unsigned char)c); +*/ + addVal = 0; + if (c == 0) + c = '\n'; + putchar(c); + } + count++; + } +} + +void encode_out(int v) { + if (count <= 7) + v += (0x63 << count); + v++; + putchar(v); +} + +void encode() { + int c; + count = 0; + while ((c = getchar()) != EOF) { + if (c == '\n') { + c = 0; + } + + if (c >= 192) { + int _c = 195; + encode_out(_c); + c -= 64; + encode_out(c); + } + else { + encode_out(c); + } + count++; + } +} diff --git a/tools/label_screenshot.sh b/tools/label_screenshot.sh new file mode 100644 index 0000000..262c66d --- /dev/null +++ b/tools/label_screenshot.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +in=$1 + +out=$1.new + + +convert $in -fill white -box '#00000080' \ + -gravity North -annotate +0+10 ' ~Scumbag City~ by Pennywise ' \ + -pointsize 20 $out diff --git a/tools/minimap.cpp b/tools/minimap.cpp index 307b80d..3fc3359 100644 --- a/tools/minimap.cpp +++ b/tools/minimap.cpp @@ -1,7 +1,60 @@ #include +#include #include "opengta.h" +#include "dataholder.h" #include "log.h" +uint32_t green = 0x00dd00ff; +uint32_t red = 0xdd0000ff; +uint32_t blue = 0x0000ddff; + +uint32_t field = green; +uint32_t building = 0xdf9f6fff; +uint32_t water = blue; +uint32_t road = 0xdadadaff; +uint32_t pavement = 0x8a9aa0ff; + +uint32_t map_color[] = { + 0x000000ff, + water, + road, + pavement, + field, + building, + 0xffffffff, + 0xff0000ff +}; + + +void save_map_level(OpenGTA::Map & map, size_t level, const char* out_prefix) { + SDL_Surface* surface = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA, + 256, 256, 32,// rmask, gmask, bmask, amask); + 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); + SDL_LockSurface(surface); + uint32_t* dst = static_cast(surface->pixels); + + for (int i = 0; i < 256; i++) { + for (int j = 0; j < 256; j++) { + PHYSFS_uint16 emptycount = map.getNumBlocksAtNew(j,i); + if (level < emptycount) { + OpenGTA::Map::BlockInfo* bi = map.getBlockAtNew(j, i, level); + *dst = map_color[bi->blockType()]; + } + else { + *dst = map_color[0]; + } + ++dst; + } + } + + SDL_UnlockSurface(surface); + std::ostringstream ostr; + ostr << out_prefix << "_" << level << ".bmp"; + SDL_SaveBMP(surface, ostr.str().c_str()); + + +} + int main(int argc, char* argv[]) { if (argc < 2) { @@ -15,32 +68,16 @@ int main(int argc, char* argv[]) { PHYSFS_addToSearchPath("gtadata.zip", 1); std::string map_filename(argv[1]); + OpenGTA::MainMsgHolder::Instance().load("ENGLISH.FXT"); OpenGTA::Map map(map_filename); - uint32_t green = 0x00dd00ff; - uint32_t red = 0xdd0000ff; - uint32_t blue = 0x0000ddff; - - uint32_t field = green; - uint32_t building = 0xdf9f6fff; - uint32_t water = blue; - uint32_t road = 0xdadadaff; - uint32_t pavement = 0x8a9aa0ff; - - uint32_t map_color[] = { - 0x000000ff, - water, - road, - pavement, - field, - building, - 0xffffffff, - 0xff0000ff - }; SDL_Init(SDL_INIT_VIDEO); + for (size_t i = 0; i < 7; i++) + save_map_level(map, i, "out"); +#if 0 // FIXME: doesn't work right #if SDL_BYTEORDER == SDL_BIG_ENDIAN #define rmask 0xff000000 @@ -102,6 +139,8 @@ int main(int argc, char* argv[]) { } SDL_UnlockSurface(surface); SDL_SaveBMP(surface, "out.bmp"); +#endif + SDL_Quit(); return 0; diff --git a/tools/package_binary.sh b/tools/package_binary.sh new file mode 100644 index 0000000..43fc0b0 --- /dev/null +++ b/tools/package_binary.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +DLL_NAMES_W32=*.dll #"SDL.dll" + +function binary() { + local ex_name=$1 + if [ "$HOST" == "WIN32" ]; then + echo $ex_name".exe" + echo $DLL_NAMES_W32 + else + echo $ex_name + fi +} + +function host_txt() { + if [ "$HOST" == "WIN32" ]; then + unix2dos $@ + fi + echo "$@" +} + +function list_files() { + binary viewer + echo licenses/* + host_txt license.txt readme.txt cvs_changelog.txt + host_txt doc/using_mods.txt +} + +R_DATE=$(cat ogta_version) +if [ "$HOST" == "WIN32" ]; then + ZIP_FILE_NAME=ogta_sneak-preview-${R_DATE}_win32 + + list_files | xargs zip $ZIP_FILE_NAME +else + TAR_FILE_NAME=ogta_sneak-preview-${R_DATE}_linux.tar.bz2 + + list_files | xargs tar jvcf $TAR_FILE_NAME +fi diff --git a/tools/picasa_ls.sh b/tools/picasa_ls.sh new file mode 100755 index 0000000..b144a4b --- /dev/null +++ b/tools/picasa_ls.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +TMP_FILE=/tmp/picasa_lst.$$ + +function fetch() { + wget -O $TMP_FILE 'http://picasaweb.google.com/data/feed/base/user/under.northern.sky/albumid/5015283825893823185?kind=photo&alt=rss&hl=en_US' +} + +function extract() { + local _file=$1 + echo 'cat /rss/channel/item[*]/enclosure|/rss/channel/item[*]/link' \ + | xmllint --shell $_file | grep http | sed \ + -e 's|^.*url="||' -e 's|".*$||' -e 's|<\/*link>||g' +} + +fetch +extract $TMP_FILE | { + while read a; do + basename $a + read b + echo $b + echo + done +} +rm -f $TMP_FILE diff --git a/tools/plot_stats.sh b/tools/plot_stats.sh new file mode 100755 index 0000000..c5c3c7d --- /dev/null +++ b/tools/plot_stats.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +if [ ! -e stats ]; then + echo "start me in the archive dir after creatings 'stats'" + exit 1 +fi + +sh ../tools/stats_recalc.sh < stats > stats2 +gnuplot < 255) @@ -51,7 +57,7 @@ namespace Util { return (z < mapRef.getNumBlocksAtNew(x, y)); } - OpenGTA::Map::BlockInfo & CellIterator::getBlock() { + OpenGTA::Map::BlockInfo & CellIterator::getBlock() const { assert(isValid()); return *mapRef.getBlockAtNew(x, y, z); } @@ -61,4 +67,76 @@ namespace Util { return (IABS(x - o.x) + IABS(y - o.y) + IABS(z - o.z)); } + bool CellIterator::isBlockType(uint8_t t) const { + if (!isValid()) + return false; + return (getBlock().blockType() == t); + } + + std::pair CellIterator::findTypeInCol(uint8_t t) const { + if (isBlockType(t)) + return std::make_pair(true, *this); + CellIterator below = down(); + while (below.isValid()) { + if (below.isBlockType(t)) + return std::make_pair(true, below); + below = below.down(); + } + CellIterator above = up(); + while (above.isValid()) { + if (above.isBlockType(t)) + return std::make_pair(true, above); + above = above.up(); + } + return std::make_pair(false, *this); + } + + std::pair CellIterator::findNeighbourWithType( + uint8_t t, float angle_hint) { + assert(isValid()); + + if (angle_hint >= 315 || angle_hint < 45) { + std::pair p = top().findTypeInCol(t); +// if (p.first) INFO << p.second.x << " " << p.second.y << " " << p.second.z << std::endl; + if (p.first) return p; + } + if (angle_hint >= 0 || angle_hint < 90) { + std::pair p = top().right().findTypeInCol(t); +// if (p.first) INFO << p.second.x << " " << p.second.y << " " << p.second.z << std::endl; + if (p.first) return p; + } + if (angle_hint >= 45 && angle_hint < 135) { + std::pair p = right().findTypeInCol(t); +// if (p.first) INFO << p.second.x << " " << p.second.y << " " << p.second.z << std::endl; + if (p.first) return p; + } + if (angle_hint >= 90 && angle_hint < 180) { + std::pair p = right().bottom().findTypeInCol(t); +// if (p.first) INFO << p.second.x << " " << p.second.y << " " << p.second.z << std::endl; + if (p.first) return p; + } + if (angle_hint >= 135 && angle_hint < 225) { + std::pair p = bottom().findTypeInCol(t); +// if (p.first) INFO << p.second.x << " " << p.second.y << " " << p.second.z << std::endl; + if (p.first) return p; + } + if (angle_hint >= 180 && angle_hint < 270) { + std::pair p = left().bottom().findTypeInCol(t); +// if (p.first) INFO << p.second.x << " " << p.second.y << " " << p.second.z << std::endl; + if (p.first) return p; + } + if (angle_hint >= 225 && angle_hint < 315) { + std::pair p = left().findTypeInCol(t); +// if (p.first) INFO << p.second.x << " " << p.second.y << " " << p.second.z << std::endl; + if (p.first) return p; + } + if (angle_hint >= 270 && angle_hint < 360) { + std::pair p = top().left().findTypeInCol(t); +// if (p.first) INFO << p.second.x << " " << p.second.y << " " << p.second.z << std::endl; + if (p.first) return p; + } + return std::make_pair(false, *this); + + } + } diff --git a/util/cell_iterator.h b/util/cell_iterator.h index 38ca56d..47016c3 100644 --- a/util/cell_iterator.h +++ b/util/cell_iterator.h @@ -31,6 +31,7 @@ namespace Util { float distance(const Vector3D & p1, const Vector3D & p2); float xz_angle(const Vector3D & from, const Vector3D & to); + float xz_turn_angle(const Vector3D & from, const Vector3D & to); class CellIterator { public: @@ -89,8 +90,11 @@ namespace Util { p.z -= 1; return p; } + bool isBlockType(uint8_t t) const; + std::pair findTypeInCol(uint8_t t) const; + std::pair findNeighbourWithType(uint8_t t, float angle_hint); int x, y, z; - OpenGTA::Map::BlockInfo & getBlock(); + OpenGTA::Map::BlockInfo & getBlock() const; private: OpenGTA::Map & mapRef; }; diff --git a/util/file_helper.cpp b/util/file_helper.cpp index fce88ba..702bb72 100644 --- a/util/file_helper.cpp +++ b/util/file_helper.cpp @@ -26,6 +26,7 @@ #include "m_exceptions.h" #include "file_helper.h" #include "buffercache.h" +#include "log.h" #ifndef OGTA_DEFAULT_DATA_PATH #define OGTA_DEFAULT_DATA_PATH "gtadata.zip" @@ -117,4 +118,24 @@ namespace Util { PHYSFS_close(fd); return buffer; } + + const std::string FileHelper::lang2MsgFilename(const char *l) { + assert(l); + std::string lang(l); + if (lang.size() > 2) + lang = lang.substr(0, 2); + std::transform(lang.begin(), lang.end(), lang.begin(), tolower); + if (lang == "en") + return std::string("ENGLISH.FXT"); + else if (lang == "de") + return std::string("GERMAN.FXT"); + else if (lang == "fr") + return std::string("FRENCH.FXT"); + else if (lang == "it") + return std::string("ITALIAN.FXT"); + + WARN << "Unknown language: " << l << " - falling back to english" + << std::endl; + return std::string("ENGLISH.FXT"); + } } diff --git a/util/file_helper.h b/util/file_helper.h index f12f16a..31b4df3 100644 --- a/util/file_helper.h +++ b/util/file_helper.h @@ -40,6 +40,7 @@ namespace Util { bool existsInVFS(const std::string & file) const; PHYSFS_file* openReadVFS(const std::string & file) const; unsigned char* bufferFromVFS(PHYSFS_file*) const; + static const std::string lang2MsgFilename(const char* l); private: std::string baseDataPath; std::string modDataPath; diff --git a/util/gui.cpp b/util/gui.cpp new file mode 100644 index 0000000..754f700 --- /dev/null +++ b/util/gui.cpp @@ -0,0 +1,559 @@ +#include "gui.h" +#include "m_exceptions.h" +#include "dataholder.h" +#include "gl_spritecache.h" +#include "gl_screen.h" +#ifdef WITH_LUA +#include "lua_vm.h" +#endif +#include +#include "localplayer.h" + +extern float screen_gamma; +namespace GUI { + Object::Object(const SDL_Rect & r) : + id(0), rect(), color(), borderColor(), drawBorder(false), + 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(), borderColor(), drawBorder(false), + 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(), borderColor(), drawBorder(false), + manager(ManagerHolder::Instance()) { + copyRect(r); + copyColor(c); + } + void Object::draw() { + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + 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(); + if (drawBorder) + draw_border(); + glDisable(GL_BLEND); + } + void Object::draw_border() { + glColor4ub(borderColor.r, borderColor.g, borderColor.b, + borderColor.unused); + glBegin(GL_LINE_LOOP); + 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() { + if (texId == 0) + return; + 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); + if (drawBorder) + draw_border(); + } + + 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); + if (drawBorder) + draw_border(); + } + + void Label::draw() { + glPushMatrix(); + glColor4ub(color.r, color.g, color.b, color.unused); + glEnable(GL_TEXTURE_2D); + if (align == 0) { + glTranslatef(rect.x, rect.y, 0); + rect.w = uint16_t(font->drawString(text)); + } + else if (align == 1) { + glTranslatef(rect.x, rect.y, 0); + rect.w = uint16_t(font->drawString_r2l(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(); + */ + glDisable(GL_TEXTURE_2D); + if (drawBorder) + draw_border(); + } + + 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); + if (drawBorder) + draw_border(); + + } + + 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; + } + glColor4f(1, 1, 1, 1); + glEnable(GL_TEXTURE_2D); + } + + Manager::~Manager() { + clearObjects(); + clearCache(); + } + + void Manager::clearObjects() { + INFO << "clearing gui objects" << std::endl; + GuiObjectListMap::iterator layer_it = guiLayers.begin(); + while (layer_it != guiLayers.end()) { + GuiObjectList & list = layer_it->second; + for (GuiObjectList::iterator i = list.begin(); i != list.end(); ++i) { + delete *i; + } + list.clear(); + ++layer_it; + } + guiLayers.clear(); + } + + void Manager::clearCache() { + INFO << "clearing gui texture cache" << std::endl; + for (GuiTextureCache::iterator i = texCache.begin(); i != texCache.end(); ++i) { + OpenGL::PagedTexture & p = i->second; + glDeleteTextures(1, &p.inPage); + } + texCache.clear(); + for (AnimationMap::iterator i = guiAnimations.begin(); i != guiAnimations.end(); ++i) { + delete i->second; + } + guiAnimations.clear(); + } + + const OpenGL::PagedTexture & Manager::getCachedImage(size_t Id) { + GuiTextureCache::iterator i = findByCacheId(Id); + if (i == texCache.end()) { + std::ostringstream o; + o << "cached texture id " << int(Id); + throw E_UNKNOWNKEY(o.str()); + } + return i->second; + } + + Manager::GuiTextureCache::iterator Manager::findByCacheId(const size_t & Id) { + return texCache.find(Id); + } + + Manager::GuiObjectListMap::iterator Manager::findLayer(uint8_t l) { + return guiLayers.find(l); + } + + void Manager::cacheImageRAW(const std::string & file, size_t k) { + texCache.insert(std::make_pair(k, ImageUtil::loadImageRAW(file))); + } + + void Manager::cacheImageRAT(const std::string & file, const std::string & palette, size_t k) { + texCache.insert(std::make_pair(k, + ImageUtil::loadImageRATWithPalette(file, palette))); + } + + ImageUtil::WidthHeightPair Manager::cacheStyleArrowSprite(const size_t id, int remap) { + OpenGTA::GraphicsBase & graphics = OpenGTA::StyleHolder::Instance().get(); + PHYSFS_uint16 t = graphics.spriteNumbers.reIndex(id, OpenGTA::GraphicsBase::SpriteNumbers::ARROW); + OpenGTA::GraphicsBase::SpriteInfo * info = graphics.getSprite(t); + texCache.insert(std::make_pair( + id, OpenGL::SpriteCacheHolder::Instance().createSprite(size_t(t), remap, 0, info) + )); + return ImageUtil::WidthHeightPair(info->w, info->h); + } + +#ifdef WITH_SDL_IMAGE + void Manager::cacheImageSDL(const std::string & file, size_t k) { + texCache.insert(std::make_pair(k, + ImageUtil::loadImageSDL(file))); + } +#endif + + void Manager::add(Object * obj, uint8_t onLevel) { + GuiObjectListMap::iterator l = findLayer(onLevel); + if (l == guiLayers.end()) { + GuiObjectList list; + list.push_back(obj); + guiLayers.insert(std::make_pair(onLevel, list)); + return; + } + GuiObjectList & list = l->second; + list.push_back(obj); + } + + void Manager::remove(Object * obj) { + for (GuiObjectListMap::iterator l = guiLayers.begin(); l != guiLayers.end(); ++l) { + GuiObjectList & list = l->second; + for (GuiObjectList::iterator m = list.begin(); m != list.end(); ++m) { + Object * o = *m; + if (o == obj) { + delete o; + list.erase(m); + return; + } + } + } + throw E_UNKNOWNKEY("not a managed object-ptr"); + } + + Object* Manager::findObject(const size_t id) { + for (GuiObjectListMap::iterator l = guiLayers.begin(); l != guiLayers.end(); ++l) { + GuiObjectList & list = l->second; + for (GuiObjectList::iterator m = list.begin(); m != list.end(); ++m) { + Object * o = *m; + if (o->id == id) + return o; + } + } + std::ostringstream o; + o << "object by id " << int(id); + throw E_UNKNOWNKEY(o.str()); + + return 0; + } + + void Manager::removeById(const size_t id) { + Object * o = findObject(id); + if (o) + remove(o); + //else + // ERROR << "failed to find object " << id << " - cannot remove it" << std::endl; + } + + bool Manager::isInside(Object & obj, Uint16 x, Uint16 y) const { + if ((obj.rect.x <= x) && (x <= obj.rect.x + obj.rect.w) && + (obj.rect.y <= y) && (y <= obj.rect.y + obj.rect.h)) + return true; + return false; + } + void Manager::receive(SDL_MouseButtonEvent & mb_event) { + Uint32 sh = OpenGL::ScreenHolder::Instance().getHeight(); + GuiObjectListMap::reverse_iterator l = guiLayers.rbegin(); + while (l != guiLayers.rend()) { + 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; + obj->receive(mb_event); + return; + } + } + ++l; + } + } + + void Manager::update(uint32_t nowticks) { + for (AnimationMap::iterator i = guiAnimations.begin(); i != guiAnimations.end(); ++i) { + i->second->update(nowticks); + } + GuiObjectListMap::iterator layer_it = guiLayers.begin(); + while (layer_it != guiLayers.end()) { + GuiObjectList & inThisLayer = layer_it->second; + for (GuiObjectList::iterator obj_it = inThisLayer.begin(); + obj_it != inThisLayer.end(); ++obj_it) { + Object * obj = *obj_it; + obj->update(nowticks); + } + ++layer_it; + } + } + + Animation* Manager::findAnimation(uint16_t id) { + AnimationMap::iterator i = guiAnimations.find(id); + return i->second; + } + void Manager::createAnimation(const std::vector & indices, uint16_t fps, size_t k) { + Animation * anim = new Animation(indices, fps); + guiAnimations.insert(std::make_pair(k, anim)); + anim->set(Util::Animation::PLAY_FORWARD, Util::Animation::LOOP); + } + + uint16_t Animation::getCurrentFrame() { + return indices[getCurrentFrameNumber()]; + } + + const int WEAPON_DISPLAY_ID = 100; + + const SDL_Rect sdl_rect(size_t a, size_t b, size_t c, size_t d) { + SDL_Rect rect; + rect.x = a; + rect.y = b; + rect.w = c; + rect.h = d; + return rect; + } + + WeaponDisplay::WeaponDisplay(const SDL_Rect & r) : Object(WEAPON_DISPLAY_ID, r), + img(sdl_rect(r.x+2, r.y+2, r.w - 4, r.h - 4), 0), + label(sdl_rect(r.x+2, r.y+r.h, r.w - 4, r.h - 4), "", "F_MTEXT.FON", 1) { + } + + void WeaponDisplay::draw() { + img.draw(); + label.draw(); + } + + size_t WeaponDisplay::getWeaponIdx(const size_t wt) { + if (wt == 0) + return 0; + if (wt < 5) + return 1000 + wt; + + return 0; + } + + void WeaponDisplay::setWeapon(const size_t wt) { + img.texId = getWeaponIdx(wt); + try { + manager.getCachedImage(img.texId); + } + catch (const Util::UnknownKey & ek) { + WARN << "GUI image for weapon " << wt << " not loaded - retrying" << std::endl; + manager.cacheStyleArrowSprite(img.texId, -1); + } + } + + void ScrollBar::draw() { + Object::draw(); + glColor3ub(innerColor.r, innerColor.g, innerColor.b); + glBegin(GL_QUADS); + glVertex2i(rect.x+2, rect.y+2); + glVertex2i(rect.x + int(rect.w * value) -2, rect.y+2); + glVertex2i(rect.x + int(rect.w * value) -2, rect.y + rect.h-2); + glVertex2i(rect.x+2, rect.y + rect.h-2); + glEnd(); + } + + void ScrollBar::receive(SDL_MouseButtonEvent & mb_event) { + value = (mb_event.x - rect.x) / float(rect.w - 4); + INFO << value << std::endl; + if (changeCB) + changeCB(value * 2); + else + WARN << "No callback function set - I ain't seen nothing" << + std::endl; + /* + SDL_SetGamma(value * 2, value * 2, value * 2); + Object * o = ManagerHolder::Instance().findObject(101); + if (o) { + std::ostringstream os; + os << "Gamma: " << value * 2; + static_cast(o)->text = os.str(); + }*/ + } + + + void screen_gamma_callback(float v) { + screen_gamma = v; + SDL_SetGamma(v, v, v); +#ifdef WITH_LUA + OpenGTA::Script::LuaVM & vm = OpenGTA::Script::LuaVMHolder::Instance(); + lua_State *L = vm.getInternalState(); + int top = lua_gettop(L); + lua_getglobal(L, "config"); + if (lua_type(L, -1) != LUA_TTABLE) { + lua_pop(L, 1); + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setglobal(L, "config"); + } + uint8_t sf = OpenGTA::StyleHolder::Instance().get().getFormat(); + if (sf) + vm.setFloat("screen_gamma_g24", v); + else + vm.setFloat("screen_gamma_gry", v); + lua_settop(L, top); +#endif + Object * o = ManagerHolder::Instance().findObject(GAMMA_LABEL_ID); + if (o) { + std::ostringstream os; + os << "Gamma: " << v; + static_cast(o)->text = os.str(); + } + /* + Object * o2 = ManagerHolder::Instance().findObject(1001); + if (o2) { + static_cast(o2)->number = screen_gamma * 3; + }*/ + + } + + AnimStatusDisplay* wantedLevel = NULL; + Label* cashLabel = NULL; + + void create_ingame_gui(bool is32bit) { + OpenGL::Screen & screen = OpenGL::ScreenHolder::Instance(); + GUI::Manager & gm = ManagerHolder::Instance(); + assert(!wantedLevel); + { + SDL_Rect r; + r.h = 32; + r.x = screen.getWidth() / 2 - 50; + r.y = screen.getHeight() - r.h; + r.w = 100; + SDL_Rect rs; + rs.x = rs.y = 0; + rs.w = rs.h = 16; + gm.cacheStyleArrowSprite(16, -1); + gm.cacheStyleArrowSprite(17, -1); + std::vector anim2frames(2); + anim2frames[0] = 16; + anim2frames[1] = 17; + gm.createAnimation(anim2frames, 10, 2); + wantedLevel = new AnimStatusDisplay(WANTED_LEVEL_ID, r, rs, 2); + /* + wantedLevel->borderColor.r = wantedLevel->borderColor.g = wantedLevel->borderColor.b = wantedLevel->borderColor.unused = 255; + wantedLevel->drawBorder = 1; + */ + gm.add(wantedLevel, 50); + } + assert(!cashLabel); + { + SDL_Rect r; + r.x = screen.getWidth() - 5; + r.y = screen.getHeight() - 30; + cashLabel = new Label(GUI::CASH_ID, r, "0", "F_MTEXT.FON", 1); + cashLabel->align = 1; + gm.add(cashLabel, 50); + } + + } + + void update_ingame_gui_values() { + OpenGTA::PlayerController & pc = OpenGTA::LocalPlayer::Instance(); + + if (wantedLevel) + wantedLevel->number = pc.getWantedLevel(); + + if (cashLabel) { + std::ostringstream os; + os << pc.getCash(); + cashLabel->text = os.str(); + } + } + + void remove_ingame_gui() { + GUI::Manager & gm = ManagerHolder::Instance(); + + if (wantedLevel) + gm.remove(wantedLevel); + wantedLevel = NULL; + + if (cashLabel) + gm.remove(cashLabel); + cashLabel = NULL; + } + +} + diff --git a/util/gui.h b/util/gui.h index 9ef142a..b8b60ed 100644 --- a/util/gui.h +++ b/util/gui.h @@ -36,6 +36,18 @@ namespace GUI { struct Object; class Animation; + /** Wrapper around GUI elements. + * + * Contains a number of lists of objects; mouse click events can be delegated + * to any element. Elements are placed into "layers"; drawing is done from + * low to high (0 .. 255), clicked-inside is tested high to low (255 ... 0). + * + * Objects _should_ have a unique id (removeById only finds the first match), + * but this is neither ensured nor required. + * + * Finally there are helper functions (which are used by derived objects) to + * load/access images/animations. + */ class Manager { public: Manager() {} @@ -47,11 +59,13 @@ namespace GUI { void draw(); void clearObjects(); void clearCache(); - void cacheImageRAW(const std::string & file, size_t asId); - void cacheImageRAT(const std::string & file, const std::string & palette, size_t asId); - void cacheImageSDL(const std::string & file, size_t asId); + void cacheImageRAW(const std::string & file, size_t id); + void cacheImageRAT(const std::string & file, const std::string & palette, size_t id); +#ifdef WITH_SDL_IMAGE + void cacheImageSDL(const std::string & file, size_t id); +#endif ImageUtil::WidthHeightPair cacheStyleArrowSprite(const size_t id, int remap); - const OpenGL::PagedTexture & getCachedImage(size_t Id); + const OpenGL::PagedTexture & getCachedImage(size_t id); void receive(SDL_MouseButtonEvent & mb_event); Animation* findAnimation(uint16_t id); void createAnimation(const std::vector & indices, uint16_t fps, size_t asAnimId); @@ -83,6 +97,8 @@ namespace GUI { uint16_t getCurrentFrame(); }; + /** Base-object - Can be used to draw coloured area & border. + */ struct Object { Object(const SDL_Rect & r); Object(const size_t Id, const SDL_Rect & r); @@ -91,10 +107,14 @@ namespace GUI { size_t id; SDL_Rect rect; SDL_Color color; + SDL_Color borderColor; + bool drawBorder; void copyRect(const SDL_Rect & src); void copyColor(const SDL_Color & src); virtual void draw(); virtual void update(Uint32 ticks) {} + virtual void receive(SDL_MouseButtonEvent & mb_event) {} + void draw_border(); Manager & manager; }; @@ -133,9 +153,11 @@ namespace GUI { const std::string & fontFile, const size_t fontScale) : Object(Id, r), text(s) { OpenGL::DrawableFont & fnt = OpenGTA::FontCacheHolder::Instance().getFont(fontFile, fontScale); font = &fnt; + align = 0; } OpenGL::DrawableFont * font; std::string text; + uint8_t align; void draw(); }; @@ -154,5 +176,68 @@ namespace GUI { std::string lastMsg; int offset; }; + + struct WeaponDisplay : public Object { + public: + WeaponDisplay(const SDL_Rect & r); + void setWeapon(const size_t wt); + void draw(); + private: + size_t getWeaponIdx(const size_t wt); + TexturedObject img; + Label label; + }; + + struct ScrollBar : public Object { + ScrollBar(const size_t Id, const SDL_Rect & r) : Object(Id, r) { + value = 0.5f; + } + void draw(); + void receive(SDL_MouseButtonEvent & mb_event); + SDL_Color innerColor; + float value; + typedef Loki::Functor SC_Functor; + SC_Functor changeCB; + }; + + template + struct Number2Status : public Object { + Number2Status(const size_t Id, const SDL_Rect & r, const SDL_Rect & ir, const size_t vId) : + Object(Id, r), + item(r, vId), + number(0), align(0), + innerRect(ir) {} + Child_T item; + V number; + uint8_t align; + SDL_Rect innerRect; + void draw() { + innerRect.x = (align == 0 ? rect.x : rect.x + rect.w - innerRect.w); + innerRect.y = rect.y; + memcpy(&item.rect, &innerRect, sizeof(rect)); + for (V k = 0; k < number; k++) { + item.draw(); + item.rect.x += (align == 0 ? item.rect.w + 1 : -item.rect.w - 1); + } + if (drawBorder) + draw_border(); + } + }; + + typedef Number2Status ImageStatusDisplay; + typedef Number2Status AnimStatusDisplay; + + void screen_gamma_callback(float v); + + void create_ingame_gui(bool is32bit); + void update_ingame_gui_values(); + void remove_ingame_gui(); + + static const uint32_t GAMMA_SCROLLBAR_ID = 100; + static const uint32_t GAMMA_LABEL_ID = 101; + + static const uint32_t CASH_ID = 200; + static const uint32_t WANTED_LEVEL_ID = 201; + } #endif diff --git a/util/image_loader.cpp b/util/image_loader.cpp index 5ff0b66..46e5981 100644 --- a/util/image_loader.cpp +++ b/util/image_loader.cpp @@ -28,6 +28,9 @@ #include "log.h" #include "cistring.h" #include "opengta.h" +#include "physfsrwops.h" +#include "SDL_image.h" +#include "m_exceptions.h" namespace ImageUtil { using OpenGL::PagedTexture; @@ -88,6 +91,7 @@ using OpenGL::PagedTexture; if (whp.first == 0 || whp.second == 0) { PHYSFS_close(fd); WARN << "aborting image load" << std::endl; + throw E_UNKNOWNKEY(name + " - RAW file size unknown"); } Util::BufferCache::LockedBuffer lbuf(nbytes); @@ -115,6 +119,7 @@ using OpenGL::PagedTexture; if (whp.first == 0 || whp.second == 0) { PHYSFS_close(fd); WARN << "aborting image load" << std::endl; + throw E_UNKNOWNKEY(name + " - RAT file size unknown"); } Util::BufferCache::LockedBuffer lb1(nbytes); PHYSFS_read(fd, lb1(), 1, nbytes); @@ -131,20 +136,53 @@ using OpenGL::PagedTexture; return createEmbeddedTexture(whp.first, whp.second, false, lb2()); } +#ifdef WITH_SDL_IMAGE + OpenGL::PagedTexture loadImageSDL(const std::string & name) { + SDL_RWops * rwops = PHYSFSRWOPS_openRead(name.c_str()); + SDL_Surface *surface = IMG_Load_RW(rwops, 1); + assert(surface); + + 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); + copyImage2Image(buffer, (uint8_t*)surface->pixels, surface->pitch, surface->h, + npot.w * bpp); + SDL_UnlockSurface(surface); + SDL_FreeSurface(surface); + + GLuint texture = 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 + GLuint createGLTexture(GLsizei w, GLsizei h, bool rgba, const void* pixels) { GLuint tex; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (!mipmapTextures) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + else + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (rgba) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - //gluBuild2DMipmaps(GL_TEXTURE_2D, 4, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels); - //gluBuild2DMipmaps(GL_TEXTURE_2D, 3, w, h, GL_RGB, GL_UNSIGNED_BYTE, pixels); + if (rgba) { + if (mipmapTextures) + gluBuild2DMipmaps(GL_TEXTURE_2D, 4, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + } + else { + if (mipmapTextures) + gluBuild2DMipmaps(GL_TEXTURE_2D, 3, w, h, GL_RGB, GL_UNSIGNED_BYTE, pixels); + else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels); + } + if (supportedMaxAnisoDegree > 1.0f) + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &supportedMaxAnisoDegree); GL_CHECKERROR; return tex; @@ -165,13 +203,86 @@ using OpenGL::PagedTexture; bool rgba, const void* pixels) { NextPowerOfTwo npot(w, h); - uint32_t bpp = (rgba ? 4 : 3); + uint8_t* buff = (uint8_t*)pixels; - uint32_t bufSize = npot.w * npot.h * bpp; - uint8_t* buff = Util::BufferCacheHolder::Instance().requestBuffer(bufSize); - copyImage2Image(buff, (uint8_t*)pixels, w * bpp, h, npot.w * bpp); + if (!(npot.w == uint32_t(w) && npot.h == uint32_t(h))) { + uint32_t bpp = (rgba ? 4 : 3); + uint32_t bufSize = npot.w * npot.h * bpp; + buff = Util::BufferCacheHolder::Instance().requestBuffer(bufSize); + copyImage2Image(buff, (uint8_t*)pixels, w * bpp, h, npot.w * bpp); + } GLuint tex = createGLTexture(npot.w, npot.h, rgba, buff); return PagedTexture(tex, 0, 0, float(w) / npot.w, float(h) / npot.h); } + +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define READINT24(x) ((x)[0]<<16 | (x)[1]<<8 | (x)[2]) +#define WRITEINT24(x, i) {(x)[0]=i>>16; (x)[1]=(i>>8)&0xff; x[2]=i&0xff; } + + uint8_t* scale2x_24bit(const uint8_t* src, const int src_width, const int src_height) { + const int srcpitch = src_width * 3; + const int dstpitch = src_width * 6; + + uint8_t *dstpix = Util::BufferCacheHolder::Instance().requestBuffer(src_width * + src_height * 3 * 4); + int E0, E1, E2, E3, B, D, E, F, H; + for(int looph = 0; looph < src_height; ++looph) + { + for(int loopw = 0; loopw < src_width; ++ loopw) + { + B = READINT24(src + (MAX(0,looph-1)*srcpitch) + (3*loopw)); + D = READINT24(src + (looph*srcpitch) + (3*MAX(0,loopw-1))); + E = READINT24(src + (looph*srcpitch) + (3*loopw)); + F = READINT24(src + (looph*srcpitch) + (3*MIN(src_width-1,loopw+1))); + H = READINT24(src + (MIN(src_height-1,looph+1)*srcpitch) + (3*loopw)); + + E0 = D == B && B != F && D != H ? D : E; + E1 = B == F && B != D && F != H ? F : E; + E2 = D == H && D != B && H != F ? D : E; + E3 = H == F && D != H && B != F ? F : E; + + WRITEINT24((dstpix + looph*2*dstpitch + loopw*2*3), E0); + WRITEINT24((dstpix + looph*2*dstpitch + (loopw*2+1)*3), E1); + WRITEINT24((dstpix + (looph*2+1)*dstpitch + loopw*2*3), E2); + WRITEINT24((dstpix + (looph*2+1)*dstpitch + (loopw*2+1)*3), E3); + } + } + return dstpix; + } + + uint8_t* scale2x_32bit(const uint8_t* src, const int src_width, const int src_height) { + const int srcpitch = src_width * 4; + const int dstpitch = src_width * 8; + + uint8_t* dstpix = Util::BufferCacheHolder::Instance().requestBuffer(src_width * + src_height * 4 * 4); + Uint32 E0, E1, E2, E3, B, D, E, F, H; + for(int looph = 0; looph < src_height; ++looph) + { + for(int loopw = 0; loopw < src_width; ++ loopw) + { + B = *(Uint32*)(src + (MAX(0,looph-1)*srcpitch) + (4*loopw)); + D = *(Uint32*)(src + (looph*srcpitch) + (4*MAX(0,loopw-1))); + E = *(Uint32*)(src + (looph*srcpitch) + (4*loopw)); + F = *(Uint32*)(src + (looph*srcpitch) + (4*MIN(src_width-1,loopw+1))); + H = *(Uint32*)(src + (MIN(src_height-1,looph+1)*srcpitch) + (4*loopw)); + + E0 = D == B && B != F && D != H ? D : E; + E1 = B == F && B != D && F != H ? F : E; + E2 = D == H && D != B && H != F ? D : E; + E3 = H == F && D != H && B != F ? F : E; + + *(Uint32*)(dstpix + looph*2*dstpitch + loopw*2*4) = E0; + *(Uint32*)(dstpix + looph*2*dstpitch + (loopw*2+1)*4) = E1; + *(Uint32*)(dstpix + (looph*2+1)*dstpitch + loopw*2*4) = E2; + *(Uint32*)(dstpix + (looph*2+1)*dstpitch + (loopw*2+1)*4) = E3; + } + } + return dstpix; + } + + bool mipmapTextures = false; + GLfloat supportedMaxAnisoDegree = 1.0f; } diff --git a/util/image_loader.h b/util/image_loader.h index e77d9eb..3835739 100644 --- a/util/image_loader.h +++ b/util/image_loader.h @@ -29,8 +29,8 @@ namespace ImageUtil { - typedef std::pair WidthHeightPair; - + /** Helper to calculate 2^k texture sizes. + */ struct NextPowerOfTwo { NextPowerOfTwo(uint32_t _w, uint32_t _h) { w = 1; h = 1; @@ -41,22 +41,41 @@ namespace ImageUtil { uint32_t h; }; + /** Run scale2x on 32bit input image. + * + * \note Uses Util::BufferCache for dst memory; lock 'src' before calling + * if it also is a BufferCache buffer. + */ + uint8_t* scale2x_32bit(const uint8_t* src, const int src_width, const int src_height); + + uint8_t* scale2x_24bit(const uint8_t* src, const int src_width, const int src_height); + + typedef std::pair WidthHeightPair; // hardcoded data for known images WidthHeightPair lookupImageSize(const std::string & name, const uint32_t size); // load a rgb image OpenGL::PagedTexture loadImageRAW(const std::string & name); // load a palette image and guess the palette filename - OpenGL::PagedTexture loadImageRAT(const std::string & name); + //OpenGL::PagedTexture loadImageRAT(const std::string & name); // load a palette image using palette file OpenGL::PagedTexture loadImageRATWithPalette(const std::string & name, const std::string & palette_file); - // plain simple garden-variety create-a-texture; needs to be ^2 - GLuint createGLTexture(GLsizei w, GLsizei h, bool rgba, const void* pixels); +#ifdef WITH_SDL_IMAGE + OpenGL::PagedTexture loadImageSDL(const std::string & name); +#endif - // blitting a buffer into another; they should exist! + extern bool mipmapTextures; + extern GLfloat supportedMaxAnisoDegree; + + // plain simple garden-variety create-a-texture; needs to be 2^k + GLuint createGLTexture(GLsizei w, GLsizei h, bool rgba, + const void* pixels); + + // blitting a buffer into another; no checks done! void copyImage2Image(uint8_t *dest, const uint8_t *src, const uint16_t srcWidth, const uint16_t srcHeight, const uint16_t destWidth); + // texture-class instance from pixel data; does transform to 2^k if required OpenGL::PagedTexture createEmbeddedTexture(GLsizei w, GLsizei h, bool rgba, const void *pixels); } diff --git a/util/key_handler.cpp b/util/key_handler.cpp new file mode 100644 index 0000000..2853862 --- /dev/null +++ b/util/key_handler.cpp @@ -0,0 +1,68 @@ +/************************************************************************ +* Copyright (c) 2005-2007 tok@openlinux.org.uk * +* * +* This software is provided as-is, without any express or implied * +* warranty. In no event will the authors be held liable for any * +* damages arising from the use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute * +* it freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must * +* not claim that you wrote the original software. If you use this * +* software in a product, an acknowledgment in the product documentation * +* would be appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must * +* not be misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source * +* distribution. * +************************************************************************/ +#include +#include "key_handler.h" +#include "log.h" + +namespace Util { + bool IngameCommonKeys::up(const uint32_t & key) { + bool handled = false; + return handled; + } + + bool IngameCommonKeys::down(const uint32_t & key) { + return false; + } + + void KeyHandlerChain::up(const uint32_t & key) { + for (ListOfHandlers::iterator i = activeHandlers.begin(); + i != activeHandlers.end(); i++) { + if ((*i)->up(key)) + return; + } + } + + void KeyHandlerChain::down(const uint32_t & key) { + for (ListOfHandlers::iterator i = activeHandlers.begin(); + i != activeHandlers.end(); i++) { + if ((*i)->down(key)) + return; + } + } + + void KeyHandlerChain::addHandler(KeyHandler * kh, bool front) { + if (front) + activeHandlers.push_front(kh); + else + activeHandlers.push_back(kh); + } + + void KeyHandlerChain::removeHandler(KeyHandler * kh) { + for (ListOfHandlers::iterator i = activeHandlers.begin(); + i != activeHandlers.end(); i++) { + if (kh == *i) + activeHandlers.erase(i); + } + ERROR << "not a valid handler pointer" << std::endl; + } +} diff --git a/util/key_handler.h b/util/key_handler.h new file mode 100644 index 0000000..8748e7b --- /dev/null +++ b/util/key_handler.h @@ -0,0 +1,86 @@ +/************************************************************************ +* 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_KEYHANDLER_H +#define UTIL_KEYHANDLER_H +#include +#include +#include +#include "pf_tree.hpp" + +namespace Util { + +/** Interface for key listeners. + * + * Must implement both keypress and release functions; + * the functions should return \em true when the input + * value is consumed by a handler. + */ +class KeyHandler { + public: + virtual ~KeyHandler() {} + virtual bool up(const uint32_t & key) = 0; + virtual bool down(const uint32_t & key) = 0; +}; + +/** Keys that do _not_ control the player character. + */ +class IngameCommonKeys : public KeyHandler { + public: + bool up(const uint32_t & key); + bool down(const uint32_t & key); +}; + +class MenuKeys : public KeyHandler { + public: + bool up(const uint32_t & key); + bool down(const uint32_t & key); +}; + +class CheatKeys : public KeyHandler { + public: + bool up(const uint32_t & key); + bool down(const uint32_t & key); + template + struct Callback_Lua { + void call(T); + }; + typedef PrefixFreeTree::Walker TreeOfCheats; + + private: + std::vector cheat_fn_refs; +}; + +class KeyHandlerChain { + public: + void up(const uint32_t & key); + void down(const uint32_t & key); + void addHandler(KeyHandler*, bool front = true); + void removeHandler(KeyHandler*); + private: + typedef std::list ListOfHandlers; + ListOfHandlers activeHandlers; +}; + +} + +#endif diff --git a/util/log.h b/util/log.h index c5f260e..778a4e8 100644 --- a/util/log.h +++ b/util/log.h @@ -12,17 +12,58 @@ #define ERROR_AND_EXIT(ec) error_code = ec; exit(ec); #define GL_CHECKERROR { int _err = glGetError(); if (_err != GL_NO_ERROR) \ Util::Log::error(__FILE__, __LINE__) << "GL error: " << _err << " = " << Util::Log::glErrorName(_err) << std::endl; } + +#define ANSI_COLOR_OFF "\033[0m" +#define ANSI_COLOR_INFO "\033[32mInfo (" +#define ANSI_COLOR_WARN "\033[33mWarning (" +#define ANSI_COLOR_ERR "\033[31mError (" + namespace Util { class Log { public: inline static std::ostream & info(const char* f, int l) { - if (level) return emptyStream; std::cout << "Info (" << f << ":" << l << "): "; return std::cout; + if (level) return emptyStream; +#ifdef LOG_USE_ANSI_COLORS + std::cout << ANSI_COLOR_INFO << +#else + std::cout << "Info (" << +#endif + f << ":" << l << "): " +#ifdef LOG_USE_ANSI_COLORS + << ANSI_COLOR_OFF; +#else + ; +#endif + return std::cout; } inline static std::ostream & warn(const char* f, int l) { - if (level > 1) return emptyStream; std::cerr << "Warning (" << f << ":" << l << "): "; return std::cerr; + if (level > 1) return emptyStream; +#ifdef LOG_USE_ANSI_COLORS + std::cerr << ANSI_COLOR_WARN << +#else + std::cerr << "Warning (" << +#endif + f << ":" << l << "): " +#ifdef LOG_USE_ANSI_COLORS + << ANSI_COLOR_OFF; +#else + ; +#endif + return std::cerr; } inline static std::ostream & error(const char* f, int l) { - std::cerr << "Error ("<< f << ":" << l << "): "; return std::cerr; +#ifdef LOG_USE_ANSI_COLORS + std::cerr << ANSI_COLOR_ERR << +#else + std::cerr << "Error (" << +#endif + f << ":" << l << "): " +#ifdef LOG_USE_ANSI_COLORS + << ANSI_COLOR_OFF; +#else + ; +#endif + return std::cerr; } static void setOutputLevel(unsigned int newLevel); static const char* glErrorName(int k); diff --git a/util/map_helper.cpp b/util/map_helper.cpp index fc68ce2..c2a1165 100644 --- a/util/map_helper.cpp +++ b/util/map_helper.cpp @@ -4,6 +4,22 @@ namespace Util { void SpriteCreationArea::setRects(const SDL_Rect & allowed, const SDL_Rect & denied) { validRects = std::make_pair(allowed, denied); + onScreen = denied; + } + + bool SpriteCreationArea::isOnScreen(const Vector3D & p) { +/* INFO << p.x << " " << p.y << " " << p.z << std::endl; + INFO << onScreen.x <<", " << onScreen.y << " -> " << + onScreen.x + onScreen.w << ", " << onScreen.y + onScreen.h << std::endl; +*/ + if ((p.x >= onScreen.x) && (p.x <= onScreen.x + onScreen.w) && + (p.z >= onScreen.y) && (p.z <= onScreen.y + onScreen.h)) + return true; + return false; + } + + bool SpriteCreationArea::isOffScreen(const Vector3D & p) { + return false; } TupleOfUint8 SpriteCreationArea::getValidCoord() { @@ -11,4 +27,29 @@ namespace Util { uint32_t y = rnd.nextUint(validRects.first.h) + validRects.first.y; return std::make_pair(x, y); } + + int item_count(MapOfPair2Int & m, int a, int b) { + MapOfPair2Int::iterator j = m.find( std::make_pair(a, b) ); + if (j == m.end()) + return 0; + return j->second; + } + + void register_item1(MapOfPair2Int & m, int a, int b) { + m.insert( std::make_pair< Pair2Int, int>( + std::make_pair(a, b), + 1) + ); + } + + void register_item(MapOfPair2Int & m, int a, int b) { + Pair2Int _p(std::make_pair(a, b)); + MapOfPair2Int::iterator j = m.find(_p); + if (j == m.end()) + register_item1(m, a, b); + else + j->second++; + } + + } diff --git a/util/map_helper.h b/util/map_helper.h index 879cc0e..a53d7b1 100644 --- a/util/map_helper.h +++ b/util/map_helper.h @@ -2,7 +2,10 @@ #define MAP_HELPER_H #include +#include #include +#include // yasli/random.h needs it +#include "math3d.h" #include "yasli/random.h" namespace Util { @@ -17,6 +20,42 @@ namespace Util { void setRects(const SDL_Rect & allowed, const SDL_Rect & denied); TupleOfUint8 getValidCoord(); Random rnd; + bool isOnScreen(const Vector3D & p); + bool isOffScreen(const Vector3D & p); + private: + SDL_Rect onScreen; }; + + + /** lesser than comparison of two std::pair. + */ + template + struct lt_pair { + bool operator() (const T & a, const T & b) { + if (a.first < b.first) + return true; + if (a.first > b.first) + return false; + return (a.second < b.second); + } + }; + + typedef std::pair Pair2Int; + typedef lt_pair > cmp_Pair2Int; + typedef std::map MapOfPair2Int; + + /** count of Pair2Int(a,b) in the map. + * @return 0 if no entry at that \e position + * @return count otherwise + */ + int item_count(MapOfPair2Int & m, int a, int b); + /** insert (may overwrite) count 1 at Pair2Int(a, b). + */ + void register_item1(MapOfPair2Int & m, int a, int b); + /** register and count Pair2Int(a, b). + */ + void register_item(MapOfPair2Int & m, int a, int b); + + } #endif diff --git a/util/pf_tree.cpp b/util/pf_tree.cpp new file mode 100644 index 0000000..19fee7b --- /dev/null +++ b/util/pf_tree.cpp @@ -0,0 +1,96 @@ +/************************************************************************ +* 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 "pf_tree.hpp" +namespace PrefixFreeTree { + + Node::~Node() { + for (MapType::iterator i = map.begin(); i != map.end(); i++) { + delete i->second; + } + map.clear(); + } + + Node & Node::insert(const char * str, size_t offset) { + size_t str_len = strlen(str); + if (offset < str_len) { + value_t node_val = str[offset]; + MapType::iterator i = map.find(node_val); + offset++; + if (i == map.end()) { + map[node_val] = new Node(); + return map[node_val]->insert(str, offset); + } + else { + if (i->second->isLeaf()) { + std::ostringstream os; + os << "Cannot enter '" << str << "' at offset " << offset << + " as a leaf node already exists"; + throw E_INVALIDFORMAT(os.str()); + } + if ((offset == str_len) && (!i->second->isLeaf())) { + std::ostringstream os; + os << "Cannot enter '" << str + << "' as a non-leaf node already exists" << std::endl; + throw E_INVALIDFORMAT(os.str()); + } + return i->second->insert(str, offset); + } + } + return *this; + } + +} + +#ifdef SIMPLE_TREE_DEMO +#include + +template +struct Echo { + void call(T t) { + std::cout << "Echo: " << t << std::endl; + } +}; + +using namespace std; +int main(int argc, char* argv[]) { + PrefixFreeTree::Walker m; + uint32_t i = 1; + while (!cin.eof()) { + std::string inputs; + cin >> inputs; + if (inputs.size()) { + std::cout << "-" << inputs << "-" << std::endl; + PrefixFreeTree::Node & n = m.insert(inputs.c_str()); + n.leaf_value = i; + i++; + } + } + + const char* input = argv[1]; + int len = strlen(input); + for (int i = 0; i < len; i++) { + m.push(input[i]); + } +} + +#endif diff --git a/util/pf_tree.hpp b/util/pf_tree.hpp new file mode 100644 index 0000000..f428dba --- /dev/null +++ b/util/pf_tree.hpp @@ -0,0 +1,75 @@ +/************************************************************************ +* 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 PREFIX_FREE_TREE_H +#define PREFIX_FREE_TREE_H + +#include +#include +#include +#include +#include "m_exceptions.h" + +namespace PrefixFreeTree { + + struct Node { + ~Node(); + typedef int value_t; + uint32_t leaf_value; + typedef std::map MapType; + MapType map; + bool isLeaf() const { return (map.size() == 0); } + Node & insert(const char * str, size_t offset = 0); + }; + +#define CHECK_HANDLE_LEAF if (curPos->isLeaf()) { Handler::call(curPos->leaf_value); } + + template class Handler> + class Walker : public Handler, public Node { + public: + Walker() : Handler(), Node(), curPos(this) {} + + void push(int v) { + MapType::iterator i = curPos->map.find(v); + if (i != curPos->map.end()) { + curPos = i->second; + CHECK_HANDLE_LEAF; + } + else { + i = map.find(v); + if (i != map.end()) { + curPos = i->second; + CHECK_HANDLE_LEAF; + } + else + curPos = this; + } + } + + private: + Node * curPos; + }; + +} +#undef CHECK_HANDLE_LEAF + +#endif diff --git a/util/sound_fx_cache.cpp b/util/sound_fx_cache.cpp index 3e68067..5a0fc9a 100644 --- a/util/sound_fx_cache.cpp +++ b/util/sound_fx_cache.cpp @@ -46,7 +46,12 @@ namespace Audio { 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); + Uint8 *mem2 = NULL; + if (file.find("000") != std::string::npos) { + mem2 = (Uint8*)Audio::resample16(mem, e.rawSize, si, e.sampleRate, 44100); + } + else + 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); } diff --git a/util/sound_resample2.cpp b/util/sound_resample2.cpp index 38192bd..6aaf259 100644 --- a/util/sound_resample2.cpp +++ b/util/sound_resample2.cpp @@ -20,6 +20,7 @@ * 3. This notice may not be removed or altered from any source * * distribution. * ************************************************************************/ +#include #include "sound_resample2.h" #include "interpolate.hpp" @@ -89,4 +90,58 @@ namespace Audio { while (src < src_end); return stereo_data; } + + Sint16 *resample16 (Uint8 * src, size_t sourcelen, size_t & size, + int rate, int wanted_rate) { + int fp_pos = 0; + int fp_speed = (1 << 16) * rate / wanted_rate; + size = sourcelen; + while (size & 0xFFFF0000) + size >>= 1, rate = (rate >> 1) + 1; + size = (size * wanted_rate / rate) << 1; + + Sint16 *stereo_data = new Sint16[size]; + Sint16 *data = stereo_data; + Uint8 *src_end = src + sourcelen; + + int result; + int a = *(src + 0); + a = a + (*(src + 1) << 8); + int b = *(src + 2); + b = b + (*(src + 3) << 8); + int c = *(src + 4); + c = c + (*(src + 5) << 8); + + + std::cout << a << " " << b << " " << c << std::endl; + Math::Interpolator::Cubic inter(a * 0.8333f, b * 0.8333f, c * 0.8333f); + do + { + do + { + result = int(inter.getAt(fp_pos / float(0x0000FFFF))); + if (result < -32768) + result = -32768; + else if (result > 32767) + result = 32767; + *data++ = result; + + fp_pos += fp_speed; + } + while (!(fp_pos & 0xFFFF0000)); + src++; + fp_pos &= 0x0000FFFF; + if (src + 2 < src_end) + { + c = *(src + 2); + c = c + (*(src + 3) << 8); + inter.shiftAndFeed (c * 0.8333f); + } + else + inter.shift (); + } + while (src < src_end); + return stereo_data; + } + } diff --git a/util/sound_resample2.h b/util/sound_resample2.h index f4c9c66..13eb93c 100644 --- a/util/sound_resample2.h +++ b/util/sound_resample2.h @@ -28,7 +28,7 @@ namespace Audio { Sint16 *resample_new (Uint8 * sourcedata, size_t sourcelen, size_t & destlen, int current_rate, int wanted_rate); - Sint16 *resample_new_mono (Uint8 * sourcedata, size_t sourcelen, + Sint16 *resample16 (Uint8 * sourcedata, size_t sourcelen, size_t & destlen, int current_rate, int wanted_rate); } diff --git a/util/sound_system.cpp b/util/sound_system.cpp index 436e944..8d280bc 100644 --- a/util/sound_system.cpp +++ b/util/sound_system.cpp @@ -1,6 +1,7 @@ #include #include #include "sound_system.h" +#include "sound_music_player.h" #include "physfsrwops.h" #include "m_exceptions.h" #include "log.h" @@ -10,7 +11,12 @@ namespace Audio { #ifdef WITH_SOUND SoundSystem::SoundSystem() : device(), chunkCache() { SDL_InitSubSystem(SDL_INIT_AUDIO); - device.open(); + try { + device.open(); + } + catch (const Exception & e) { + ERROR << e.what() << std::endl; + } enabled = true; if (device.getStatus() == SoundDevice::OPEN) Sound_Init(); @@ -59,6 +65,8 @@ namespace Audio { } void SoundSystem::listMusicDecoders() { + if (!enabled) + return; std::cout << "* Supported music decoders *" << std::endl; const Sound_DecoderInfo **i; for (i = Sound_AvailableDecoders(); *i != NULL; i++) { @@ -91,7 +99,13 @@ int main(int argc, char* argv[]) { SoundSystem noisemaker; noisemaker.listMusicDecoders(); - noisemaker.playMusic(argv[1]); + if (argc == 2) + noisemaker.playMusic(argv[1]); + if (argc == 3) { + noisemaker.playFx(argv[1], atoi(argv[2])); + while (Mix_Playing(-1)) + SDL_Delay(500); + } MusicPlayerCtrl::musicFinishedCB = CB_MusicDone; while (MusicPlayerCtrl::isPlaying) { SDL_Delay(1000); diff --git a/util/sound_system.h b/util/sound_system.h index b3dc8cc..8ad0cb8 100644 --- a/util/sound_system.h +++ b/util/sound_system.h @@ -18,8 +18,8 @@ namespace Audio { SoundSystem(); ~SoundSystem(); void playFx(std::string file, size_t idx); - void SoundSystem::playMusic(std::string file); - void SoundSystem::listMusicDecoders(); + void playMusic(std::string file); + void listMusicDecoders(); bool enabled; }; } diff --git a/viewer.cpp b/viewer.cpp index 48625b3..274cbeb 100644 --- a/viewer.cpp +++ b/viewer.cpp @@ -42,10 +42,15 @@ #include "navdata.h" #include "opengta.h" #include "spritemanager.h" +#include "gl_spritecache.h" #include "timer.h" #ifdef WITH_LUA #include "lua_addon/lua_vm.h" +#include "lua_addon/lua_stackguard.h" #endif +#include "gui.h" +#include "font_cache.h" +#include "ai.h" #define getPedById getPed #define removePedById removePed @@ -54,10 +59,12 @@ extern SDL_Surface* screen; extern int global_EC; extern int global_Done; +extern int global_Restart; GLfloat mapPos[3] = {12.0f, 12.0f, 20.0f}; OpenGTA::CityView *city = NULL; -OpenGL::DrawableFont* m_font = NULL; +//OpenGL::DrawableFont* m_font = NULL; +GUI::Label * fps_label = NULL; int city_num = 0; const char* styles_8[3] = { "STYLE001.GRY", "STYLE002.GRY", "STYLE003.GRY" }; @@ -81,6 +88,11 @@ int ped_anim = 0; int bbox_toggle = 0; int texsprite_toggle = 0; int follow_toggle = 0; +float anisotropic_filter_degree = 2.0f; +int mipmap_textures = -1; +int vsync_config = -1; +int city_blocks_area = -1; +int config_scale2x = 1; OpenGTA::SpriteObject::Animation pedAnim(0, 0); #ifdef OGTA_DEFAULT_GRAPHICS_G24 bool highcolor_data = true; @@ -93,6 +105,10 @@ bool player_toggle_run = false; const char* script_file = NULL; int paused = 0; int next_station_zoom = 0; +bool gamma_slide = false; +float screen_gamma = 1.0f; + +Vector3D test_dot(-1, -1, -1); /* void ERROR(const char* s) { @@ -106,8 +122,8 @@ void on_exit() { SDL_Quit(); if (city) delete city; - if (m_font) - delete m_font; + //if (m_font) + // delete m_font; PHYSFS_deinit(); if (global_EC) std::cerr << "Exiting after fatal problem - please see output above" << std::endl; @@ -123,6 +139,17 @@ void print_usage(const char* argv0) { " -c k : 0 = 8bit GRY, 1 = 24bit G24" << std::endl << " -f : fullscreen on program-start" << std::endl << " -V : show version & compile-time switches" << std::endl << + " -M k : texture mipmaps: 0 = disable, 1 = enable" << std::endl << + " -x k : scale2x sprites: 0 = disable, 1 = enable" << std::endl << + " -v k : vertical sync: 0 = disable, 1 = try with SDL" << +#ifdef LINUX + ", 2 = try with GLX" << +#elif WIN32 + ", 2 = try with GLW" << +#endif + std::endl << + " -a f : anisotropic texture filtering degree: 1.0 = disabled" + << std::endl << std::endl << " -m map_file -g style_file : load specified files" << std::endl << " -w width -h height : screen dimension" << std::endl << @@ -132,12 +159,13 @@ void print_usage(const char* argv0) { "The following environment variables are used when defined:" << std::endl << " OGTA_DATA : PhysicsFS source for main data file lookup" << std::endl << " OGTA_HOME : unused - will be config/save dir" << std::endl << - " OGTA_MOD : PhysicsFS source to override main data files" << std::endl; + " OGTA_MOD : PhysicsFS source to override main data files" << std::endl << + " OGTA_LANG : defines the fxt language file to load" << std::endl; } void print_version_info() { #define PRINT_FORMATED(spaces) std::setw(spaces) << std::left << -#define PRINT_OFFSET PRINT_FORMATED(18) +#define PRINT_OFFSET PRINT_FORMATED(19) std::cout << PRINT_OFFSET "OpenGTA version:" << OGTA_VERSION_INFO << std::endl << PRINT_OFFSET "platform:" << OGTA_PLATFORM_INFO << std::endl << @@ -155,11 +183,26 @@ void print_version_info() { "no" << #endif std::endl << + PRINT_OFFSET "SDL_image support:" << +#ifdef WITH_SDL_IMAGE + "yes" << +#else + "no" << +#endif + std::endl << + PRINT_OFFSET "vsync support:" << #ifdef HAVE_SDL_VSYNC "yes" << #else "no" << +#endif + std::endl << + PRINT_OFFSET "scale2x support:" << +#ifdef DO_SCALE2X + "yes" << +#else + "no" << #endif std::endl << @@ -188,24 +231,30 @@ void parse_args(int argc, char* argv[]) { opterr = 0; #ifdef WITH_LUA -#define VIEWER_FLAGS "s:w:h:c:m:g:l:fV" +#define VIEWER_FLAGS "a:s:w:h:c:m:M:g:l:v:x:fV" #else -#define VIEWER_FLAGS "w:h:c:m:g:l:fV" +#define VIEWER_FLAGS "a:w:h:c:m:M:g:l:v:x:fV" #endif while ((c = getopt (argc, argv, VIEWER_FLAGS)) != -1) switch (c) { #ifdef WITH_LUA case 's': - script_file = std::string(optarg); + script_file = optarg; break; #endif + case 'a': + anisotropic_filter_degree = atof(optarg); + break; case 'c': highcolor_data = atoi(optarg); break; case 'm': specific_map = std::string(optarg); break; + case 'M': + mipmap_textures = atoi(optarg); + break; case 'g': specific_style = std::string(optarg); break; @@ -221,10 +270,16 @@ void parse_args(int argc, char* argv[]) { case 'f': full_screen = true; break; + case 'v': + vsync_config = atoi(optarg); + break; case 'V': print_version_info(); exit(0); break; + case 'x': + config_scale2x = atoi(optarg); + break; default: if (optopt == '?') { print_usage(argv[0]); @@ -254,7 +309,7 @@ void run_init(const char* prg_name) { // physfs-ogta Util::FileHelper & fh = GET_FILE_HELPER; if (fh.existsInSystemFS(fh.getBaseDataPath())) { - PHYSFS_addToSearchPath(GET_FILE_HELPER.getBaseDataPath().c_str(), 1); + PHYSFS_addToSearchPath(fh.getBaseDataPath().c_str(), 1); } else { WARN << "Could not load data-source: " << fh.getBaseDataPath() << std::endl; @@ -263,10 +318,12 @@ void run_init(const char* prg_name) { PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1); if (fh.existsInSystemFS(fh.getModDataPath())) - PHYSFS_addToSearchPath(GET_FILE_HELPER.getModDataPath().c_str(), 0); - + PHYSFS_addToSearchPath(fh.getModDataPath().c_str(), 0); + // screen, no window yet OpenGL::Screen & screen = OpenGL::ScreenHolder::Instance(); + + // check for a configfile #ifdef WITH_LUA if (fh.existsInVFS("config")) { char* config_as_string = (char*)fh.bufferFromVFS( @@ -274,7 +331,17 @@ void run_init(const char* prg_name) { OpenGTA::Script::LuaVM & vm = OpenGTA::Script::LuaVMHolder::Instance(); try { - vm.runString(config_as_string); + //vm.runString(config_as_string); + lua_State *L = vm.getInternalState(); + Util::LGUARD(L); + if (luaL_loadbuffer(L, config_as_string, strlen(config_as_string), "config")) + throw E_SCRIPTERROR("Error running string: " + std::string(lua_tostring(L, -1))); + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setglobal(L, "config"); + lua_setfenv(L, -2); + if (lua_pcall(L, 0, 0, 0)) + throw E_SCRIPTERROR("Error running string: " + std::string(lua_tostring(L, -1))); } catch (const Util::ScriptError & e) { std::cerr << "Error in config-file: " << e.what() << std::endl; @@ -282,54 +349,147 @@ void run_init(const char* prg_name) { exit(1); } - try { - Uint32 sw = vm.getGlobalInt("screen_width"); - if (!arg_screen_w) - arg_screen_w = sw; - } - catch (const Util::ScriptError & e) {} - try { - Uint32 sh = vm.getGlobalInt("screen_height"); - if (!arg_screen_h) - arg_screen_h = sh; - } - catch (const Util::ScriptError & e) {} - try { - Uint32 sh = vm.getGlobalInt("full_screen"); - if (!full_screen) - full_screen = sh; - } - catch (const Util::ScriptError & e) {} + lua_State *L = vm.getInternalState(); + lua_getglobal(L, "config"); + if (lua_type(L, 1) == LUA_TTABLE) { + try { + bool sh = vm.getBool("use_g24_graphics"); + highcolor_data = sh; + } + catch (const Util::ScriptError & e) {} + try { + Uint32 sw = vm.getInt("screen_width"); + if (!arg_screen_w) + arg_screen_w = sw; + } + catch (const Util::ScriptError & e) {} + try { + Uint32 sh = vm.getInt("screen_height"); + if (!arg_screen_h) + arg_screen_h = sh; + } + catch (const Util::ScriptError & e) {} + try { + int sh = vm.getInt("screen_vsync"); + screen.setupVsync(sh); + } + catch (const Util::ScriptError & e) {} + try { + bool sh = vm.getBool("full_screen"); + if (!full_screen) + full_screen = sh; + } + catch (const Util::ScriptError & e) {} - float fov = screen.getFieldOfView(); - float np = screen.getNearPlane(); - float fp = screen.getFarPlane(); - try { - fov = vm.getGlobalFloat("field_of_view"); + float fov = screen.getFieldOfView(); + float np = screen.getNearPlane(); + float fp = screen.getFarPlane(); + try { + fov = vm.getFloat("gl_field_of_view"); + } + catch (const Util::ScriptError & e) {} + try { + np = vm.getFloat("gl_near_plane"); + } + catch (const Util::ScriptError & e) {} + try { + fp = vm.getFloat("gl_far_plane"); + } + catch (const Util::ScriptError & e) {} + screen.setupGlVars(fov, np, fp); + + try { + bool sh = vm.getBool("gl_mipmap_textures"); + ImageUtil::mipmapTextures = sh; + } + catch (const Util::ScriptError & e) {} + + try { + bool sh = vm.getBool("scale2x_sprites"); + OpenGL::SpriteCacheHolder::Instance().setScale2x(sh); + } + catch (const Util::ScriptError & e) {} + + try { + int sh = vm.getInt("active_area_size"); + city_blocks_area = sh; + } + catch (const Util::ScriptError & e) {} } - catch (const Util::ScriptError & e) {} - try { - np = vm.getGlobalFloat("near_plane"); - } - catch (const Util::ScriptError & e) {} - try { - fp = vm.getGlobalFloat("far_plane"); - } - catch (const Util::ScriptError & e) {} - screen.setupGlVars(fov, np, fp); + // can't check for gl-extensions now } #endif + //INFO << "AREA:: " << city_blocks_area << std::endl; + + // check both width & height defined if ((arg_screen_h && !arg_screen_w) || (!arg_screen_h && arg_screen_w)) { WARN << "Invalid screen specified: " << arg_screen_w << "x" << arg_screen_h << " - using default" << std::endl; arg_screen_h = 0; arg_screen_w = 0; } + // fullscreen before first video init; only chance to set it on win32 screen.setFullScreenFlag(full_screen); + if (vsync_config != -1) + screen.setupVsync(vsync_config); + + // create screen screen.activate(arg_screen_w, arg_screen_h); - SDL_EnableKeyRepeat( 100, SDL_DEFAULT_REPEAT_INTERVAL ); + + SDL_EnableKeyRepeat( 0, 0 ); + //SDL_EnableKeyRepeat( 100, SDL_DEFAULT_REPEAT_INTERVAL ); + + // more setup; that requires an active screen +#ifdef WITH_LUA + OpenGTA::Script::LuaVM & vm = OpenGTA::Script::LuaVMHolder::Instance(); + lua_State *L = vm.getInternalState(); + if (lua_type(L, 1) == LUA_TTABLE) { + try { + float v = vm.getFloat("gl_anisotropic_textures"); + if (ImageUtil::supportedMaxAnisoDegree >= v) + ImageUtil::supportedMaxAnisoDegree = v; + } + catch (const Util::ScriptError & e) {} + try { + float v = (highcolor_data ? vm.getFloat("screen_gamma_g24") : + vm.getFloat("screen_gamma_gry")); + screen_gamma = v; + SDL_SetGamma(v, v, v); + } + catch (const Util::ScriptError & e) {} + } + lua_settop(L, 0); +#endif + if (ImageUtil::supportedMaxAnisoDegree >= anisotropic_filter_degree) + ImageUtil::supportedMaxAnisoDegree = anisotropic_filter_degree; + else + WARN << "Using filter degree " << ImageUtil::supportedMaxAnisoDegree << + ", requested " << anisotropic_filter_degree << " not supported" << std::endl; + + switch(mipmap_textures) { + case -1: + break; + case 0: + ImageUtil::mipmapTextures = false; + break; + default: + ImageUtil::mipmapTextures = true; + break; + } + + // before any graphics are loaded + OpenGL::SpriteCacheHolder::Instance().setScale2x(config_scale2x); + + // FIXME: basic gui setup; should not be here + GUI::Manager & gm = GUI::ManagerHolder::Instance(); + SDL_Rect rect; + rect.x = 5; + rect.y = 50; + fps_label = new GUI::Label(rect, "", "F_MTEXT.FON", 1); + //fps_label->borderColor.r = fps_label->borderColor.unused = 200; + gm.add(fps_label, 5); } @@ -338,7 +498,7 @@ void print_position() { Vector3D & e = OpenGL::CameraHolder::Instance().getEye(); Vector3D & u = OpenGL::CameraHolder::Instance().getUp(); if (!city->getViewMode()) { - INFO << cities[city_num] << ": " << city->getCurrentSector()->getFullName() << std::endl << + std::cout << cities[city_num] << ": " << city->getCurrentSector()->getFullName() << std::endl << "camera.setCenter(" << v.x << ", " << v.y << ", " << v.z << ")" << std::endl << "camera.setEye(" << e.x << ", " << e.y << ", " << e.z << ")" << std::endl << "camera.setUp(" << u.x << ", " << u.y << ", " << u.z << ")" << std::endl << @@ -347,7 +507,7 @@ void print_position() { } else { GLfloat* cp = city->getCamPos(); - INFO << cities[city_num] << ": " << city->getCurrentSector()->getFullName() << std::endl << + std::cout << cities[city_num] << ": " << city->getCurrentSector()->getFullName() << std::endl << "city_view:setCamPosition(" << cp[0] << ", " << cp[1] << ", " << cp[2] << ")" << std::endl << "city_view:setVisibleRange(" << city->getVisibleRange() << ")" << std::endl << "city_view:setTopDownView( true )" << std::endl; @@ -389,12 +549,13 @@ void handleKeyUp( SDL_keysym *keysym) { void draw_mapmode(); void create_ped_at(const Vector3D v) { - OpenGTA::Pedestrian p(Vector3D(0.3f, 0.5f, 0.3f), v, 0xffffffff); + OpenGTA::Pedestrian p(Vector3D(0.2f, 0.5f, 0.2f), v, 0xffffffff); p.remap = OpenGTA::StyleHolder::Instance().get().getRandomPedRemapNumber(); INFO << "using remap: " << p.remap << std::endl; OpenGTA::Pedestrian & pr = OpenGTA::SpriteManagerHolder::Instance().addPed(p); pr.switchToAnim(1); OpenGTA::LocalPlayer::Instance().setCtrl(pr.m_control); + GUI::create_ingame_gui(1); //pr.m_control = &OpenGTA::LocalPlayer::Instance(); //OpenGTA::SpriteManagerHolder::Instance().getPedById(0xffffffff).giveItem(1, 255); } @@ -471,7 +632,7 @@ void add_auto_ped() { v.y += 0.9f; //INFO << v.x << " " << v.y << " " << v.z << std::endl; Sint16 remap = OpenGTA::StyleHolder::Instance().get().getRandomPedRemapNumber(); - OpenGTA::Pedestrian p(Vector3D(0.3f, 0.5f, 0.3f), v, id, remap); + OpenGTA::Pedestrian p(Vector3D(0.2f, 0.5f, 0.2f), v, id, remap); OpenGTA::SpriteManagerHolder::Instance().addPed(p); OpenGTA::Pedestrian & pr2 = OpenGTA::SpriteManagerHolder::Instance().getPedById(id); pr2.switchToAnim(1); @@ -486,6 +647,7 @@ void add_auto_ped() { void toggle_player_run() { OpenGTA::PedController * pc = &OpenGTA::LocalPlayer::Instance().getCtrl(); + INFO << std::endl; if (!pc) { WARN << "no player yet!" << std::endl; @@ -497,6 +659,69 @@ void toggle_player_run() { pc->setRunning(false); } +void show_gamma_config() { + OpenGL::Screen & screen = OpenGL::ScreenHolder::Instance(); + GUI::Manager & gm = GUI::ManagerHolder::Instance(); + if (gamma_slide) { + SDL_Rect r; + + r.x = screen.getWidth() / 2; + r.y = screen.getHeight() / 2; + r.w = 200; + r.h = 30; + + GUI::ScrollBar * sb = new GUI::ScrollBar(GUI::GAMMA_SCROLLBAR_ID, r); + sb->color.r = sb->color.g = sb->color.b = 180; + sb->color.unused = 255; + sb->innerColor.r = 250; + sb->value = screen_gamma/2; + sb->changeCB = GUI::ScrollBar::SC_Functor(GUI::screen_gamma_callback); + gm.add(sb, 90); + + r.y += 40; + std::ostringstream os; + os << "Gamma: " << screen_gamma; + GUI::Label * l = new GUI::Label(GUI::GAMMA_LABEL_ID, r, os.str(), "F_MTEXT.FON", 1); + gm.add(l, 80); + + screen.setSystemMouseCursor(true); + + } + else { + gm.removeById(GUI::GAMMA_SCROLLBAR_ID); + gm.removeById(GUI::GAMMA_LABEL_ID); + screen.setSystemMouseCursor(false); + } +} + +void car_toggle() { + OpenGTA::Pedestrian & pped = OpenGTA::LocalPlayer::Instance().getPed(); + Vector3D pos = pped.pos; + std::list & list = OpenGTA::SpriteManagerHolder::Instance().getList(); + float min_dist = 360; + float _d; + std::list::iterator j = list.end(); + for (std::list::iterator i = list.begin(); i != list.end(); i++) { + if ((_d = Util::distance(pos, i->pos)) < min_dist) { + j = i; + min_dist = _d; + } + } + assert(j != list.end()); + std::cout << j->id() << " " << j->pos.x << ", " << j->pos.y << ", " << j->pos.z << std::endl; + Vector3D p_door(j->carInfo.door[0].rpx / 64.0f, 0, + j->carInfo.door[0].rpy / 64.0f); + + Vector3D p_door_global = Transform(p_door, j->m_M); + p_door_global.y += 0.2f; + std::cout << p_door_global.x << ", " << p_door_global.y << ", " << p_door_global.z << std::endl; + test_dot = p_door_global; + //pped.aiMode = 1; + //pped.aiData.pos1 = p_door_global; + OpenGTA::AI::Pedestrian::walk_pavement(&pped); + +} + void handleKeyPress( SDL_keysym *keysym ) { GLfloat* cp = city->getCamPos(); mapPos[0] = cp[0]; mapPos[1] = cp[1]; mapPos[2] = cp[2]; @@ -530,6 +755,13 @@ void handleKeyPress( SDL_keysym *keysym ) { //zoomToTrain(next_station_zoom++); //if (next_station_zoom >= OpenGTA::SpriteManagerHolder::Instance().trainSystem.getNumTrains()) // next_station_zoom = 0; + global_Restart = 1; + global_Done = 1; + return; + { + Vector3D p(cam.getEye()); + OpenGTA::MapHolder::Instance().get().getNearestLocationByType(0, p.x, p.z); + } break; case SDLK_F2: bbox_toggle = (bbox_toggle ? 0 : 1); @@ -558,8 +790,12 @@ void handleKeyPress( SDL_keysym *keysym ) { cam.releaseFollowMode(); OpenGTA::SpriteManagerHolder::Instance().removePedById(0xffffffff); OpenGTA::SpriteManagerHolder::Instance().removeDeadStuff(); + GUI::remove_ingame_gui(); } break; + case SDLK_RETURN: + car_toggle(); + break; case SDLK_F5: draw_arrows = (draw_arrows ? 0 : 1); city->setDrawHeadingArrows(draw_arrows); @@ -579,6 +815,10 @@ void handleKeyPress( SDL_keysym *keysym ) { case SDLK_F10: city->setDrawLines(city->getDrawLines() ? 0 : 1); break; + case SDLK_F12: + gamma_slide = (gamma_slide ? 0 : 1); + show_gamma_config(); + break; case SDLK_LSHIFT: toggle_player_run(); break; @@ -658,11 +898,16 @@ void handleKeyPress( SDL_keysym *keysym ) { OpenGTA::LocalPlayer::Instance().getCtrl().setMoveBack(); break; case 'f': +//FIXME: simply ignored on windows for now +#ifndef WIN32 OpenGL::ScreenHolder::Instance().toggleFullscreen(); +#endif +#if 0 #ifdef WIN32 city->resetTextures(); - m_font->resetTextures(); + //m_font->resetTextures(); OpenGL::SpriteCacheHolder::Instance().clearAll(); +#endif #endif break; case 'r': @@ -723,20 +968,35 @@ void drawScene(Uint32 ticks) { OpenGL::ScreenHolder::Instance().set3DProjection(); city->draw(ticks); - OpenGL::ScreenHolder::Instance().setFlatProjection(); + glColor3f(1, 0, 0); + glDisable(GL_TEXTURE_2D); + glBegin(GL_POINTS); + glVertex3f(test_dot.x, test_dot.y, test_dot.z); + glEnd(); + glEnable(GL_TEXTURE_2D); + glColor3f(1, 1, 1); + + OpenGL::ScreenHolder::Instance().setFlatProjection(); + glDisable(GL_DEPTH_TEST); + glPushMatrix(); glTranslatef(10, 10, 0); - m_font->drawString(city->getCurrentSector()->getFullName()); + OpenGL::DrawableFont & m_font = OpenGTA::FontCacheHolder::Instance().getFont("F_MTEXT.FON", 1); + m_font.drawString(city->getCurrentSector()->getFullName()); glPopMatrix(); - glPushMatrix(); + + /*glPushMatrix(); glTranslatef(5, 50, 0); std::ostringstream strstr; strstr << fps << " fps"; m_font->drawString(strstr.str()); - glPopMatrix(); + glPopMatrix();*/ + GUI::ManagerHolder::Instance().draw(); + num_frames_drawn += 1; + glEnable(GL_DEPTH_TEST); SDL_GL_SwapBuffers(); } @@ -747,9 +1007,9 @@ void draw_mapmode() { bool done_map = false; OpenGL::Screen & screen = OpenGL::ScreenHolder::Instance(); screen.setSystemMouseCursor(true); - GLfloat _scale = 1; - GLfloat dx = 0; - GLfloat dy = 0; + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glDisable(GL_DEPTH_TEST); + INFO << map_tex.coords[1].u << std::endl; while(!done_map) { while (SDL_PollEvent(&event)) { switch(event.type) { @@ -761,31 +1021,20 @@ void draw_mapmode() { case SDLK_ESCAPE: done_map = true; break; - case '-': - _scale += 0.1f; - break; - case '+': - _scale -= 0.1f; - break; - case SDLK_LEFT: - dx -= 0.1f; - break; - case SDLK_RIGHT: - dx += 0.1f; - break; - case SDLK_UP: - dy += 0.1f; - break; - case SDLK_DOWN: - dy -= 0.1f; - break; default: break; } break; + case SDL_MOUSEBUTTONDOWN: + INFO << event.button.x / 600.0f * 255<< " " << event.button.y / 600.0f * 255 << std::endl; + mapPos[0] = event.button.x / 600.0f * 255; + mapPos[2] = event.button.y / 600.0f * 255; + //mapPos[1] = 10; + done_map = true; + break; case SDL_MOUSEMOTION: -// std::cout << "Mouse move: x " << event.motion.x << " y " << -// event.motion.y << std::endl; + std::cout << "Mouse move: x " << event.motion.x << " y " << + event.motion.y << std::endl; break; default: break; @@ -796,119 +1045,71 @@ void draw_mapmode() { screen.setFlatProjection(); glBindTexture(GL_TEXTURE_2D, map_tex.inPage); - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glScalef(_scale, _scale, 1); - glTranslatef(dx, dy, 0); + //glMatrixMode(GL_TEXTURE); + //if (_scale < 1) + // glScalef(_scale, _scale, 1); + + uint32_t h = screen.getHeight(); glBegin(GL_QUADS); - glTexCoord2f(map_tex.coords[0].u, map_tex.coords[0].v); + glTexCoord2f(0, 0); glVertex2i(0, 0); - glTexCoord2f(map_tex.coords[1].u, map_tex.coords[0].v); - glVertex2i(screen.getWidth(), 0); + glTexCoord2f(map_tex.coords[1].u, 0); + glVertex2i(h, 0); glTexCoord2f(map_tex.coords[1].u, map_tex.coords[1].v); - glVertex2i(screen.getWidth(), screen.getHeight()); - glTexCoord2f(map_tex.coords[0].u, map_tex.coords[1].v); - glVertex2i(0, screen.getHeight()); + glVertex2i(h, h); + glTexCoord2f(0, map_tex.coords[1].v); + glVertex2i(0, h); glEnd(); + const OpenGTA::Map::LocationMap & lmap = OpenGTA::MapHolder::Instance().get().getLocationMap(); + OpenGTA::Map::LocationMap::const_iterator i = lmap.begin(); + glDisable(GL_TEXTURE_2D); + while (i != lmap.end()) { + if (i->first == 2) { + i++; + continue; + } + uint8_t l_type = i->first; + float l_x, l_y; + l_x = i->second->x / 255.0f * h;// * map_tex.coords[1].u; + l_y = i->second->y / 255.0f * h;// * map_tex.coords[1].u; + //INFO << int(l_type) << ": " << l_x << " " << l_y << std::endl; + glBegin(GL_LINE_STRIP); + glVertex2f(l_x - 5, l_y - 5); + glVertex2f(l_x + 5, l_y - 5); + glVertex2f(l_x + 5, l_y + 5); + glVertex2f(l_x - 5, l_y + 5); + + glEnd(); + ++i; + } + + glEnable(GL_TEXTURE_2D); SDL_GL_SwapBuffers(); SDL_Delay(20); } screen.setSystemMouseCursor(false); + glEnable(GL_DEPTH_TEST); glMatrixMode(GL_TEXTURE); glLoadIdentity(); // the texture class doesn't cleanup! glDeleteTextures(1, &map_tex.inPage); } -#if 0 -void parse_args(int argc, char* argv[]) { - int index; - int c; - - opterr = 0; - -#ifdef WITH_LUA -#define VIEWER_FLAGS "s:w:h:c:m:g:l:f" -#else -#define VIEWER_FLAGS "w:h:c:m:g:l:f" -#endif - while ((c = getopt (argc, argv, VIEWER_FLAGS)) != -1) - switch (c) - { -#ifdef WITH_LUA - case 's': - script_file = optarg; - break; -#endif - case 'c': - highcolor_data = atoi(optarg); - break; - case 'm': - specific_map = std::string(optarg); - break; - case 'g': - specific_style = std::string(optarg); - break; - case 'w': - arg_screen_w = atoi(optarg); - break; - case 'h': - arg_screen_h = atoi(optarg); - break; - case 'l': - Util::Log::setOutputLevel(atoi(optarg)); - break; - case 'f': - full_screen = true; - break; - case '?': - if (isprint (optopt)) - ERROR << "Unknown option `-" << char(optopt) << "'" << std::endl; - else - ERROR << "Unknown option character `" << optopt << "'" << std::endl; - default: - abort (); - } - - for (index = optind; index < argc; index++) - city_num = atoi(argv[index]); - - if (city_num > 2) { - ERROR << "Invalid city number: " << city_num << std::endl; - exit(1); - } -} - -void run_init(const char* prgname) { - PHYSFS_init("mapview"); - //PHYSFS_addToSearchPath("gtadata.zip", 1); - Util::FileHelper & fh = GET_FILE_HELPER; - if (fh.existsInSystemFS(fh.getBaseDataPath())) - PHYSFS_addToSearchPath(GET_FILE_HELPER.getBaseDataPath().c_str(), 1); - else { - WARN << "Could not load data-source: " << fh.getBaseDataPath() <<" -- fallback to current directory"<< std::endl; - PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1); - } - if (fh.existsInSystemFS(fh.getModDataPath())) - PHYSFS_addToSearchPath(GET_FILE_HELPER.getModDataPath().c_str(), 0); - - OpenGL::Screen & screen = OpenGL::ScreenHolder::Instance(); - screen.setFullScreenFlag(full_screen); - screen.activate(arg_screen_w, arg_screen_h); - //SDL_EnableKeyRepeat( 100, SDL_DEFAULT_REPEAT_INTERVAL ); -} -#endif - void run_main() { SDL_Event event; - OpenGTA::MainMsgHolder::Instance().load("ENGLISH.FXT"); + const char * lang = getenv("OGTA_LANG"); + if (!lang) + lang = getenv("LANG"); + if (!lang) + lang = "en"; + OpenGTA::MainMsgHolder::Instance().load(Util::FileHelper::lang2MsgFilename(lang)); - m_font = new OpenGL::DrawableFont(); - m_font->loadFont("F_MTEXT.FON"); - m_font->setScale(1); + //m_font = new OpenGL::DrawableFont(); + //m_font->loadFont("F_MTEXT.FON"); + //m_font->setScale(1); glEnable(GL_TEXTURE_2D); glPolygonMode(GL_FRONT, GL_FILL); @@ -917,7 +1118,7 @@ void run_main() { //glEnable(GL_BLEND); //glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, 0); + glAlphaFunc(GL_GREATER, 2/255.0f);//0); city = new OpenGTA::CityView(); if (specific_map.size() > 0 && specific_style.size() > 0) { @@ -929,13 +1130,14 @@ void run_main() { else city->loadMap(cities[city_num], styles_8[city_num]); } + if (city_blocks_area > -1) + city->setVisibleRange(city_blocks_area); city->setPosition(mapPos[0], mapPos[1], mapPos[2]); OpenGL::Camera & cam = OpenGL::CameraHolder::Instance(); //cam.setVectors( Vector3D(4, 10, 4), Vector3D(4, 0.0f, 4.0f), Vector3D(0, 0, -1) ); cam.setVectors( Vector3D(12, 20, 12), Vector3D(13.0f, 19.0f, 13.0f), Vector3D(0, 1, 0) ); - #ifdef TIMER_OPENSTEER_CLOCK Timer & timer = TimerHolder::Instance(); timer.update(); @@ -948,13 +1150,14 @@ void run_main() { #ifdef WITH_LUA OpenGTA::Script::LuaVM & vm = OpenGTA::Script::LuaVMHolder::Instance(); vm.setCityView(*city); + vm.setMap(OpenGTA::MapHolder::Instance().get()); if (script_file) vm.runFile(script_file); - //vm.runString("function game_tick() print('tick...') end"); bool vm_tick_ok = true; script_last_tick = last_tick; #endif - + + GUI::Manager & guiManager = GUI::ManagerHolder::Instance(); while(!global_Done && !global_EC) { while (SDL_PollEvent(&event)) { @@ -980,6 +1183,9 @@ void run_main() { case SDL_MOUSEMOTION: //std::cout << "Mouse move: x " << float(event.motion.x)/screen->w << " y " << float(event.motion.y)/screen->h << std::endl; break; + case SDL_MOUSEBUTTONDOWN: + guiManager.receive(event.button); + break; default: break; } @@ -992,6 +1198,8 @@ void run_main() { #endif OpenGTA::SpriteManagerHolder::Instance().update(now_ticks); city->blockAnims->update(now_ticks); + GUI::ManagerHolder::Instance().update(now_ticks); + GUI::update_ingame_gui_values(); if (!paused) { drawScene(now_ticks - last_tick); last_tick = now_ticks; @@ -1018,9 +1226,19 @@ void run_main() { fps = num_frames_drawn / 2; num_frames_drawn = 0; fps_last_tick = now_ticks; + std::ostringstream os; + os << fps << " fps"; + fps_label->text = os.str(); +#ifdef WITH_LUA + vm.setGlobalInt("current_fps", fps); +#endif } //#endif // SDL_Delay(10); } +#ifdef WITH_LUA + vm.runFile("scripts/dump_config.lua"); +#endif + }