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 51KB

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