tr_model.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. // tr_models.c -- model loading and caching
  19. #include "tr_local.h"
  20. #define LL(x) x=LittleLong(x)
  21. static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *name );
  22. static qboolean R_LoadMD4 (model_t *mod, void *buffer, const char *name );
  23. model_t *loadmodel;
  24. /*
  25. ** R_GetModelByHandle
  26. */
  27. model_t *R_GetModelByHandle( qhandle_t index ) {
  28. model_t *mod;
  29. // out of range gets the defualt model
  30. if ( index < 1 || index >= tr.numModels ) {
  31. return tr.models[0];
  32. }
  33. mod = tr.models[index];
  34. return mod;
  35. }
  36. //===============================================================================
  37. /*
  38. ** R_AllocModel
  39. */
  40. model_t *R_AllocModel( void ) {
  41. model_t *mod;
  42. if ( tr.numModels == MAX_MOD_KNOWN ) {
  43. return NULL;
  44. }
  45. mod = ri.Hunk_Alloc( sizeof( *tr.models[tr.numModels] ), h_low );
  46. mod->index = tr.numModels;
  47. tr.models[tr.numModels] = mod;
  48. tr.numModels++;
  49. return mod;
  50. }
  51. /*
  52. ====================
  53. RE_RegisterModel
  54. Loads in a model for the given name
  55. Zero will be returned if the model fails to load.
  56. An entry will be retained for failed models as an
  57. optimization to prevent disk rescanning if they are
  58. asked for again.
  59. ====================
  60. */
  61. qhandle_t RE_RegisterModel( const char *name ) {
  62. model_t *mod;
  63. unsigned *buf;
  64. int lod;
  65. int ident;
  66. qboolean loaded;
  67. qhandle_t hModel;
  68. int numLoaded;
  69. if ( !name || !name[0] ) {
  70. ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" );
  71. return 0;
  72. }
  73. if ( strlen( name ) >= MAX_QPATH ) {
  74. Com_Printf( "Model name exceeds MAX_QPATH\n" );
  75. return 0;
  76. }
  77. //
  78. // search the currently loaded models
  79. //
  80. for ( hModel = 1 ; hModel < tr.numModels; hModel++ ) {
  81. mod = tr.models[hModel];
  82. if ( !strcmp( mod->name, name ) ) {
  83. if( mod->type == MOD_BAD ) {
  84. return 0;
  85. }
  86. return hModel;
  87. }
  88. }
  89. // allocate a new model_t
  90. if ( ( mod = R_AllocModel() ) == NULL ) {
  91. ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name);
  92. return 0;
  93. }
  94. // only set the name after the model has been successfully loaded
  95. Q_strncpyz( mod->name, name, sizeof( mod->name ) );
  96. // make sure the render thread is stopped
  97. R_SyncRenderThread();
  98. mod->numLods = 0;
  99. //
  100. // load the files
  101. //
  102. numLoaded = 0;
  103. for ( lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod-- ) {
  104. char filename[1024];
  105. strcpy( filename, name );
  106. if ( lod != 0 ) {
  107. char namebuf[80];
  108. if ( strrchr( filename, '.' ) ) {
  109. *strrchr( filename, '.' ) = 0;
  110. }
  111. sprintf( namebuf, "_%d.md3", lod );
  112. strcat( filename, namebuf );
  113. }
  114. ri.FS_ReadFile( filename, (void **)&buf );
  115. if ( !buf ) {
  116. continue;
  117. }
  118. loadmodel = mod;
  119. ident = LittleLong(*(unsigned *)buf);
  120. if ( ident == MD4_IDENT ) {
  121. loaded = R_LoadMD4( mod, buf, name );
  122. } else {
  123. if ( ident != MD3_IDENT ) {
  124. ri.Printf (PRINT_WARNING,"RE_RegisterModel: unknown fileid for %s\n", name);
  125. goto fail;
  126. }
  127. loaded = R_LoadMD3( mod, lod, buf, name );
  128. }
  129. ri.FS_FreeFile (buf);
  130. if ( !loaded ) {
  131. if ( lod == 0 ) {
  132. goto fail;
  133. } else {
  134. break;
  135. }
  136. } else {
  137. mod->numLods++;
  138. numLoaded++;
  139. // if we have a valid model and are biased
  140. // so that we won't see any higher detail ones,
  141. // stop loading them
  142. // if ( lod <= r_lodbias->integer ) {
  143. // break;
  144. // }
  145. }
  146. }
  147. if ( numLoaded ) {
  148. // duplicate into higher lod spots that weren't
  149. // loaded, in case the user changes r_lodbias on the fly
  150. for ( lod-- ; lod >= 0 ; lod-- ) {
  151. mod->numLods++;
  152. mod->md3[lod] = mod->md3[lod+1];
  153. }
  154. return mod->index;
  155. }
  156. #ifdef _DEBUG
  157. else {
  158. ri.Printf (PRINT_WARNING,"RE_RegisterModel: couldn't load %s\n", name);
  159. }
  160. #endif
  161. fail:
  162. // we still keep the model_t around, so if the model name is asked for
  163. // again, we won't bother scanning the filesystem
  164. mod->type = MOD_BAD;
  165. return 0;
  166. }
  167. /*
  168. =================
  169. R_LoadMD3
  170. =================
  171. */
  172. static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name ) {
  173. int i, j;
  174. md3Header_t *pinmodel;
  175. md3Frame_t *frame;
  176. md3Surface_t *surf;
  177. md3Shader_t *shader;
  178. md3Triangle_t *tri;
  179. md3St_t *st;
  180. md3XyzNormal_t *xyz;
  181. md3Tag_t *tag;
  182. int version;
  183. int size;
  184. pinmodel = (md3Header_t *)buffer;
  185. version = LittleLong (pinmodel->version);
  186. if (version != MD3_VERSION) {
  187. ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n",
  188. mod_name, version, MD3_VERSION);
  189. return qfalse;
  190. }
  191. mod->type = MOD_MESH;
  192. size = LittleLong(pinmodel->ofsEnd);
  193. mod->dataSize += size;
  194. mod->md3[lod] = ri.Hunk_Alloc( size, h_low );
  195. Com_Memcpy (mod->md3[lod], buffer, LittleLong(pinmodel->ofsEnd) );
  196. LL(mod->md3[lod]->ident);
  197. LL(mod->md3[lod]->version);
  198. LL(mod->md3[lod]->numFrames);
  199. LL(mod->md3[lod]->numTags);
  200. LL(mod->md3[lod]->numSurfaces);
  201. LL(mod->md3[lod]->ofsFrames);
  202. LL(mod->md3[lod]->ofsTags);
  203. LL(mod->md3[lod]->ofsSurfaces);
  204. LL(mod->md3[lod]->ofsEnd);
  205. if ( mod->md3[lod]->numFrames < 1 ) {
  206. ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name );
  207. return qfalse;
  208. }
  209. // swap all the frames
  210. frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );
  211. for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {
  212. frame->radius = LittleFloat( frame->radius );
  213. for ( j = 0 ; j < 3 ; j++ ) {
  214. frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
  215. frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
  216. frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
  217. }
  218. }
  219. // swap all the tags
  220. tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );
  221. for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {
  222. for ( j = 0 ; j < 3 ; j++ ) {
  223. tag->origin[j] = LittleFloat( tag->origin[j] );
  224. tag->axis[0][j] = LittleFloat( tag->axis[0][j] );
  225. tag->axis[1][j] = LittleFloat( tag->axis[1][j] );
  226. tag->axis[2][j] = LittleFloat( tag->axis[2][j] );
  227. }
  228. }
  229. // swap all the surfaces
  230. surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );
  231. for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {
  232. LL(surf->ident);
  233. LL(surf->flags);
  234. LL(surf->numFrames);
  235. LL(surf->numShaders);
  236. LL(surf->numTriangles);
  237. LL(surf->ofsTriangles);
  238. LL(surf->numVerts);
  239. LL(surf->ofsShaders);
  240. LL(surf->ofsSt);
  241. LL(surf->ofsXyzNormals);
  242. LL(surf->ofsEnd);
  243. if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
  244. ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
  245. mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
  246. }
  247. if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
  248. ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
  249. mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
  250. }
  251. // change to surface identifier
  252. surf->ident = SF_MD3;
  253. // lowercase the surface name so skin compares are faster
  254. Q_strlwr( surf->name );
  255. // strip off a trailing _1 or _2
  256. // this is a crutch for q3data being a mess
  257. j = strlen( surf->name );
  258. if ( j > 2 && surf->name[j-2] == '_' ) {
  259. surf->name[j-2] = 0;
  260. }
  261. // register the shaders
  262. shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
  263. for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) {
  264. shader_t *sh;
  265. sh = R_FindShader( shader->name, LIGHTMAP_NONE, qtrue );
  266. if ( sh->defaultShader ) {
  267. shader->shaderIndex = 0;
  268. } else {
  269. shader->shaderIndex = sh->index;
  270. }
  271. }
  272. // swap all the triangles
  273. tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
  274. for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
  275. LL(tri->indexes[0]);
  276. LL(tri->indexes[1]);
  277. LL(tri->indexes[2]);
  278. }
  279. // swap all the ST
  280. st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
  281. for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
  282. st->st[0] = LittleFloat( st->st[0] );
  283. st->st[1] = LittleFloat( st->st[1] );
  284. }
  285. // swap all the XyzNormals
  286. xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
  287. for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ )
  288. {
  289. xyz->xyz[0] = LittleShort( xyz->xyz[0] );
  290. xyz->xyz[1] = LittleShort( xyz->xyz[1] );
  291. xyz->xyz[2] = LittleShort( xyz->xyz[2] );
  292. xyz->normal = LittleShort( xyz->normal );
  293. }
  294. // find the next surface
  295. surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
  296. }
  297. return qtrue;
  298. }
  299. /*
  300. =================
  301. R_LoadMD4
  302. =================
  303. */
  304. static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) {
  305. int i, j, k, lodindex;
  306. md4Header_t *pinmodel, *md4;
  307. md4Frame_t *frame;
  308. md4LOD_t *lod;
  309. md4Surface_t *surf;
  310. md4Triangle_t *tri;
  311. md4Vertex_t *v;
  312. int version;
  313. int size;
  314. shader_t *sh;
  315. int frameSize;
  316. pinmodel = (md4Header_t *)buffer;
  317. version = LittleLong (pinmodel->version);
  318. if (version != MD4_VERSION) {
  319. ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has wrong version (%i should be %i)\n",
  320. mod_name, version, MD4_VERSION);
  321. return qfalse;
  322. }
  323. mod->type = MOD_MD4;
  324. size = LittleLong(pinmodel->ofsEnd);
  325. mod->dataSize += size;
  326. md4 = mod->md4 = ri.Hunk_Alloc( size, h_low );
  327. Com_Memcpy( md4, buffer, LittleLong(pinmodel->ofsEnd) );
  328. LL(md4->ident);
  329. LL(md4->version);
  330. LL(md4->numFrames);
  331. LL(md4->numBones);
  332. LL(md4->numLODs);
  333. LL(md4->ofsFrames);
  334. LL(md4->ofsLODs);
  335. LL(md4->ofsEnd);
  336. if ( md4->numFrames < 1 ) {
  337. ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has no frames\n", mod_name );
  338. return qfalse;
  339. }
  340. // we don't need to swap tags in the renderer, they aren't used
  341. // swap all the frames
  342. frameSize = (int)( &((md4Frame_t *)0)->bones[ md4->numBones ] );
  343. for ( i = 0 ; i < md4->numFrames ; i++, frame++) {
  344. frame = (md4Frame_t *) ( (byte *)md4 + md4->ofsFrames + i * frameSize );
  345. frame->radius = LittleFloat( frame->radius );
  346. for ( j = 0 ; j < 3 ; j++ ) {
  347. frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
  348. frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
  349. frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
  350. }
  351. for ( j = 0 ; j < md4->numBones * sizeof( md4Bone_t ) / 4 ; j++ ) {
  352. ((float *)frame->bones)[j] = LittleFloat( ((float *)frame->bones)[j] );
  353. }
  354. }
  355. // swap all the LOD's
  356. lod = (md4LOD_t *) ( (byte *)md4 + md4->ofsLODs );
  357. for ( lodindex = 0 ; lodindex < md4->numLODs ; lodindex++ ) {
  358. // swap all the surfaces
  359. surf = (md4Surface_t *) ( (byte *)lod + lod->ofsSurfaces );
  360. for ( i = 0 ; i < lod->numSurfaces ; i++) {
  361. LL(surf->ident);
  362. LL(surf->numTriangles);
  363. LL(surf->ofsTriangles);
  364. LL(surf->numVerts);
  365. LL(surf->ofsVerts);
  366. LL(surf->ofsEnd);
  367. if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
  368. ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
  369. mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
  370. }
  371. if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
  372. ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
  373. mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
  374. }
  375. // change to surface identifier
  376. surf->ident = SF_MD4;
  377. // lowercase the surface name so skin compares are faster
  378. Q_strlwr( surf->name );
  379. // register the shaders
  380. sh = R_FindShader( surf->shader, LIGHTMAP_NONE, qtrue );
  381. if ( sh->defaultShader ) {
  382. surf->shaderIndex = 0;
  383. } else {
  384. surf->shaderIndex = sh->index;
  385. }
  386. // swap all the triangles
  387. tri = (md4Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
  388. for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
  389. LL(tri->indexes[0]);
  390. LL(tri->indexes[1]);
  391. LL(tri->indexes[2]);
  392. }
  393. // swap all the vertexes
  394. // FIXME
  395. // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left
  396. // in for reference.
  397. //v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts + 12);
  398. v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts);
  399. for ( j = 0 ; j < surf->numVerts ; j++ ) {
  400. v->normal[0] = LittleFloat( v->normal[0] );
  401. v->normal[1] = LittleFloat( v->normal[1] );
  402. v->normal[2] = LittleFloat( v->normal[2] );
  403. v->texCoords[0] = LittleFloat( v->texCoords[0] );
  404. v->texCoords[1] = LittleFloat( v->texCoords[1] );
  405. v->numWeights = LittleLong( v->numWeights );
  406. for ( k = 0 ; k < v->numWeights ; k++ ) {
  407. v->weights[k].boneIndex = LittleLong( v->weights[k].boneIndex );
  408. v->weights[k].boneWeight = LittleFloat( v->weights[k].boneWeight );
  409. v->weights[k].offset[0] = LittleFloat( v->weights[k].offset[0] );
  410. v->weights[k].offset[1] = LittleFloat( v->weights[k].offset[1] );
  411. v->weights[k].offset[2] = LittleFloat( v->weights[k].offset[2] );
  412. }
  413. // FIXME
  414. // This makes TFC's skeletons work. Shouldn't be necessary anymore, but left
  415. // in for reference.
  416. //v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 );
  417. v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights]);
  418. }
  419. // find the next surface
  420. surf = (md4Surface_t *)( (byte *)surf + surf->ofsEnd );
  421. }
  422. // find the next LOD
  423. lod = (md4LOD_t *)( (byte *)lod + lod->ofsEnd );
  424. }
  425. return qtrue;
  426. }
  427. //=============================================================================
  428. /*
  429. ** RE_BeginRegistration
  430. */
  431. void RE_BeginRegistration( glconfig_t *glconfigOut ) {
  432. R_Init();
  433. *glconfigOut = glConfig;
  434. R_SyncRenderThread();
  435. tr.viewCluster = -1; // force markleafs to regenerate
  436. R_ClearFlares();
  437. RE_ClearScene();
  438. tr.registered = qtrue;
  439. // NOTE: this sucks, for some reason the first stretch pic is never drawn
  440. // without this we'd see a white flash on a level load because the very
  441. // first time the level shot would not be drawn
  442. RE_StretchPic(0, 0, 0, 0, 0, 0, 1, 1, 0);
  443. }
  444. //=============================================================================
  445. /*
  446. ===============
  447. R_ModelInit
  448. ===============
  449. */
  450. void R_ModelInit( void ) {
  451. model_t *mod;
  452. // leave a space for NULL model
  453. tr.numModels = 0;
  454. mod = R_AllocModel();
  455. mod->type = MOD_BAD;
  456. }
  457. /*
  458. ================
  459. R_Modellist_f
  460. ================
  461. */
  462. void R_Modellist_f( void ) {
  463. int i, j;
  464. model_t *mod;
  465. int total;
  466. int lods;
  467. total = 0;
  468. for ( i = 1 ; i < tr.numModels; i++ ) {
  469. mod = tr.models[i];
  470. lods = 1;
  471. for ( j = 1 ; j < MD3_MAX_LODS ; j++ ) {
  472. if ( mod->md3[j] && mod->md3[j] != mod->md3[j-1] ) {
  473. lods++;
  474. }
  475. }
  476. ri.Printf( PRINT_ALL, "%8i : (%i) %s\n",mod->dataSize, lods, mod->name );
  477. total += mod->dataSize;
  478. }
  479. ri.Printf( PRINT_ALL, "%8i : Total models\n", total );
  480. #if 0 // not working right with new hunk
  481. if ( tr.world ) {
  482. ri.Printf( PRINT_ALL, "\n%8i : %s\n", tr.world->dataSize, tr.world->name );
  483. }
  484. #endif
  485. }
  486. //=============================================================================
  487. /*
  488. ================
  489. R_GetTag
  490. ================
  491. */
  492. static md3Tag_t *R_GetTag( md3Header_t *mod, int frame, const char *tagName ) {
  493. md3Tag_t *tag;
  494. int i;
  495. if ( frame >= mod->numFrames ) {
  496. // it is possible to have a bad frame while changing models, so don't error
  497. frame = mod->numFrames - 1;
  498. }
  499. tag = (md3Tag_t *)((byte *)mod + mod->ofsTags) + frame * mod->numTags;
  500. for ( i = 0 ; i < mod->numTags ; i++, tag++ ) {
  501. if ( !strcmp( tag->name, tagName ) ) {
  502. return tag; // found it
  503. }
  504. }
  505. return NULL;
  506. }
  507. /*
  508. ================
  509. R_LerpTag
  510. ================
  511. */
  512. int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame,
  513. float frac, const char *tagName ) {
  514. md3Tag_t *start, *end;
  515. int i;
  516. float frontLerp, backLerp;
  517. model_t *model;
  518. model = R_GetModelByHandle( handle );
  519. if ( !model->md3[0] ) {
  520. AxisClear( tag->axis );
  521. VectorClear( tag->origin );
  522. return qfalse;
  523. }
  524. start = R_GetTag( model->md3[0], startFrame, tagName );
  525. end = R_GetTag( model->md3[0], endFrame, tagName );
  526. if ( !start || !end ) {
  527. AxisClear( tag->axis );
  528. VectorClear( tag->origin );
  529. return qfalse;
  530. }
  531. frontLerp = frac;
  532. backLerp = 1.0f - frac;
  533. for ( i = 0 ; i < 3 ; i++ ) {
  534. tag->origin[i] = start->origin[i] * backLerp + end->origin[i] * frontLerp;
  535. tag->axis[0][i] = start->axis[0][i] * backLerp + end->axis[0][i] * frontLerp;
  536. tag->axis[1][i] = start->axis[1][i] * backLerp + end->axis[1][i] * frontLerp;
  537. tag->axis[2][i] = start->axis[2][i] * backLerp + end->axis[2][i] * frontLerp;
  538. }
  539. VectorNormalize( tag->axis[0] );
  540. VectorNormalize( tag->axis[1] );
  541. VectorNormalize( tag->axis[2] );
  542. return qtrue;
  543. }
  544. /*
  545. ====================
  546. R_ModelBounds
  547. ====================
  548. */
  549. void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) {
  550. model_t *model;
  551. md3Header_t *header;
  552. md3Frame_t *frame;
  553. model = R_GetModelByHandle( handle );
  554. if ( model->bmodel ) {
  555. VectorCopy( model->bmodel->bounds[0], mins );
  556. VectorCopy( model->bmodel->bounds[1], maxs );
  557. return;
  558. }
  559. if ( !model->md3[0] ) {
  560. VectorClear( mins );
  561. VectorClear( maxs );
  562. return;
  563. }
  564. header = model->md3[0];
  565. frame = (md3Frame_t *)( (byte *)header + header->ofsFrames );
  566. VectorCopy( frame->bounds[0], mins );
  567. VectorCopy( frame->bounds[1], maxs );
  568. }