File: | client/renderer/r_model_alias.cpp |
Location: | line 500, column 20 |
Description: | Array subscript is undefined |
1 | /** | ||
2 | * @file | ||
3 | * @brief shared alias model loading code (md2, md3) | ||
4 | */ | ||
5 | |||
6 | /* | ||
7 | Copyright (C) 1997-2001 Id Software, Inc. | ||
8 | |||
9 | This program is free software; you can redistribute it and/or | ||
10 | modify it under the terms of the GNU General Public License | ||
11 | as published by the Free Software Foundation; either version 2 | ||
12 | of the License, or (at your option) any later version. | ||
13 | |||
14 | This program is distributed in the hope that it will be useful, | ||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
17 | |||
18 | See the GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
23 | |||
24 | */ | ||
25 | |||
26 | #include "r_local.h" | ||
27 | #include "../../shared/parse.h" | ||
28 | #include "r_state.h" | ||
29 | |||
30 | /* | ||
31 | ============================================================================== | ||
32 | ALIAS MODELS | ||
33 | ============================================================================== | ||
34 | */ | ||
35 | |||
36 | void R_ModLoadAnims (mAliasModel_t *mod, const char *animname) | ||
37 | { | ||
38 | const char *text, *token; | ||
39 | mAliasAnim_t *anim; | ||
40 | int n; | ||
41 | /* load the tags */ | ||
42 | byte *animbuf = NULL__null; | ||
43 | const char *buffer; | ||
44 | |||
45 | FS_LoadFile(animname, &animbuf); | ||
46 | |||
47 | buffer = (const char *)animbuf; | ||
48 | |||
49 | /* count the animations */ | ||
50 | n = Com_CountTokensInBuffer(buffer); | ||
51 | |||
52 | if ((n % 4) != 0) { | ||
53 | FS_FreeFile(animbuf); | ||
54 | Com_Error(ERR_DROP1, "invalid syntax: %s", animname); | ||
55 | } | ||
56 | |||
57 | /* each animation definition is made out of 4 tokens */ | ||
58 | n /= 4; | ||
59 | if (n > MAX_ANIMS128) | ||
60 | n = MAX_ANIMS128; | ||
61 | |||
62 | mod->animdata = Mem_PoolAllocTypeN(mAliasAnim_t, n, vid_modelPool)static_cast<mAliasAnim_t*>(_Mem_Alloc((sizeof(mAliasAnim_t ) * (n)),true,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,62)); | ||
63 | anim = mod->animdata; | ||
64 | text = buffer; | ||
65 | mod->num_anims = 0; | ||
66 | |||
67 | do { | ||
68 | /* get the name */ | ||
69 | token = Com_Parse(&text); | ||
70 | if (!text) | ||
71 | break; | ||
72 | Q_strncpyz(anim->name, token, sizeof(anim->name))Q_strncpyzDebug( anim->name, token, sizeof(anim->name), "src/client/renderer/r_model_alias.cpp", 72 ); | ||
73 | |||
74 | /* get the start */ | ||
75 | token = Com_Parse(&text); | ||
76 | if (!text) | ||
77 | break; | ||
78 | anim->from = atoi(token); | ||
79 | if (anim->from < 0) | ||
80 | Com_Error(ERR_FATAL0, "R_ModLoadAnims: negative start frame for %s", animname); | ||
81 | else if (anim->from > mod->num_frames) | ||
82 | Com_Error(ERR_FATAL0, "R_ModLoadAnims: start frame is higher than models frame count (%i) (model: %s)", | ||
83 | mod->num_frames, animname); | ||
84 | |||
85 | /* get the end */ | ||
86 | token = Com_Parse(&text); | ||
87 | if (!text) | ||
88 | break; | ||
89 | anim->to = atoi(token); | ||
90 | if (anim->to < 0) | ||
91 | Com_Error(ERR_FATAL0, "R_ModLoadAnims: negative start frame for %s", animname); | ||
92 | else if (anim->to > mod->num_frames) | ||
93 | Com_Error(ERR_FATAL0, "R_ModLoadAnims: end frame is higher than models frame count (%i) (model: %s)", | ||
94 | mod->num_frames, animname); | ||
95 | |||
96 | /* get the fps */ | ||
97 | token = Com_Parse(&text); | ||
98 | if (!text) | ||
99 | break; | ||
100 | anim->time = (atof(token) > 0.01) ? (1000.0 / atof(token)) : (1000.0 / 0.01); | ||
101 | |||
102 | /* add it */ | ||
103 | mod->num_anims++; | ||
104 | anim++; | ||
105 | } while (mod->num_anims < n); | ||
106 | |||
107 | FS_FreeFile(animbuf); | ||
108 | } | ||
109 | |||
110 | |||
111 | /** | ||
112 | * @brief Calculates a per-vertex tangentspace basis and stores it in GL arrays attached to the mesh | ||
113 | * @param mesh The mesh to calculate normals for | ||
114 | * @param framenum The animation frame to calculate normals for | ||
115 | * @param translate The frame translation for the given animation frame | ||
116 | * @param backlerp Whether to store the results in the GL arrays for the previous keyframe or the next keyframe | ||
117 | * @sa R_ModCalcUniqueNormalsAndTangents | ||
118 | */ | ||
119 | static void R_ModCalcNormalsAndTangents (mAliasMesh_t *mesh, int framenum, const vec3_t translate, bool backlerp) | ||
120 | { | ||
121 | int i, j; | ||
122 | mAliasVertex_t *vertexes = &mesh->vertexes[framenum * mesh->num_verts]; | ||
123 | mAliasCoord_tvec2_t *stcoords = mesh->stcoords; | ||
124 | const int numIndexes = mesh->num_tris * 3; | ||
125 | const int32_t *indexArray = mesh->indexes; | ||
126 | vec3_t triangleNormals[MAX_ALIAS_TRIS4096]; | ||
127 | vec3_t triangleTangents[MAX_ALIAS_TRIS4096]; | ||
128 | vec3_t triangleBitangents[MAX_ALIAS_TRIS4096]; | ||
129 | float *texcoords, *verts, *normals, *tangents; | ||
130 | |||
131 | /* set up array pointers for either the previous keyframe or the next keyframe */ | ||
132 | texcoords = mesh->texcoords; | ||
133 | if (backlerp) { | ||
134 | verts = mesh->verts; | ||
135 | normals = mesh->normals; | ||
136 | tangents = mesh->tangents; | ||
137 | } else { | ||
138 | verts = mesh->next_verts; | ||
139 | normals = mesh->next_normals; | ||
140 | tangents = mesh->next_tangents; | ||
141 | } | ||
142 | |||
143 | /* calculate per-triangle surface normals and tangents*/ | ||
144 | for (i = 0, j = 0; i < numIndexes; i += 3, j++) { | ||
145 | vec3_t dir1, dir2; | ||
146 | vec2_t dir1uv, dir2uv; | ||
147 | |||
148 | /* calculate two mostly perpendicular edge directions */ | ||
149 | VectorSubtract(vertexes[indexArray[i + 0]].point, vertexes[indexArray[i + 1]].point, dir1)((dir1)[0]=(vertexes[indexArray[i + 0]].point)[0]-(vertexes[indexArray [i + 1]].point)[0],(dir1)[1]=(vertexes[indexArray[i + 0]].point )[1]-(vertexes[indexArray[i + 1]].point)[1],(dir1)[2]=(vertexes [indexArray[i + 0]].point)[2]-(vertexes[indexArray[i + 1]].point )[2]); | ||
150 | VectorSubtract(vertexes[indexArray[i + 2]].point, vertexes[indexArray[i + 1]].point, dir2)((dir2)[0]=(vertexes[indexArray[i + 2]].point)[0]-(vertexes[indexArray [i + 1]].point)[0],(dir2)[1]=(vertexes[indexArray[i + 2]].point )[1]-(vertexes[indexArray[i + 1]].point)[1],(dir2)[2]=(vertexes [indexArray[i + 2]].point)[2]-(vertexes[indexArray[i + 1]].point )[2]); | ||
151 | Vector2Subtract(stcoords[indexArray[i + 0]], stcoords[indexArray[i + 1]], dir1uv)((dir1uv)[0]=(stcoords[indexArray[i + 0]])[0]-(stcoords[indexArray [i + 1]])[0],(dir1uv)[1]=(stcoords[indexArray[i + 0]])[1]-(stcoords [indexArray[i + 1]])[1]); | ||
152 | Vector2Subtract(stcoords[indexArray[i + 2]], stcoords[indexArray[i + 1]], dir2uv)((dir2uv)[0]=(stcoords[indexArray[i + 2]])[0]-(stcoords[indexArray [i + 1]])[0],(dir2uv)[1]=(stcoords[indexArray[i + 2]])[1]-(stcoords [indexArray[i + 1]])[1]); | ||
153 | |||
154 | /* we have two edge directions, we can calculate a third vector from | ||
155 | * them, which is the direction of the surface normal */ | ||
156 | CrossProduct(dir1, dir2, triangleNormals[j]); | ||
157 | /* normalize */ | ||
158 | VectorNormalizeFast(triangleNormals[j]); | ||
159 | |||
160 | /* then we use the texture coordinates to calculate a tangent space */ | ||
161 | if ((dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]) != 0.0) { | ||
162 | const float frac = 1.0 / (dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]); | ||
163 | vec3_t tmp1, tmp2; | ||
164 | |||
165 | /* calculate tangent */ | ||
166 | VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1)((tmp1)[0]=(-1.0 * dir2uv[1] * frac)*(dir1)[0],(tmp1)[1]=(-1.0 * dir2uv[1] * frac)*(dir1)[1],(tmp1)[2]=(-1.0 * dir2uv[1] * frac )*(dir1)[2]); | ||
167 | VectorMul(dir1uv[1] * frac, dir2, tmp2)((tmp2)[0]=(dir1uv[1] * frac)*(dir2)[0],(tmp2)[1]=(dir1uv[1] * frac)*(dir2)[1],(tmp2)[2]=(dir1uv[1] * frac)*(dir2)[2]); | ||
168 | VectorAdd(tmp1, tmp2, triangleTangents[j])((triangleTangents[j])[0]=(tmp1)[0]+(tmp2)[0],(triangleTangents [j])[1]=(tmp1)[1]+(tmp2)[1],(triangleTangents[j])[2]=(tmp1)[2 ]+(tmp2)[2]); | ||
169 | |||
170 | /* calculate bitangent */ | ||
171 | VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1)((tmp1)[0]=(-1.0 * dir2uv[0] * frac)*(dir1)[0],(tmp1)[1]=(-1.0 * dir2uv[0] * frac)*(dir1)[1],(tmp1)[2]=(-1.0 * dir2uv[0] * frac )*(dir1)[2]); | ||
172 | VectorMul(dir1uv[0] * frac, dir2, tmp2)((tmp2)[0]=(dir1uv[0] * frac)*(dir2)[0],(tmp2)[1]=(dir1uv[0] * frac)*(dir2)[1],(tmp2)[2]=(dir1uv[0] * frac)*(dir2)[2]); | ||
173 | VectorAdd(tmp1, tmp2, triangleBitangents[j])((triangleBitangents[j])[0]=(tmp1)[0]+(tmp2)[0],(triangleBitangents [j])[1]=(tmp1)[1]+(tmp2)[1],(triangleBitangents[j])[2]=(tmp1) [2]+(tmp2)[2]); | ||
174 | |||
175 | /* normalize */ | ||
176 | VectorNormalizeFast(triangleTangents[j]); | ||
177 | VectorNormalizeFast(triangleBitangents[j]); | ||
178 | } else { | ||
179 | VectorClear(triangleTangents[j])((triangleTangents[j])[0]=(triangleTangents[j])[1]=(triangleTangents [j])[2]=0); | ||
180 | VectorClear(triangleBitangents[j])((triangleBitangents[j])[0]=(triangleBitangents[j])[1]=(triangleBitangents [j])[2]=0); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | /* for each vertex */ | ||
185 | for (i = 0; i < mesh->num_verts; i++) { | ||
186 | vec3_t n, b, v; | ||
187 | vec4_t t; | ||
188 | const int len = mesh->revIndexes[i].length; | ||
189 | const int32_t *list = mesh->revIndexes[i].list; | ||
190 | |||
191 | VectorClear(n)((n)[0]=(n)[1]=(n)[2]=0); | ||
192 | VectorClear(t)((t)[0]=(t)[1]=(t)[2]=0); | ||
193 | VectorClear(b)((b)[0]=(b)[1]=(b)[2]=0); | ||
194 | |||
195 | /* for each vertex that got mapped to this one (ie. for each triangle this vertex is a part of) */ | ||
196 | for (j = 0; j < len; j++) { | ||
197 | const int32_t idx = list[j] / 3; | ||
198 | VectorAdd(n, triangleNormals[idx], n)((n)[0]=(n)[0]+(triangleNormals[idx])[0],(n)[1]=(n)[1]+(triangleNormals [idx])[1],(n)[2]=(n)[2]+(triangleNormals[idx])[2]); | ||
199 | VectorAdd(t, triangleTangents[idx], t)((t)[0]=(t)[0]+(triangleTangents[idx])[0],(t)[1]=(t)[1]+(triangleTangents [idx])[1],(t)[2]=(t)[2]+(triangleTangents[idx])[2]); | ||
200 | VectorAdd(b, triangleBitangents[idx], b)((b)[0]=(b)[0]+(triangleBitangents[idx])[0],(b)[1]=(b)[1]+(triangleBitangents [idx])[1],(b)[2]=(b)[2]+(triangleBitangents[idx])[2]); | ||
201 | } | ||
202 | |||
203 | /* normalization here does shared-vertex smoothing */ | ||
204 | VectorNormalizeFast(n); | ||
205 | VectorNormalizeFast(t); | ||
206 | VectorNormalizeFast(b); | ||
207 | |||
208 | /* Grahm-Schmidt orthogonalization */ | ||
209 | Orthogonalize(t, n); | ||
210 | |||
211 | /* calculate handedness */ | ||
212 | CrossProduct(n, t, v); | ||
213 | t[3] = (DotProduct(v, b)((v)[0]*(b)[0]+(v)[1]*(b)[1]+(v)[2]*(b)[2]) < 0.0) ? -1.0 : 1.0; | ||
214 | |||
215 | /* copy this vertex's info to all the right places in the arrays */ | ||
216 | for (j = 0; j < len; j++) { | ||
217 | const int32_t idx = list[j]; | ||
218 | const int meshIndex = mesh->indexes[list[j]]; | ||
219 | Vector2Copy(stcoords[meshIndex], (texcoords + (2 * idx)))(((texcoords + (2 * idx)))[0]=(stcoords[meshIndex])[0],((texcoords + (2 * idx)))[1]=(stcoords[meshIndex])[1]); | ||
220 | VectorAdd(vertexes[meshIndex].point, translate, (verts + (3 * idx)))(((verts + (3 * idx)))[0]=(vertexes[meshIndex].point)[0]+(translate )[0],((verts + (3 * idx)))[1]=(vertexes[meshIndex].point)[1]+ (translate)[1],((verts + (3 * idx)))[2]=(vertexes[meshIndex]. point)[2]+(translate)[2]); | ||
221 | VectorCopy(n, (normals + (3 * idx)))(((normals + (3 * idx)))[0]=(n)[0],((normals + (3 * idx)))[1] =(n)[1],((normals + (3 * idx)))[2]=(n)[2]); | ||
222 | Vector4Copy(t, (tangents + (4 * idx)))(((tangents + (4 * idx)))[0]=(t)[0],((tangents + (4 * idx)))[ 1]=(t)[1],((tangents + (4 * idx)))[2]=(t)[2],((tangents + (4 * idx)))[3]=(t)[3]); | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | |||
227 | /** | ||
228 | * @brief Tries to load a mdx file that contains the normals and the tangents for a model. | ||
229 | * @sa R_ModCalcNormalsAndTangents | ||
230 | * @sa R_ModCalcUniqueNormalsAndTangents | ||
231 | * @param mod The model to load the mdx file for | ||
232 | */ | ||
233 | bool R_ModLoadMDX (model_t *mod) | ||
234 | { | ||
235 | int i; | ||
236 | for (i = 0; i < mod->alias.num_meshes; i++) { | ||
237 | mAliasMesh_t *mesh = &mod->alias.meshes[i]; | ||
238 | char mdxFileName[MAX_QPATH64]; | ||
239 | byte *buffer = NULL__null, *buf; | ||
240 | const int32_t *intbuf; | ||
241 | uint32_t version; | ||
242 | int sharedTris[MAX_ALIAS_VERTS8192]; | ||
243 | |||
244 | Com_StripExtension(mod->name, mdxFileName, sizeof(mdxFileName)); | ||
245 | Com_DefaultExtension(mdxFileName, sizeof(mdxFileName), ".mdx"); | ||
246 | |||
247 | if (FS_LoadFile(mdxFileName, &buffer) == -1) | ||
248 | return false; | ||
249 | |||
250 | buf = buffer; | ||
251 | if (strncmp((const char *) buf, IDMDXHEADER"UFOMDX", strlen(IDMDXHEADER"UFOMDX"))) { | ||
252 | FS_FreeFile(buf); | ||
253 | Com_Error(ERR_DROP1, "No mdx file buffer given"); | ||
254 | } | ||
255 | buffer += strlen(IDMDXHEADER"UFOMDX") * sizeof(char); | ||
256 | version = LittleLong(*(uint32_t*) buffer)(int)(*(uint32_t*) buffer); | ||
257 | if (version != MDX_VERSION1) { | ||
258 | FS_FreeFile(buf); | ||
259 | Com_Error(ERR_DROP1, "Invalid version of the mdx file, expected %i, found %i", | ||
260 | MDX_VERSION1, version); | ||
261 | } | ||
262 | buffer += sizeof(uint32_t); | ||
263 | |||
264 | intbuf = (const int32_t *) buffer; | ||
265 | |||
266 | mesh->num_verts = LittleLong(*intbuf)(int)(*intbuf); | ||
267 | if (mesh->num_verts <= 0 || mesh->num_verts > MAX_ALIAS_VERTS8192) { | ||
268 | FS_FreeFile(buf); | ||
269 | Com_Error(ERR_DROP1, "mdx file for %s has to many (or no) vertices: %i", mod->name, mesh->num_verts); | ||
270 | } | ||
271 | intbuf++; | ||
272 | mesh->num_indexes = LittleLong(*intbuf)(int)(*intbuf); | ||
273 | intbuf++; | ||
274 | |||
275 | mesh->indexes = Mem_PoolAllocTypeN(int32_t, mesh->num_indexes, vid_modelPool)static_cast<int32_t*>(_Mem_Alloc((sizeof(int32_t) * (mesh ->num_indexes)),true,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,275)); | ||
276 | mesh->revIndexes = Mem_PoolAllocTypeN(mIndexList_t, mesh->num_verts, vid_modelPool)static_cast<mIndexList_t*>(_Mem_Alloc((sizeof(mIndexList_t ) * (mesh->num_verts)),true,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,276)); | ||
277 | mesh->vertexes = Mem_PoolAllocTypeN(mAliasVertex_t, mesh->num_verts * mod->alias.num_frames, vid_modelPool)static_cast<mAliasVertex_t*>(_Mem_Alloc((sizeof(mAliasVertex_t ) * (mesh->num_verts * mod->alias.num_frames)),true,((vid_modelPool )),(0),"src/client/renderer/r_model_alias.cpp",277)); | ||
278 | |||
279 | /* load index that maps triangle verts to Vertex objects */ | ||
280 | for (i = 0; i < mesh->num_indexes; i++) { | ||
281 | mesh->indexes[i] = LittleLong(*intbuf)(int)(*intbuf); | ||
282 | intbuf++; | ||
283 | } | ||
284 | |||
285 | for (i = 0; i < mesh->num_verts; i++) | ||
286 | sharedTris[i] = 0; | ||
287 | |||
288 | /* set up reverse-index that maps Vertex objects to a list of triangle verts */ | ||
289 | for (i = 0; i < mesh->num_indexes; i++) | ||
290 | sharedTris[mesh->indexes[i]]++; | ||
291 | |||
292 | for (i = 0; i < mesh->num_verts; i++) { | ||
293 | mesh->revIndexes[i].length = 0; | ||
294 | mesh->revIndexes[i].list = Mem_PoolAllocTypeN(int32_t, sharedTris[i], vid_modelPool)static_cast<int32_t*>(_Mem_Alloc((sizeof(int32_t) * (sharedTris [i])),true,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,294)); | ||
295 | } | ||
296 | |||
297 | for (i = 0; i < mesh->num_indexes; i++) | ||
298 | mesh->revIndexes[mesh->indexes[i]].list[mesh->revIndexes[mesh->indexes[i]].length++] = i; | ||
299 | |||
300 | FS_FreeFile(buf); | ||
301 | } | ||
302 | |||
303 | return true; | ||
304 | } | ||
305 | |||
306 | /** | ||
307 | * @brief Calculates normals and tangents for all frames and does vertex merging based on smoothness | ||
308 | * @param mesh The mesh to calculate normals for | ||
309 | * @param nFrames How many frames the mesh has | ||
310 | * @param smoothness How aggressively should normals be smoothed; value is compared with dotproduct of vectors to decide if they should be merged | ||
311 | * @sa R_ModCalcNormalsAndTangents | ||
312 | */ | ||
313 | void R_ModCalcUniqueNormalsAndTangents (mAliasMesh_t *mesh, int nFrames, float smoothness) | ||
314 | { | ||
315 | int i, j; | ||
316 | vec3_t triangleNormals[MAX_ALIAS_TRIS4096]; | ||
317 | vec3_t triangleTangents[MAX_ALIAS_TRIS4096]; | ||
318 | vec3_t triangleBitangents[MAX_ALIAS_TRIS4096]; | ||
319 | const mAliasVertex_t *vertexes = mesh->vertexes; | ||
320 | mAliasCoord_tvec2_t *stcoords = mesh->stcoords; | ||
321 | mAliasComplexVertex_t tmpVertexes[MAX_ALIAS_VERTS8192]; | ||
322 | vec3_t tmpBitangents[MAX_ALIAS_VERTS8192]; | ||
323 | const int numIndexes = mesh->num_tris * 3; | ||
324 | const int32_t *indexArray = mesh->indexes; | ||
325 | int indRemap[MAX_ALIAS_VERTS8192]; | ||
326 | int sharedTris[MAX_ALIAS_VERTS8192]; | ||
327 | int numVerts = 0; | ||
328 | |||
329 | if (numIndexes >= MAX_ALIAS_VERTS8192) | ||
| |||
330 | Com_Error(ERR_DROP1, "model %s has too many tris", mesh->name); | ||
331 | |||
332 | int32_t* const newIndexArray = Mem_PoolAllocTypeN(int32_t, numIndexes, vid_modelPool)static_cast<int32_t*>(_Mem_Alloc((sizeof(int32_t) * (numIndexes )),true,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,332)); | ||
333 | |||
334 | /* calculate per-triangle surface normals */ | ||
335 | for (i = 0, j = 0; i < numIndexes; i += 3, j++) { | ||
| |||
| |||
336 | vec3_t dir1, dir2; | ||
337 | vec2_t dir1uv, dir2uv; | ||
338 | |||
339 | /* calculate two mostly perpendicular edge directions */ | ||
340 | VectorSubtract(vertexes[indexArray[i + 0]].point, vertexes[indexArray[i + 1]].point, dir1)((dir1)[0]=(vertexes[indexArray[i + 0]].point)[0]-(vertexes[indexArray [i + 1]].point)[0],(dir1)[1]=(vertexes[indexArray[i + 0]].point )[1]-(vertexes[indexArray[i + 1]].point)[1],(dir1)[2]=(vertexes [indexArray[i + 0]].point)[2]-(vertexes[indexArray[i + 1]].point )[2]); | ||
341 | VectorSubtract(vertexes[indexArray[i + 2]].point, vertexes[indexArray[i + 1]].point, dir2)((dir2)[0]=(vertexes[indexArray[i + 2]].point)[0]-(vertexes[indexArray [i + 1]].point)[0],(dir2)[1]=(vertexes[indexArray[i + 2]].point )[1]-(vertexes[indexArray[i + 1]].point)[1],(dir2)[2]=(vertexes [indexArray[i + 2]].point)[2]-(vertexes[indexArray[i + 1]].point )[2]); | ||
342 | Vector2Subtract(stcoords[indexArray[i + 0]], stcoords[indexArray[i + 1]], dir1uv)((dir1uv)[0]=(stcoords[indexArray[i + 0]])[0]-(stcoords[indexArray [i + 1]])[0],(dir1uv)[1]=(stcoords[indexArray[i + 0]])[1]-(stcoords [indexArray[i + 1]])[1]); | ||
343 | Vector2Subtract(stcoords[indexArray[i + 2]], stcoords[indexArray[i + 1]], dir2uv)((dir2uv)[0]=(stcoords[indexArray[i + 2]])[0]-(stcoords[indexArray [i + 1]])[0],(dir2uv)[1]=(stcoords[indexArray[i + 2]])[1]-(stcoords [indexArray[i + 1]])[1]); | ||
344 | |||
345 | /* we have two edge directions, we can calculate a third vector from | ||
346 | * them, which is the direction of the surface normal */ | ||
347 | CrossProduct(dir1, dir2, triangleNormals[j]); | ||
348 | |||
349 | /* then we use the texture coordinates to calculate a tangent space */ | ||
350 | if ((dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]) != 0.0) { | ||
| |||
351 | const float frac = 1.0 / (dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]); | ||
352 | vec3_t tmp1, tmp2; | ||
353 | |||
354 | /* calculate tangent */ | ||
355 | VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1)((tmp1)[0]=(-1.0 * dir2uv[1] * frac)*(dir1)[0],(tmp1)[1]=(-1.0 * dir2uv[1] * frac)*(dir1)[1],(tmp1)[2]=(-1.0 * dir2uv[1] * frac )*(dir1)[2]); | ||
356 | VectorMul(dir1uv[1] * frac, dir2, tmp2)((tmp2)[0]=(dir1uv[1] * frac)*(dir2)[0],(tmp2)[1]=(dir1uv[1] * frac)*(dir2)[1],(tmp2)[2]=(dir1uv[1] * frac)*(dir2)[2]); | ||
357 | VectorAdd(tmp1, tmp2, triangleTangents[j])((triangleTangents[j])[0]=(tmp1)[0]+(tmp2)[0],(triangleTangents [j])[1]=(tmp1)[1]+(tmp2)[1],(triangleTangents[j])[2]=(tmp1)[2 ]+(tmp2)[2]); | ||
358 | |||
359 | /* calculate bitangent */ | ||
360 | VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1)((tmp1)[0]=(-1.0 * dir2uv[0] * frac)*(dir1)[0],(tmp1)[1]=(-1.0 * dir2uv[0] * frac)*(dir1)[1],(tmp1)[2]=(-1.0 * dir2uv[0] * frac )*(dir1)[2]); | ||
361 | VectorMul(dir1uv[0] * frac, dir2, tmp2)((tmp2)[0]=(dir1uv[0] * frac)*(dir2)[0],(tmp2)[1]=(dir1uv[0] * frac)*(dir2)[1],(tmp2)[2]=(dir1uv[0] * frac)*(dir2)[2]); | ||
362 | VectorAdd(tmp1, tmp2, triangleBitangents[j])((triangleBitangents[j])[0]=(tmp1)[0]+(tmp2)[0],(triangleBitangents [j])[1]=(tmp1)[1]+(tmp2)[1],(triangleBitangents[j])[2]=(tmp1) [2]+(tmp2)[2]); | ||
363 | } else { | ||
364 | const float frac = 1.0 / (0.00001); | ||
365 | vec3_t tmp1, tmp2; | ||
366 | |||
367 | /* calculate tangent */ | ||
368 | VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1)((tmp1)[0]=(-1.0 * dir2uv[1] * frac)*(dir1)[0],(tmp1)[1]=(-1.0 * dir2uv[1] * frac)*(dir1)[1],(tmp1)[2]=(-1.0 * dir2uv[1] * frac )*(dir1)[2]); | ||
369 | VectorMul(dir1uv[1] * frac, dir2, tmp2)((tmp2)[0]=(dir1uv[1] * frac)*(dir2)[0],(tmp2)[1]=(dir1uv[1] * frac)*(dir2)[1],(tmp2)[2]=(dir1uv[1] * frac)*(dir2)[2]); | ||
370 | VectorAdd(tmp1, tmp2, triangleTangents[j])((triangleTangents[j])[0]=(tmp1)[0]+(tmp2)[0],(triangleTangents [j])[1]=(tmp1)[1]+(tmp2)[1],(triangleTangents[j])[2]=(tmp1)[2 ]+(tmp2)[2]); | ||
371 | |||
372 | /* calculate bitangent */ | ||
373 | VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1)((tmp1)[0]=(-1.0 * dir2uv[0] * frac)*(dir1)[0],(tmp1)[1]=(-1.0 * dir2uv[0] * frac)*(dir1)[1],(tmp1)[2]=(-1.0 * dir2uv[0] * frac )*(dir1)[2]); | ||
374 | VectorMul(dir1uv[0] * frac, dir2, tmp2)((tmp2)[0]=(dir1uv[0] * frac)*(dir2)[0],(tmp2)[1]=(dir1uv[0] * frac)*(dir2)[1],(tmp2)[2]=(dir1uv[0] * frac)*(dir2)[2]); | ||
375 | VectorAdd(tmp1, tmp2, triangleBitangents[j])((triangleBitangents[j])[0]=(tmp1)[0]+(tmp2)[0],(triangleBitangents [j])[1]=(tmp1)[1]+(tmp2)[1],(triangleBitangents[j])[2]=(tmp1) [2]+(tmp2)[2]); | ||
376 | } | ||
377 | |||
378 | /* normalize */ | ||
379 | VectorNormalizeFast(triangleNormals[j]); | ||
380 | VectorNormalizeFast(triangleTangents[j]); | ||
381 | VectorNormalizeFast(triangleBitangents[j]); | ||
382 | |||
383 | Orthogonalize(triangleTangents[j], triangleBitangents[j]); | ||
384 | } | ||
385 | |||
386 | /* do smoothing */ | ||
387 | for (i = 0; i < numIndexes; i++) { | ||
| |||
| |||
388 | const int idx = (i - i % 3) / 3; | ||
389 | VectorCopy(triangleNormals[idx], tmpVertexes[i].normal)((tmpVertexes[i].normal)[0]=(triangleNormals[idx])[0],(tmpVertexes [i].normal)[1]=(triangleNormals[idx])[1],(tmpVertexes[i].normal )[2]=(triangleNormals[idx])[2]); | ||
390 | VectorCopy(triangleTangents[idx], tmpVertexes[i].tangent)((tmpVertexes[i].tangent)[0]=(triangleTangents[idx])[0],(tmpVertexes [i].tangent)[1]=(triangleTangents[idx])[1],(tmpVertexes[i].tangent )[2]=(triangleTangents[idx])[2]); | ||
391 | VectorCopy(triangleBitangents[idx], tmpBitangents[i])((tmpBitangents[i])[0]=(triangleBitangents[idx])[0],(tmpBitangents [i])[1]=(triangleBitangents[idx])[1],(tmpBitangents[i])[2]=(triangleBitangents [idx])[2]); | ||
392 | |||
393 | for (j = 0; j < numIndexes; j++) { | ||
| |||
| |||
394 | const int idx2 = (j - j % 3) / 3; | ||
395 | /* don't add a vertex with itself */ | ||
396 | if (j == i) | ||
| |||
397 | continue; | ||
| |||
398 | |||
399 | /* only average normals if vertices have the same position | ||
400 | * and the normals aren't too far apart to start with */ | ||
401 | if (VectorEqual(vertexes[indexArray[i]].point, vertexes[indexArray[j]].point)((fabs(((vertexes[indexArray[i]].point)[0])-((vertexes[indexArray [j]].point)[0]))<0.0000000001)?(fabs(((vertexes[indexArray [i]].point)[1])-((vertexes[indexArray[j]].point)[1]))<0.0000000001 )?(fabs(((vertexes[indexArray[i]].point)[2])-((vertexes[indexArray [j]].point)[2]))<0.0000000001)?1:0:0:0) | ||
402 | && DotProduct(triangleNormals[idx], triangleNormals[idx2])((triangleNormals[idx])[0]*(triangleNormals[idx2])[0]+(triangleNormals [idx])[1]*(triangleNormals[idx2])[1]+(triangleNormals[idx])[2 ]*(triangleNormals[idx2])[2]) > smoothness) { | ||
403 | /* average the normals */ | ||
404 | VectorAdd(tmpVertexes[i].normal, triangleNormals[idx2], tmpVertexes[i].normal)((tmpVertexes[i].normal)[0]=(tmpVertexes[i].normal)[0]+(triangleNormals [idx2])[0],(tmpVertexes[i].normal)[1]=(tmpVertexes[i].normal) [1]+(triangleNormals[idx2])[1],(tmpVertexes[i].normal)[2]=(tmpVertexes [i].normal)[2]+(triangleNormals[idx2])[2]); | ||
405 | |||
406 | /* if the tangents match as well, average them too. | ||
407 | * Note that having matching normals without matching tangents happens | ||
408 | * when the order of vertices in two triangles sharing the vertex | ||
409 | * in question is different. This happens quite frequently if the | ||
410 | * modeler does not go out of their way to avoid it. */ | ||
411 | |||
412 | if (Vector2Equal(stcoords[indexArray[i]], stcoords[indexArray[j]])((fabs(((stcoords[indexArray[i]])[0])-((stcoords[indexArray[j ]])[0]))<0.0000000001)?(fabs(((stcoords[indexArray[i]])[1] )-((stcoords[indexArray[j]])[1]))<0.0000000001)?1:0:0) | ||
413 | && DotProduct(triangleTangents[idx], triangleTangents[idx2])((triangleTangents[idx])[0]*(triangleTangents[idx2])[0]+(triangleTangents [idx])[1]*(triangleTangents[idx2])[1]+(triangleTangents[idx]) [2]*(triangleTangents[idx2])[2]) > smoothness | ||
414 | && DotProduct(triangleBitangents[idx], triangleBitangents[idx2])((triangleBitangents[idx])[0]*(triangleBitangents[idx2])[0]+( triangleBitangents[idx])[1]*(triangleBitangents[idx2])[1]+(triangleBitangents [idx])[2]*(triangleBitangents[idx2])[2]) > smoothness) { | ||
415 | /* average the tangents */ | ||
416 | VectorAdd(tmpVertexes[i].tangent, triangleTangents[idx2], tmpVertexes[i].tangent)((tmpVertexes[i].tangent)[0]=(tmpVertexes[i].tangent)[0]+(triangleTangents [idx2])[0],(tmpVertexes[i].tangent)[1]=(tmpVertexes[i].tangent )[1]+(triangleTangents[idx2])[1],(tmpVertexes[i].tangent)[2]= (tmpVertexes[i].tangent)[2]+(triangleTangents[idx2])[2]); | ||
417 | VectorAdd(tmpBitangents[i], triangleBitangents[idx2], tmpBitangents[i])((tmpBitangents[i])[0]=(tmpBitangents[i])[0]+(triangleBitangents [idx2])[0],(tmpBitangents[i])[1]=(tmpBitangents[i])[1]+(triangleBitangents [idx2])[1],(tmpBitangents[i])[2]=(tmpBitangents[i])[2]+(triangleBitangents [idx2])[2]); | ||
418 | } | ||
419 | } | ||
420 | } | ||
421 | |||
422 | VectorNormalizeFast(tmpVertexes[i].normal); | ||
423 | VectorNormalizeFast(tmpVertexes[i].tangent); | ||
424 | VectorNormalizeFast(tmpBitangents[i]); | ||
425 | } | ||
426 | |||
427 | /* assume all vertices are unique until proven otherwise */ | ||
428 | for (i = 0; i < numIndexes; i++) | ||
| |||
| |||
429 | indRemap[i] = -1; | ||
430 | |||
431 | /* merge vertices that have become identical */ | ||
432 | for (i = 0; i < numIndexes; i++) { | ||
| |||
| |||
433 | vec3_t n, b, t, v; | ||
434 | if (indRemap[i] != -1) | ||
| |||
435 | continue; | ||
436 | |||
437 | for (j = i + 1; j < numIndexes; j++) { | ||
| |||
438 | if (Vector2Equal(stcoords[indexArray[i]], stcoords[indexArray[j]])((fabs(((stcoords[indexArray[i]])[0])-((stcoords[indexArray[j ]])[0]))<0.0000000001)?(fabs(((stcoords[indexArray[i]])[1] )-((stcoords[indexArray[j]])[1]))<0.0000000001)?1:0:0) | ||
439 | && VectorEqual(vertexes[indexArray[i]].point, vertexes[indexArray[j]].point)((fabs(((vertexes[indexArray[i]].point)[0])-((vertexes[indexArray [j]].point)[0]))<0.0000000001)?(fabs(((vertexes[indexArray [i]].point)[1])-((vertexes[indexArray[j]].point)[1]))<0.0000000001 )?(fabs(((vertexes[indexArray[i]].point)[2])-((vertexes[indexArray [j]].point)[2]))<0.0000000001)?1:0:0:0) | ||
440 | && (DotProduct(tmpVertexes[i].normal, tmpVertexes[j].normal)((tmpVertexes[i].normal)[0]*(tmpVertexes[j].normal)[0]+(tmpVertexes [i].normal)[1]*(tmpVertexes[j].normal)[1]+(tmpVertexes[i].normal )[2]*(tmpVertexes[j].normal)[2]) > smoothness) | ||
441 | && (DotProduct(tmpVertexes[i].tangent, tmpVertexes[j].tangent)((tmpVertexes[i].tangent)[0]*(tmpVertexes[j].tangent)[0]+(tmpVertexes [i].tangent)[1]*(tmpVertexes[j].tangent)[1]+(tmpVertexes[i].tangent )[2]*(tmpVertexes[j].tangent)[2]) > smoothness)) { | ||
442 | indRemap[j] = i; | ||
443 | newIndexArray[j] = numVerts; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | VectorCopy(tmpVertexes[i].normal, n)((n)[0]=(tmpVertexes[i].normal)[0],(n)[1]=(tmpVertexes[i].normal )[1],(n)[2]=(tmpVertexes[i].normal)[2]); | ||
448 | VectorCopy(tmpVertexes[i].tangent, t)((t)[0]=(tmpVertexes[i].tangent)[0],(t)[1]=(tmpVertexes[i].tangent )[1],(t)[2]=(tmpVertexes[i].tangent)[2]); | ||
449 | VectorCopy(tmpBitangents[i], b)((b)[0]=(tmpBitangents[i])[0],(b)[1]=(tmpBitangents[i])[1],(b )[2]=(tmpBitangents[i])[2]); | ||
450 | |||
451 | /* normalization here does shared-vertex smoothing */ | ||
452 | VectorNormalizeFast(n); | ||
453 | VectorNormalizeFast(t); | ||
454 | VectorNormalizeFast(b); | ||
455 | |||
456 | /* Grahm-Schmidt orthogonalization */ | ||
457 | VectorMul(DotProduct(t, n), n, v)((v)[0]=(((t)[0]*(n)[0]+(t)[1]*(n)[1]+(t)[2]*(n)[2]))*(n)[0], (v)[1]=(((t)[0]*(n)[0]+(t)[1]*(n)[1]+(t)[2]*(n)[2]))*(n)[1],( v)[2]=(((t)[0]*(n)[0]+(t)[1]*(n)[1]+(t)[2]*(n)[2]))*(n)[2]); | ||
458 | VectorSubtract(t, v, t)((t)[0]=(t)[0]-(v)[0],(t)[1]=(t)[1]-(v)[1],(t)[2]=(t)[2]-(v)[ 2]); | ||
459 | VectorNormalizeFast(t); | ||
460 | |||
461 | /* calculate handedness */ | ||
462 | CrossProduct(n, t, v); | ||
463 | tmpVertexes[i].tangent[3] = (DotProduct(v, b)((v)[0]*(b)[0]+(v)[1]*(b)[1]+(v)[2]*(b)[2]) < 0.0) ? -1.0 : 1.0; | ||
| |||
464 | VectorCopy(n, tmpVertexes[i].normal)((tmpVertexes[i].normal)[0]=(n)[0],(tmpVertexes[i].normal)[1] =(n)[1],(tmpVertexes[i].normal)[2]=(n)[2]); | ||
465 | VectorCopy(t, tmpVertexes[i].tangent)((tmpVertexes[i].tangent)[0]=(t)[0],(tmpVertexes[i].tangent)[ 1]=(t)[1],(tmpVertexes[i].tangent)[2]=(t)[2]); | ||
466 | |||
467 | newIndexArray[i] = numVerts++; | ||
468 | indRemap[i] = i; | ||
469 | } | ||
470 | |||
471 | for (i = 0; i < numVerts; i++) | ||
| |||
| |||
472 | sharedTris[i] = 0; | ||
473 | |||
474 | for (i = 0; i < numIndexes; i++) | ||
| |||
475 | sharedTris[newIndexArray[i]]++; | ||
476 | |||
477 | /* set up reverse-index that maps Vertex objects to a list of triangle verts */ | ||
478 | mesh->revIndexes = Mem_PoolAllocTypeN(mIndexList_t, numVerts, vid_modelPool)static_cast<mIndexList_t*>(_Mem_Alloc((sizeof(mIndexList_t ) * (numVerts)),true,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,478)); | ||
479 | for (i = 0; i < numVerts; i++) { | ||
| |||
| |||
480 | mesh->revIndexes[i].length = 0; | ||
481 | mesh->revIndexes[i].list = Mem_PoolAllocTypeN(int32_t, sharedTris[i], vid_modelPool)static_cast<int32_t*>(_Mem_Alloc((sizeof(int32_t) * (sharedTris [i])),true,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,481)); | ||
482 | } | ||
483 | |||
484 | /* merge identical vertexes, storing only unique ones */ | ||
485 | mAliasVertex_t* const newVertexes = Mem_PoolAllocTypeN(mAliasVertex_t, numVerts * nFrames, vid_modelPool)static_cast<mAliasVertex_t*>(_Mem_Alloc((sizeof(mAliasVertex_t ) * (numVerts * nFrames)),true,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,485)); | ||
486 | mAliasCoord_tvec2_t* const newStcoords = Mem_PoolAllocTypeN(mAliasCoord_t, numVerts, vid_modelPool)static_cast<vec2_t*>(_Mem_Alloc((sizeof(vec2_t) * (numVerts )),true,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,486)); | ||
487 | for (i = 0; i < numIndexes; i++) { | ||
| |||
| |||
488 | const int idx = indexArray[indRemap[i]]; | ||
489 | const int idx2 = newIndexArray[i]; | ||
490 | |||
491 | /* add vertex to new vertex array */ | ||
492 | VectorCopy(vertexes[idx].point, newVertexes[idx2].point)((newVertexes[idx2].point)[0]=(vertexes[idx].point)[0],(newVertexes [idx2].point)[1]=(vertexes[idx].point)[1],(newVertexes[idx2]. point)[2]=(vertexes[idx].point)[2]); | ||
493 | Vector2Copy(stcoords[idx], newStcoords[idx2])((newStcoords[idx2])[0]=(stcoords[idx])[0],(newStcoords[idx2] )[1]=(stcoords[idx])[1]); | ||
494 | mesh->revIndexes[idx2].list[mesh->revIndexes[idx2].length++] = i; | ||
495 | } | ||
496 | |||
497 | /* copy over the points from successive frames */ | ||
498 | for (i = 1; i < nFrames; i++) { | ||
| |||
499 | for (j = 0; j < numIndexes; j++) { | ||
| |||
| |||
500 | const int idx = indexArray[indRemap[j]] + (mesh->num_verts * i); | ||
| |||
501 | const int idx2 = newIndexArray[j] + (numVerts * i); | ||
502 | |||
503 | VectorCopy(vertexes[idx].point, newVertexes[idx2].point)((newVertexes[idx2].point)[0]=(vertexes[idx].point)[0],(newVertexes [idx2].point)[1]=(vertexes[idx].point)[1],(newVertexes[idx2]. point)[2]=(vertexes[idx].point)[2]); | ||
504 | } | ||
505 | } | ||
506 | |||
507 | /* copy new arrays back into original mesh */ | ||
508 | Mem_Free(mesh->stcoords)_Mem_Free((mesh->stcoords),"src/client/renderer/r_model_alias.cpp" ,508); | ||
509 | Mem_Free(mesh->indexes)_Mem_Free((mesh->indexes),"src/client/renderer/r_model_alias.cpp" ,509); | ||
510 | Mem_Free(mesh->vertexes)_Mem_Free((mesh->vertexes),"src/client/renderer/r_model_alias.cpp" ,510); | ||
511 | |||
512 | mesh->num_verts = numVerts; | ||
513 | mesh->vertexes = newVertexes; | ||
514 | mesh->stcoords = newStcoords; | ||
515 | mesh->indexes = newIndexArray; | ||
516 | } | ||
517 | |||
518 | image_t* R_AliasModelGetSkin (const char *modelFileName, const char *skin) | ||
519 | { | ||
520 | image_t* result; | ||
521 | if (skin[0] != '.') | ||
522 | result = R_FindImage(skin, it_skin); | ||
523 | else { | ||
524 | char path[MAX_QPATH64]; | ||
525 | Com_ReplaceFilename(modelFileName, skin + 1, path, sizeof(path)); | ||
526 | result = R_FindImage(path, it_skin); | ||
527 | } | ||
528 | return result; | ||
529 | } | ||
530 | |||
531 | image_t* R_AliasModelState (const model_t *mod, int *mesh, int *frame, int *oldFrame, int *skin) | ||
532 | { | ||
533 | /* check animations */ | ||
534 | if ((*frame >= mod->alias.num_frames) || *frame < 0) { | ||
535 | Com_Printf("R_AliasModelState %s: no such frame %d (# %i)\n", mod->name, *frame, mod->alias.num_frames); | ||
536 | *frame = 0; | ||
537 | } | ||
538 | if ((*oldFrame >= mod->alias.num_frames) || *oldFrame < 0) { | ||
539 | Com_Printf("R_AliasModelState %s: no such oldframe %d (# %i)\n", mod->name, *oldFrame, mod->alias.num_frames); | ||
540 | *oldFrame = 0; | ||
541 | } | ||
542 | |||
543 | if (*mesh < 0 || *mesh >= mod->alias.num_meshes) | ||
544 | *mesh = 0; | ||
545 | |||
546 | if (!mod->alias.meshes) | ||
547 | return NULL__null; | ||
548 | |||
549 | /* use default skin - this is never null - but maybe the placeholder texture */ | ||
550 | if (*skin < 0 || *skin >= mod->alias.meshes[*mesh].num_skins) | ||
551 | *skin = 0; | ||
552 | |||
553 | if (!mod->alias.meshes[*mesh].num_skins) | ||
554 | Com_Error(ERR_DROP1, "Model with no skins"); | ||
555 | |||
556 | if (mod->alias.meshes[*mesh].skins[*skin].skin->texnum <= 0) | ||
557 | Com_Error(ERR_DROP1, "Texture is already freed and no longer uploaded, texnum is invalid for model %s", | ||
558 | mod->name); | ||
559 | |||
560 | return mod->alias.meshes[*mesh].skins[*skin].skin; | ||
561 | } | ||
562 | |||
563 | /** | ||
564 | * @brief Converts the model data into the opengl arrays | ||
565 | * @param mod The model to convert | ||
566 | * @param mesh The particular mesh of the model to convert | ||
567 | * @param backlerp The linear back interpolation when loading the data | ||
568 | * @param framenum The frame number of the mesh to load (if animated) | ||
569 | * @param oldframenum The old frame number (used to interpolate) | ||
570 | * @param prerender If this is @c true, all data is filled to the arrays. If @c false, then | ||
571 | * e.g. the normals are only filled to the arrays if the lighting is activated. | ||
572 | * | ||
573 | * @note If GLSL programs are enabled, the actual interpolation will be done on the GPU, but | ||
574 | * this function is still needed to fill the GL arrays for the keyframes | ||
575 | */ | ||
576 | void R_FillArrayData (mAliasModel_t* mod, mAliasMesh_t *mesh, float backlerp, int framenum, int oldframenum, bool prerender) | ||
577 | { | ||
578 | const mAliasFrame_t *frame, *oldframe; | ||
579 | vec3_t move; | ||
580 | const float frontlerp = 1.0 - backlerp; | ||
581 | vec3_t r_mesh_verts[MAX_ALIAS_VERTS8192]; | ||
582 | vec_t *texcoord_array, *vertex_array_3d; | ||
583 | |||
584 | frame = mod->frames + framenum; | ||
585 | oldframe = mod->frames + oldframenum; | ||
586 | |||
587 | /* try to do keyframe-interpolation on the GPU if possible*/ | ||
588 | if (r_state.lighting_enabled) { | ||
589 | /* we only need to change the array data if we've switched to a new keyframe */ | ||
590 | if (mod->curFrame != framenum) { | ||
591 | /* if we're rendering frames in order, the "next" keyframe from the previous | ||
592 | * time through will be our "previous" keyframe now, so we can swap pointers | ||
593 | * instead of generating it again from scratch */ | ||
594 | if (mod->curFrame == oldframenum) { | ||
595 | vec_t *tmp1 = mesh->verts; | ||
596 | vec_t *tmp2 = mesh->normals; | ||
597 | vec_t *tmp3 = mesh->tangents; | ||
598 | |||
599 | mesh->verts = mesh->next_verts; | ||
600 | mesh->next_verts = tmp1; | ||
601 | |||
602 | mesh->normals = mesh->next_normals; | ||
603 | mesh->next_normals = tmp2; | ||
604 | |||
605 | mesh->tangents = mesh->next_tangents; | ||
606 | mesh->next_tangents = tmp3; | ||
607 | |||
608 | /* if we're alternating between two keyframes, we don't need to generate | ||
609 | * anything; otherwise, generate the "next" keyframe*/ | ||
610 | if (mod->oldFrame != framenum) | ||
611 | R_ModCalcNormalsAndTangents(mesh, framenum, frame->translate, false); | ||
612 | } else { | ||
613 | /* if we're starting a new animation or otherwise not rendering keyframes | ||
614 | * in order, we need to fill the arrays for both keyframes */ | ||
615 | R_ModCalcNormalsAndTangents(mesh, oldframenum, oldframe->translate, true); | ||
616 | R_ModCalcNormalsAndTangents(mesh, framenum, frame->translate, false); | ||
617 | } | ||
618 | /* keep track of which keyframes are currently stored in our arrays */ | ||
619 | mod->oldFrame = oldframenum; | ||
620 | mod->curFrame = framenum; | ||
621 | } | ||
622 | } else { /* otherwise, we have to do it on the CPU */ | ||
623 | const mAliasVertex_t *v, *ov; | ||
624 | int i; | ||
625 | assert(mesh->num_verts < lengthof(r_mesh_verts))(__builtin_expect(!(mesh->num_verts < (sizeof(r_mesh_verts ) / sizeof(*(r_mesh_verts)))), 0) ? __assert_rtn(__func__, "src/client/renderer/r_model_alias.cpp" , 625, "mesh->num_verts < lengthof(r_mesh_verts)") : (void )0); | ||
626 | v = &mesh->vertexes[framenum * mesh->num_verts]; | ||
627 | ov = &mesh->vertexes[oldframenum * mesh->num_verts]; | ||
628 | |||
629 | if (prerender) | ||
630 | R_ModCalcNormalsAndTangents(mesh, 0, oldframe->translate, true); | ||
631 | |||
632 | for (i = 0; i < 3; i++) | ||
633 | move[i] = backlerp * oldframe->translate[i] + frontlerp * frame->translate[i]; | ||
634 | |||
635 | for (i = 0; i < mesh->num_verts; i++, v++, ov++) { /* lerp the verts */ | ||
636 | VectorSet(r_mesh_verts[i],((r_mesh_verts[i])[0]=(move[0] + ov->point[0] * backlerp + v->point[0] * frontlerp), (r_mesh_verts[i])[1]=(move[1] + ov->point[1] * backlerp + v->point[1] * frontlerp), (r_mesh_verts [i])[2]=(move[2] + ov->point[2] * backlerp + v->point[2 ] * frontlerp)) | ||
637 | move[0] + ov->point[0] * backlerp + v->point[0] * frontlerp,((r_mesh_verts[i])[0]=(move[0] + ov->point[0] * backlerp + v->point[0] * frontlerp), (r_mesh_verts[i])[1]=(move[1] + ov->point[1] * backlerp + v->point[1] * frontlerp), (r_mesh_verts [i])[2]=(move[2] + ov->point[2] * backlerp + v->point[2 ] * frontlerp)) | ||
638 | move[1] + ov->point[1] * backlerp + v->point[1] * frontlerp,((r_mesh_verts[i])[0]=(move[0] + ov->point[0] * backlerp + v->point[0] * frontlerp), (r_mesh_verts[i])[1]=(move[1] + ov->point[1] * backlerp + v->point[1] * frontlerp), (r_mesh_verts [i])[2]=(move[2] + ov->point[2] * backlerp + v->point[2 ] * frontlerp)) | ||
639 | move[2] + ov->point[2] * backlerp + v->point[2] * frontlerp)((r_mesh_verts[i])[0]=(move[0] + ov->point[0] * backlerp + v->point[0] * frontlerp), (r_mesh_verts[i])[1]=(move[1] + ov->point[1] * backlerp + v->point[1] * frontlerp), (r_mesh_verts [i])[2]=(move[2] + ov->point[2] * backlerp + v->point[2 ] * frontlerp)); | ||
640 | } | ||
641 | |||
642 | R_ReallocateStateArrays(mesh->num_tris * 3); | ||
643 | R_ReallocateTexunitArray(&texunit_diffuser_state.texunits[0], mesh->num_tris * 3); | ||
644 | texcoord_array = texunit_diffuser_state.texunits[0].texcoord_array; | ||
645 | vertex_array_3d = r_state.vertex_array_3d; | ||
646 | |||
647 | /** @todo damn slow - optimize this */ | ||
648 | for (i = 0; i < mesh->num_tris; i++) { /* draw the tris */ | ||
649 | int j; | ||
650 | for (j = 0; j < 3; j++) { | ||
651 | const int arrayIndex = 3 * i + j; | ||
652 | const int meshIndex = mesh->indexes[arrayIndex]; | ||
653 | Vector2Copy(mesh->stcoords[meshIndex], texcoord_array)((texcoord_array)[0]=(mesh->stcoords[meshIndex])[0],(texcoord_array )[1]=(mesh->stcoords[meshIndex])[1]); | ||
654 | VectorCopy(r_mesh_verts[meshIndex], vertex_array_3d)((vertex_array_3d)[0]=(r_mesh_verts[meshIndex])[0],(vertex_array_3d )[1]=(r_mesh_verts[meshIndex])[1],(vertex_array_3d)[2]=(r_mesh_verts [meshIndex])[2]); | ||
655 | |||
656 | texcoord_array += 2; | ||
657 | vertex_array_3d += 3; | ||
658 | } | ||
659 | } | ||
660 | } | ||
661 | } | ||
662 | |||
663 | /** | ||
664 | * @brief Allocates data arrays for animated models. Only called once at loading time. | ||
665 | */ | ||
666 | void R_ModLoadArrayData (mAliasModel_t *mod, mAliasMesh_t *mesh, bool loadNormals) | ||
667 | { | ||
668 | const int v = mesh->num_tris * 3 * 3; | ||
669 | const int t = mesh->num_tris * 3 * 4; | ||
670 | const int st = mesh->num_tris * 3 * 2; | ||
671 | |||
672 | assert(mesh->verts == NULL)(__builtin_expect(!(mesh->verts == __null), 0) ? __assert_rtn (__func__, "src/client/renderer/r_model_alias.cpp", 672, "mesh->verts == NULL" ) : (void)0); | ||
673 | assert(mesh->texcoords == NULL)(__builtin_expect(!(mesh->texcoords == __null), 0) ? __assert_rtn (__func__, "src/client/renderer/r_model_alias.cpp", 673, "mesh->texcoords == NULL" ) : (void)0); | ||
674 | assert(mesh->normals == NULL)(__builtin_expect(!(mesh->normals == __null), 0) ? __assert_rtn (__func__, "src/client/renderer/r_model_alias.cpp", 674, "mesh->normals == NULL" ) : (void)0); | ||
675 | assert(mesh->tangents == NULL)(__builtin_expect(!(mesh->tangents == __null), 0) ? __assert_rtn (__func__, "src/client/renderer/r_model_alias.cpp", 675, "mesh->tangents == NULL" ) : (void)0); | ||
676 | assert(mesh->next_verts == NULL)(__builtin_expect(!(mesh->next_verts == __null), 0) ? __assert_rtn (__func__, "src/client/renderer/r_model_alias.cpp", 676, "mesh->next_verts == NULL" ) : (void)0); | ||
677 | assert(mesh->next_normals == NULL)(__builtin_expect(!(mesh->next_normals == __null), 0) ? __assert_rtn (__func__, "src/client/renderer/r_model_alias.cpp", 677, "mesh->next_normals == NULL" ) : (void)0); | ||
678 | assert(mesh->next_tangents == NULL)(__builtin_expect(!(mesh->next_tangents == __null), 0) ? __assert_rtn (__func__, "src/client/renderer/r_model_alias.cpp", 678, "mesh->next_tangents == NULL" ) : (void)0); | ||
679 | |||
680 | mesh->verts = Mem_PoolAllocTypeN(float, v, vid_modelPool)static_cast<float*>(_Mem_Alloc((sizeof(float) * (v)),true ,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,680)); | ||
681 | mesh->normals = Mem_PoolAllocTypeN(float, v, vid_modelPool)static_cast<float*>(_Mem_Alloc((sizeof(float) * (v)),true ,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,681)); | ||
682 | mesh->tangents = Mem_PoolAllocTypeN(float, t, vid_modelPool)static_cast<float*>(_Mem_Alloc((sizeof(float) * (t)),true ,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,682)); | ||
683 | mesh->texcoords = Mem_PoolAllocTypeN(float, st, vid_modelPool)static_cast<float*>(_Mem_Alloc((sizeof(float) * (st)),true ,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,683)); | ||
684 | if (mod->num_frames == 1) { | ||
685 | R_FillArrayData(mod, mesh, 0.0, 0, 0, loadNormals); | ||
686 | } else { | ||
687 | mesh->next_verts = Mem_PoolAllocTypeN(float, v, vid_modelPool)static_cast<float*>(_Mem_Alloc((sizeof(float) * (v)),true ,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,687)); | ||
688 | mesh->next_normals = Mem_PoolAllocTypeN(float, v, vid_modelPool)static_cast<float*>(_Mem_Alloc((sizeof(float) * (v)),true ,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,688)); | ||
689 | mesh->next_tangents = Mem_PoolAllocTypeN(float, t, vid_modelPool)static_cast<float*>(_Mem_Alloc((sizeof(float) * (t)),true ,((vid_modelPool)),(0),"src/client/renderer/r_model_alias.cpp" ,689)); | ||
690 | |||
691 | mod->curFrame = -1; | ||
692 | mod->oldFrame = -1; | ||
693 | } | ||
694 | } |