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

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