Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

Game.cpp 63KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930
  1. /*!
  2. * \file src/Game.cpp
  3. * \brief Game abstraction
  4. *
  5. * \author xythobuz
  6. */
  7. #ifdef __APPLE__
  8. #include <OpenGL/gl.h>
  9. #else
  10. #include <GL/gl.h>
  11. #endif
  12. #include <algorithm>
  13. #include <map>
  14. #include <cstdlib>
  15. #include "main.h"
  16. #include "Console.h"
  17. #include "Game.h"
  18. #include "utils/strings.h"
  19. #include "games/TombRaider1.h"
  20. // Old Code compatibility
  21. #define TexelScale 256.0f
  22. skeletal_model_t *gLaraModel;
  23. #ifndef EXPERIMENTAL_UNFIFIED_ROOM_GEOMETERY
  24. #define TextureLimit 24
  25. #endif
  26. #ifdef EXPERIMENTAL
  27. std::vector<unsigned int> gColorTextureHACK;
  28. #endif
  29. #ifdef MULTITEXTURE
  30. std::map<int, int> gMapTex2Bump;
  31. #endif
  32. Game::Game() {
  33. mLoaded = false;
  34. mName = NULL;
  35. mLara = NULL;
  36. mTextureStart = 0;
  37. mTextureLevelOffset = 0;
  38. mTextureOffset = 0;
  39. mRender = NULL;
  40. }
  41. Game::~Game() {
  42. destroy();
  43. if (mRender)
  44. delete mRender;
  45. }
  46. int Game::initialize() {
  47. // Set up Renderer
  48. mRender = new Render();
  49. mRender->initTextures(getOpenRaider().mDataDir, &mTextureStart, &mTextureLevelOffset);
  50. // Enable Renderer
  51. mRender->setMode(Render::modeLoadScreen);
  52. // Enable World Hopping
  53. getWorld().setFlag(World::fEnableHopping);
  54. return 0;
  55. }
  56. void Game::destroy() {
  57. if (mName)
  58. delete [] mName;
  59. mLoaded = false;
  60. mRender->setMode(Render::modeDisabled);
  61. getWorld().destroy();
  62. mRender->ClearWorld();
  63. getSound().clear(); // Remove all previously loaded sounds
  64. }
  65. int Game::loadLevel(const char *level) {
  66. if (mLoaded)
  67. destroy();
  68. mName = bufferString("%s", level);
  69. // Load the level pak into TombRaider
  70. getConsole().print("Loading %s", mName);
  71. int error = mTombRaider.Load(mName);
  72. if (error != 0) {
  73. return error;
  74. }
  75. // If required, load the external sound effect file MAIN.SFX into TombRaider
  76. if ((mTombRaider.getEngine() == TR_VERSION_2) || (mTombRaider.getEngine() == TR_VERSION_3)) {
  77. char *tmp = bufferString("%sMAIN.SFX", level); // Ensure theres enough space
  78. size_t length = strlen(tmp);
  79. size_t dir = 0;
  80. for (int i = length - 1; i >= 0; i--) {
  81. if ((tmp[i] == '/') || (tmp[i] == '\\')) {
  82. dir = i + 1; // Find where the filename (bla.tr2) starts
  83. break;
  84. }
  85. }
  86. strcpy(tmp + dir, "MAIN.SFX"); // overwrite the name itself with MAIN.SFX
  87. tmp[dir + 8] = '\0';
  88. error = mTombRaider.loadSFX(tmp);
  89. if (error != 0) {
  90. getConsole().print("Could not load %s", tmp);
  91. }
  92. delete [] tmp;
  93. }
  94. // Process data
  95. processTextures();
  96. processRooms();
  97. processModels();
  98. processSprites();
  99. processMoveables();
  100. processPakSounds();
  101. // Free pak file
  102. mTombRaider.reset();
  103. // Check if the level contains Lara
  104. if (mLara == NULL) {
  105. getConsole().print("Can't find Lara entity in level pak!");
  106. return -1;
  107. }
  108. mLoaded = true;
  109. mRender->setMode(Render::modeVertexLight);
  110. return 0;
  111. }
  112. void Game::handleAction(ActionEvents action, bool isFinished) {
  113. if (mLoaded) {
  114. if (action == forwardAction) {
  115. getWorld().moveEntity(mLara, 'f');
  116. } else if (action == backwardAction) {
  117. getWorld().moveEntity(mLara, 'b');
  118. } else if (action == leftAction) {
  119. getWorld().moveEntity(mLara, 'l');
  120. } else if (action == rightAction) {
  121. getWorld().moveEntity(mLara, 'r');
  122. }
  123. }
  124. }
  125. void Game::handleMouseMotion(int xrel, int yrel) {
  126. if (mLoaded) {
  127. // Move Camera on X Axis
  128. if (xrel > 0)
  129. while (xrel-- > 0)
  130. getCamera().command(CAMERA_ROTATE_RIGHT);
  131. else if (xrel < 0)
  132. while (xrel++ < 0)
  133. getCamera().command(CAMERA_ROTATE_LEFT);
  134. // Move Camera on Y Axis
  135. if (yrel > 0)
  136. while (yrel-- > 0)
  137. getCamera().command(CAMERA_ROTATE_UP);
  138. else if (yrel < 0)
  139. while (yrel++ < 0)
  140. getCamera().command(CAMERA_ROTATE_DOWN);
  141. // Fix Laras rotation
  142. mLara->angles[1] = getCamera().getRadianYaw();
  143. mLara->angles[2] = getCamera().getRadianPitch();
  144. }
  145. }
  146. void Game::display() {
  147. mRender->Display();
  148. }
  149. int Game::command(std::vector<char *> *args) {
  150. if (args->size() < 1) {
  151. getConsole().print("Invalid use of game-command!");
  152. return -1;
  153. }
  154. char *cmd = args->at(0);
  155. if (strcmp(cmd, "mode") == 0) {
  156. if (args->size() > 1) {
  157. char *mode = args->at(1);
  158. if (strcmp(mode, "wireframe") == 0) {
  159. if (mLoaded) {
  160. mRender->setMode(Render::modeWireframe);
  161. getConsole().print("Wireframe mode");
  162. } else {
  163. getConsole().print("Load a level to set this mode!");
  164. return -2;
  165. }
  166. } else if (strcmp(mode, "solid") == 0) {
  167. if (mLoaded) {
  168. mRender->setMode(Render::modeSolid);
  169. getConsole().print("Solid mode");
  170. } else {
  171. getConsole().print("Load a level to set this mode!");
  172. return -3;
  173. }
  174. } else if (strcmp(mode, "texture") == 0) {
  175. if (mLoaded) {
  176. mRender->setMode(Render::modeTexture);
  177. getConsole().print("Texture mode");
  178. } else {
  179. getConsole().print("Load a level to set this mode!");
  180. return -4;
  181. }
  182. } else if (strcmp(mode, "vertexlight") == 0) {
  183. if (mLoaded) {
  184. mRender->setMode(Render::modeVertexLight);
  185. getConsole().print("Vertexlight mode");
  186. } else {
  187. getConsole().print("Load a level to set this mode!");
  188. return -5;
  189. }
  190. } else if (strcmp(mode, "titlescreen") == 0) {
  191. mRender->setMode(Render::modeLoadScreen);
  192. getConsole().print("Titlescreen mode");
  193. } else {
  194. getConsole().print("Invalid use of mode command (%s)!", mode);
  195. return -6;
  196. }
  197. } else {
  198. getConsole().print("Invalid use of mode command!");
  199. return -7;
  200. }
  201. } else if (strcmp(cmd, "move") == 0) {
  202. if (args->size() > 1) {
  203. if (mLoaded) {
  204. char *move = args->at(1);
  205. if (strcmp(move, "walk") == 0) {
  206. mLara->moveType = worldMoveType_walk;
  207. getConsole().print("Lara is walking...");
  208. } else if (strcmp(move, "fly") == 0) {
  209. mLara->moveType = worldMoveType_fly;
  210. getConsole().print("Lara is flying...");
  211. } else if (strcmp(move, "noclip") == 0) {
  212. mLara->moveType = worldMoveType_noClipping;
  213. getConsole().print("Lara is noclipping...");
  214. } else {
  215. getConsole().print("Invalid use of move command (%s)!", move);
  216. return -8;
  217. }
  218. } else {
  219. getConsole().print("Load a level to change the movement type!");
  220. return -9;
  221. }
  222. } else {
  223. getConsole().print("Invalid use of move command!");
  224. return -10;
  225. }
  226. } else if (strcmp(cmd, "sound") == 0) {
  227. if (args->size() > 1) {
  228. getSound().play(atoi(args->at(1)));
  229. } else {
  230. getConsole().print("Invalid use of sound command!");
  231. return -11;
  232. }
  233. } else if (strcmp(cmd, "animate") == 0) {
  234. if (args->size() > 1) {
  235. char c = args->at(1)[0];
  236. if (c == 'n') {
  237. // Step all skeletal models to their next animation
  238. if (mRender->getFlags() & Render::fAnimateAllModels) {
  239. for (unsigned int i = 0; i < mRender->mModels.size(); i++) {
  240. SkeletalModel *m = mRender->mModels[i];
  241. if (m->getAnimation() < ((int)m->model->animation.size() - 1))
  242. m->setAnimation(m->getAnimation() + 1);
  243. else
  244. if (m->getAnimation() != 0)
  245. m->setAnimation(0);
  246. }
  247. } else {
  248. getConsole().print("Animations need to be enabled!");
  249. }
  250. } else if (c == 'p') {
  251. // Step all skeletal models to their previous animation
  252. if (mRender->getFlags() & Render::fAnimateAllModels) {
  253. for (unsigned int i = 0; i < mRender->mModels.size(); i++) {
  254. SkeletalModel *m = mRender->mModels[i];
  255. if (m->getAnimation() > 0)
  256. m->setAnimation(m->getAnimation() - 1);
  257. else
  258. if (m->model->animation.size() > 0)
  259. m->setAnimation(m->model->animation.size() - 1);
  260. }
  261. } else {
  262. getConsole().print("Animations need to be enabled!");
  263. }
  264. } else {
  265. // Enable or disable animating all skeletal models
  266. bool b;
  267. if (readBool(args->at(1), &b) < 0) {
  268. getConsole().print("Pass BOOL to animate command!");
  269. return -12;
  270. }
  271. if (b)
  272. mRender->setFlags(Render::fAnimateAllModels);
  273. else
  274. mRender->clearFlags(Render::fAnimateAllModels);
  275. getConsole().print(b ? "Animating all models" : "No longer animating all models");
  276. }
  277. } else {
  278. getConsole().print("Invalid use of animate command!");
  279. return -13;
  280. }
  281. } else if (strcmp(cmd, "help") == 0) {
  282. if (args->size() < 2) {
  283. getConsole().print("game-command Usage:");
  284. getConsole().print(" game COMMAND");
  285. getConsole().print("Available commands:");
  286. getConsole().print(" move [walk|fly|noclip]");
  287. getConsole().print(" sound INT");
  288. getConsole().print(" mode MODE");
  289. getConsole().print(" animate [BOOL|n|p]");
  290. getConsole().print(" light BOOL");
  291. } else if (strcmp(args->at(1), "sound") == 0) {
  292. getConsole().print("game-sound-command Usage:");
  293. getConsole().print(" game sound INT");
  294. getConsole().print("Where INT is a valid sound ID integer");
  295. } else if (strcmp(args->at(1), "move") == 0) {
  296. getConsole().print("game-move-command Usage:");
  297. getConsole().print(" game move COMMAND");
  298. getConsole().print("Where COMMAND is one of the following:");
  299. getConsole().print(" walk");
  300. getConsole().print(" fly");
  301. getConsole().print(" noclip");
  302. } else if (strcmp(args->at(1), "mode") == 0) {
  303. getConsole().print("game-mode-command Usage:");
  304. getConsole().print(" game mode MODE");
  305. getConsole().print("Where MODE is one of the following:");
  306. getConsole().print(" wireframe");
  307. getConsole().print(" solid");
  308. getConsole().print(" texture");
  309. getConsole().print(" vertexlight");
  310. getConsole().print(" titlescreen");
  311. } else if (strcmp(args->at(1), "animate") == 0) {
  312. getConsole().print("game-animate-command Usage:");
  313. getConsole().print(" game animate [n|p|BOOL]");
  314. getConsole().print("Where the commands have the following meaning:");
  315. getConsole().print(" BOOL to (de)activate animating all models");
  316. getConsole().print(" n to step all models to their next animation");
  317. getConsole().print(" p to step all models to their previous animation");
  318. } else {
  319. getConsole().print("No help available for game %s.", args->at(1));
  320. return -14;
  321. }
  322. } else if (strcmp(cmd, "light") == 0) {
  323. if (args->size() >= 2) {
  324. bool b;
  325. if (readBool(args->at(1), &b) < 0) {
  326. getConsole().print("Pass BOOL to light command!");
  327. return -15;
  328. }
  329. if (b)
  330. mRender->setFlags(Render::fGL_Lights);
  331. else
  332. mRender->clearFlags(Render::fGL_Lights);
  333. getConsole().print("GL-Lights are now %s", b ? "on" : "off");
  334. } else {
  335. getConsole().print("Invalid use of game-light-command!");
  336. return -16;
  337. }
  338. } else {
  339. getConsole().print("Invalid use of game-command (%s)!", cmd);
  340. return -17;
  341. }
  342. return 0;
  343. }
  344. void Game::processPakSounds()
  345. {
  346. unsigned char *riff;
  347. unsigned int riffSz;
  348. //tr2_sound_source_t *sound;
  349. //tr2_sound_details_t *detail;
  350. //float pos[3];
  351. unsigned int i;
  352. int id;
  353. /* detail
  354. short sample;
  355. short volume;
  356. short sound_range;
  357. short flags; // bits 8-15: priority?, 2-7: number of sound samples
  358. // in this group, bits 0-1: channel number
  359. */
  360. printf("Processing pak sound files: ");
  361. for (i = 0; i < mTombRaider.getSoundSamplesCount(); ++i)
  362. {
  363. mTombRaider.getSoundSample(i, &riffSz, &riff);
  364. getSound().addWave(riff, riffSz, &id, Sound::SoundFlagsNone);
  365. //if (((i + 1) == TR_SOUND_F_PISTOL) && (id > 0))
  366. //{
  367. //m_testSFX = id;
  368. //}
  369. delete [] riff;
  370. // sound[i].sound_id; // internal sound index
  371. // sound[i].flags; // 0x40, 0x80, or 0xc0
  372. //pos[0] = sound[i].x;
  373. //pos[1] = sound[i].y;
  374. //pos[2] = sound[i].z;
  375. //getSound().SourceAt(id, pos);
  376. //printf(".");
  377. //fflush(stdout);
  378. }
  379. printf("Done! Found %u files.\n", mTombRaider.getSoundSamplesCount());
  380. }
  381. void Game::processTextures()
  382. {
  383. unsigned char *image;
  384. unsigned char *bumpmap;
  385. int i;
  386. printf("Processing TR textures: ");
  387. //if ( mTombRaider.getNumBumpMaps())
  388. // gBumpMapStart = mTombRaider.NumTextures();
  389. for (i = 0; i < mTombRaider.NumTextures(); ++i)
  390. {
  391. mTombRaider.Texture(i, &image, &bumpmap);
  392. // Overwrite any previous level textures on load
  393. mRender->loadTexture(image, 256, 256, mTextureLevelOffset + i);
  394. #ifdef MULTITEXTURE
  395. gMapTex2Bump[mTextureLevelOffset + i] = -1;
  396. #endif
  397. if (bumpmap)
  398. {
  399. #ifdef MULTITEXTURE
  400. gMapTex2Bump[mTextureLevelOffset + i] = mTextureLevelOffset + i +
  401. mTombRaider.NumTextures();
  402. #endif
  403. mRender->loadTexture(bumpmap, 256, 256, mTextureLevelOffset + i +
  404. mTombRaider.NumTextures());
  405. }
  406. if (image)
  407. delete [] image;
  408. if (bumpmap)
  409. delete [] bumpmap;
  410. //printf(".");
  411. //fflush(stdout);
  412. }
  413. mTextureOffset = mTextureLevelOffset + mTombRaider.NumTextures();
  414. printf("Done! Found %d textures.\n", mTombRaider.NumTextures());
  415. }
  416. void Game::processSprites()
  417. {
  418. int i, j, k, l, x, y, s_index, width, height;
  419. float scale, width2, height2;
  420. tr2_sprite_texture_t *sprite;
  421. tr2_sprite_texture_t *sprite_textures;
  422. tr2_sprite_sequence_t *sprite_sequence;
  423. sprite_seq_t *r_mesh;
  424. tr2_item_t *item;
  425. item = mTombRaider.Item();
  426. sprite_textures = mTombRaider.Sprite();
  427. sprite_sequence = mTombRaider.SpriteSequence();
  428. scale = 4.0;
  429. printf("Processing sprites: ");
  430. for (i = 0; i < mTombRaider.NumItems() - 1; ++i)
  431. {
  432. // It's a mesh, skip it
  433. if (mTombRaider.Engine() == TR_VERSION_1 && item[i].intensity1 == -1)
  434. continue;
  435. k = item[i].object_id;
  436. // Search the SpriteSequence list
  437. // (if we didn't already decide that it's a mesh)
  438. for (j = 0; j < (int)mTombRaider.NumSpriteSequences(); ++j)
  439. {
  440. if (sprite_sequence[j].object_id == k)
  441. {
  442. k = item[i].object_id;
  443. s_index = sprite_sequence[j].offset;
  444. r_mesh = new sprite_seq_t;
  445. getWorld().addSprite(r_mesh);
  446. r_mesh->num_sprites = -sprite_sequence[j].negative_length;
  447. r_mesh->sprite = new sprite_t[r_mesh->num_sprites];
  448. for (l = 0; l < r_mesh->num_sprites; ++l)
  449. {
  450. sprite = &sprite_textures[s_index];
  451. width = sprite->width >> 8;
  452. height = sprite->height >> 8;
  453. x = sprite->x;
  454. y = sprite->y;
  455. width2 = width * scale;
  456. height2 = height * scale;
  457. // For vising use
  458. r_mesh->sprite[l].pos[0] = item[i].x;
  459. r_mesh->sprite[l].pos[1] = item[i].y;
  460. r_mesh->sprite[l].pos[2] = item[i].z;
  461. r_mesh->sprite[l].texture = sprite->tile + mTextureStart;
  462. r_mesh->sprite[l].radius = width2 / 2.0f;
  463. r_mesh->sprite[l].vertex[0].pos[0] = -width2 / 2.0f;
  464. r_mesh->sprite[l].vertex[1].pos[0] = -width2 / 2.0f;
  465. r_mesh->sprite[l].vertex[2].pos[0] = width2 / 2.0f;
  466. r_mesh->sprite[l].vertex[3].pos[0] = width2 / 2.0f;
  467. r_mesh->sprite[l].vertex[0].pos[1] = 0;
  468. r_mesh->sprite[l].vertex[1].pos[1] = -height2;
  469. r_mesh->sprite[l].vertex[2].pos[1] = -height2;
  470. r_mesh->sprite[l].vertex[3].pos[1] = 0;
  471. r_mesh->sprite[l].vertex[0].pos[2] = 0;
  472. r_mesh->sprite[l].vertex[1].pos[2] = 0;
  473. r_mesh->sprite[l].vertex[2].pos[2] = 0;
  474. r_mesh->sprite[l].vertex[3].pos[2] = 0;
  475. r_mesh->sprite[l].texel[3].st[0] = (vec_t)(x+width)/TexelScale;
  476. r_mesh->sprite[l].texel[3].st[1] = (vec_t)(y+height)/TexelScale;
  477. r_mesh->sprite[l].texel[2].st[0] = (vec_t)(x+width)/TexelScale;
  478. r_mesh->sprite[l].texel[2].st[1] = (vec_t)(y)/TexelScale;
  479. r_mesh->sprite[l].texel[1].st[0] = (vec_t)(x) /TexelScale;
  480. r_mesh->sprite[l].texel[1].st[1] = (vec_t)(y) /TexelScale;
  481. r_mesh->sprite[l].texel[0].st[0] = (vec_t)(x) / TexelScale;
  482. r_mesh->sprite[l].texel[0].st[1] = (vec_t)(y+height)/TexelScale;
  483. //printf(".");
  484. //fflush(stdout);
  485. }
  486. }
  487. }
  488. }
  489. printf("Done! Found %d sprites.\n", mTombRaider.NumSpriteSequences());
  490. }
  491. void Game::processMoveables()
  492. {
  493. std::vector<unsigned int> cache;
  494. std::vector<skeletal_model_t *> cache2;
  495. tr2_mesh_t *mesh = NULL;
  496. tr2_moveable_t *moveable = NULL;
  497. tr2_meshtree_t *meshtree = NULL;
  498. tr2_item_t *item = NULL;
  499. tr2_animation_t *animation = NULL;
  500. unsigned short *frame = NULL;
  501. tr2_sprite_sequence_t *sprite_sequence = NULL;
  502. tr2_object_texture_t *object_texture = NULL;
  503. int i, j, object_id;
  504. int ent = 0;
  505. unsigned int statCount = 0;
  506. frame = mTombRaider.Frame();
  507. moveable = mTombRaider.Moveable();
  508. meshtree = mTombRaider.MeshTree();
  509. mesh = mTombRaider.Mesh();
  510. object_texture = mTombRaider.ObjectTextures();
  511. item = mTombRaider.Item();
  512. animation = mTombRaider.Animation();
  513. sprite_sequence = mTombRaider.SpriteSequence();
  514. printf("Processing skeletal models: ");
  515. for (i = 0; i < mTombRaider.NumItems(); ++i)
  516. {
  517. object_id = item[i].object_id;
  518. // It may not be a moveable, test for sprite
  519. if (!(mTombRaider.Engine() == TR_VERSION_1 && item[i].intensity1 == -1))
  520. {
  521. for (j = 0; j < (int)mTombRaider.NumSpriteSequences(); ++j)
  522. {
  523. if (sprite_sequence[j].object_id == object_id)
  524. break;
  525. }
  526. // It's not a moveable, skip sprite
  527. if (j != (int)mTombRaider.NumSpriteSequences())
  528. {
  529. //printf("s");
  530. //fflush(stdout);
  531. continue;
  532. }
  533. }
  534. for (j = 0; j < (int)mTombRaider.NumMoveables(); ++j)
  535. {
  536. if ((int)moveable[j].object_id == object_id)
  537. break;
  538. }
  539. // It's not a moveable or even a sprite?, skip unknown
  540. if (j == (int)mTombRaider.NumMoveables())
  541. {
  542. //printf("?"); // what the wolf?
  543. //fflush(stdout);
  544. continue;
  545. }
  546. processMoveable(j, i, &ent, cache2, cache, object_id);
  547. statCount++;
  548. }
  549. // Get models that aren't items
  550. for (i = 0; i < mTombRaider.NumMoveables(); ++i)
  551. {
  552. switch ((int)moveable[i].object_id)
  553. {
  554. case 30:
  555. case 2: // Which tr needs this as model again?
  556. processMoveable(i, i, &ent, cache2, cache,
  557. (int)moveable[i].object_id);
  558. break;
  559. default:
  560. switch (mTombRaider.Engine())
  561. {
  562. case TR_VERSION_1:
  563. switch ((int)moveable[i].object_id)
  564. {
  565. case TombRaider1::LaraMutant:
  566. processMoveable(i, i, &ent, cache2, cache,
  567. (int)moveable[i].object_id);
  568. break;
  569. }
  570. break;
  571. case TR_VERSION_4:
  572. switch ((int)moveable[i].object_id)
  573. {
  574. case TR4_PISTOLS_ANIM:
  575. case TR4_UZI_ANIM:
  576. case TR4_SHOTGUN_ANIM:
  577. case TR4_CROSSBOW_ANIM:
  578. case TR4_GRENADE_GUN_ANIM:
  579. case TR4_SIXSHOOTER_ANIM:
  580. processMoveable(i, i, &ent, cache2, cache,
  581. (int)moveable[i].object_id);
  582. break;
  583. }
  584. break;
  585. case TR_VERSION_2:
  586. case TR_VERSION_3:
  587. case TR_VERSION_5:
  588. case TR_VERSION_UNKNOWN:
  589. break;
  590. }
  591. }
  592. }
  593. printf("Done! Found %d models.\n", mTombRaider.NumMoveables() + statCount);
  594. }
  595. void Game::processMoveable(int index, int i, int *ent,
  596. std::vector<skeletal_model_t *> &cache2,
  597. std::vector<unsigned int> &cache, int object_id)
  598. {
  599. skeletal_model_t *r_model = NULL;
  600. skeletal_model_t *c_model = NULL;
  601. animation_frame_t *animation_frame = NULL;
  602. tr2_mesh_t *mesh = NULL;
  603. tr2_moveable_t *moveable = NULL;
  604. tr2_meshtree_t *meshtree = NULL;
  605. tr2_item_t *item = NULL;
  606. tr2_animation_t *animation = NULL;
  607. tr2_meshtree_t *mesh_tree = NULL;
  608. bone_frame_t *bone = NULL;
  609. bone_tag_t *tag = NULL;
  610. entity_t *thing = NULL;
  611. SkeletalModel *sModel = 0x0;
  612. unsigned short *frame;
  613. int j, k, a, frame_step;
  614. unsigned int l, frame_offset, frame_count, f;
  615. float pos[3];
  616. float yaw;
  617. bool lara = false;
  618. int skyMesh;
  619. skyMesh = mTombRaider.getSkyModelId();
  620. frame = mTombRaider.Frame();
  621. moveable = mTombRaider.Moveable();
  622. meshtree = mTombRaider.MeshTree();
  623. mesh = mTombRaider.Mesh();
  624. item = mTombRaider.Item();
  625. animation = mTombRaider.Animation();
  626. pos[0] = item[i].x;
  627. pos[1] = item[i].y;
  628. pos[2] = item[i].z;
  629. yaw = ((item[i].angle >> 14) & 0x03);
  630. yaw *= 90;
  631. thing = new entity_t;
  632. thing->id = (*ent)++;
  633. thing->type = 0x00;
  634. thing->pos[0] = item[i].x;
  635. thing->pos[1] = item[i].y;
  636. thing->pos[2] = item[i].z;
  637. thing->angles[1] = yaw;
  638. thing->objectId = moveable[index].object_id;
  639. thing->moving = false;
  640. thing->animate = false;
  641. sModel = new SkeletalModel();
  642. mRender->addSkeletalModel(sModel);
  643. thing->tmpHook = sModel; // temp hack to keep a running version during refactoring
  644. if (mTombRaider.Engine() == TR_VERSION_1)
  645. {
  646. switch (thing->objectId)
  647. {
  648. case TombRaider1::Wolf:
  649. thing->state = TombRaider1::WolfState_Lying;
  650. //thing->animate = true;
  651. sModel->setAnimation(3);
  652. sModel->setFrame(0);
  653. break;
  654. }
  655. }
  656. //! \fixme Check here and see if we already have one for object_id later
  657. // if (getWorld().isCachedSkeletalModel(moveable[index].object_id))
  658. // {
  659. // thing->modelId = mRender->add(sModel);
  660. // return;
  661. // }
  662. r_model = new skeletal_model_t;
  663. r_model->id = moveable[index].object_id;
  664. // Gather more info if this is lara
  665. if (moveable[index].object_id == 0)
  666. {
  667. gLaraModel = r_model; // hack to avoid broken system until new event sys
  668. lara = true;
  669. getCamera().translate(pos[0], pos[1] - 470, pos[2]);
  670. thing->type = 0x02;
  671. mLara = thing; // Mongoose 2002.03.22, Cheap hack for now
  672. mLara->master = 0x0;
  673. switch (mTombRaider.Engine())
  674. {
  675. case TR_VERSION_3:
  676. mLara->modelId = i;
  677. sModel->setAnimation(TR_ANIAMTION_RUN);
  678. sModel->setIdleAnimation(TR_ANIAMTION_STAND);
  679. r_model->tr4Overlay = false;
  680. break;
  681. case TR_VERSION_4:
  682. mLara->modelId = i;
  683. sModel->setAnimation(TR_ANIAMTION_RUN);
  684. sModel->setIdleAnimation(TR_ANIAMTION_STAND);
  685. // Only TR4 lara has 2 layer bone tags/meshes per bone frame
  686. r_model->tr4Overlay = true;
  687. break;
  688. case TR_VERSION_1:
  689. case TR_VERSION_2:
  690. case TR_VERSION_5:
  691. case TR_VERSION_UNKNOWN:
  692. mLara->modelId = index;
  693. sModel->setAnimation(TR_ANIAMTION_RUN);
  694. sModel->setIdleAnimation(TR_ANIAMTION_STAND);
  695. r_model->tr4Overlay = false;
  696. break;
  697. }
  698. r_model->ponytailId = 0;
  699. }
  700. else
  701. {
  702. lara = false;
  703. r_model->ponytailId = -1;
  704. }
  705. // Animation
  706. a = moveable[index].animation;
  707. frame_offset = animation[a].frame_offset / 2;
  708. frame_step = animation[a].frame_size;
  709. int frame_cycle = 0;
  710. if (a >= (int)mTombRaider.NumAnimations())
  711. {
  712. a = mTombRaider.NumFrames() - frame_offset;
  713. }
  714. else
  715. {
  716. a = (animation[a].frame_offset / 2) - frame_offset;
  717. }
  718. if (frame_step != 0) // prevent divide-by-zero errors
  719. a /= frame_step;
  720. if (a != 0) // prevent divide-by-zero errors
  721. frame_offset += frame_step * (frame_cycle % a);
  722. if (a < 0)
  723. {
  724. //continue;
  725. return;
  726. }
  727. //! \fixme Might be better UID for each model, but this seems to work well
  728. j = object_id;
  729. // We only want one copy of the skeletal model in memory
  730. unsigned int foundIndex;
  731. bool found = false;
  732. for (foundIndex = 0; foundIndex < cache.size(); foundIndex++) {
  733. if ((int)cache[foundIndex] == j) {
  734. found = true;
  735. break;
  736. }
  737. }
  738. if (!found)
  739. {
  740. sModel->model = r_model;
  741. getWorld().addEntity(thing);
  742. k = getWorld().addModel(r_model);
  743. cache.push_back(j);
  744. cache2.push_back(r_model);
  745. switch (mTombRaider.Engine())
  746. {
  747. case TR_VERSION_4:
  748. if (mLara && moveable[index].object_id == 30)
  749. {
  750. r_model->ponytailId = k;
  751. r_model->ponytailMeshId = moveable[index].starting_mesh;
  752. r_model->ponytailNumMeshes = ((moveable[index].num_meshes > 0) ?
  753. moveable[index].num_meshes : 0);
  754. r_model->ponytailAngle = -90.0f;
  755. r_model->ponytail[0] = -3;
  756. r_model->ponytail[1] = -22;
  757. r_model->ponytail[2] = -20;
  758. r_model->ponyOff = 40;
  759. r_model->ponyOff2 = 32;
  760. r_model->pigtails = false;
  761. // Try to guess pigtails by looking for certian num verts in head
  762. if (mesh[moveable[0].starting_mesh].num_vertices > 80)
  763. {
  764. r_model->pigtails = true;
  765. r_model->ponyOff -= 20;
  766. r_model->ponytail[1] -= 32;
  767. }
  768. mRender->setFlags(Render::fRenderPonytail);
  769. getConsole().print("Found known ponytail");
  770. }
  771. break; // ?
  772. case TR_VERSION_1:
  773. case TR_VERSION_2:
  774. case TR_VERSION_3:
  775. case TR_VERSION_5:
  776. case TR_VERSION_UNKNOWN:
  777. if (mLara && moveable[index].object_id == 2)
  778. {
  779. r_model->ponytailId = k;
  780. r_model->ponytailMeshId = moveable[index].starting_mesh;
  781. r_model->ponytailNumMeshes = ((moveable[index].num_meshes > 0) ?
  782. moveable[index].num_meshes : 0);
  783. r_model->ponytailAngle = -90.0f;
  784. r_model->ponytail[0] = 0;
  785. r_model->ponytail[1] = -20;
  786. r_model->ponytail[2] = -20;
  787. r_model->ponyOff = 40;
  788. r_model->ponyOff2 = 0;
  789. mRender->setFlags(Render::fRenderPonytail);
  790. getConsole().print("Found ponytail?");
  791. }
  792. break;
  793. }
  794. }
  795. else
  796. {
  797. // Already cached
  798. delete r_model;
  799. c_model = cache2[foundIndex];
  800. sModel->model = c_model;
  801. getWorld().addEntity(thing);
  802. getWorld().addModel(c_model);
  803. printf("c");
  804. return;
  805. }
  806. int aloop = mTombRaider.getNumAnimsForMoveable(index);
  807. #ifdef DEBUG_MOVEABLE
  808. printf("\nanimation = %i, num_animations = %i\n",
  809. moveable[index].animation, aloop);
  810. printf("\nitem[%i].flags = %i\nentity[%i]\n",
  811. i, item[i].flags, thing->id);
  812. #endif
  813. //a = moveable[index].animation;
  814. //frame_offset = animation[a].frame_offset / 2;
  815. //frame_step = animation[a].frame_size;
  816. for (; a < aloop; ++a,
  817. frame_offset = animation[a].frame_offset / 2,
  818. frame_step = animation[a].frame_size)
  819. {
  820. animation_frame = new animation_frame_t;
  821. r_model->animation.push_back(animation_frame);
  822. frame_count = (animation[a].frame_end - animation[a].frame_start) + 1;
  823. animation_frame->rate = animation[a].frame_rate;
  824. #ifdef DEBUG_MOVEABLE
  825. printf("animation[%i] state and unknowns = %i, %i, %i, %i, %i\n",
  826. a, animation[a].state_id, animation[a].unknown1,
  827. animation[a].unknown2, animation[a].unknown3,
  828. animation[a].unknown4);
  829. printf("animation[%i].frame_rate = %i\n",
  830. a, animation[a].frame_rate);
  831. printf("animation[%i].next_animation = %i\n",
  832. a, animation[a].next_animation);
  833. printf("animation[%i].frame_offset = %u\n",
  834. a, animation[a].frame_offset);
  835. printf("animation[%i].anim_command = %i\n",
  836. a, animation[a].anim_command);
  837. printf("animation[%i].num_anim_commands = %i\n",
  838. a, animation[a].num_anim_commands);
  839. printf("animation[%i].state_change_offset = %i\n",
  840. a, animation[a].state_change_offset);
  841. printf(" frame_offset = %u\n",
  842. frame_offset);
  843. #endif
  844. // Get all the frames for aniamtion
  845. for (f = 0; f < frame_count; ++f, frame_offset += frame_step)
  846. {
  847. // HACK: Lara's ObjectID is 315, but her meshes start at 0, so make a
  848. // quick substitution (so she doesn't appear as a bunch of thighs)
  849. if (index == 0 && mTombRaider.Engine() == TR_VERSION_3)
  850. {
  851. for (j = 0; j < (int)mTombRaider.NumMoveables() && !index; ++j)
  852. {
  853. if (moveable[j].object_id == 315)
  854. index = j;
  855. }
  856. }
  857. // Fix Lara in TR4
  858. if (index == 0 && mTombRaider.Engine() == TR_VERSION_4)
  859. {
  860. for (j = 0; j < (int)mTombRaider.NumMoveables() && !index; ++j)
  861. {
  862. // Body is ItemID 8, joints are ItemID 9
  863. // (TR4 demo: body is ItemID 10, joints are ItemID 11)
  864. if (moveable[j].object_id == 8)
  865. index = j;
  866. }
  867. }
  868. else if (moveable[index].object_id == 8 &&
  869. mTombRaider.Engine() == TR_VERSION_4)
  870. {
  871. // KLUDGE to do "skinning"
  872. index = 0;
  873. for (j = 0; j < (int)mTombRaider.NumMoveables() && !index; ++j)
  874. {
  875. // Body is ItemID 8, joints are ItemID 9
  876. // (TR4 demo: body is ItemID 10, joints are ItemID 11)
  877. if (moveable[j].object_id == 9)
  878. index = j;
  879. }
  880. }
  881. #ifdef DEBUG_MOVEABLE
  882. printf("animation[%i].boneframe[%u] = offset %u, step %i\n",
  883. a, f, frame_offset, frame_step);
  884. #endif
  885. // Mongoose 2002.08.15, Was
  886. // if (frame_offset + 8 > _tombraider.NumFrames())
  887. if (frame_offset > mTombRaider.NumFrames())
  888. {
  889. getConsole().print("WARNING: Bad animation frame %i > %i",
  890. frame_offset, mTombRaider.NumFrames());
  891. // Mongoose 2002.08.15, Attempt to skip more likely bad animation data
  892. getConsole().print("WARNING: Handling bad animation data...");
  893. return; //continue;
  894. }
  895. // Generate bone frames and tags per frame ////////////
  896. bone = new bone_frame_t;
  897. animation_frame->frame.push_back(bone);
  898. // Init translate for bone frame
  899. bone->pos[0] = (short)frame[frame_offset + 6];
  900. bone->pos[1] = (short)frame[frame_offset + 7];
  901. bone->pos[2] = (short)frame[frame_offset + 8];
  902. bone->yaw = yaw;
  903. //printf("%f %f %f\n", bone->pos[0], bone->pos[1], bone->pos[2]);
  904. l = 9; // First angle offset in this Frame
  905. // Run through the tag and calculate the rotation and offset
  906. for (j = 0; j < (int)moveable[index].num_meshes; ++j)
  907. {
  908. tag = new bone_tag_t;
  909. bone->tag.push_back(tag);
  910. tag->off[0] = 0.0;
  911. tag->off[1] = 0.0;
  912. tag->off[2] = 0.0;
  913. tag->flag = 0x00;
  914. tag->rot[0] = 0.0;
  915. tag->rot[1] = 0.0;
  916. tag->rot[2] = 0.0;
  917. tag->mesh = moveable[index].starting_mesh + j;
  918. // Setup offsets to produce skeletion
  919. if (j == 0)
  920. {
  921. // Since we use bone's offset, these aren't used
  922. tag->off[0] = 0.0;
  923. tag->off[1] = 0.0;
  924. tag->off[2] = 0.0;
  925. // Always push tag[0], this isn't really used either
  926. tag->flag = 0x02;
  927. }
  928. else // Nonprimary tag - position relative to first tag
  929. {
  930. int *tree;
  931. // Hack: moveable[index].mesh_tree is a byte offset
  932. // into mesh_tree[], so we have to convert to index
  933. tree = (int *)(void *)meshtree;
  934. mesh_tree = (tr2_meshtree_t *)&tree[moveable[index].mesh_tree
  935. + ((j - 1) * 4)];
  936. tag->off[0] = mesh_tree->x;
  937. tag->off[1] = mesh_tree->y;
  938. tag->off[2] = mesh_tree->z;
  939. tag->flag = (char)mesh_tree->flags;
  940. }
  941. // Setup tag rotations
  942. mTombRaider.computeRotationAngles(&frame, &frame_offset, &l,
  943. tag->rot, tag->rot+1, tag->rot+2);
  944. }
  945. }
  946. }
  947. if (i == skyMesh)
  948. {
  949. mRender->setSkyMesh(i, //moveable[i].starting_mesh,
  950. (mTombRaider.Engine() == TR_VERSION_2));
  951. }
  952. //printf(".");
  953. //fflush(stdout);
  954. }
  955. bool compareFaceTextureId(const void *voidA, const void *voidB)
  956. {
  957. texture_tri_t *a = (texture_tri_t *)voidA, *b = (texture_tri_t *)voidB;
  958. if (!a || !b)
  959. return false; // error really
  960. return (a->texture < b->texture);
  961. }
  962. #ifdef EXPERIMENTAL
  963. void Game::setupTextureColor(texture_tri_t *r_tri, float *colorf)
  964. {
  965. unsigned char color[4];
  966. unsigned int colorI;
  967. color[0] = (unsigned char)(colorf[0]*255.0f);
  968. color[1] = (unsigned char)(colorf[1]*255.0f);
  969. color[2] = (unsigned char)(colorf[2]*255.0f);
  970. color[3] = (unsigned char)(colorf[3]*255.0f);
  971. ((unsigned char *)(&colorI))[3] = color[0];
  972. ((unsigned char *)(&colorI))[2] = color[1];
  973. ((unsigned char *)(&colorI))[1] = color[2];
  974. ((unsigned char *)(&colorI))[0] = color[3];
  975. bool found = false;
  976. unsigned int foundIndex = 0;
  977. for (foundIndex = 0; foundIndex < gColorTextureHACK.size(); foundIndex++) {
  978. if (gColorTextureHACK[foundIndex] == colorI) {
  979. found = true;
  980. break;
  981. }
  982. }
  983. if (!found)
  984. {
  985. gColorTextureHACK.push_back(colorI);
  986. r_tri->texture = mTextureOffset + gColorTextureHACK.size();
  987. mRender->loadTexture(Texture::generateColorTexture(color, 32, 32),
  988. 32, 32,
  989. r_tri->texture);
  990. #ifdef DEBUG_COLOR_TEXTURE_GEN
  991. printf("Color 0x%02x%02x%02x%02x | 0x%08xto texture[%u]?\n",
  992. color[0], color[1], color[2], color[3], colorI,
  993. gColorTextureHACK.size());
  994. #endif
  995. }
  996. else
  997. {
  998. //printf("Color already loaded %i -> 0x%08x\n",
  999. // gColorTextureHACK.getCurrentIndex(),
  1000. // gColorTextureHACK.current());
  1001. r_tri->texture = mTextureOffset + foundIndex;
  1002. }
  1003. //r_tri->texture = white; // White texture
  1004. }
  1005. #endif
  1006. void Game::processModels()
  1007. {
  1008. printf("Processing meshes: ");
  1009. for (int index = 0; index < mTombRaider.getMeshCount(); index++) {
  1010. int i, j, count, texture;
  1011. int vertexIndices[6];
  1012. float st[12];
  1013. float color[4];
  1014. unsigned short transparency;
  1015. texture_tri_t *r_tri;
  1016. // Assert common sense
  1017. if (index < 0 || !mTombRaider.isMeshValid(index))
  1018. {
  1019. //! \fixme allow sparse lists with matching ids instead?
  1020. getWorld().addMesh(NULL); // Filler, to make meshes array ids align
  1021. //printf("x");
  1022. //fflush(stdout);
  1023. return;
  1024. }
  1025. #ifndef EXPERIMENTAL
  1026. // WHITE texture id
  1027. int white = 0;
  1028. #endif
  1029. model_mesh_t *mesh = new model_mesh_t;
  1030. // Mongoose 2002.08.30, Testing support for 'shootable' models ( traceable )
  1031. mTombRaider.getMeshCollisionInfo(index, mesh->center, &mesh->radius);
  1032. //! \fixme Arrays don't work either =)
  1033. // Mesh geometery, colors, etc
  1034. mTombRaider.getMeshVertexArrays(index,
  1035. &mesh->vertexCount, &mesh->vertices,
  1036. &mesh->normalCount, &mesh->normals,
  1037. &mesh->colorCount, &mesh->colors);
  1038. // Textured Triangles
  1039. count = mTombRaider.getMeshTexturedTriangleCount(index);
  1040. mesh->texturedTriangles.reserve(count); // little faster
  1041. for (i = 0; i < count; ++i)
  1042. {
  1043. r_tri = new texture_tri_t;
  1044. mTombRaider.getMeshTexturedTriangle(index, i,
  1045. r_tri->index,
  1046. r_tri->st,
  1047. &r_tri->texture,
  1048. &r_tri->transparency);
  1049. r_tri->texture += mTextureStart;
  1050. // Add to face vector
  1051. mesh->texturedTriangles.push_back(r_tri);
  1052. }
  1053. // Coloured Triangles
  1054. count = mTombRaider.getMeshColoredTriangleCount(index);
  1055. mesh->coloredTriangles.reserve(count); // little faster
  1056. for (i = 0; i < count; i++)
  1057. {
  1058. r_tri = new texture_tri_t;
  1059. mTombRaider.getMeshColoredTriangle(index, i,
  1060. r_tri->index,
  1061. color);
  1062. r_tri->st[0] = color[0];
  1063. r_tri->st[1] = color[1];
  1064. r_tri->st[2] = color[2];
  1065. r_tri->st[3] = color[3];
  1066. r_tri->st[4] = 1.0;
  1067. r_tri->st[5] = 1.0;
  1068. #ifdef EXPERIMENTAL
  1069. setupTextureColor(r_tri, color);
  1070. #else
  1071. r_tri->texture = white; // White texture
  1072. #endif
  1073. r_tri->transparency = 0;
  1074. // Add to face vector
  1075. mesh->coloredTriangles.push_back(r_tri);
  1076. }
  1077. // Textured Rectangles
  1078. count = mTombRaider.getMeshTexturedRectangleCount(index);
  1079. mesh->texturedRectangles.reserve(count*2); // little faster
  1080. for (i = 0; i < count; ++i)
  1081. {
  1082. mTombRaider.getMeshTexturedRectangle(index, i,
  1083. vertexIndices,
  1084. st,
  1085. &texture,
  1086. &transparency);
  1087. r_tri = new texture_tri_t;
  1088. for (j = 0; j < 3; ++j)
  1089. r_tri->index[j] = vertexIndices[j];
  1090. for (j = 0; j < 6; ++j)
  1091. r_tri->st[j] = st[j];
  1092. r_tri->texture = texture + mTextureStart;
  1093. r_tri->transparency = transparency;
  1094. // Add to face vector
  1095. mesh->texturedRectangles.push_back(r_tri);
  1096. r_tri = new texture_tri_t;
  1097. for (j = 3; j < 6; ++j)
  1098. r_tri->index[j-3] = vertexIndices[j];
  1099. for (j = 6; j < 12; ++j)
  1100. r_tri->st[j-6] = st[j];
  1101. r_tri->texture = texture + mTextureStart;
  1102. r_tri->transparency = transparency;
  1103. // Add to face vector
  1104. mesh->texturedRectangles.push_back(r_tri);
  1105. }
  1106. // Coloured Rectangles
  1107. count = mTombRaider.getMeshColoredRectangleCount(index);
  1108. mesh->coloredRectangles.reserve(count*2); // little faster
  1109. for (i = 0; i < count; ++i)
  1110. {
  1111. mTombRaider.getMeshColoredRectangle(index, i,
  1112. vertexIndices,
  1113. color);
  1114. r_tri = new texture_tri_t;
  1115. for (j = 0; j < 3; ++j)
  1116. r_tri->index[j] = vertexIndices[j];
  1117. //for (j = 0; j < 6; ++j)
  1118. // r_tri->st[j] = st[j];
  1119. r_tri->st[0] = color[0];
  1120. r_tri->st[1] = color[1];
  1121. r_tri->st[2] = color[2];
  1122. r_tri->st[3] = color[3];
  1123. r_tri->st[4] = 1.0;
  1124. r_tri->st[5] = 1.0;
  1125. #ifdef EXPERIMENTAL
  1126. //for (j = 6; j < 12; ++j)
  1127. // r_tri->st[j-6] = st[j];
  1128. setupTextureColor(r_tri, color);
  1129. #else
  1130. r_tri->texture = white; // White texture
  1131. #endif
  1132. r_tri->transparency = 0;
  1133. // Add to face vector
  1134. mesh->coloredRectangles.push_back(r_tri);
  1135. r_tri = new texture_tri_t;
  1136. for (j = 3; j < 6; ++j)
  1137. r_tri->index[j-3] = vertexIndices[j];
  1138. //for (j = 6; j < 12; ++j)
  1139. // r_tri->st[j-6] = st[j];
  1140. r_tri->st[0] = color[0];
  1141. r_tri->st[1] = color[1];
  1142. r_tri->st[2] = color[2];
  1143. r_tri->st[3] = color[3];
  1144. r_tri->st[4] = 1.0;
  1145. r_tri->st[5] = 1.0;
  1146. #ifdef EXPERIMENTAL
  1147. setupTextureColor(r_tri, color);
  1148. #else
  1149. r_tri->texture = white; // White texture
  1150. #endif
  1151. r_tri->transparency = 0;
  1152. // Add to face vector
  1153. mesh->coloredRectangles.push_back(r_tri);
  1154. }
  1155. // Sort faces by texture
  1156. std::sort(mesh->texturedTriangles.begin(), mesh->texturedTriangles.end(), compareFaceTextureId);
  1157. std::sort(mesh->coloredTriangles.begin(), mesh->coloredTriangles.end(), compareFaceTextureId);
  1158. std::sort(mesh->texturedRectangles.begin(), mesh->texturedRectangles.end(), compareFaceTextureId);
  1159. std::sort(mesh->coloredRectangles.begin(), mesh->coloredRectangles.end(), compareFaceTextureId);
  1160. getWorld().addMesh(mesh);
  1161. //printf(".");
  1162. //fflush(stdout);
  1163. }
  1164. printf("Done! Found %d meshes.\n", mTombRaider.getMeshCount());
  1165. }
  1166. void Game::processRooms()
  1167. {
  1168. printf("Processing rooms: ");
  1169. for (int index = 0; index < mTombRaider.NumRooms(); index++) {
  1170. unsigned int i, j, count;
  1171. room_mesh_t *r_mesh = NULL;
  1172. RenderRoom *rRoom = NULL;
  1173. Matrix transform;
  1174. if (!mTombRaider.isRoomValid(index))
  1175. {
  1176. getConsole().print("WARNING: Handling invalid vertex array in room");
  1177. getWorld().addRoom(0x0);
  1178. mRender->addRoom(0x0);
  1179. //printf("x");
  1180. //fflush(stdout);
  1181. return;
  1182. }
  1183. rRoom = new RenderRoom();
  1184. r_mesh = new room_mesh_t;
  1185. r_mesh->id = index;
  1186. mTombRaider.getRoomInfo(index, &r_mesh->flags, r_mesh->pos,
  1187. r_mesh->bbox_min, r_mesh->bbox_max);
  1188. // Adjust positioning for OR world coord translation
  1189. r_mesh->bbox_min[0] += r_mesh->pos[0];
  1190. r_mesh->bbox_max[0] += r_mesh->pos[0];
  1191. r_mesh->bbox_min[2] += r_mesh->pos[2];
  1192. r_mesh->bbox_max[2] += r_mesh->pos[2];
  1193. // Mongoose 2002.04.03, Setup 3d transform
  1194. transform.setIdentity();
  1195. transform.translate(r_mesh->pos);
  1196. // Setup portals
  1197. float portalVertices[12];
  1198. count = mTombRaider.getRoomPortalCount(index);
  1199. //! \fixme OR wrongly uses a cached adj room list for rendering vis
  1200. r_mesh->adjacentRooms.reserve(count + 1);
  1201. // Current room is always first
  1202. r_mesh->adjacentRooms.push_back(index);
  1203. for (i = 0; i < count; ++i)
  1204. {
  1205. portal_t *portal = new portal_t;
  1206. mTombRaider.getRoomPortal(index, i,
  1207. &portal->adjoining_room, portal->normal,
  1208. portalVertices);
  1209. for (j = 0; j < 4; ++j)
  1210. {
  1211. portal->vertices[j][0] = portalVertices[j*3];
  1212. portal->vertices[j][1] = portalVertices[j*3+1];
  1213. portal->vertices[j][2] = portalVertices[j*3+2];
  1214. // Relative coors in vis portals
  1215. transform.multiply3v(portal->vertices[j], portal->vertices[j]);
  1216. }
  1217. r_mesh->adjacentRooms.push_back(portal->adjoining_room);
  1218. r_mesh->portals.push_back(portal);
  1219. }
  1220. // Physics/gameplay use /////////////////////////////
  1221. //! \fixme Use more of sector structure, boxes, and floordata
  1222. // List of sectors in this room
  1223. unsigned int sectorFlags;
  1224. int floorDataIndex, boxIndex, roomBelow, roomAbove;
  1225. count = mTombRaider.getRoomSectorCount(index, &r_mesh->numZSectors,
  1226. &r_mesh->numXSectors);
  1227. r_mesh->sectors.reserve(count);
  1228. for (i = 0; i < count; ++i)
  1229. {
  1230. sector_t *sector = new sector_t;
  1231. mTombRaider.getRoomSector(index, i, &sectorFlags,
  1232. &sector->ceiling, &sector->floor,
  1233. &floorDataIndex, &boxIndex, &roomBelow,
  1234. &roomAbove);
  1235. if (sectorFlags & tombraiderSector_wall)
  1236. {
  1237. sector->wall = true;
  1238. }
  1239. else
  1240. {
  1241. sector->wall = false;
  1242. }
  1243. r_mesh->sectors.push_back(sector);
  1244. }
  1245. // Setup collision boxes ( Should use sectors, but this is a test )
  1246. count = mTombRaider.getRoomBoxCount(index);
  1247. r_mesh->boxes.reserve(count);
  1248. //! fixme Only to be done only on room[0]? I don't think so...
  1249. for (i = 0; !index && i < count; ++i)
  1250. {
  1251. box_t *box = new box_t;
  1252. mTombRaider.getRoomBox(index, i,
  1253. box->a.pos, box->b.pos, box->c.pos, box->d.pos);
  1254. r_mesh->boxes.push_back(box);
  1255. }
  1256. // Setup room lights /////////////////////////////////////
  1257. unsigned int lightFlags, lightType;
  1258. count = mTombRaider.getRoomLightCount(index);
  1259. rRoom->lights.reserve(count);
  1260. for (i = 0; i < count; ++i)
  1261. {
  1262. Light *light = new Light();
  1263. mTombRaider.getRoomLight(index, i,
  1264. light->mPos, light->mColor, light->mDir,
  1265. &light->mAtt, &light->mCutoff,
  1266. &lightType, &lightFlags);
  1267. switch (lightType)
  1268. {
  1269. case tombraiderLight_typeDirectional:
  1270. light->mType = Light::typeDirectional;
  1271. break;
  1272. case tombraiderLight_typeSpot:
  1273. light->mType = Light::typeSpot;
  1274. break;
  1275. case tombraiderLight_typePoint:
  1276. default:
  1277. light->mType = Light::typePoint;
  1278. }
  1279. rRoom->lights.push_back(light);
  1280. }
  1281. // Room geometery //////////////////////////////////
  1282. //#define EXPERIMENTAL_UNFIFIED_ROOM_GEOMETERY
  1283. #ifdef EXPERIMENTAL_UNFIFIED_ROOM_GEOMETERY
  1284. unsigned int vertexCount, normalCount, colorCount, triCount;
  1285. vec_t *vertexArray;
  1286. vec_t *normalArray;
  1287. vec_t *colorArray;
  1288. unsigned int *indices, *flags;
  1289. float *texCoords;
  1290. int *textures;
  1291. mTombRaider.getRoomVertexArrays(index,
  1292. &vertexCount, &vertexArray,
  1293. &normalCount, &normalArray,
  1294. &colorCount, &colorArray);
  1295. rRoom->mesh.bufferVertexArray(vertexCount, (vec_t *)vertexArray);
  1296. rRoom->mesh.bufferNormalArray(normalCount, (vec_t *)normalArray);
  1297. rRoom->mesh.bufferColorArray(vertexCount, (vec_t *)colorArray);
  1298. mTombRaider.getRoomTriangles(index, mTextureStart,
  1299. &triCount, &indices, &texCoords, &textures,
  1300. &flags);
  1301. rRoom->mesh.bufferTriangles(triCount, indices, texCoords, textures, flags);
  1302. #else
  1303. float rgba[4];
  1304. float xyz[3];
  1305. count = mTombRaider.getRoomVertexCount(index);
  1306. rRoom->mesh.allocateVertices(count);
  1307. rRoom->mesh.allocateNormals(0); // count
  1308. rRoom->mesh.allocateColors(count);
  1309. for (i = 0; i < count; ++i)
  1310. {
  1311. mTombRaider.getRoomVertex(index, i, xyz, rgba);
  1312. rRoom->mesh.setVertex(i, xyz[0], xyz[1], xyz[2]);
  1313. rRoom->mesh.setColor(i, rgba);
  1314. }
  1315. // Mongoose 2002.06.09, Setup allocation of meshes and polygons
  1316. // Counters ( Textured polygon lists are allocated per texture)
  1317. // ( Textures are mapped to these meshes )
  1318. int triangle_counter[TextureLimit];
  1319. int triangle_counter_alpha[TextureLimit];
  1320. int rectangle_counter[TextureLimit];
  1321. int rectangle_counter_alpha[TextureLimit];
  1322. int tris_mesh_map[TextureLimit];
  1323. int rect_mesh_map[TextureLimit];
  1324. for (i = 0; i < TextureLimit; ++i)
  1325. {
  1326. triangle_counter[i] = 0;
  1327. triangle_counter_alpha[i] = 0;
  1328. rectangle_counter[i] = 0;
  1329. rectangle_counter_alpha[i] = 0;
  1330. tris_mesh_map[i] = -1;
  1331. rect_mesh_map[i] = -1;
  1332. }
  1333. unsigned int numTris = 0;
  1334. unsigned int numQuads = 0;
  1335. int texture;
  1336. unsigned int r, t, q, v, flags;
  1337. unsigned int indices[4];
  1338. float texCoords[8];
  1339. count = mTombRaider.getRoomTriangleCount(index);
  1340. // Mongoose 2002.08.15, Presort by alpha and texture and setup mapping
  1341. for (t = 0; t < count; ++t)
  1342. {
  1343. mTombRaider.getRoomTriangle(index, t,
  1344. indices, texCoords, &texture, &flags);
  1345. texture += mTextureStart;
  1346. if (texture > (int)TextureLimit)
  1347. {
  1348. getConsole().print("Handling bad room[%i].tris[%i].texture = %i",
  1349. index, t, texture);
  1350. texture = TextureLimit - 1;
  1351. }
  1352. // Counters set up polygon allocation
  1353. if (flags & tombraiderFace_Alpha ||
  1354. flags & tombraiderFace_PartialAlpha)
  1355. {
  1356. triangle_counter_alpha[texture] += 1;
  1357. }
  1358. else
  1359. {
  1360. triangle_counter[texture] += 1;
  1361. }
  1362. // Counter sets up texture id to mesh id mapping
  1363. if (tris_mesh_map[texture] == -1)
  1364. {
  1365. tris_mesh_map[texture] = ++numTris;
  1366. }
  1367. }
  1368. count = mTombRaider.getRoomRectangleCount(index);
  1369. for (r = 0; r < count; ++r)
  1370. {
  1371. mTombRaider.getRoomRectangle(index, r,
  1372. indices, texCoords, &texture, &flags);
  1373. texture += mTextureStart;
  1374. if (texture > (int)TextureLimit)
  1375. {
  1376. getConsole().print("Handling bad room[%i].quad[%i].texture = %i",
  1377. index, r, texture);
  1378. texture = TextureLimit - 1;
  1379. }
  1380. if (flags & tombraiderFace_Alpha ||
  1381. flags & tombraiderFace_PartialAlpha)
  1382. {
  1383. rectangle_counter_alpha[texture] += 1;
  1384. }
  1385. else
  1386. {
  1387. rectangle_counter[texture] += 1;
  1388. }
  1389. if (rect_mesh_map[texture] == -1)
  1390. {
  1391. rect_mesh_map[texture] = ++numQuads;
  1392. }
  1393. }
  1394. // Allocate indexed polygon meshes
  1395. rRoom->mesh.allocateTriangles(numTris);
  1396. rRoom->mesh.allocateRectangles(numQuads);
  1397. for (i = 0, j = 0; i < TextureLimit; ++i)
  1398. {
  1399. if (tris_mesh_map[i] > 0)
  1400. {
  1401. j = tris_mesh_map[i] - 1;
  1402. t = triangle_counter[i];
  1403. rRoom->mesh.mTris[j].texture = i;
  1404. #ifdef MULTITEXTURE
  1405. rRoom->mesh.mTris[j].bumpmap = gMapTex2Bump[i];
  1406. #endif
  1407. rRoom->mesh.mTris[j].cnum_triangles = 0;
  1408. rRoom->mesh.mTris[j].num_triangles = 0;
  1409. rRoom->mesh.mTris[j].cnum_alpha_triangles = 0;
  1410. rRoom->mesh.mTris[j].num_alpha_triangles = 0;
  1411. rRoom->mesh.mTris[j].triangles = 0x0;
  1412. rRoom->mesh.mTris[j].alpha_triangles = 0x0;
  1413. rRoom->mesh.mTris[j].texcoors = 0x0;
  1414. rRoom->mesh.mTris[j].texcoors2 = 0x0;
  1415. if (t > 0)
  1416. {
  1417. rRoom->mesh.mTris[j].num_triangles = t;
  1418. rRoom->mesh.mTris[j].triangles = new unsigned int[t*3];
  1419. rRoom->mesh.mTris[j].num_texcoors = t * 3;
  1420. rRoom->mesh.mTris[j].texcoors = new vec2_t[t * 3];
  1421. }
  1422. t = triangle_counter_alpha[i];
  1423. if (t > 0)
  1424. {
  1425. rRoom->mesh.mTris[j].num_alpha_triangles = t;
  1426. rRoom->mesh.mTris[j].alpha_triangles = new unsigned int[t*3];
  1427. rRoom->mesh.mTris[j].num_texcoors2 = t * 3;
  1428. rRoom->mesh.mTris[j].texcoors2 = new vec2_t[t * 3];
  1429. }
  1430. }
  1431. ///////////////////////////////////////////
  1432. if (rect_mesh_map[i] > 0)
  1433. {
  1434. j = rect_mesh_map[i] - 1;
  1435. r = rectangle_counter[i];
  1436. rRoom->mesh.mQuads[j].texture = i;
  1437. #ifdef MULTITEXTURE
  1438. rRoom->mesh.mQuads[j].bumpmap = gMapTex2Bump[i];
  1439. #endif
  1440. rRoom->mesh.mQuads[j].cnum_quads = 0;
  1441. rRoom->mesh.mQuads[j].num_quads = 0;
  1442. rRoom->mesh.mQuads[j].cnum_alpha_quads = 0;
  1443. rRoom->mesh.mQuads[j].num_alpha_quads = 0;
  1444. rRoom->mesh.mQuads[j].quads = 0x0;
  1445. rRoom->mesh.mQuads[j].alpha_quads = 0x0;
  1446. rRoom->mesh.mQuads[j].texcoors = 0x0;
  1447. rRoom->mesh.mQuads[j].texcoors2 = 0x0;
  1448. if (r > 0)
  1449. {
  1450. rRoom->mesh.mQuads[j].num_quads = r;
  1451. rRoom->mesh.mQuads[j].quads = new unsigned int[r*4];
  1452. rRoom->mesh.mQuads[j].num_texcoors = r * 4;
  1453. rRoom->mesh.mQuads[j].texcoors = new vec2_t[r * 4];
  1454. }
  1455. r = rectangle_counter_alpha[i];
  1456. if (r > 0)
  1457. {
  1458. rRoom->mesh.mQuads[j].num_alpha_quads = r;
  1459. rRoom->mesh.mQuads[j].alpha_quads = new unsigned int[r*4];
  1460. rRoom->mesh.mQuads[j].num_texcoors2 = r * 4;
  1461. rRoom->mesh.mQuads[j].texcoors2 = new vec2_t[r * 4];
  1462. }
  1463. }
  1464. }
  1465. // Generate textured triangles
  1466. count = mTombRaider.getRoomTriangleCount(index);
  1467. for (t = 0; t < count; ++t)
  1468. {
  1469. mTombRaider.getRoomTriangle(index, t,
  1470. indices, texCoords, &texture, &flags);
  1471. // Adjust texture id using mTextureStart to map into
  1472. // correct textures
  1473. texture += mTextureStart;
  1474. j = tris_mesh_map[texture] - 1;
  1475. // Setup per vertex
  1476. for (i = 0; i < 3; ++i)
  1477. {
  1478. // Get vertex index {(0, a), (1, b), (2, c)}
  1479. v = indices[i];
  1480. if ((flags & tombraiderFace_Alpha ||
  1481. flags & tombraiderFace_PartialAlpha) &&
  1482. rRoom->mesh.mTris[j].num_alpha_triangles > 0)
  1483. {
  1484. q = rRoom->mesh.mTris[j].cnum_alpha_triangles*3+i;
  1485. rRoom->mesh.mTris[j].alpha_triangles[q] = v;
  1486. rRoom->mesh.mTris[j].texcoors2[q][0] = texCoords[i*2];
  1487. rRoom->mesh.mTris[j].texcoors2[q][1] = texCoords[i*2+1];
  1488. }
  1489. else if (rRoom->mesh.mTris[j].num_triangles > 0)
  1490. {
  1491. q = rRoom->mesh.mTris[j].cnum_triangles*3+i;
  1492. rRoom->mesh.mTris[j].triangles[q] = v;
  1493. rRoom->mesh.mTris[j].texcoors[q][0] = texCoords[i*2];
  1494. rRoom->mesh.mTris[j].texcoors[q][1] = texCoords[i*2+1];
  1495. }
  1496. // Partial alpha hack
  1497. if (flags & tombraiderFace_PartialAlpha)
  1498. {
  1499. //rRoom->mesh.colors[v].rgba[3] = 0.45;
  1500. }
  1501. }
  1502. if (flags & tombraiderFace_Alpha ||
  1503. flags & tombraiderFace_PartialAlpha)
  1504. {
  1505. rRoom->mesh.mTris[j].cnum_alpha_triangles++;
  1506. }
  1507. else
  1508. {
  1509. rRoom->mesh.mTris[j].cnum_triangles++;
  1510. }
  1511. }
  1512. // Generate textured quads
  1513. count = mTombRaider.getRoomRectangleCount(index);
  1514. for (r = 0; r < count; ++r)
  1515. {
  1516. mTombRaider.getRoomRectangle(index, r,
  1517. indices, texCoords, &texture, &flags);
  1518. // Adjust texture id using mTextureStart to map into
  1519. // correct textures
  1520. texture += mTextureStart;
  1521. if (texture > (int)TextureLimit)
  1522. {
  1523. texture = TextureLimit - 1;
  1524. }
  1525. j = rect_mesh_map[texture] - 1;
  1526. if (rRoom->mesh.mQuads[j].num_quads <= 0 &&
  1527. rRoom->mesh.mQuads[j].num_alpha_quads <= 0)
  1528. continue;
  1529. // Setup per vertex
  1530. for (i = 0; i < 4; ++i)
  1531. {
  1532. // Get vertex index {(0, a), (1, b), (2, c), (3, d)}
  1533. v = indices[i];
  1534. if ((flags & tombraiderFace_Alpha ||
  1535. flags & tombraiderFace_PartialAlpha) &&
  1536. rRoom->mesh.mQuads[j].num_alpha_quads > 0)
  1537. {
  1538. q = rRoom->mesh.mQuads[j].cnum_alpha_quads*4+i;
  1539. rRoom->mesh.mQuads[j].alpha_quads[q] = v;
  1540. rRoom->mesh.mQuads[j].texcoors2[q][0] = texCoords[i*2];
  1541. rRoom->mesh.mQuads[j].texcoors2[q][1] = texCoords[i*2+1];
  1542. }
  1543. else if (rRoom->mesh.mQuads[j].num_quads > 0)
  1544. {
  1545. q = rRoom->mesh.mQuads[j].cnum_quads*4+i;
  1546. rRoom->mesh.mQuads[j].quads[q] = v;
  1547. rRoom->mesh.mQuads[j].texcoors[q][0] = texCoords[i*2];
  1548. rRoom->mesh.mQuads[j].texcoors[q][1] = texCoords[i*2+1];
  1549. }
  1550. // Partial alpha hack
  1551. if (flags & tombraiderFace_PartialAlpha)
  1552. {
  1553. //rRoom->mesh.colors[v].rgba[3] = 0.45;
  1554. }
  1555. }
  1556. if (flags & tombraiderFace_Alpha ||
  1557. flags & tombraiderFace_PartialAlpha)
  1558. {
  1559. rRoom->mesh.mQuads[j].cnum_alpha_quads++;
  1560. }
  1561. else
  1562. {
  1563. rRoom->mesh.mQuads[j].cnum_quads++;
  1564. }
  1565. }
  1566. #endif
  1567. // Room models
  1568. count = mTombRaider.getRoomModelCount(index);
  1569. r_mesh->models.reserve(count);
  1570. for (i = 0; i < count; ++i)
  1571. {
  1572. static_model_t *model = new static_model_t;
  1573. mTombRaider.getRoomModel(index, i,
  1574. &model->index, model->pos, &model->yaw);
  1575. r_mesh->models.push_back(model);
  1576. }
  1577. // Room sprites
  1578. float spriteVertices[12];
  1579. float spriteTexCoords[8];
  1580. count = mTombRaider.getRoomSpriteCount(index);
  1581. r_mesh->sprites.reserve(count);
  1582. for (i = 0; i < count; ++i)
  1583. {
  1584. sprite_t *sprite = new sprite_t;
  1585. mTombRaider.getRoomSprite(index, i,
  1586. 10.0f, &sprite->texture, sprite->pos,
  1587. spriteVertices, spriteTexCoords);
  1588. sprite->texture += mTextureStart; // OpenRaider preloads some textures
  1589. sprite->vertex[0].pos[0] = spriteVertices[0];
  1590. sprite->vertex[0].pos[1] = spriteVertices[1];
  1591. sprite->vertex[0].pos[2] = spriteVertices[2];
  1592. sprite->vertex[1].pos[0] = spriteVertices[3];
  1593. sprite->vertex[1].pos[1] = spriteVertices[4];
  1594. sprite->vertex[1].pos[2] = spriteVertices[5];
  1595. sprite->vertex[2].pos[0] = spriteVertices[6];
  1596. sprite->vertex[2].pos[1] = spriteVertices[7];
  1597. sprite->vertex[2].pos[2] = spriteVertices[8];
  1598. sprite->vertex[3].pos[0] = spriteVertices[9];
  1599. sprite->vertex[3].pos[1] = spriteVertices[10];
  1600. sprite->vertex[3].pos[2] = spriteVertices[11];
  1601. sprite->texel[0].st[0] = spriteTexCoords[0];
  1602. sprite->texel[0].st[1] = spriteTexCoords[1];
  1603. sprite->texel[1].st[0] = spriteTexCoords[2];
  1604. sprite->texel[1].st[1] = spriteTexCoords[3];
  1605. sprite->texel[2].st[0] = spriteTexCoords[4];
  1606. sprite->texel[2].st[1] = spriteTexCoords[5];
  1607. sprite->texel[3].st[0] = spriteTexCoords[6];
  1608. sprite->texel[3].st[1] = spriteTexCoords[7];
  1609. r_mesh->sprites.push_back(sprite);
  1610. }
  1611. getWorld().addRoom(r_mesh);
  1612. rRoom->room = r_mesh;
  1613. mRender->addRoom(rRoom);
  1614. //printf(".");
  1615. //fflush(stdout);
  1616. }
  1617. printf("Done! Found %d rooms.\n", mTombRaider.NumRooms());
  1618. }