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.

OpenRaider.cpp 95KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434
  1. /*!
  2. * \file include/OpenRaider.h
  3. * \brief Main Game Singleton
  4. *
  5. * \author Mongoose
  6. */
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <stdio.h>
  10. #include <stdarg.h>
  11. #include <unistd.h>
  12. #include <math.h>
  13. #include <sys/types.h>
  14. #include <dirent.h>
  15. #include "World.h"
  16. #include "SkeletalModel.h"
  17. #include "utils/time.h"
  18. #include "OpenRaider.h"
  19. #include "games/TombRaider1.h" // tmp stop-gap
  20. enum OpenRaiderText { textConsole = 2, textMenu = 3, textOutput = 4 };
  21. const unsigned int TextureLimit = 24;
  22. const float TexelScale = 256.0f;
  23. World gWorld;
  24. std::map<int, int> gMapTex2Bump;
  25. Vector <unsigned int> gColorTextureHACK;
  26. int gTextureOffset;
  27. entity_t *LARA = 0x0;
  28. skeletal_model_t *gLaraModel = 0x0;
  29. char *gFontFilename = 0x0;
  30. ////////////////////////////////////////////////////////////
  31. // Constructors
  32. ////////////////////////////////////////////////////////////
  33. OpenRaider *OpenRaider::mInstance = 0x0;
  34. OpenRaider *OpenRaider::Instance()
  35. {
  36. if (mInstance == 0x0)
  37. {
  38. mInstance = new OpenRaider();
  39. }
  40. return mInstance;
  41. }
  42. void killOpenRaiderSingleton() {
  43. printf("Shutting down Game...\n");
  44. // Requires public deconstructor
  45. delete OpenRaider::Instance();
  46. printf("\nThanks for testing %s\n", VERSION);
  47. printf("Build date: %s @ %s\n", __DATE__, __TIME__);
  48. printf("Build host: %s\n", BUILD_HOST);
  49. printf("Web site : http://github.com/xythobuz/OpenRaider\n");
  50. printf("Contact : xythobuz@xythobuz.de\n");
  51. }
  52. OpenRaider::OpenRaider() : SDLSystem()
  53. {
  54. m_pakDir = 0x0;
  55. m_audioDir = 0x0;
  56. m_homeDir = 0x0;
  57. m_mouseX = 2.5;
  58. m_mouseY = 0.5;
  59. m_texOffset = 0;
  60. mLevelTextureOffset = 0;
  61. m_testSFX = -1;
  62. mText = NULL;
  63. m_flags = 0;
  64. m_mapName[0] = '\0';
  65. /*! \todo Replace numbers with enum modes.
  66. * Only do this when you know the amount of commands + 1 (0 reserved)
  67. */
  68. mMode[addCommandMode("[OpenRaider.Engine]")] = 2;
  69. mMode[addCommandMode("[Video.OpenGL]")] = 0;
  70. mMode[addCommandMode("[Audio.OpenAL]")] = 1;
  71. mMode[addCommandMode("[OpenRaider.Console]")] = 4;
  72. mMode[addCommandMode("[Input.Mouse]")] = 3;
  73. }
  74. OpenRaider::~OpenRaider() {
  75. /*! \fixme GL call to critical section,
  76. * needs mutex really -- Mongoose 2002.01.02
  77. */
  78. m_render.setMode(Render::modeDisabled);
  79. //sleep(1);
  80. printf("Removing World...\n");
  81. gWorld.destroy();
  82. printf("Cleaning up...\n");
  83. for (mMapList.start(); mMapList.forward(); mMapList.next()) {
  84. if (mMapList.current())
  85. delete [] mMapList.current();
  86. }
  87. for (mMusicList.start(); mMusicList.forward(); mMusicList.next()) {
  88. if (mMusicList.current())
  89. delete [] mMusicList.current();
  90. }
  91. if (m_pakDir)
  92. delete [] m_pakDir;
  93. if (m_audioDir)
  94. delete [] m_audioDir;
  95. if (m_homeDir)
  96. delete [] m_homeDir;
  97. if (gFontFilename)
  98. delete [] gFontFilename;
  99. }
  100. ////////////////////////////////////////////////////////////
  101. // Public Accessors
  102. ////////////////////////////////////////////////////////////
  103. ////////////////////////////////////////////////////////////
  104. // Public Mutators
  105. ////////////////////////////////////////////////////////////
  106. void eventAnimTest(int anim)
  107. {
  108. if (LARA)
  109. {
  110. SkeletalModel *mdl = static_cast<SkeletalModel *>(LARA->tmpHook);
  111. if (mdl)
  112. {
  113. mdl->setAnimation(anim);
  114. }
  115. }
  116. }
  117. void percent_callback(int p) {
  118. OpenRaider &game = *OpenRaider::Instance();
  119. switch (p) {
  120. case 10:
  121. game.print(false, "Level textures loaded");
  122. break;
  123. default:
  124. game.print(false, "Level pak %i%% loaded", p);
  125. break;
  126. }
  127. }
  128. void openraider_warning(const char *func_name, const char *warning,
  129. const char *filename, int line)
  130. {
  131. printf("%s> WARNING %s %s:%i\n", func_name, warning, filename, line);
  132. }
  133. void openraider_error(const char *func_name, const char *error,
  134. const char *filename, int line)
  135. {
  136. printf("%s> ERROR %s %s:%i\n", func_name, error, filename, line);
  137. }
  138. void OpenRaider::handleMouseMotionEvent(float x, float y)
  139. {
  140. if (x > 0)
  141. {
  142. while (x-- > 0) // Tried to fix very slow camera movements
  143. m_camera.command(CAMERA_ROTATE_RIGHT);
  144. if (LARA)
  145. {
  146. switch (LARA->moveType)
  147. {
  148. case worldMoveType_swim:
  149. case worldMoveType_fly:
  150. case worldMoveType_noClipping:
  151. eventAnimTest(TR_ANIAMTION_SWIM_R);
  152. break;
  153. case worldMoveType_walk:
  154. case worldMoveType_walkNoSwim:
  155. eventAnimTest(TR_ANIAMTION_TURN_L); // TURN left always for now
  156. break;
  157. }
  158. LARA->moving = true;
  159. }
  160. }
  161. else if (x < 0)
  162. {
  163. while (x++ < 0) // Tried to fix very slow camera movements
  164. m_camera.command(CAMERA_ROTATE_LEFT);
  165. if (LARA)
  166. {
  167. switch (LARA->moveType)
  168. {
  169. case worldMoveType_swim:
  170. case worldMoveType_fly:
  171. case worldMoveType_noClipping:
  172. eventAnimTest(TR_ANIAMTION_SWIM_L);
  173. break;
  174. case worldMoveType_walk:
  175. case worldMoveType_walkNoSwim:
  176. eventAnimTest(TR_ANIAMTION_TURN_L);
  177. break;
  178. }
  179. LARA->moving = true;
  180. }
  181. }
  182. if (y > 0)
  183. while (y-- > 0) // Tried to fix very slow camera movements
  184. m_camera.command(CAMERA_ROTATE_UP);
  185. else if (y < 0)
  186. while (y++ < 0) // Tried to fix very slow camera movements
  187. m_camera.command(CAMERA_ROTATE_DOWN);
  188. if (LARA)
  189. {
  190. LARA->angles[1] = m_camera.getRadianYaw();
  191. LARA->angles[2] = m_camera.getRadianPitch();
  192. }
  193. }
  194. void OpenRaider::handleKeyReleaseEvent(unsigned int key, unsigned int mod)
  195. {
  196. }
  197. void OpenRaider::handleBoundKeyPressEvent(unsigned int key)
  198. {
  199. switch (key)
  200. {
  201. case OpenRaiderKey_jump:
  202. m_camera.command(CAMERA_MOVE_UP);
  203. if (LARA)
  204. {
  205. LARA->moving = true;
  206. }
  207. break;
  208. case OpenRaiderKey_crouch:
  209. m_camera.command(CAMERA_MOVE_DOWN);
  210. if (LARA)
  211. {
  212. LARA->moving = true;
  213. }
  214. break;
  215. case OpenRaiderKey_forward:
  216. gWorld.moveEntity(LARA, 'f');
  217. if (LARA && LARA->moving)
  218. {
  219. switch (LARA->moveType)
  220. {
  221. case worldMoveType_swim:
  222. case worldMoveType_fly:
  223. case worldMoveType_noClipping:
  224. eventAnimTest(TR_ANIAMTION_SWIM);
  225. break;
  226. case worldMoveType_walk:
  227. case worldMoveType_walkNoSwim:
  228. eventAnimTest(TR_ANIAMTION_RUN);
  229. break;
  230. }
  231. }
  232. else if (LARA)
  233. {
  234. switch (LARA->moveType)
  235. {
  236. case worldMoveType_swim:
  237. case worldMoveType_fly:
  238. case worldMoveType_noClipping:
  239. eventAnimTest(TR_ANIAMTION_SWIM_IDLE);
  240. break;
  241. case worldMoveType_walk:
  242. case worldMoveType_walkNoSwim:
  243. eventAnimTest(TR_ANIAMTION_HIT_WALL_FRONT);
  244. break;
  245. }
  246. }
  247. else
  248. {
  249. m_camera.command(CAMERA_MOVE_FORWARD);
  250. }
  251. break;
  252. case OpenRaiderKey_backward:
  253. gWorld.moveEntity(LARA, 'b');
  254. if (LARA && LARA->moving)
  255. {
  256. switch (LARA->moveType)
  257. {
  258. case worldMoveType_swim:
  259. case worldMoveType_fly:
  260. case worldMoveType_noClipping:
  261. eventAnimTest(TR_ANIAMTION_SWIM);
  262. break;
  263. case worldMoveType_walk:
  264. case worldMoveType_walkNoSwim:
  265. eventAnimTest(TR_ANIAMTION_RUN);
  266. break;
  267. }
  268. }
  269. break;
  270. case OpenRaiderKey_left:
  271. gWorld.moveEntity(LARA, 'l');
  272. if (LARA && LARA->moving)
  273. {
  274. switch (LARA->moveType)
  275. {
  276. case worldMoveType_swim:
  277. case worldMoveType_fly:
  278. case worldMoveType_noClipping:
  279. eventAnimTest(TR_ANIAMTION_SWIM);
  280. break;
  281. case worldMoveType_walk:
  282. case worldMoveType_walkNoSwim:
  283. eventAnimTest(TR_ANIAMTION_RUN);
  284. break;
  285. }
  286. }
  287. else if (!LARA)
  288. {
  289. m_camera.command(CAMERA_MOVE_LEFT);
  290. }
  291. break;
  292. case OpenRaiderKey_right:
  293. gWorld.moveEntity(LARA, 'r');
  294. if (LARA && LARA->moving)
  295. {
  296. switch (LARA->moveType)
  297. {
  298. case worldMoveType_swim:
  299. case worldMoveType_fly:
  300. case worldMoveType_noClipping:
  301. eventAnimTest(TR_ANIAMTION_SWIM);
  302. break;
  303. case worldMoveType_walk:
  304. case worldMoveType_walkNoSwim:
  305. eventAnimTest(TR_ANIAMTION_RUN);
  306. break;
  307. }
  308. }
  309. else if (!LARA)
  310. {
  311. m_camera.command(CAMERA_MOVE_RIGHT);
  312. }
  313. break;
  314. case OpenRaiderKey_panRight:
  315. m_camera.command(CAMERA_ROTATE_RIGHT);
  316. break;
  317. case OpenRaiderKey_panLeft:
  318. m_camera.command(CAMERA_ROTATE_LEFT);
  319. break;
  320. case OpenRaiderKey_tiltDown:
  321. m_camera.command(CAMERA_ROTATE_DOWN);
  322. break;
  323. case OpenRaiderKey_tiltUp:
  324. m_camera.command(CAMERA_ROTATE_UP);
  325. break;
  326. }
  327. }
  328. void OpenRaider::handleBoundKeyReleaseEvent(unsigned int key)
  329. {
  330. switch (key)
  331. {
  332. case '`': // Temp hack also until console is rolled back
  333. //i = 2;
  334. if (mConsoleMode)
  335. {
  336. //buffer[0] = '>';
  337. //buffer[1] = ' ';
  338. //buffer[2] = 0;
  339. mText->setActive(textConsole, true);
  340. }
  341. else
  342. {
  343. mText->setActive(textConsole, false);
  344. //buffer[0] = 0;
  345. }
  346. break;
  347. case OpenRaiderKey_forward:
  348. case OpenRaiderKey_backward:
  349. case OpenRaiderKey_right:
  350. case OpenRaiderKey_left:
  351. if (LARA)
  352. {
  353. LARA->moving = false;
  354. }
  355. }
  356. }
  357. void OpenRaider::handleConsoleKeyPressEvent(unsigned int key,unsigned int mod)
  358. {
  359. static char lastCmd[64] = "2 ";
  360. static unsigned int i = 0;
  361. char *buffer;
  362. unsigned int len;
  363. // Cheap console test
  364. len = mText->GetStringLen(textConsole);
  365. buffer = mText->GetBuffer(textConsole);
  366. //printf("- 0x%x\n", key);
  367. if (key == mConsoleKey)
  368. {
  369. i = 2;
  370. if (mConsoleMode)
  371. {
  372. buffer[0] = '>';
  373. buffer[1] = ' ';
  374. buffer[2] = 0;
  375. mText->setActive(textConsole, true);
  376. }
  377. else
  378. {
  379. mText->setActive(textConsole, false);
  380. buffer[0] = 0;
  381. }
  382. }
  383. else if (mConsoleMode && len > i+1)
  384. {
  385. switch (key)
  386. {
  387. case SYS_KEY_UP:
  388. i = lastCmd[0];
  389. lastCmd[0] = '>';
  390. mText->SetString(textConsole, "%s", lastCmd);
  391. break;
  392. case 0:
  393. break;
  394. case '\b':
  395. if (i > 2)
  396. {
  397. buffer[--i] = 0;
  398. }
  399. break;
  400. case '\r':
  401. case '\n':
  402. strncpy(lastCmd, buffer, 63);
  403. lastCmd[0] = (char)i;
  404. command("[OpenRaider.Console]");
  405. command(buffer);
  406. i = 2;
  407. buffer[0] = '>';
  408. buffer[1] = ' ';
  409. buffer[2] = 0;
  410. break;
  411. default:
  412. // Workaround until proper SDL2 text input is used
  413. if ((key >= 1073742049) && (key <= 1073742051))
  414. break;
  415. if (mod & (SYS_MOD_KEY_RSHIFT | SYS_MOD_KEY_LSHIFT) &&
  416. key > 96 && key < 123)
  417. {
  418. buffer[i++] = (char)(key - 32);
  419. }
  420. else
  421. {
  422. if (mod & (SYS_MOD_KEY_RSHIFT | SYS_MOD_KEY_LSHIFT))
  423. {
  424. if (key == '-')
  425. key = '_';
  426. }
  427. buffer[i++] = (char)key;
  428. }
  429. buffer[i] = 0;
  430. }
  431. }
  432. }
  433. void OpenRaider::menuMapListMove(char dir, bool show) {
  434. if (dir == 'f') {
  435. mMapList.next();
  436. if (!mMapList.forward())
  437. mMapList.start();
  438. } else if (dir == 'b') {
  439. mMapList.prev();
  440. if (!mMapList.backward())
  441. mMapList.finish();
  442. } else if (dir == 'n') {
  443. size_t slashPos = strcspn(mMapList.current(), "/");
  444. if (slashPos < strlen(mMapList.current())) {
  445. char *dirName = new char[slashPos + 1];
  446. dirName[slashPos] = '\0';
  447. strncpy(dirName, mMapList.current(), slashPos);
  448. do {
  449. menuMapListMove('f', false);
  450. } while (strstr(mMapList.current(), dirName) != NULL);
  451. delete []dirName;
  452. } else {
  453. do {
  454. menuMapListMove('f', false);
  455. } while (strstr(mMapList.current(), "/") == NULL);
  456. }
  457. } else if (dir == 'p') {
  458. size_t slashPos = strcspn(mMapList.current(), "/");
  459. if (slashPos < strlen(mMapList.current())) {
  460. char *dirName = new char[slashPos + 1];
  461. dirName[slashPos] = '\0';
  462. strncpy(dirName, mMapList.current(), slashPos);
  463. do {
  464. menuMapListMove('b', false);
  465. } while (strstr(mMapList.current(), dirName) != NULL);
  466. // Yeah, cheap...
  467. strncpy(dirName, mMapList.current(), slashPos);
  468. do {
  469. menuMapListMove('b', false);
  470. } while (strstr(mMapList.current(), dirName) != NULL);
  471. menuMapListMove('f', false);
  472. delete []dirName;
  473. } else {
  474. do {
  475. menuMapListMove('b', false);
  476. } while (strstr(mMapList.current(), "/") == NULL);
  477. }
  478. }
  479. if (show) {
  480. if (mMapList.current())
  481. mText->SetString(textMenu, "Load %s?", mMapList.current());
  482. else
  483. mText->SetString(textMenu, "See README for map install");
  484. }
  485. }
  486. void OpenRaider::handleKeyPressEvent(unsigned int key, unsigned int mod)
  487. {
  488. static bool menu = false;
  489. // Cheap menu test
  490. if (menu)
  491. {
  492. switch (key)
  493. {
  494. case SYS_KEY_ESC:
  495. menu = false;
  496. mText->SetString(textMenu, " ");
  497. mText->setActive(textMenu, false);
  498. break;
  499. case SYS_KEY_ENTER:
  500. loadLevel(mMapList.current());
  501. mText->SetString(textMenu, " ");
  502. mText->setActive(textMenu, false);
  503. menu = false;
  504. break;
  505. case SYS_KEY_DOWN:
  506. menuMapListMove('b', true);
  507. break;
  508. case SYS_KEY_UP:
  509. menuMapListMove('f', true);
  510. break;
  511. case SYS_KEY_LEFT:
  512. menuMapListMove('p', true);
  513. break;
  514. case SYS_KEY_RIGHT:
  515. menuMapListMove('n', true);
  516. break;
  517. }
  518. return;
  519. }
  520. switch (key)
  521. {
  522. case SYS_KEY_ESC:
  523. menu = true;
  524. mText->SetString(textMenu, "Select a map UP/DOWN");
  525. mText->setActive(textMenu, true);
  526. break;
  527. case SYS_KEY_ENTER:
  528. if (mod & SYS_MOD_KEY_LALT)
  529. {
  530. toggleFullscreen();
  531. }
  532. break;
  533. }
  534. ////////////////////////////////////////////////////////////
  535. switch (key)
  536. {
  537. case SYS_MOUSE_LEFT:
  538. if (LARA)
  539. {
  540. eventAnimTest(15);
  541. }
  542. break;
  543. case '/':
  544. if (LARA)
  545. {
  546. entity_t *e = new entity_t;
  547. e->pos[0] = LARA->pos[0];
  548. e->pos[1] = LARA->pos[1] - 256.0f; // crawling H
  549. e->pos[2] = LARA->pos[2];
  550. e->type = 61;
  551. e->master = LARA->master;
  552. LARA->master = e;
  553. }
  554. break;
  555. case '[':
  556. if (LARA)
  557. {
  558. SkeletalModel *mdl = static_cast<SkeletalModel *>(LARA->tmpHook);
  559. if (mdl)
  560. {
  561. mdl->setIdleAnimation(mdl->getIdleAnimation() - 1);
  562. mdl->setAnimation(mdl->getIdleAnimation());
  563. print(false, "AFRAME %i\n", mdl->getIdleAnimation());
  564. }
  565. }
  566. break;
  567. case ']':
  568. if (LARA)
  569. {
  570. SkeletalModel *mdl = static_cast<SkeletalModel *>(LARA->tmpHook);
  571. if (mdl)
  572. {
  573. mdl->setIdleAnimation(mdl->getIdleAnimation() + 1);
  574. mdl->setAnimation(mdl->getIdleAnimation());
  575. print(false, "AFRAME %i\n", mdl->getIdleAnimation());
  576. }
  577. }
  578. break;
  579. case 'r':
  580. if (m_flags & OpenRaider_EnableSound) {
  581. if (m_testSFX < mSound.registeredSources()) {
  582. mSound.play(m_testSFX);
  583. }
  584. }
  585. break;
  586. }
  587. }
  588. void OpenRaider::print(bool dump_stdout, const char *format, ...)
  589. {
  590. static char buffer[128];
  591. va_list args;
  592. unsigned int l;
  593. va_start(args, format);
  594. vsnprintf(buffer, 128, format, args);
  595. l = strlen(buffer);
  596. if (!l || !buffer[0])
  597. {
  598. return;
  599. }
  600. // Strip message of trailing newline
  601. if (buffer[l-1] == '\n')
  602. {
  603. buffer[l-1] = 0;
  604. }
  605. // Print to game 'console'
  606. if (mText)
  607. {
  608. mText->SetString(textOutput, "%s", buffer);
  609. }
  610. // Print to stdout
  611. if (dump_stdout)
  612. {
  613. fprintf(stdout, "> %s\n", buffer);
  614. }
  615. va_end(args);
  616. // Mongoose 2002.08.14, Currently, you must request
  617. // frame redraws in this mode
  618. if (m_flags & OpenRaider_Loading)
  619. {
  620. gameFrame();
  621. }
  622. }
  623. void OpenRaider::start()
  624. {
  625. vec3_t up;
  626. char *filename;
  627. printf("\n[Starting %s]\n\n", VERSION);
  628. filename = fullPath("~/.OpenRaider/OpenRaider.init", 0);
  629. if (loadResourceFile(filename) < 0)
  630. {
  631. printf("Could not find ~/.OpenRaider/OpenRaider.init\n");
  632. if (loadResourceFile("OpenRaider.init") < 0)
  633. {
  634. shutdown(-1);
  635. }
  636. printf("Loaded defaults...\n");
  637. }
  638. delete [] filename;
  639. m_camera.reset();
  640. m_camera.setSensitivityX(m_mouseX);
  641. m_camera.setSensitivityY(m_mouseY);
  642. m_camera.setSpeed(512);
  643. up[0] = 0.0;
  644. up[1] = -1.0;
  645. up[2] = 0.0;
  646. m_camera.setUp(up);
  647. if (mMapList.empty())
  648. {
  649. printf("No maps in map list, please edit your OpenRaider.init\n");
  650. shutdown(0);
  651. }
  652. // Mongoose 2002.08.13, System protected members abuse
  653. m_fovY = 40.0f;
  654. m_clipFar = 600000.0f;
  655. m_clipNear = 10.0f;
  656. // Mongoose 2002.08.13, This starts GL context
  657. printf("\n[Starting video subsystem...]\n");
  658. initVideo(m_width, m_height, false);
  659. // Mongoose 2002.01.02, Disable rendering to avoid GL call conflicts
  660. m_render.setMode(Render::modeDisabled);
  661. m_render.Init(m_width, m_height);
  662. m_render.initTextures(m_homeDir, &m_texOffset, &mLevelTextureOffset);
  663. m_render.RegisterCamera(&m_camera);
  664. mText = m_render.GetString();
  665. // Mongoose 2002.01.03, Good idea?
  666. m_render.setMode(Render::modeLoadScreen);
  667. // Mongoose 2002.01.02, Load external audio tracks and fx
  668. // General audio init
  669. initSound();
  670. // Old room movement
  671. gWorld.setFlag(World::fEnableHopping);
  672. // reenabled, what should be the new room movement? --xythobuz
  673. systemTimerReset();
  674. runGame();
  675. }
  676. void OpenRaider::initSound()
  677. {
  678. if (!(m_flags & OpenRaider_EnableSound) || mSound.init() < 0)
  679. {
  680. print(true, "Disabling sound...\n");
  681. m_flags &= ~OpenRaider_EnableSound;
  682. return;
  683. }
  684. #ifdef OBSOLETE
  685. char filename[128];
  686. int id;
  687. printf("Processing external sound files: ");
  688. // Mongoose 2001.12.31, Use music list from init script
  689. if (mMusicList.Empty())
  690. {
  691. print(true, "No music in map list, please edit your OpenRaider.init\n");
  692. }
  693. else
  694. {
  695. snprintf(filename, 126, "%s%s", m_audioDir, mMusicList[0]);
  696. filename[127] = 0;
  697. if (!mSound.addFile(filename, &id, mSound.SoundFlagsLoop))
  698. {
  699. mSound.play(id);
  700. printf("m");
  701. fflush(stdout);
  702. }
  703. }
  704. //snprintf(filename, 126, "%s%s", m_homeDir, "sample.wav");
  705. //filename[127] = 0;
  706. //mSound.addFile(filename, &m_testSFX, mSound.SoundFlagsNone);
  707. printf(".");
  708. fflush(stdout);
  709. printf("\n");
  710. #endif
  711. }
  712. void OpenRaider::processPakSounds()
  713. {
  714. unsigned char *riff;
  715. unsigned int riffSz;
  716. //tr2_sound_source_t *sound;
  717. //tr2_sound_details_t *detail;
  718. //float pos[3];
  719. unsigned int i;
  720. int id;
  721. /* detail
  722. short sample;
  723. short volume;
  724. short sound_range;
  725. short flags; // bits 8-15: priority?, 2-7: number of sound samples
  726. // in this group, bits 0-1: channel number
  727. */
  728. if (!(m_flags & OpenRaider_EnableSound))
  729. return;
  730. printf("Processing pak sound files: ");
  731. for (i = 0; i < m_tombraider.getSoundSamplesCount(); ++i)
  732. {
  733. print(false, "Processing pak sounds: %i / %i",
  734. i, m_tombraider.getSoundSamplesCount());
  735. m_tombraider.getSoundSample(i, &riffSz, &riff);
  736. mSound.addWave(riff, riffSz, &id, mSound.SoundFlagsNone);
  737. if (((i + 1) == TR_SOUND_F_PISTOL) && (id > 0))
  738. {
  739. m_testSFX = id;
  740. }
  741. delete [] riff;
  742. // sound[i].sound_id; // internal sound index
  743. // sound[i].flags; // 0x40, 0x80, or 0xc0
  744. //pos[0] = sound[i].x;
  745. //pos[1] = sound[i].y;
  746. //pos[2] = sound[i].z;
  747. //mSound.SourceAt(id, pos);
  748. //printf(".");
  749. //fflush(stdout);
  750. }
  751. printf("Done! Found %u files.\n", m_tombraider.getSoundSamplesCount());
  752. }
  753. void OpenRaider::loadLevel(char *mapname)
  754. {
  755. int i, j, len;
  756. char filename[256];
  757. // Mongoose 2002.03.23, Clear last loaded 'world'
  758. m_render.setMode(Render::modeDisabled);
  759. m_render.ClearWorld();
  760. gWorld.destroy();
  761. // Mongoose 2002.01.02, Now draw load screen, since external
  762. // GL textures are loaded and renderer is initialized
  763. m_render.setMode(Render::modeLoadScreen);
  764. gameFrame();
  765. /* 2003.07.05, Mongoose - No longer seeding, and looking for
  766. map to load -- load this map or fail and return */
  767. snprintf(filename, 254, "%s%s", m_pakDir, mapname);
  768. filename[255] = 0;
  769. len = strlen(filename);
  770. for (i = len, j = 0; i > 0; --i, ++j)
  771. {
  772. if (filename[i] == '/' || filename[i] == '\\')
  773. break;
  774. }
  775. j--;
  776. memset(m_mapName, 0, 32);
  777. for (i = 0; i < len - j && i < 30; ++i)
  778. {
  779. m_mapName[i] = filename[i + len - j];
  780. }
  781. m_tombraider.setDebug(m_flags & OpenRaider_DebugMap);
  782. m_flags |= OpenRaider_Loading;
  783. print(true, "Level %s loading", m_mapName);
  784. if (m_tombraider.Load(filename, percent_callback))
  785. {
  786. print(true, "ERROR: Failed to load level %s\n", m_mapName);
  787. return;
  788. }
  789. else
  790. {
  791. char altSfx[256];
  792. switch (m_tombraider.getEngine())
  793. {
  794. case TR_VERSION_2:
  795. case TR_VERSION_3:
  796. // Now loads eg. "tr3/MAIN.SFX" instead of "tr3/SHORE.TR2.sfx"
  797. filename[len - j] = '\0';
  798. snprintf(altSfx, 255, "%sMAIN.SFX", filename);
  799. print(true, "Loading alternate SFX for TR2 or TR3 pak at %sMAIN.SFX\n", filename);
  800. m_tombraider.loadSFX(altSfx);
  801. break;
  802. case TR_VERSION_1:
  803. case TR_VERSION_4:
  804. case TR_VERSION_5:
  805. case TR_VERSION_UNKNOWN:
  806. break;
  807. }
  808. }
  809. print(true, "Optimizing and translating pak data...");
  810. m_flags ^= OpenRaider_Loading;
  811. // Mongoose 2002.08.16, Used to cache TR4 textures at 10% of file load
  812. // in a callback - then with other engines process them here
  813. m_render.setMode(Render::modeDisabled);
  814. //sleep(1); // Why should we sleep here? -- xythobuz
  815. processTextures();
  816. m_render.setMode(Render::modeLoadScreen);
  817. print(true, "Level textures cached\n");
  818. // Cache/process rooms
  819. printf("Processing rooms: ");
  820. for (i = 0; i < m_tombraider.NumRooms(); ++i)
  821. {
  822. processRoom(i);
  823. print(false, "Processing rooms: %i/%i", i, m_tombraider.NumRooms());
  824. }
  825. printf("Done! Found %d rooms.\n", m_tombraider.NumRooms());
  826. // Cache/process meshes
  827. printf("Processing meshes: ");
  828. for (i = 0; i < m_tombraider.getMeshCount(); ++i)
  829. {
  830. m_render.setMode(Render::modeDisabled);
  831. processModel(i);
  832. m_render.setMode(Render::modeLoadScreen);
  833. print(false, "Processing meshes: %i/%i", i, m_tombraider.getMeshCount());
  834. }
  835. printf("Done! Found %d meshes.\n", m_tombraider.getMeshCount());
  836. // Cache/process sprites
  837. processSprites();
  838. // Cache/process skeletal models
  839. processMoveables();
  840. // Cache/process sound fx
  841. processPakSounds();
  842. // Mongoose 2002.01.02, Go ahead and free the TR pak
  843. m_tombraider.reset();
  844. print(true, "Level pak freed from memory, Starting game...");
  845. /*! \fixme GL call to critical section,
  846. * needs mutex really -- Mongoose 2002.01.02
  847. */
  848. m_render.setMode(Render::modeDisabled);
  849. sleep(1);
  850. // Draw game, level is loaded
  851. m_render.setMode(Render::modeVertexLight);
  852. m_flags ^= OpenRaider_Loading;
  853. }
  854. void OpenRaider::gameFrame()
  855. {
  856. SkeletalModel *mdl = 0x0;
  857. unsigned int ticks;
  858. float time;
  859. // Remember: ticks in milliseconds, time in hundredths
  860. ticks = systemTimerGet();
  861. time = ticks * 0.1f;
  862. switch (m_render.getMode())
  863. {
  864. case Render::modeDisabled:
  865. break;
  866. case Render::modeLoadScreen:
  867. if ((ticks % 10000) > 1)
  868. {
  869. m_render.drawLoadScreen();
  870. swapBuffersGL();
  871. }
  872. break;
  873. default:
  874. if (LARA)
  875. {
  876. mdl = static_cast<SkeletalModel *>(LARA->tmpHook);
  877. if (mdl)
  878. {
  879. float elapsed = time - mdl->lastTime;
  880. if (elapsed > mdl->rate)
  881. {
  882. if (mdl->getAnimation() == 0 &&
  883. (mdl->getFrame() == 2 || mdl->getFrame() == 10))
  884. {
  885. if (m_flags & OpenRaider_EnableSound)
  886. {
  887. if (TR_SOUND_FOOTSTEP0 < mSound.registeredSources())
  888. mSound.play(TR_SOUND_FOOTSTEP0);
  889. }
  890. }
  891. else if (mdl->getAnimation() == 15)
  892. {
  893. eventAnimTest(TR_ANIAMTION_RUN);
  894. }
  895. mdl->setFrame(mdl->getFrame()+1);
  896. mdl->lastTime = elapsed / mdl->rate;
  897. }
  898. else
  899. {
  900. mdl->lastTime = time;
  901. }
  902. }
  903. }
  904. m_render.Display();
  905. swapBuffersGL();
  906. if (mdl && mdl->getAnimation() == 12)
  907. {
  908. switch (LARA->moveType)
  909. {
  910. case worldMoveType_swim:
  911. case worldMoveType_fly:
  912. case worldMoveType_noClipping:
  913. eventAnimTest(TR_ANIAMTION_SWIM_IDLE);
  914. break;
  915. case worldMoveType_walk:
  916. case worldMoveType_walkNoSwim:
  917. eventAnimTest(TR_ANIAMTION_STAND);
  918. break;
  919. }
  920. LARA->moving = false;
  921. }
  922. }
  923. if (m_flags & OpenRaider_ShowFPS)
  924. {
  925. static unsigned int frames = 0;
  926. static float lastTime = 0.0f;
  927. ++frames;
  928. // Only update every second, so it can't be affected
  929. // by fast/slow cards it only counts frames instead
  930. // of estimating
  931. if (time - lastTime > 100.0f)
  932. {
  933. if (mText)
  934. mText->SetString(1, "%dFPS", frames);
  935. lastTime = time;
  936. frames = 0;
  937. }
  938. }
  939. }
  940. void OpenRaider::processTextures()
  941. {
  942. unsigned char *image;
  943. unsigned char *bumpmap;
  944. int i;
  945. printf("Processing TR textures: ");
  946. //if ( m_tombraider.getNumBumpMaps())
  947. // gBumpMapStart = m_tombraider.NumTextures();
  948. for (i = 0; i < m_tombraider.NumTextures(); ++i)
  949. {
  950. print(false, "Processing textures: %i/%i", i, m_tombraider.NumTextures());
  951. m_tombraider.Texture(i, &image, &bumpmap);
  952. // Overwrite any previous level textures on load
  953. m_render.loadTexture(image, 256, 256, mLevelTextureOffset + i);
  954. gMapTex2Bump[mLevelTextureOffset + i] = -1;
  955. if (bumpmap)
  956. {
  957. gMapTex2Bump[mLevelTextureOffset + i] = mLevelTextureOffset + i +
  958. m_tombraider.NumTextures();
  959. m_render.loadTexture(bumpmap, 256, 256, mLevelTextureOffset + i +
  960. m_tombraider.NumTextures());
  961. }
  962. if (image)
  963. delete [] image;
  964. if (bumpmap)
  965. delete [] bumpmap;
  966. //printf(".");
  967. //fflush(stdout);
  968. }
  969. gTextureOffset = mLevelTextureOffset + m_tombraider.NumTextures();
  970. printf("Done! Found %d textures.\n", m_tombraider.NumTextures());
  971. }
  972. ////////////////////////////////////////////////////////////
  973. // Private Accessors
  974. ////////////////////////////////////////////////////////////
  975. ////////////////////////////////////////////////////////////
  976. // Private Mutators
  977. ////////////////////////////////////////////////////////////
  978. void OpenRaider::soundEvent(int type, int id, vec3_t pos, vec3_t angles) {
  979. if (m_flags & OpenRaider_EnableSound) {
  980. switch (type) {
  981. case 0: // Reset listener position
  982. mSound.listenAt(pos, angles);
  983. break;
  984. default:
  985. if (id < mSound.registeredSources()) {
  986. mSound.sourceAt(id, pos);
  987. mSound.play(id);
  988. }
  989. }
  990. }
  991. }
  992. void OpenRaider::processSprites()
  993. {
  994. int i, j, k, l, x, y, s_index, width, height;
  995. float scale, width2, height2;
  996. tr2_sprite_texture_t *sprite;
  997. tr2_sprite_texture_t *sprite_textures;
  998. tr2_sprite_sequence_t *sprite_sequence;
  999. sprite_seq_t *r_mesh;
  1000. tr2_item_t *item;
  1001. item = m_tombraider.Item();
  1002. sprite_textures = m_tombraider.Sprite();
  1003. sprite_sequence = m_tombraider.SpriteSequence();
  1004. scale = 4.0;
  1005. printf("Processing sprites: ");
  1006. for (i = 0; i < m_tombraider.NumItems() - 1; ++i)
  1007. {
  1008. print(false, "Processing sprites in Items: %i/%i",
  1009. i, m_tombraider.NumItems());
  1010. // It's a mesh, skip it
  1011. if (m_tombraider.Engine() == TR_VERSION_1 && item[i].intensity1 == -1)
  1012. continue;
  1013. k = item[i].object_id;
  1014. // Search the SpriteSequence list
  1015. // (if we didn't already decide that it's a mesh)
  1016. for (j = 0; j < (int)m_tombraider.NumSpriteSequences(); ++j)
  1017. {
  1018. if (sprite_sequence[j].object_id == k)
  1019. {
  1020. k = item[i].object_id;
  1021. s_index = sprite_sequence[j].offset;
  1022. r_mesh = new sprite_seq_t;
  1023. gWorld.addSprite(r_mesh);
  1024. r_mesh->num_sprites = -sprite_sequence[j].negative_length;
  1025. r_mesh->sprite = new sprite_t[r_mesh->num_sprites];
  1026. for (l = 0; l < r_mesh->num_sprites; ++l)
  1027. {
  1028. sprite = &sprite_textures[s_index];
  1029. width = sprite->width >> 8;
  1030. height = sprite->height >> 8;
  1031. x = sprite->x;
  1032. y = sprite->y;
  1033. width2 = width * scale;
  1034. height2 = height * scale;
  1035. // For vising use
  1036. r_mesh->sprite[l].pos[0] = item[i].x;
  1037. r_mesh->sprite[l].pos[1] = item[i].y;
  1038. r_mesh->sprite[l].pos[2] = item[i].z;
  1039. r_mesh->sprite[l].texture = sprite->tile + m_texOffset;
  1040. r_mesh->sprite[l].radius = width2 / 2.0f;
  1041. r_mesh->sprite[l].vertex[0].pos[0] = -width2 / 2.0f;
  1042. r_mesh->sprite[l].vertex[1].pos[0] = -width2 / 2.0f;
  1043. r_mesh->sprite[l].vertex[2].pos[0] = width2 / 2.0f;
  1044. r_mesh->sprite[l].vertex[3].pos[0] = width2 / 2.0f;
  1045. r_mesh->sprite[l].vertex[0].pos[1] = 0;
  1046. r_mesh->sprite[l].vertex[1].pos[1] = -height2;
  1047. r_mesh->sprite[l].vertex[2].pos[1] = -height2;
  1048. r_mesh->sprite[l].vertex[3].pos[1] = 0;
  1049. r_mesh->sprite[l].vertex[0].pos[2] = 0;
  1050. r_mesh->sprite[l].vertex[1].pos[2] = 0;
  1051. r_mesh->sprite[l].vertex[2].pos[2] = 0;
  1052. r_mesh->sprite[l].vertex[3].pos[2] = 0;
  1053. r_mesh->sprite[l].texel[3].st[0] = (vec_t)(x+width)/TexelScale;
  1054. r_mesh->sprite[l].texel[3].st[1] = (vec_t)(y+height)/TexelScale;
  1055. r_mesh->sprite[l].texel[2].st[0] = (vec_t)(x+width)/TexelScale;
  1056. r_mesh->sprite[l].texel[2].st[1] = (vec_t)(y)/TexelScale;
  1057. r_mesh->sprite[l].texel[1].st[0] = (vec_t)(x) /TexelScale;
  1058. r_mesh->sprite[l].texel[1].st[1] = (vec_t)(y) /TexelScale;
  1059. r_mesh->sprite[l].texel[0].st[0] = (vec_t)(x) / TexelScale;
  1060. r_mesh->sprite[l].texel[0].st[1] = (vec_t)(y+height)/TexelScale;
  1061. //printf(".");
  1062. //fflush(stdout);
  1063. }
  1064. }
  1065. }
  1066. }
  1067. printf("Done! Found %d sprites.\n", m_tombraider.NumSpriteSequences());
  1068. }
  1069. void OpenRaider::processMoveables()
  1070. {
  1071. List<unsigned int> cache;
  1072. List<skeletal_model_t *> cache2;
  1073. tr2_mesh_t *mesh = NULL;
  1074. tr2_moveable_t *moveable = NULL;
  1075. tr2_meshtree_t *meshtree = NULL;
  1076. tr2_item_t *item = NULL;
  1077. tr2_animation_t *animation = NULL;
  1078. unsigned short *frame = NULL;
  1079. tr2_sprite_sequence_t *sprite_sequence = NULL;
  1080. tr2_object_texture_t *object_texture = NULL;
  1081. int i, j, object_id;
  1082. int ent = 0;
  1083. unsigned int statCount = 0;
  1084. frame = m_tombraider.Frame();
  1085. moveable = m_tombraider.Moveable();
  1086. meshtree = m_tombraider.MeshTree();
  1087. mesh = m_tombraider.Mesh();
  1088. object_texture = m_tombraider.ObjectTextures();
  1089. item = m_tombraider.Item();
  1090. animation = m_tombraider.Animation();
  1091. sprite_sequence = m_tombraider.SpriteSequence();
  1092. printf("Processing skeletal models: ");
  1093. for (i = 0; i < m_tombraider.NumItems(); ++i)
  1094. {
  1095. object_id = item[i].object_id;
  1096. // It may not be a moveable, test for sprite
  1097. if (!(m_tombraider.Engine() == TR_VERSION_1 && item[i].intensity1 == -1))
  1098. {
  1099. for (j = 0; j < (int)m_tombraider.NumSpriteSequences(); ++j)
  1100. {
  1101. if (sprite_sequence[j].object_id == object_id)
  1102. break;
  1103. }
  1104. // It's not a moveable, skip sprite
  1105. if (j != (int)m_tombraider.NumSpriteSequences())
  1106. {
  1107. //printf("s");
  1108. //fflush(stdout);
  1109. continue;
  1110. }
  1111. }
  1112. for (j = 0; j < (int)m_tombraider.NumMoveables(); ++j)
  1113. {
  1114. if ((int)moveable[j].object_id == object_id)
  1115. break;
  1116. }
  1117. // It's not a moveable or even a sprite?, skip unknown
  1118. if (j == (int)m_tombraider.NumMoveables())
  1119. {
  1120. //printf("?"); // what the wolf?
  1121. //fflush(stdout);
  1122. continue;
  1123. }
  1124. processMoveable(j, i, &ent, cache2, cache, object_id);
  1125. statCount++;
  1126. }
  1127. // Get models that aren't items
  1128. for (i = 0; i < m_tombraider.NumMoveables(); ++i)
  1129. {
  1130. print(false, "Processing skeletal models: %i/%i",
  1131. i, m_tombraider.NumMoveables());
  1132. switch ((int)moveable[i].object_id)
  1133. {
  1134. case 30:
  1135. case 2: // Which tr needs this as model again?
  1136. processMoveable(i, i, &ent, cache2, cache,
  1137. (int)moveable[i].object_id);
  1138. break;
  1139. default:
  1140. switch (m_tombraider.Engine())
  1141. {
  1142. case TR_VERSION_1:
  1143. switch ((int)moveable[i].object_id)
  1144. {
  1145. case TombRaider1::LaraMutant:
  1146. processMoveable(i, i, &ent, cache2, cache,
  1147. (int)moveable[i].object_id);
  1148. break;
  1149. }
  1150. break;
  1151. case TR_VERSION_4:
  1152. switch ((int)moveable[i].object_id)
  1153. {
  1154. case TR4_PISTOLS_ANIM:
  1155. case TR4_UZI_ANIM:
  1156. case TR4_SHOTGUN_ANIM:
  1157. case TR4_CROSSBOW_ANIM:
  1158. case TR4_GRENADE_GUN_ANIM:
  1159. case TR4_SIXSHOOTER_ANIM:
  1160. processMoveable(i, i, &ent, cache2, cache,
  1161. (int)moveable[i].object_id);
  1162. break;
  1163. }
  1164. break;
  1165. case TR_VERSION_2:
  1166. case TR_VERSION_3:
  1167. case TR_VERSION_5:
  1168. case TR_VERSION_UNKNOWN:
  1169. break;
  1170. }
  1171. }
  1172. }
  1173. printf("Done! Found %d models.\n", m_tombraider.NumMoveables() + statCount);
  1174. }
  1175. void OpenRaider::processMoveable(int index, int i, int *ent,
  1176. List<skeletal_model_t *> &cache2,
  1177. List<unsigned int> &cache, int object_id)
  1178. {
  1179. skeletal_model_t *r_model = NULL;
  1180. skeletal_model_t *c_model = NULL;
  1181. animation_frame_t *animation_frame = NULL;
  1182. tr2_mesh_t *mesh = NULL;
  1183. tr2_moveable_t *moveable = NULL;
  1184. tr2_meshtree_t *meshtree = NULL;
  1185. tr2_item_t *item = NULL;
  1186. tr2_animation_t *animation = NULL;
  1187. tr2_meshtree_t *mesh_tree = NULL;
  1188. bone_frame_t *bone = NULL;
  1189. bone_tag_t *tag = NULL;
  1190. entity_t *thing = NULL;
  1191. SkeletalModel *sModel = 0x0;
  1192. unsigned short *frame;
  1193. int j, k, a, frame_step;
  1194. unsigned int l, frame_offset, frame_count, f;
  1195. float pos[3];
  1196. float yaw;
  1197. bool lara = false;
  1198. int skyMesh;
  1199. skyMesh = m_tombraider.getSkyModelId();
  1200. frame = m_tombraider.Frame();
  1201. moveable = m_tombraider.Moveable();
  1202. meshtree = m_tombraider.MeshTree();
  1203. mesh = m_tombraider.Mesh();
  1204. item = m_tombraider.Item();
  1205. animation = m_tombraider.Animation();
  1206. pos[0] = item[i].x;
  1207. pos[1] = item[i].y;
  1208. pos[2] = item[i].z;
  1209. yaw = ((item[i].angle >> 14) & 0x03);
  1210. yaw *= 90;
  1211. thing = new entity_t;
  1212. thing->id = (*ent)++;
  1213. thing->type = 0x00;
  1214. thing->pos[0] = item[i].x;
  1215. thing->pos[1] = item[i].y;
  1216. thing->pos[2] = item[i].z;
  1217. thing->angles[1] = yaw;
  1218. thing->objectId = moveable[index].object_id;
  1219. thing->moving = false;
  1220. thing->animate = false;
  1221. sModel = new SkeletalModel();
  1222. m_render.addSkeletalModel(sModel);
  1223. thing->tmpHook = sModel; // temp hack to keep a running version during refactoring
  1224. if (m_tombraider.Engine() == TR_VERSION_1)
  1225. {
  1226. switch (thing->objectId)
  1227. {
  1228. case TombRaider1::Wolf:
  1229. thing->state = TombRaider1::WolfState_Lying;
  1230. //thing->animate = true;
  1231. sModel->setAnimation(3);
  1232. sModel->setFrame(0);
  1233. break;
  1234. }
  1235. }
  1236. //! \fixme Check here and see if we already have one for object_id later
  1237. // if (gWorld.isCachedSkeletalModel(moveable[index].object_id))
  1238. // {
  1239. // thing->modelId = m_render.add(sModel);
  1240. // return;
  1241. // }
  1242. r_model = new skeletal_model_t;
  1243. r_model->id = moveable[index].object_id;
  1244. // Gather more info if this is lara
  1245. if (moveable[index].object_id == 0)
  1246. {
  1247. gLaraModel = r_model; // hack to avoid broken system until new event sys
  1248. lara = true;
  1249. m_camera.translate(pos[0], pos[1] - 470, pos[2]);
  1250. thing->type = 0x02;
  1251. LARA = thing; // Mongoose 2002.03.22, Cheap hack for now
  1252. LARA->master = 0x0;
  1253. switch (m_tombraider.Engine())
  1254. {
  1255. case TR_VERSION_3:
  1256. LARA->modelId = i;
  1257. sModel->setAnimation(TR_ANIAMTION_RUN);
  1258. sModel->setIdleAnimation(TR_ANIAMTION_STAND);
  1259. r_model->tr4Overlay = false;
  1260. break;
  1261. case TR_VERSION_4:
  1262. LARA->modelId = i;
  1263. sModel->setAnimation(TR_ANIAMTION_RUN);
  1264. sModel->setIdleAnimation(TR_ANIAMTION_STAND);
  1265. // Only TR4 lara has 2 layer bone tags/meshes per bone frame
  1266. r_model->tr4Overlay = true;
  1267. break;
  1268. case TR_VERSION_1:
  1269. case TR_VERSION_2:
  1270. case TR_VERSION_5:
  1271. case TR_VERSION_UNKNOWN:
  1272. LARA->modelId = index;
  1273. sModel->setAnimation(TR_ANIAMTION_RUN);
  1274. sModel->setIdleAnimation(TR_ANIAMTION_STAND);
  1275. r_model->tr4Overlay = false;
  1276. break;
  1277. }
  1278. r_model->ponytailId = 0;
  1279. }
  1280. else
  1281. {
  1282. lara = false;
  1283. r_model->ponytailId = -1;
  1284. }
  1285. // Animation
  1286. a = moveable[index].animation;
  1287. frame_offset = animation[a].frame_offset / 2;
  1288. frame_step = animation[a].frame_size;
  1289. int frame_cycle = 0;
  1290. if (a >= (int)m_tombraider.NumAnimations())
  1291. {
  1292. a = m_tombraider.NumFrames() - frame_offset;
  1293. }
  1294. else
  1295. {
  1296. a = (animation[a].frame_offset / 2) - frame_offset;
  1297. }
  1298. if (frame_step != 0) // prevent divide-by-zero errors
  1299. a /= frame_step;
  1300. if (a != 0) // prevent divide-by-zero errors
  1301. frame_offset += frame_step * (frame_cycle % a);
  1302. if (a < 0)
  1303. {
  1304. //continue;
  1305. return;
  1306. }
  1307. //! \fixme Might be better UID for each model, but this seems to work well
  1308. j = object_id;
  1309. // We only want one copy of the skeletal model in memory
  1310. if (cache.Empty() || cache.SearchKey(j) == UINT_MAX)
  1311. {
  1312. sModel->model = r_model;
  1313. gWorld.addEntity(thing);
  1314. k = gWorld.addModel(r_model);
  1315. cache.Add(j);
  1316. cache2.Add(r_model);
  1317. switch (m_tombraider.Engine())
  1318. {
  1319. case TR_VERSION_4:
  1320. if (LARA && moveable[index].object_id == 30)
  1321. {
  1322. r_model->ponytailId = k;
  1323. r_model->ponytailMeshId = moveable[index].starting_mesh;
  1324. r_model->ponytailNumMeshes = ((moveable[index].num_meshes > 0) ?
  1325. moveable[index].num_meshes : 0);
  1326. r_model->ponytailAngle = -90.0f;
  1327. r_model->ponytail[0] = -3;
  1328. r_model->ponytail[1] = -22;
  1329. r_model->ponytail[2] = -20;
  1330. r_model->ponyOff = 40;
  1331. r_model->ponyOff2 = 32;
  1332. r_model->pigtails = false;
  1333. // Try to guess pigtails by looking for certian num verts in head
  1334. if (mesh[moveable[0].starting_mesh].num_vertices > 80)
  1335. {
  1336. r_model->pigtails = true;
  1337. r_model->ponyOff -= 20;
  1338. r_model->ponytail[1] -= 32;
  1339. }
  1340. m_render.setFlags(Render::fRenderPonytail);
  1341. print(true, "Found known ponytail\n");
  1342. }
  1343. break; // ?
  1344. case TR_VERSION_1:
  1345. case TR_VERSION_2:
  1346. case TR_VERSION_3:
  1347. case TR_VERSION_5:
  1348. case TR_VERSION_UNKNOWN:
  1349. if (LARA && moveable[index].object_id == 2)
  1350. {
  1351. r_model->ponytailId = k;
  1352. r_model->ponytailMeshId = moveable[index].starting_mesh;
  1353. r_model->ponytailNumMeshes = ((moveable[index].num_meshes > 0) ?
  1354. moveable[index].num_meshes : 0);
  1355. r_model->ponytailAngle = -90.0f;
  1356. r_model->ponytail[0] = 0;
  1357. r_model->ponytail[1] = -20;
  1358. r_model->ponytail[2] = -20;
  1359. r_model->ponyOff = 40;
  1360. r_model->ponyOff2 = 0;
  1361. m_render.setFlags(Render::fRenderPonytail);
  1362. print(true, "Found ponytail?\n");
  1363. }
  1364. break;
  1365. }
  1366. }
  1367. else
  1368. {
  1369. delete r_model;
  1370. c_model = cache2[cache.SearchKey(j)];
  1371. sModel->model = c_model;
  1372. gWorld.addEntity(thing);
  1373. gWorld.addModel(c_model);
  1374. //printf("c"); // it's already cached
  1375. //fflush(stdout);
  1376. //continue;
  1377. return;
  1378. }
  1379. int aloop = m_tombraider.getNumAnimsForMoveable(index);
  1380. #ifdef DEBUG
  1381. if (m_flags & OpenRaider_DebugModel)
  1382. {
  1383. printf("\nanimation = %i, num_animations = %i\n",
  1384. moveable[index].animation, aloop);
  1385. printf("\nitem[%i].flags = %i\nentity[%i]\n",
  1386. i, item[i].flags, thing->id);
  1387. }
  1388. #endif
  1389. //a = moveable[index].animation;
  1390. //frame_offset = animation[a].frame_offset / 2;
  1391. //frame_step = animation[a].frame_size;
  1392. for (; a < aloop; ++a,
  1393. frame_offset = animation[a].frame_offset / 2,
  1394. frame_step = animation[a].frame_size)
  1395. {
  1396. animation_frame = new animation_frame_t;
  1397. r_model->animation.pushBack(animation_frame);
  1398. frame_count = (animation[a].frame_end - animation[a].frame_start) + 1;
  1399. animation_frame->rate = animation[a].frame_rate;
  1400. #ifdef DEBUG
  1401. if (m_flags & OpenRaider_DebugModel)
  1402. {
  1403. printf("animation[%i] state and unknowns = %i, %i, %i, %i, %i\n",
  1404. a, animation[a].state_id, animation[a].unknown1,
  1405. animation[a].unknown2, animation[a].unknown3,
  1406. animation[a].unknown4);
  1407. printf("animation[%i].frame_rate = %i\n",
  1408. a, animation[a].frame_rate);
  1409. printf("animation[%i].next_animation = %i\n",
  1410. a, animation[a].next_animation);
  1411. printf("animation[%i].frame_offset = %u\n",
  1412. a, animation[a].frame_offset);
  1413. printf("animation[%i].anim_command = %i\n",
  1414. a, animation[a].anim_command);
  1415. printf("animation[%i].num_anim_commands = %i\n",
  1416. a, animation[a].num_anim_commands);
  1417. printf("animation[%i].state_change_offset = %i\n",
  1418. a, animation[a].state_change_offset);
  1419. printf(" frame_offset = %u\n",
  1420. frame_offset);
  1421. }
  1422. #endif
  1423. // Get all the frames for aniamtion
  1424. for (f = 0; f < frame_count; ++f, frame_offset += frame_step)
  1425. {
  1426. // HACK: Lara's ObjectID is 315, but her meshes start at 0, so make a
  1427. // quick substitution (so she doesn't appear as a bunch of thighs)
  1428. if (index == 0 && m_tombraider.Engine() == TR_VERSION_3)
  1429. {
  1430. for (j = 0; j < (int)m_tombraider.NumMoveables() && !index; ++j)
  1431. {
  1432. if (moveable[j].object_id == 315)
  1433. index = j;
  1434. }
  1435. }
  1436. // Fix Lara in TR4
  1437. if (index == 0 && m_tombraider.Engine() == TR_VERSION_4)
  1438. {
  1439. for (j = 0; j < (int)m_tombraider.NumMoveables() && !index; ++j)
  1440. {
  1441. // Body is ItemID 8, joints are ItemID 9
  1442. // (TR4 demo: body is ItemID 10, joints are ItemID 11)
  1443. if (moveable[j].object_id == 8)
  1444. index = j;
  1445. }
  1446. }
  1447. else if (moveable[index].object_id == 8 &&
  1448. m_tombraider.Engine() == TR_VERSION_4)
  1449. {
  1450. // KLUDGE to do "skinning"
  1451. index = 0;
  1452. for (j = 0; j < (int)m_tombraider.NumMoveables() && !index; ++j)
  1453. {
  1454. // Body is ItemID 8, joints are ItemID 9
  1455. // (TR4 demo: body is ItemID 10, joints are ItemID 11)
  1456. if (moveable[j].object_id == 9)
  1457. index = j;
  1458. }
  1459. }
  1460. #ifdef DEBUG
  1461. if (m_flags & OpenRaider_DebugModel)
  1462. {
  1463. printf("animation[%i].boneframe[%u] = offset %u, step %i\n",
  1464. a, f, frame_offset, frame_step);
  1465. }
  1466. #endif
  1467. // Mongoose 2002.08.15, Was
  1468. // if (frame_offset + 8 > _tombraider.NumFrames())
  1469. if (frame_offset > m_tombraider.NumFrames())
  1470. {
  1471. print(true, "WARNING: Bad animation frame %i > %i\n",
  1472. frame_offset, m_tombraider.NumFrames());
  1473. // Mongoose 2002.08.15, Attempt to skip more likely bad animation data
  1474. print(true, "WARNING: Handling bad animation data...");
  1475. return; //continue;
  1476. }
  1477. // Generate bone frames and tags per frame ////////////
  1478. bone = new bone_frame_t;
  1479. animation_frame->frame.pushBack(bone);
  1480. // Init translate for bone frame
  1481. bone->pos[0] = (short)frame[frame_offset + 6];
  1482. bone->pos[1] = (short)frame[frame_offset + 7];
  1483. bone->pos[2] = (short)frame[frame_offset + 8];
  1484. bone->yaw = yaw;
  1485. //printf("%f %f %f\n", bone->pos[0], bone->pos[1], bone->pos[2]);
  1486. l = 9; // First angle offset in this Frame
  1487. // Run through the tag and calculate the rotation and offset
  1488. for (j = 0; j < (int)moveable[index].num_meshes; ++j)
  1489. {
  1490. tag = new bone_tag_t;
  1491. bone->tag.pushBack(tag);
  1492. tag->off[0] = 0.0;
  1493. tag->off[1] = 0.0;
  1494. tag->off[2] = 0.0;
  1495. tag->flag = 0x00;
  1496. tag->rot[0] = 0.0;
  1497. tag->rot[1] = 0.0;
  1498. tag->rot[2] = 0.0;
  1499. tag->mesh = moveable[index].starting_mesh + j;
  1500. // Setup offsets to produce skeletion
  1501. if (j == 0)
  1502. {
  1503. // Since we use bone's offset, these aren't used
  1504. tag->off[0] = 0.0;
  1505. tag->off[1] = 0.0;
  1506. tag->off[2] = 0.0;
  1507. // Always push tag[0], this isn't really used either
  1508. tag->flag = 0x02;
  1509. }
  1510. else // Nonprimary tag - position relative to first tag
  1511. {
  1512. int *tree;
  1513. // Hack: moveable[index].mesh_tree is a byte offset
  1514. // into mesh_tree[], so we have to convert to index
  1515. tree = (int *)(void *)meshtree;
  1516. mesh_tree = (tr2_meshtree_t *)&tree[moveable[index].mesh_tree
  1517. + ((j - 1) * 4)];
  1518. tag->off[0] = mesh_tree->x;
  1519. tag->off[1] = mesh_tree->y;
  1520. tag->off[2] = mesh_tree->z;
  1521. tag->flag = (char)mesh_tree->flags;
  1522. }
  1523. // Setup tag rotations
  1524. m_tombraider.computeRotationAngles(&frame, &frame_offset, &l,
  1525. tag->rot, tag->rot+1, tag->rot+2);
  1526. }
  1527. }
  1528. }
  1529. if (i == skyMesh)
  1530. {
  1531. m_render.setSkyMesh(i, //moveable[i].starting_mesh,
  1532. (m_tombraider.Engine() == TR_VERSION_2));
  1533. }
  1534. //printf(".");
  1535. //fflush(stdout);
  1536. }
  1537. int compareFaceTextureId(const void *voidA, const void *voidB)
  1538. {
  1539. texture_tri_t *a = (texture_tri_t *)voidA, *b = (texture_tri_t *)voidB;
  1540. if (!a || !b)
  1541. return -1; // error really
  1542. // less than
  1543. if (a->texture < b->texture)
  1544. return -1;
  1545. // greater than ( no need for equal )
  1546. return 1;
  1547. }
  1548. void setupTextureColor(texture_tri_t *r_tri, Render *render, float *colorf)
  1549. {
  1550. unsigned char color[4];
  1551. unsigned int colorI;
  1552. color[0] = (unsigned char)(colorf[0]*255.0f);
  1553. color[1] = (unsigned char)(colorf[1]*255.0f);
  1554. color[2] = (unsigned char)(colorf[2]*255.0f);
  1555. color[3] = (unsigned char)(colorf[3]*255.0f);
  1556. ((unsigned char *)(&colorI))[3] = color[0];
  1557. ((unsigned char *)(&colorI))[2] = color[1];
  1558. ((unsigned char *)(&colorI))[1] = color[2];
  1559. ((unsigned char *)(&colorI))[0] = color[3];
  1560. if (!gColorTextureHACK.find(colorI))
  1561. {
  1562. gColorTextureHACK.pushBack(colorI);
  1563. r_tri->texture = gTextureOffset + gColorTextureHACK.size();
  1564. render->loadTexture(Texture::generateColorTexture(color, 32, 32),
  1565. 32, 32,
  1566. r_tri->texture);
  1567. #ifdef DEBUG_COLOR_TEXTURE_GEN
  1568. printf("Color 0x%02x%02x%02x%02x | 0x%08xto texture[%u]?\n",
  1569. color[0], color[1], color[2], color[3], colorI,
  1570. gColorTextureHACK.size());
  1571. #endif
  1572. }
  1573. else
  1574. {
  1575. //printf("Color already loaded %i -> 0x%08x\n",
  1576. // gColorTextureHACK.getCurrentIndex(),
  1577. // gColorTextureHACK.current());
  1578. r_tri->texture = gTextureOffset + gColorTextureHACK.getCurrentIndex();
  1579. }
  1580. //r_tri->texture = white; // White texture
  1581. }
  1582. void OpenRaider::processModel(int index)
  1583. {
  1584. int i, j, count, texture;
  1585. int vertexIndices[6];
  1586. float st[12];
  1587. float color[4];
  1588. unsigned short transparency;
  1589. texture_tri_t *r_tri;
  1590. // Assert common sense
  1591. if (index < 0 || !m_tombraider.isMeshValid(index))
  1592. {
  1593. //! \fixme allow sparse lists with matching ids instead?
  1594. gWorld.addMesh(NULL); // Filler, to make meshes array ids align
  1595. //printf("x");
  1596. //fflush(stdout);
  1597. return;
  1598. }
  1599. #ifndef EXPERIMENTAL
  1600. // WHITE texture id
  1601. int white = 0;
  1602. #endif
  1603. model_mesh_t *mesh = new model_mesh_t;
  1604. // Mongoose 2002.08.30, Testing support for 'shootable' models ( traceable )
  1605. m_tombraider.getMeshCollisionInfo(index, mesh->center, &mesh->radius);
  1606. //! \fixme Arrays don't work either =)
  1607. // Mesh geometery, colors, etc
  1608. m_tombraider.getMeshVertexArrays(index,
  1609. &mesh->vertexCount, &mesh->vertices,
  1610. &mesh->normalCount, &mesh->normals,
  1611. &mesh->colorCount, &mesh->colors);
  1612. // Textured Triangles
  1613. count = m_tombraider.getMeshTexturedTriangleCount(index);
  1614. mesh->texturedTriangles.reserve(count); // little faster
  1615. for (i = 0; i < count; ++i)
  1616. {
  1617. r_tri = new texture_tri_t;
  1618. m_tombraider.getMeshTexturedTriangle(index, i,
  1619. r_tri->index,
  1620. r_tri->st,
  1621. &r_tri->texture,
  1622. &r_tri->transparency);
  1623. r_tri->texture += m_texOffset;
  1624. // Add to face vector
  1625. mesh->texturedTriangles.pushBack(r_tri);
  1626. }
  1627. // Coloured Triangles
  1628. count = m_tombraider.getMeshColoredTriangleCount(index);
  1629. mesh->coloredTriangles.reserve(count); // little faster
  1630. for (i = 0; i < count; i++)
  1631. {
  1632. r_tri = new texture_tri_t;
  1633. m_tombraider.getMeshColoredTriangle(index, i,
  1634. r_tri->index,
  1635. color);
  1636. r_tri->st[0] = color[0];
  1637. r_tri->st[1] = color[1];
  1638. r_tri->st[2] = color[2];
  1639. r_tri->st[3] = color[3];
  1640. r_tri->st[4] = 1.0;
  1641. r_tri->st[5] = 1.0;
  1642. #ifdef EXPERIMENTAL
  1643. setupTextureColor(r_tri, &m_render, color);
  1644. #else
  1645. r_tri->texture = white; // White texture
  1646. #endif
  1647. r_tri->transparency = 0;
  1648. // Add to face vector
  1649. mesh->coloredTriangles.pushBack(r_tri);
  1650. }
  1651. // Textured Rectangles
  1652. count = m_tombraider.getMeshTexturedRectangleCount(index);
  1653. mesh->texturedRectangles.reserve(count*2); // little faster
  1654. for (i = 0; i < count; ++i)
  1655. {
  1656. m_tombraider.getMeshTexturedRectangle(index, i,
  1657. vertexIndices,
  1658. st,
  1659. &texture,
  1660. &transparency);
  1661. r_tri = new texture_tri_t;
  1662. for (j = 0; j < 3; ++j)
  1663. r_tri->index[j] = vertexIndices[j];
  1664. for (j = 0; j < 6; ++j)
  1665. r_tri->st[j] = st[j];
  1666. r_tri->texture = texture + m_texOffset;
  1667. r_tri->transparency = transparency;
  1668. // Add to face vector
  1669. mesh->texturedRectangles.pushBack(r_tri);
  1670. r_tri = new texture_tri_t;
  1671. for (j = 3; j < 6; ++j)
  1672. r_tri->index[j-3] = vertexIndices[j];
  1673. for (j = 6; j < 12; ++j)
  1674. r_tri->st[j-6] = st[j];
  1675. r_tri->texture = texture + m_texOffset;
  1676. r_tri->transparency = transparency;
  1677. // Add to face vector
  1678. mesh->texturedRectangles.pushBack(r_tri);
  1679. }
  1680. // Coloured Rectangles
  1681. count = m_tombraider.getMeshColoredRectangleCount(index);
  1682. mesh->coloredRectangles.reserve(count*2); // little faster
  1683. for (i = 0; i < count; ++i)
  1684. {
  1685. m_tombraider.getMeshColoredRectangle(index, i,
  1686. vertexIndices,
  1687. color);
  1688. r_tri = new texture_tri_t;
  1689. for (j = 0; j < 3; ++j)
  1690. r_tri->index[j] = vertexIndices[j];
  1691. //for (j = 0; j < 6; ++j)
  1692. // r_tri->st[j] = st[j];
  1693. r_tri->st[0] = color[0];
  1694. r_tri->st[1] = color[1];
  1695. r_tri->st[2] = color[2];
  1696. r_tri->st[3] = color[3];
  1697. r_tri->st[4] = 1.0;
  1698. r_tri->st[5] = 1.0;
  1699. #ifdef EXPERIMENTAL
  1700. //for (j = 6; j < 12; ++j)
  1701. // r_tri->st[j-6] = st[j];
  1702. setupTextureColor(r_tri, &m_render, color);
  1703. #else
  1704. r_tri->texture = white; // White texture
  1705. #endif
  1706. r_tri->transparency = 0;
  1707. // Add to face vector
  1708. mesh->coloredRectangles.pushBack(r_tri);
  1709. r_tri = new texture_tri_t;
  1710. for (j = 3; j < 6; ++j)
  1711. r_tri->index[j-3] = vertexIndices[j];
  1712. //for (j = 6; j < 12; ++j)
  1713. // r_tri->st[j-6] = st[j];
  1714. r_tri->st[0] = color[0];
  1715. r_tri->st[1] = color[1];
  1716. r_tri->st[2] = color[2];
  1717. r_tri->st[3] = color[3];
  1718. r_tri->st[4] = 1.0;
  1719. r_tri->st[5] = 1.0;
  1720. #ifdef EXPERIMENTAL
  1721. setupTextureColor(r_tri, &m_render, color);
  1722. #else
  1723. r_tri->texture = white; // White texture
  1724. #endif
  1725. r_tri->transparency = 0;
  1726. // Add to face vector
  1727. mesh->coloredRectangles.pushBack(r_tri);
  1728. }
  1729. // Sort faces by texture
  1730. mesh->texturedTriangles.qSort(compareFaceTextureId);
  1731. mesh->coloredTriangles.qSort(compareFaceTextureId);
  1732. mesh->texturedRectangles.qSort(compareFaceTextureId);
  1733. mesh->coloredRectangles.qSort(compareFaceTextureId);
  1734. gWorld.addMesh(mesh);
  1735. //printf(".");
  1736. //fflush(stdout);
  1737. }
  1738. #define MATRIX_TRANSFORMS
  1739. void OpenRaider::processRoom(int index)
  1740. {
  1741. unsigned int i, j, count;
  1742. room_mesh_t *r_mesh = NULL;
  1743. RenderRoom *rRoom = NULL;
  1744. #ifdef MATRIX_TRANSFORMS
  1745. Matrix transform;
  1746. #endif
  1747. if (!m_tombraider.isRoomValid(index))
  1748. {
  1749. openraider_error("OpenRaider::RoomSetup", "Invalid room index",
  1750. __FILE__, __LINE__);
  1751. print(false, "WARNING: Handling invalid vertex array in room");
  1752. gWorld.addRoom(0x0);
  1753. m_render.addRoom(0x0);
  1754. //printf("x");
  1755. //fflush(stdout);
  1756. return;
  1757. }
  1758. rRoom = new RenderRoom();
  1759. r_mesh = new room_mesh_t;
  1760. r_mesh->id = index;
  1761. m_tombraider.getRoomInfo(index, &r_mesh->flags, r_mesh->pos,
  1762. r_mesh->bbox_min, r_mesh->bbox_max);
  1763. // Adjust positioning for OR world coord translation
  1764. r_mesh->bbox_min[0] += r_mesh->pos[0];
  1765. r_mesh->bbox_max[0] += r_mesh->pos[0];
  1766. r_mesh->bbox_min[2] += r_mesh->pos[2];
  1767. r_mesh->bbox_max[2] += r_mesh->pos[2];
  1768. // Mongoose 2002.04.03, Setup 3d transform
  1769. #ifdef MATRIX_TRANSFORMS
  1770. transform.setIdentity();
  1771. transform.translate(r_mesh->pos);
  1772. #endif
  1773. // Setup portals
  1774. float portalVertices[12];
  1775. count = m_tombraider.getRoomPortalCount(index);
  1776. //! \fixme OR wrongly uses a cached adj room list for rendering vis
  1777. r_mesh->adjacentRooms.reserve(count + 1);
  1778. r_mesh->adjacentRooms.setError(-1);
  1779. // Current room is always first
  1780. r_mesh->adjacentRooms.pushBack(index);
  1781. for (i = 0; i < count; ++i)
  1782. {
  1783. portal_t *portal = new portal_t;
  1784. m_tombraider.getRoomPortal(index, i,
  1785. &portal->adjoining_room, portal->normal,
  1786. portalVertices);
  1787. for (j = 0; j < 4; ++j)
  1788. {
  1789. portal->vertices[j][0] = portalVertices[j*3];
  1790. portal->vertices[j][1] = portalVertices[j*3+1];
  1791. portal->vertices[j][2] = portalVertices[j*3+2];
  1792. // Relative coors in vis portals
  1793. #ifdef MATRIX_TRANSFORMS
  1794. transform.multiply3v(portal->vertices[j], portal->vertices[j]);
  1795. #else
  1796. portal->vertices[j][0] += r_mesh->pos[0];
  1797. portal->vertices[j][1] += r_mesh->pos[1];
  1798. portal->vertices[j][2] += r_mesh->pos[2];
  1799. #endif
  1800. }
  1801. r_mesh->adjacentRooms.pushBack(portal->adjoining_room);
  1802. r_mesh->portals.pushBack(portal);
  1803. }
  1804. // Physics/gameplay use /////////////////////////////
  1805. //! \fixme Use more of sector structure, boxes, and floordata
  1806. // List of sectors in this room
  1807. unsigned int sectorFlags;
  1808. int floorDataIndex, boxIndex, roomBelow, roomAbove;
  1809. count = m_tombraider.getRoomSectorCount(index, &r_mesh->numZSectors,
  1810. &r_mesh->numXSectors);
  1811. r_mesh->sectors.reserve(count);
  1812. r_mesh->sectors.setError(0x0);
  1813. for (i = 0; i < count; ++i)
  1814. {
  1815. sector_t *sector = new sector_t;
  1816. m_tombraider.getRoomSector(index, i, &sectorFlags,
  1817. &sector->ceiling, &sector->floor,
  1818. &floorDataIndex, &boxIndex, &roomBelow,
  1819. &roomAbove);
  1820. if (sectorFlags & tombraiderSector_wall)
  1821. {
  1822. sector->wall = true;
  1823. }
  1824. else
  1825. {
  1826. sector->wall = false;
  1827. }
  1828. r_mesh->sectors.pushBack(sector);
  1829. }
  1830. // Setup collision boxes ( Should use sectors, but this is a test )
  1831. count = m_tombraider.getRoomBoxCount(index);
  1832. r_mesh->boxes.reserve(count);
  1833. r_mesh->boxes.setError(0x0);
  1834. //! fixme Only to be done only on room[0]? I don't think so...
  1835. for (i = 0; !index && i < count; ++i)
  1836. {
  1837. box_t *box = new box_t;
  1838. m_tombraider.getRoomBox(index, i,
  1839. box->a.pos, box->b.pos, box->c.pos, box->d.pos);
  1840. r_mesh->boxes.pushBack(box);
  1841. }
  1842. // Setup room lights /////////////////////////////////////
  1843. unsigned int lightFlags, lightType;
  1844. count = m_tombraider.getRoomLightCount(index);
  1845. rRoom->lights.reserve(count);
  1846. rRoom->lights.setError(0x0);
  1847. for (i = 0; i < count; ++i)
  1848. {
  1849. Light *light = new Light();
  1850. m_tombraider.getRoomLight(index, i,
  1851. light->mPos, light->mColor, light->mDir,
  1852. &light->mAtt, &light->mCutoff,
  1853. &lightType, &lightFlags);
  1854. switch (lightType)
  1855. {
  1856. case tombraiderLight_typeDirectional:
  1857. light->mType = Light::typeDirectional;
  1858. break;
  1859. case tombraiderLight_typeSpot:
  1860. light->mType = Light::typeSpot;
  1861. break;
  1862. case tombraiderLight_typePoint:
  1863. default:
  1864. light->mType = Light::typePoint;
  1865. }
  1866. rRoom->lights.pushBack(light);
  1867. }
  1868. // Room geometery //////////////////////////////////
  1869. //#define EXPERIMENTAL_UNFIFIED_ROOM_GEOMETERY
  1870. #ifdef EXPERIMENTAL_UNFIFIED_ROOM_GEOMETERY
  1871. unsigned int vertexCount, normalCount, colorCount, triCount;
  1872. vec_t *vertexArray;
  1873. vec_t *normalArray;
  1874. vec_t *colorArray;
  1875. unsigned int *indices, *flags;
  1876. float *texCoords;
  1877. int *textures;
  1878. m_tombraider.getRoomVertexArrays(index,
  1879. &vertexCount, &vertexArray,
  1880. &normalCount, &normalArray,
  1881. &colorCount, &colorArray);
  1882. rRoom->mesh.bufferVertexArray(vertexCount, (vec_t *)vertexArray);
  1883. rRoom->mesh.bufferNormalArray(normalCount, (vec_t *)normalArray);
  1884. rRoom->mesh.bufferColorArray(vertexCount, (vec_t *)colorArray);
  1885. m_tombraider.getRoomTriangles(index, m_texOffset,
  1886. &triCount, &indices, &texCoords, &textures,
  1887. &flags);
  1888. rRoom->mesh.bufferTriangles(triCount, indices, texCoords, textures, flags);
  1889. #else
  1890. float rgba[4];
  1891. float xyz[3];
  1892. count = m_tombraider.getRoomVertexCount(index);
  1893. rRoom->mesh.allocateVertices(count);
  1894. rRoom->mesh.allocateNormals(0); // count
  1895. rRoom->mesh.allocateColors(count);
  1896. for (i = 0; i < count; ++i)
  1897. {
  1898. m_tombraider.getRoomVertex(index, i, xyz, rgba);
  1899. rRoom->mesh.setVertex(i, xyz[0], xyz[1], xyz[2]);
  1900. rRoom->mesh.setColor(i, rgba);
  1901. }
  1902. // Mongoose 2002.06.09, Setup allocation of meshes and polygons
  1903. // Counters ( Textured polygon lists are allocated per texture)
  1904. // ( Textures are mapped to these meshes )
  1905. int triangle_counter[TextureLimit];
  1906. int triangle_counter_alpha[TextureLimit];
  1907. int rectangle_counter[TextureLimit];
  1908. int rectangle_counter_alpha[TextureLimit];
  1909. int tris_mesh_map[TextureLimit];
  1910. int rect_mesh_map[TextureLimit];
  1911. for (i = 0; i < TextureLimit; ++i)
  1912. {
  1913. triangle_counter[i] = 0;
  1914. triangle_counter_alpha[i] = 0;
  1915. rectangle_counter[i] = 0;
  1916. rectangle_counter_alpha[i] = 0;
  1917. tris_mesh_map[i] = -1;
  1918. rect_mesh_map[i] = -1;
  1919. }
  1920. unsigned int numTris = 0;
  1921. unsigned int numQuads = 0;
  1922. int texture;
  1923. unsigned int r, t, q, v, flags;
  1924. unsigned int indices[4];
  1925. float texCoords[8];
  1926. count = m_tombraider.getRoomTriangleCount(index);
  1927. // Mongoose 2002.08.15, Presort by alpha and texture and setup mapping
  1928. for (t = 0; t < count; ++t)
  1929. {
  1930. m_tombraider.getRoomTriangle(index, t,
  1931. indices, texCoords, &texture, &flags);
  1932. texture += m_texOffset;
  1933. if (texture > (int)TextureLimit)
  1934. {
  1935. print(true, "Handling bad room[%i].tris[%i].texture = %i",
  1936. index, t, texture);
  1937. texture = TextureLimit - 1;
  1938. }
  1939. // Counters set up polygon allocation
  1940. if (flags & tombraiderFace_Alpha ||
  1941. flags & tombraiderFace_PartialAlpha)
  1942. {
  1943. triangle_counter_alpha[texture] += 1;
  1944. }
  1945. else
  1946. {
  1947. triangle_counter[texture] += 1;
  1948. }
  1949. // Counter sets up texture id to mesh id mapping
  1950. if (tris_mesh_map[texture] == -1)
  1951. {
  1952. tris_mesh_map[texture] = ++numTris;
  1953. }
  1954. }
  1955. count = m_tombraider.getRoomRectangleCount(index);
  1956. for (r = 0; r < count; ++r)
  1957. {
  1958. m_tombraider.getRoomRectangle(index, r,
  1959. indices, texCoords, &texture, &flags);
  1960. texture += m_texOffset;
  1961. if (texture > (int)TextureLimit)
  1962. {
  1963. print(true, "Handling bad room[%i].quad[%i].texture = %i",
  1964. index, r, texture);
  1965. texture = TextureLimit - 1;
  1966. }
  1967. if (flags & tombraiderFace_Alpha ||
  1968. flags & tombraiderFace_PartialAlpha)
  1969. {
  1970. rectangle_counter_alpha[texture] += 1;
  1971. }
  1972. else
  1973. {
  1974. rectangle_counter[texture] += 1;
  1975. }
  1976. if (rect_mesh_map[texture] == -1)
  1977. {
  1978. rect_mesh_map[texture] = ++numQuads;
  1979. }
  1980. }
  1981. // Allocate indexed polygon meshes
  1982. rRoom->mesh.allocateTriangles(numTris);
  1983. rRoom->mesh.allocateRectangles(numQuads);
  1984. for (i = 0, j = 0; i < TextureLimit; ++i)
  1985. {
  1986. if (tris_mesh_map[i] > 0)
  1987. {
  1988. j = tris_mesh_map[i] - 1;
  1989. t = triangle_counter[i];
  1990. rRoom->mesh.mTris[j].texture = i;
  1991. #ifdef MULTITEXTURE
  1992. rRoom->mesh.mTris[j].bumpmap = gMapTex2Bump[i];
  1993. #endif
  1994. rRoom->mesh.mTris[j].cnum_triangles = 0;
  1995. rRoom->mesh.mTris[j].num_triangles = 0;
  1996. rRoom->mesh.mTris[j].cnum_alpha_triangles = 0;
  1997. rRoom->mesh.mTris[j].num_alpha_triangles = 0;
  1998. rRoom->mesh.mTris[j].triangles = 0x0;
  1999. rRoom->mesh.mTris[j].alpha_triangles = 0x0;
  2000. rRoom->mesh.mTris[j].texcoors = 0x0;
  2001. rRoom->mesh.mTris[j].texcoors2 = 0x0;
  2002. if (t > 0)
  2003. {
  2004. rRoom->mesh.mTris[j].num_triangles = t;
  2005. rRoom->mesh.mTris[j].triangles = new unsigned int[t*3];
  2006. rRoom->mesh.mTris[j].num_texcoors = t * 3;
  2007. rRoom->mesh.mTris[j].texcoors = new vec2_t[t * 3];
  2008. }
  2009. t = triangle_counter_alpha[i];
  2010. if (t > 0)
  2011. {
  2012. rRoom->mesh.mTris[j].num_alpha_triangles = t;
  2013. rRoom->mesh.mTris[j].alpha_triangles = new unsigned int[t*3];
  2014. rRoom->mesh.mTris[j].num_texcoors2 = t * 3;
  2015. rRoom->mesh.mTris[j].texcoors2 = new vec2_t[t * 3];
  2016. }
  2017. }
  2018. ///////////////////////////////////////////
  2019. if (rect_mesh_map[i] > 0)
  2020. {
  2021. j = rect_mesh_map[i] - 1;
  2022. r = rectangle_counter[i];
  2023. rRoom->mesh.mQuads[j].texture = i;
  2024. #ifdef MULTITEXTURE
  2025. rRoom->mesh.mQuads[j].bumpmap = gMapTex2Bump[i];
  2026. #endif
  2027. rRoom->mesh.mQuads[j].cnum_quads = 0;
  2028. rRoom->mesh.mQuads[j].num_quads = 0;
  2029. rRoom->mesh.mQuads[j].cnum_alpha_quads = 0;
  2030. rRoom->mesh.mQuads[j].num_alpha_quads = 0;
  2031. rRoom->mesh.mQuads[j].quads = 0x0;
  2032. rRoom->mesh.mQuads[j].alpha_quads = 0x0;
  2033. rRoom->mesh.mQuads[j].texcoors = 0x0;
  2034. rRoom->mesh.mQuads[j].texcoors2 = 0x0;
  2035. if (r > 0)
  2036. {
  2037. rRoom->mesh.mQuads[j].num_quads = r;
  2038. rRoom->mesh.mQuads[j].quads = new unsigned int[r*4];
  2039. rRoom->mesh.mQuads[j].num_texcoors = r * 4;
  2040. rRoom->mesh.mQuads[j].texcoors = new vec2_t[r * 4];
  2041. }
  2042. r = rectangle_counter_alpha[i];
  2043. if (r > 0)
  2044. {
  2045. rRoom->mesh.mQuads[j].num_alpha_quads = r;
  2046. rRoom->mesh.mQuads[j].alpha_quads = new unsigned int[r*4];
  2047. rRoom->mesh.mQuads[j].num_texcoors2 = r * 4;
  2048. rRoom->mesh.mQuads[j].texcoors2 = new vec2_t[r * 4];
  2049. }
  2050. }
  2051. }
  2052. // Generate textured triangles
  2053. count = m_tombraider.getRoomTriangleCount(index);
  2054. for (t = 0; t < count; ++t)
  2055. {
  2056. m_tombraider.getRoomTriangle(index, t,
  2057. indices, texCoords, &texture, &flags);
  2058. // Adjust texture id using m_texOffset to map into
  2059. // correct textures
  2060. texture += m_texOffset;
  2061. j = tris_mesh_map[texture] - 1;
  2062. // Setup per vertex
  2063. for (i = 0; i < 3; ++i)
  2064. {
  2065. // Get vertex index {(0, a), (1, b), (2, c)}
  2066. v = indices[i];
  2067. if ((flags & tombraiderFace_Alpha ||
  2068. flags & tombraiderFace_PartialAlpha) &&
  2069. rRoom->mesh.mTris[j].num_alpha_triangles > 0)
  2070. {
  2071. q = rRoom->mesh.mTris[j].cnum_alpha_triangles*3+i;
  2072. rRoom->mesh.mTris[j].alpha_triangles[q] = v;
  2073. rRoom->mesh.mTris[j].texcoors2[q][0] = texCoords[i*2];
  2074. rRoom->mesh.mTris[j].texcoors2[q][1] = texCoords[i*2+1];
  2075. }
  2076. else if (rRoom->mesh.mTris[j].num_triangles > 0)
  2077. {
  2078. q = rRoom->mesh.mTris[j].cnum_triangles*3+i;
  2079. rRoom->mesh.mTris[j].triangles[q] = v;
  2080. rRoom->mesh.mTris[j].texcoors[q][0] = texCoords[i*2];
  2081. rRoom->mesh.mTris[j].texcoors[q][1] = texCoords[i*2+1];
  2082. }
  2083. // Partial alpha hack
  2084. if (flags & tombraiderFace_PartialAlpha)
  2085. {
  2086. //rRoom->mesh.colors[v].rgba[3] = 0.45;
  2087. }
  2088. }
  2089. if (flags & tombraiderFace_Alpha ||
  2090. flags & tombraiderFace_PartialAlpha)
  2091. {
  2092. rRoom->mesh.mTris[j].cnum_alpha_triangles++;
  2093. }
  2094. else
  2095. {
  2096. rRoom->mesh.mTris[j].cnum_triangles++;
  2097. }
  2098. }
  2099. // Generate textured quads
  2100. count = m_tombraider.getRoomRectangleCount(index);
  2101. for (r = 0; r < count; ++r)
  2102. {
  2103. m_tombraider.getRoomRectangle(index, r,
  2104. indices, texCoords, &texture, &flags);
  2105. // Adjust texture id using m_texOffset to map into
  2106. // correct textures
  2107. texture += m_texOffset;
  2108. if (texture > (int)TextureLimit)
  2109. {
  2110. texture = TextureLimit - 1;
  2111. }
  2112. j = rect_mesh_map[texture] - 1;
  2113. if (rRoom->mesh.mQuads[j].num_quads <= 0 &&
  2114. rRoom->mesh.mQuads[j].num_alpha_quads <= 0)
  2115. continue;
  2116. // Setup per vertex
  2117. for (i = 0; i < 4; ++i)
  2118. {
  2119. // Get vertex index {(0, a), (1, b), (2, c), (3, d)}
  2120. v = indices[i];
  2121. if ((flags & tombraiderFace_Alpha ||
  2122. flags & tombraiderFace_PartialAlpha) &&
  2123. rRoom->mesh.mQuads[j].num_alpha_quads > 0)
  2124. {
  2125. q = rRoom->mesh.mQuads[j].cnum_alpha_quads*4+i;
  2126. rRoom->mesh.mQuads[j].alpha_quads[q] = v;
  2127. rRoom->mesh.mQuads[j].texcoors2[q][0] = texCoords[i*2];
  2128. rRoom->mesh.mQuads[j].texcoors2[q][1] = texCoords[i*2+1];
  2129. }
  2130. else if (rRoom->mesh.mQuads[j].num_quads > 0)
  2131. {
  2132. q = rRoom->mesh.mQuads[j].cnum_quads*4+i;
  2133. rRoom->mesh.mQuads[j].quads[q] = v;
  2134. rRoom->mesh.mQuads[j].texcoors[q][0] = texCoords[i*2];
  2135. rRoom->mesh.mQuads[j].texcoors[q][1] = texCoords[i*2+1];
  2136. }
  2137. // Partial alpha hack
  2138. if (flags & tombraiderFace_PartialAlpha)
  2139. {
  2140. //rRoom->mesh.colors[v].rgba[3] = 0.45;
  2141. }
  2142. }
  2143. if (flags & tombraiderFace_Alpha ||
  2144. flags & tombraiderFace_PartialAlpha)
  2145. {
  2146. rRoom->mesh.mQuads[j].cnum_alpha_quads++;
  2147. }
  2148. else
  2149. {
  2150. rRoom->mesh.mQuads[j].cnum_quads++;
  2151. }
  2152. }
  2153. #endif
  2154. // Room models
  2155. count = m_tombraider.getRoomModelCount(index);
  2156. r_mesh->models.reserve(count);
  2157. r_mesh->models.setError(0x0);
  2158. for (i = 0; i < count; ++i)
  2159. {
  2160. static_model_t *model = new static_model_t;
  2161. m_tombraider.getRoomModel(index, i,
  2162. &model->index, model->pos, &model->yaw);
  2163. r_mesh->models.pushBack(model);
  2164. }
  2165. // Room sprites
  2166. float spriteVertices[12];
  2167. float spriteTexCoords[8];
  2168. count = m_tombraider.getRoomSpriteCount(index);
  2169. r_mesh->sprites.reserve(count);
  2170. r_mesh->sprites.setError(0x0);
  2171. for (i = 0; i < count; ++i)
  2172. {
  2173. sprite_t *sprite = new sprite_t;
  2174. m_tombraider.getRoomSprite(index, i,
  2175. 10.0f, &sprite->texture, sprite->pos,
  2176. spriteVertices, spriteTexCoords);
  2177. sprite->texture += m_texOffset; // OpenRaider preloads some textures
  2178. sprite->vertex[0].pos[0] = spriteVertices[0];
  2179. sprite->vertex[0].pos[1] = spriteVertices[1];
  2180. sprite->vertex[0].pos[2] = spriteVertices[2];
  2181. sprite->vertex[1].pos[0] = spriteVertices[3];
  2182. sprite->vertex[1].pos[1] = spriteVertices[4];
  2183. sprite->vertex[1].pos[2] = spriteVertices[5];
  2184. sprite->vertex[2].pos[0] = spriteVertices[6];
  2185. sprite->vertex[2].pos[1] = spriteVertices[7];
  2186. sprite->vertex[2].pos[2] = spriteVertices[8];
  2187. sprite->vertex[3].pos[0] = spriteVertices[9];
  2188. sprite->vertex[3].pos[1] = spriteVertices[10];
  2189. sprite->vertex[3].pos[2] = spriteVertices[11];
  2190. sprite->texel[0].st[0] = spriteTexCoords[0];
  2191. sprite->texel[0].st[1] = spriteTexCoords[1];
  2192. sprite->texel[1].st[0] = spriteTexCoords[2];
  2193. sprite->texel[1].st[1] = spriteTexCoords[3];
  2194. sprite->texel[2].st[0] = spriteTexCoords[4];
  2195. sprite->texel[2].st[1] = spriteTexCoords[5];
  2196. sprite->texel[3].st[0] = spriteTexCoords[6];
  2197. sprite->texel[3].st[1] = spriteTexCoords[7];
  2198. r_mesh->sprites.pushBack(sprite);
  2199. }
  2200. gWorld.addRoom(r_mesh);
  2201. rRoom->room = r_mesh;
  2202. m_render.addRoom(rRoom);
  2203. //printf(".");
  2204. //fflush(stdout);
  2205. }
  2206. //! \fixme Use rc_get_bool consistently!
  2207. void OpenRaider::consoleCommand(char *cmd)
  2208. {
  2209. bool b = false;
  2210. if (!cmd || !cmd[0])
  2211. return;
  2212. // Mongoose 2003.05.31, Strip off decp console prefix
  2213. if (cmd[0] == '>')
  2214. {
  2215. rc_command(">", cmd);
  2216. }
  2217. if (rc_command("quit", cmd))
  2218. {
  2219. shutdown(0);
  2220. }
  2221. else if (rc_command("fly", cmd))
  2222. {
  2223. if (LARA)
  2224. {
  2225. LARA->moveType = worldMoveType_fly;
  2226. }
  2227. print(false, "World clipping is [SPACEY]");
  2228. }
  2229. else if (rc_command("walk", cmd))
  2230. {
  2231. if (LARA)
  2232. {
  2233. LARA->moveType = worldMoveType_walk;
  2234. }
  2235. print(false, "World clipping is [ON]");
  2236. }
  2237. else if (rc_command("ghost", cmd))
  2238. {
  2239. if (LARA)
  2240. {
  2241. LARA->moveType = worldMoveType_noClipping;
  2242. }
  2243. print(false, "World clipping is [OFF]");
  2244. }
  2245. else if (rc_command("loadlevel", cmd))
  2246. {
  2247. loadLevel(cmd);
  2248. }
  2249. else if (rc_command("play", cmd))
  2250. {
  2251. if (m_flags & OpenRaider_EnableSound)
  2252. {
  2253. mSound.play(atoi(cmd));
  2254. }
  2255. }
  2256. else if (rc_command("sensitivity.x", cmd))
  2257. {
  2258. m_mouseX = static_cast<float>(atof(cmd));
  2259. }
  2260. else if (rc_command("sensitivity.y", cmd))
  2261. {
  2262. m_mouseY = static_cast<float>(atof(cmd));
  2263. }
  2264. else if (rc_command("texture", cmd))
  2265. {
  2266. int error, tex = atoi(cmd);
  2267. if ((error = m_render.showTextureDebug(tex)) < 0)
  2268. print(false, "Could not load texture %d (%d)!", tex, error);
  2269. else
  2270. print(false, "Displaying texture %d in %d...", tex, error);
  2271. }
  2272. else if (rc_command("r_pigtails", cmd))
  2273. {
  2274. if (gLaraModel)
  2275. {
  2276. gLaraModel->pigtails = atoi(cmd);
  2277. if (gLaraModel->pigtails)
  2278. {
  2279. gLaraModel->ponyOff -= 20;
  2280. gLaraModel->ponytail[1] -= 32;
  2281. }
  2282. else
  2283. {
  2284. gLaraModel->ponyOff += 20;
  2285. gLaraModel->ponytail[1] += 32;
  2286. }
  2287. }
  2288. }
  2289. else if (rc_command("r_ponyangle", cmd))
  2290. {
  2291. if (gLaraModel)
  2292. {
  2293. gLaraModel->ponytailAngle = atoi(cmd);
  2294. }
  2295. }
  2296. else if (rc_command("r_ponyx", cmd))
  2297. {
  2298. if (gLaraModel)
  2299. {
  2300. gLaraModel->ponytail[0] = atoi(cmd);
  2301. }
  2302. }
  2303. else if (rc_command("r_ponyy", cmd))
  2304. {
  2305. if (gLaraModel)
  2306. {
  2307. gLaraModel->ponytail[1] = atoi(cmd);
  2308. }
  2309. }
  2310. else if (rc_command("r_ponyz", cmd))
  2311. {
  2312. if (gLaraModel)
  2313. {
  2314. gLaraModel->ponytail[2] = atoi(cmd);
  2315. }
  2316. }
  2317. else if (rc_command("r_animate", cmd))
  2318. {
  2319. rc_get_bool(cmd, &b);
  2320. if (b)
  2321. {
  2322. m_render.setFlags(Render::fAnimateAllModels);
  2323. print(false, "Animating all models");
  2324. }
  2325. else
  2326. {
  2327. m_render.clearFlags(Render::fAnimateAllModels);
  2328. print(false, "No longer animating all models");
  2329. }
  2330. }
  2331. else if (rc_command("r_ponytail", cmd))
  2332. {
  2333. rc_get_bool(cmd, &b);
  2334. if (b)
  2335. {
  2336. m_render.setFlags(Render::fRenderPonytail);
  2337. print(false, "Rendering ponytail");
  2338. }
  2339. else
  2340. {
  2341. m_render.clearFlags(Render::fRenderPonytail);
  2342. print(false, "No longer rendering ponytail");
  2343. }
  2344. }
  2345. else if (rc_command("r_light", cmd))
  2346. {
  2347. rc_get_bool(cmd, &b);
  2348. if (b)
  2349. {
  2350. m_render.setFlags(Render::fGL_Lights);
  2351. }
  2352. else
  2353. {
  2354. m_render.clearFlags(Render::fGL_Lights);
  2355. }
  2356. }
  2357. else if (rc_command("hop", cmd))
  2358. {
  2359. rc_get_bool(cmd, &b);
  2360. if (b)
  2361. {
  2362. gWorld.setFlag(World::fEnableHopping);
  2363. print(true, "Room hopping is on");
  2364. }
  2365. else
  2366. {
  2367. gWorld.clearFlag(World::fEnableHopping);
  2368. print(true, "Room hopping is off");
  2369. }
  2370. }
  2371. else if (rc_command("r_fog", cmd))
  2372. {
  2373. rc_get_bool(cmd, &b);
  2374. if (b)
  2375. {
  2376. m_render.setFlags(Render::fFog);
  2377. }
  2378. else
  2379. {
  2380. m_render.clearFlags(Render::fFog);
  2381. }
  2382. }
  2383. else if (rc_command("wireframe", cmd))
  2384. {
  2385. m_render.setMode(Render::modeWireframe);
  2386. print(false, "wireframe mode");
  2387. }
  2388. else if (rc_command("solid", cmd))
  2389. {
  2390. m_render.setMode(Render::modeSolid);
  2391. print(false, "solid mode");
  2392. }
  2393. else if (rc_command("texture", cmd))
  2394. {
  2395. m_render.setMode(Render::modeTexture);
  2396. print(false, "texture mode");
  2397. }
  2398. else if (rc_command("vertexlight", cmd))
  2399. {
  2400. m_render.setMode(Render::modeVertexLight);
  2401. print(false, "vertexlight mode");
  2402. }
  2403. else if (rc_command("titlescreen", cmd))
  2404. {
  2405. m_render.setMode(Render::modeLoadScreen);
  2406. print(false, "titlescreen mode");
  2407. }
  2408. else if (rc_command("r_viewmodel", cmd))
  2409. {
  2410. if (LARA)
  2411. {
  2412. SkeletalModel *smdl = static_cast<SkeletalModel *>(LARA->tmpHook);
  2413. skeletal_model_t *mdl = gWorld.getModel(atoi(cmd));
  2414. if (smdl)
  2415. {
  2416. smdl->setModel(mdl);
  2417. }
  2418. }
  2419. //m_render.ViewModel(LARA, atoi(cmd));
  2420. }
  2421. else if (rc_command("r_oneroom", cmd))
  2422. {
  2423. rc_get_bool(cmd, &b);
  2424. if (b)
  2425. {
  2426. m_render.setFlags(Render::fOneRoom);
  2427. }
  2428. else
  2429. {
  2430. m_render.clearFlags(Render::fOneRoom);
  2431. }
  2432. }
  2433. else if (rc_command("r_allrooms", cmd))
  2434. {
  2435. rc_get_bool(cmd, &b);
  2436. if (b)
  2437. {
  2438. m_render.setFlags(Render::fAllRooms);
  2439. }
  2440. else
  2441. {
  2442. m_render.clearFlags(Render::fAllRooms);
  2443. }
  2444. print(true, "Rendering all rooms [%s]", (atoi(cmd) == 0) ? "off" : "on");
  2445. }
  2446. else if (rc_command("r_sprite", cmd))
  2447. {
  2448. rc_get_bool(cmd, &b);
  2449. if (b)
  2450. {
  2451. m_render.setFlags(Render::fSprites);
  2452. }
  2453. else
  2454. {
  2455. m_render.clearFlags(Render::fSprites);
  2456. }
  2457. }
  2458. else if (rc_command("r_roommodel", cmd))
  2459. {
  2460. rc_get_bool(cmd, &b);
  2461. if (b)
  2462. {
  2463. m_render.setFlags(Render::fRoomModels);
  2464. }
  2465. else
  2466. {
  2467. m_render.clearFlags(Render::fRoomModels);
  2468. }
  2469. }
  2470. else if (rc_command("r_entmodel", cmd))
  2471. {
  2472. rc_get_bool(cmd, &b);
  2473. if (b)
  2474. {
  2475. m_render.setFlags(Render::fEntityModels);
  2476. }
  2477. else
  2478. {
  2479. m_render.clearFlags(Render::fEntityModels);
  2480. }
  2481. }
  2482. else if (rc_command("r_particle", cmd))
  2483. {
  2484. rc_get_bool(cmd, &b);
  2485. if (b)
  2486. {
  2487. m_render.setFlags(Render::fParticles);
  2488. }
  2489. else
  2490. {
  2491. m_render.clearFlags(Render::fParticles);
  2492. }
  2493. }
  2494. else if (rc_command("r_vis", cmd))
  2495. {
  2496. rc_get_bool(cmd, &b);
  2497. if (b)
  2498. {
  2499. m_render.setFlags(Render::fUsePortals);
  2500. }
  2501. else
  2502. {
  2503. m_render.clearFlags(Render::fUsePortals);
  2504. }
  2505. }
  2506. else if (rc_command("r_upf", cmd))
  2507. {
  2508. rc_get_bool(cmd, &b);
  2509. if (b)
  2510. {
  2511. m_render.setFlags(Render::fUpdateRoomListPerFrame);
  2512. }
  2513. else
  2514. {
  2515. m_render.clearFlags(Render::fUpdateRoomListPerFrame);
  2516. }
  2517. }
  2518. else if (rc_command("r_portal", cmd))
  2519. {
  2520. rc_get_bool(cmd, &b);
  2521. if (b)
  2522. {
  2523. m_render.setFlags(Render::fPortals);
  2524. }
  2525. else
  2526. {
  2527. m_render.clearFlags(Render::fPortals);
  2528. }
  2529. }
  2530. else if (rc_command("r_vmodel", cmd))
  2531. {
  2532. rc_get_bool(cmd, &b);
  2533. if (b)
  2534. {
  2535. m_render.setFlags(Render::fViewModel);
  2536. }
  2537. else
  2538. {
  2539. m_render.clearFlags(Render::fViewModel);
  2540. }
  2541. }
  2542. else if (rc_command("r_ralpha", cmd))
  2543. {
  2544. rc_get_bool(cmd, &b);
  2545. if (b)
  2546. {
  2547. m_render.setFlags(Render::fRoomAlpha);
  2548. }
  2549. else
  2550. {
  2551. m_render.clearFlags(Render::fRoomAlpha);
  2552. }
  2553. }
  2554. else if (rc_command("resize", cmd))
  2555. {
  2556. if (rc_command("xga", cmd))
  2557. {
  2558. resize(1024, 768);
  2559. m_render.Update(1024, 768);
  2560. }
  2561. else if (rc_command("svga", cmd))
  2562. {
  2563. resize(800, 600);
  2564. m_render.Update(800, 600);
  2565. }
  2566. else if (rc_command("vga", cmd))
  2567. {
  2568. resize(640, 460);
  2569. m_render.Update(640, 460);
  2570. }
  2571. }
  2572. else if (rc_command("sshot", cmd))
  2573. {
  2574. char *tmp = fullPath("~/.OpenRaider/sshots/", '/');
  2575. char *sfilename = bufferString("%s%s", tmp, VERSION);
  2576. m_render.screenShot(sfilename);
  2577. delete [] tmp;
  2578. delete [] sfilename;
  2579. print(false, "Took screenshot");
  2580. }
  2581. else if (rc_command("fullscreen", cmd))
  2582. {
  2583. toggleFullscreen();
  2584. }
  2585. else if (rc_command("showfps", cmd))
  2586. {
  2587. m_flags |= OpenRaider_ShowFPS;
  2588. rc_get_bool(cmd, &b);
  2589. if (!b)
  2590. {
  2591. m_flags ^= OpenRaider_ShowFPS;
  2592. }
  2593. }
  2594. else if (rc_command("bind", cmd))
  2595. {
  2596. if (rc_command("+forward", cmd))
  2597. {
  2598. bindKeyCommand("+forward", atoi(cmd), OpenRaiderKey_forward);
  2599. }
  2600. else if (rc_command("+console", cmd))
  2601. {
  2602. bindKeyCommand("+console", atoi(cmd), OpenRaiderKey_console);
  2603. }
  2604. else if (rc_command("+backward", cmd))
  2605. {
  2606. bindKeyCommand("+backward", atoi(cmd), OpenRaiderKey_backward);
  2607. }
  2608. else if (rc_command("+jump", cmd))
  2609. {
  2610. bindKeyCommand("+jump", atoi(cmd), OpenRaiderKey_jump);
  2611. }
  2612. else if (rc_command("+crouch", cmd))
  2613. {
  2614. bindKeyCommand("+crouch", atoi(cmd), OpenRaiderKey_crouch);
  2615. }
  2616. else if (rc_command("+right", cmd))
  2617. {
  2618. bindKeyCommand("+right", atoi(cmd), OpenRaiderKey_right);
  2619. }
  2620. else if (rc_command("+left", cmd))
  2621. {
  2622. bindKeyCommand("+left", atoi(cmd), OpenRaiderKey_left);
  2623. }
  2624. else if (rc_command("+attack", cmd))
  2625. {
  2626. bindKeyCommand("+attack", atoi(cmd), OpenRaiderKey_attack);
  2627. }
  2628. }
  2629. else if (rc_command("set", cmd))
  2630. {
  2631. if (rc_command("mousegrab", cmd))
  2632. {
  2633. setGrabMouse(atoi(cmd));
  2634. print(true, "Mouse grabbing [%s]", atoi(cmd) ? "on" : "off");
  2635. }
  2636. }
  2637. else if (rc_command("stat", cmd))
  2638. {
  2639. if (rc_command("fps", cmd))
  2640. {
  2641. m_flags ^= OpenRaider_ShowFPS;
  2642. }
  2643. else if (rc_command("pos", cmd))
  2644. {
  2645. if (LARA)
  2646. {
  2647. print(true, "Room %2i Pos %.0f %.0f %.0f Yaw %.0f Pitch %.0f",
  2648. LARA->room,
  2649. LARA->pos[0], LARA->pos[1], LARA->pos[2],
  2650. HEL_RAD_TO_DEG(LARA->angles[1]),
  2651. HEL_RAD_TO_DEG(LARA->angles[2]));
  2652. }
  2653. }
  2654. else if (rc_command("room", cmd))
  2655. {
  2656. if (rc_command("flags", cmd))
  2657. {
  2658. if (LARA)
  2659. {
  2660. print(true, "Room[%i] flags: 0x%x",
  2661. LARA->room,
  2662. gWorld.getRoomInfo(LARA->room));
  2663. }
  2664. }
  2665. }
  2666. }
  2667. }
  2668. void OpenRaider::loadPakFolderRecursive(const char *dir) {
  2669. struct dirent *ep;
  2670. DIR *pakDir;
  2671. pakDir = opendir(dir);
  2672. if (pakDir != NULL) {
  2673. while ((ep = readdir(pakDir)) != NULL) {
  2674. if (ep->d_type == DT_DIR) {
  2675. if ((strcmp(".", ep->d_name) != 0)
  2676. && (strcmp("..", ep->d_name) != 0)) {
  2677. char *tmp = bufferString("%s%s", dir, ep->d_name);
  2678. char *next = fullPath(tmp, '/');
  2679. loadPakFolderRecursive(next);
  2680. delete next;
  2681. delete tmp;
  2682. }
  2683. } else {
  2684. char *fullPathMap = bufferString("%s%s", dir, ep->d_name);
  2685. char *lowerPath = bufferString("%s", fullPathMap);
  2686. for (char *p = lowerPath; *p; ++p) *p = (char)tolower(*p);
  2687. // Check for valid extension
  2688. if (stringEndsWith(lowerPath, ".phd")
  2689. || stringEndsWith(lowerPath, ".tr2")
  2690. || stringEndsWith(lowerPath, ".tr4")
  2691. || stringEndsWith(lowerPath, ".trc")) {
  2692. if (m_tombraider.checkMime(fullPathMap) == 0) {
  2693. // printf("Validated pak: '%s'\n", fullPathMap);
  2694. // Just load relative filename
  2695. mMapList.pushBack(bufferString("%s", (fullPathMap + strlen(m_pakDir))));
  2696. } else {
  2697. printf("ERROR: pak file '%s' not found or invalid\n", fullPathMap);
  2698. delete [] fullPathMap;
  2699. }
  2700. }
  2701. delete [] lowerPath;
  2702. }
  2703. }
  2704. closedir(pakDir);
  2705. } else {
  2706. printf("Could not open PAK dir %s!\n", dir);
  2707. }
  2708. }
  2709. void OpenRaider::handleCommand(char *cmd, unsigned int mode)
  2710. {
  2711. bool b;
  2712. int i;
  2713. // So we can use switch stmt, translate the Ids
  2714. mode = mMode[mode];
  2715. switch (mode)
  2716. {
  2717. case 0: // [Video.OpenGL]
  2718. if (rc_command("Width", cmd))
  2719. {
  2720. m_width = atoi(cmd);
  2721. }
  2722. else if (rc_command("Height", cmd))
  2723. {
  2724. m_height = atoi(cmd);
  2725. }
  2726. else if (rc_command("FullScreen", cmd))
  2727. {
  2728. rc_get_bool(cmd, &b);
  2729. m_flags |= OpenRaider_FullScreen;
  2730. if (!b)
  2731. {
  2732. m_flags ^= OpenRaider_FullScreen;
  2733. }
  2734. }
  2735. else if (rc_command("Font", cmd))
  2736. {
  2737. gFontFilename = fullPath(cmd, 0);
  2738. }
  2739. else if (rc_command("Driver", cmd))
  2740. {
  2741. if (cmd[0])
  2742. {
  2743. setDriverGL(cmd);
  2744. }
  2745. }
  2746. else
  2747. {
  2748. printf("Command> [Video.OpenGL] Unknown command '%s'\n", cmd);
  2749. }
  2750. break;
  2751. case 1: // [Audio.OpenAL]
  2752. if (rc_command("Enable", cmd))
  2753. {
  2754. rc_get_bool(cmd, &b);
  2755. m_flags |= OpenRaider_EnableSound;
  2756. if (!b)
  2757. {
  2758. m_flags ^= OpenRaider_EnableSound;
  2759. }
  2760. }
  2761. else
  2762. {
  2763. printf("Command> [Audio.OpenAL] Unknown command '%s'\n", cmd);
  2764. }
  2765. break;
  2766. case 2: // [OpenRaider.Engine]
  2767. if (rc_command("PakDir", cmd))
  2768. {
  2769. if (m_pakDir)
  2770. {
  2771. delete [] m_pakDir;
  2772. }
  2773. m_pakDir = fullPath(cmd, '/');
  2774. // Recursively search for level paks instead of
  2775. // naming individual levels 2014-02-21 xythobuz
  2776. loadPakFolderRecursive(m_pakDir);
  2777. }
  2778. else if (rc_command("HomeDir", cmd))
  2779. {
  2780. if (m_homeDir)
  2781. {
  2782. delete [] m_homeDir;
  2783. }
  2784. i = strlen(cmd);
  2785. m_homeDir = fullPath(cmd, '/');
  2786. }
  2787. else if (rc_command("AudioDir", cmd))
  2788. {
  2789. if (m_audioDir)
  2790. {
  2791. delete [] m_audioDir;
  2792. }
  2793. m_audioDir = fullPath(cmd, '/');
  2794. }
  2795. else if (rc_command("MapDebug", cmd))
  2796. {
  2797. rc_get_bool(cmd, &b);
  2798. m_flags |= OpenRaider_DebugMap;
  2799. if (!b)
  2800. {
  2801. m_flags ^= OpenRaider_DebugMap;
  2802. }
  2803. }
  2804. // Mongoose 2001.12.31, Added music list back
  2805. else if (rc_command("Music", cmd))
  2806. {
  2807. if (cmd[0])
  2808. {
  2809. char *music;
  2810. i = strlen(cmd);
  2811. music = new char[i+1];
  2812. strncpy(music, cmd, i);
  2813. music[i] = 0;
  2814. mMusicList.pushBack(music);
  2815. }
  2816. }
  2817. else if (rc_command("DisplayFPS", cmd))
  2818. {
  2819. rc_get_bool(cmd, &b);
  2820. m_flags |= OpenRaider_ShowFPS;
  2821. if (!b)
  2822. {
  2823. m_flags ^= OpenRaider_ShowFPS;
  2824. }
  2825. }
  2826. else if (rc_command("ModelDebug", cmd))
  2827. {
  2828. rc_get_bool(cmd, &b);
  2829. m_flags |= OpenRaider_DebugModel;
  2830. if (!b)
  2831. {
  2832. m_flags ^= OpenRaider_DebugModel;
  2833. }
  2834. }
  2835. else if (rc_command("DumpTexture", cmd))
  2836. {
  2837. rc_get_bool(cmd, &b);
  2838. m_flags |= OpenRaider_DumpTexture;
  2839. if (!b)
  2840. {
  2841. m_flags ^= OpenRaider_DumpTexture;
  2842. }
  2843. }
  2844. else
  2845. {
  2846. printf("Command> [OpenRaider.Engine] Unknown command '%s'\n", cmd);
  2847. }
  2848. break;
  2849. case 3: // [Input.Mouse]
  2850. if (rc_command("SensitivityX", cmd))
  2851. {
  2852. m_mouseX = static_cast<float>(atof(cmd));
  2853. }
  2854. else if (rc_command("SensitivityY", cmd))
  2855. {
  2856. m_mouseY = static_cast<float>(atof(cmd));
  2857. }
  2858. else
  2859. {
  2860. printf("Command> [Input.Mouse] Unknown command '%s'\n", cmd);
  2861. }
  2862. break;
  2863. case 4:
  2864. if (cmd[1] == '.')
  2865. {
  2866. cmd[0] = '>';
  2867. cmd[1] = ' ';
  2868. for (i = strlen(cmd) - 1; i >= 0; --i)
  2869. {
  2870. if (cmd[i] == '.' || cmd[i] == '=')
  2871. {
  2872. cmd[i] = ' ';
  2873. }
  2874. }
  2875. }
  2876. consoleCommand(cmd);
  2877. break;
  2878. }
  2879. }
  2880. int main(int argc, char *argv[]) {
  2881. if (argc != 1) {
  2882. printf("Usage:\n\t%s\n", argv[0]);
  2883. return 1;
  2884. }
  2885. OpenRaider *game = OpenRaider::Instance();
  2886. atexit(killOpenRaiderSingleton);
  2887. game->start();
  2888. return 0;
  2889. }