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

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