1 #ifndef H_MESH
2 #define H_MESH
3
4 #include "core.h"
5 #include "format.h"
6
7 enum CommonTexType {
8 CTEX_FLASH,
9 CTEX_HEALTH,
10 CTEX_OXYGEN,
11 CTEX_OPTION,
12 CTEX_WHITE_ROOM,
13 CTEX_WHITE_OBJECT,
14 CTEX_WHITE_SPRITE,
15 CTEX_MAX,
16 };
17
18 TR::TextureInfo CommonTex[CTEX_MAX];
19 TR::TextureInfo &whiteRoom = CommonTex[CTEX_WHITE_ROOM];
20 TR::TextureInfo &whiteObject = CommonTex[CTEX_WHITE_OBJECT];
21 TR::TextureInfo &whiteSprite = CommonTex[CTEX_WHITE_SPRITE];
22
23 #define PLANE_DETAIL 48
24 #define CIRCLE_SEGS 16
25
26 #define DYN_MESH_FACES 2048
27 #define DOUBLE_SIDED 2
28
29 #define WATER_VOLUME_HEIGHT (768 * 2)
30 #define WATER_VOLUME_OFFSET 4
31
32 const Color32 COLOR_WHITE( 255, 255, 255, 255 );
33
34 struct Mesh : GAPI::Mesh {
35 int aIndex;
36
MeshMesh37 Mesh(Index *indices, int iCount, Vertex *vertices, int vCount, int aCount, bool dynamic) : GAPI::Mesh(dynamic), aIndex(0) {
38 init(indices, iCount, vertices, vCount, aCount);
39 }
40
~MeshMesh41 virtual ~Mesh() {
42 deinit();
43 }
44
initRangeMesh45 void initRange(MeshRange &range) {
46 initNextRange(range, aIndex);
47 }
48
renderMesh49 void render(const MeshRange &range) {
50 Core::DIP(this, range);
51 }
52 };
53
54 #define CHECK_ROOM_NORMAL(f) \
55 vec3 o = d.vertices[f.vertices[0]].pos;\
56 vec3 a = o - d.vertices[f.vertices[1]].pos;\
57 vec3 b = o - d.vertices[f.vertices[2]].pos;\
58 o = b.cross(a).normal() * 32767.0f;\
59 f.normal.x = (int)o.x;\
60 f.normal.y = (int)o.y;\
61 f.normal.z = (int)o.z;
62
63 #define ADD_ROOM_FACE(_indices, iCount, vCount, vStart, _vertices, f, t) \
64 addFace(_indices, iCount, vCount, vStart, _vertices, f, &t,\
65 d.vertices[f.vertices[0]].pos,\
66 d.vertices[f.vertices[1]].pos,\
67 d.vertices[f.vertices[2]].pos,\
68 d.vertices[f.vertices[3]].pos);\
69 for (int k = 0; k < (f.triangle ? 3 : 4); k++) {\
70 TR::Room::Data::Vertex &v = d.vertices[f.vertices[k]];\
71 Vertex &rv = _vertices[vCount++];\
72 rv.coord = short4( v.pos.x, v.pos.y, v.pos.z, 0 );\
73 rv.normal = short4( f.normal.x, f.normal.y, f.normal.z, f.triangle ? 1 : 0 );\
74 rv.color = ubyte4( 255, 255, 255, 255 );\
75 rv.light = ubyte4( v.color.r, v.color.g, v.color.b, 255 );\
76 }
77
78
intensityf(uint16 lighting)79 float intensityf(uint16 lighting) {
80 // ASSERT(lighting >= 0 && lighting <= 0x1FFF);
81 lighting = min(lighting, uint16(0x1FFF));
82 return (0x1FFF - lighting) / float(0x1FFF);
83 }
84
intensity(int lighting)85 uint8 intensity(int lighting) {
86 return uint8(intensityf(lighting) * 255);
87 }
88
89 struct MeshBuilder {
90 Index dynIndices[DYN_MESH_FACES * 3];
91 Vertex dynVertices[DYN_MESH_FACES * 3];
92 MeshRange dynRange;
93 int dynICount;
94 int dynVCount;
95 Mesh *dynMesh;
96
97 Mesh *mesh;
98 Texture *atlas;
99 TR::Level *level;
100
101 // level
102 struct Geometry {
103 int count;
104 MeshRange ranges[100];
105
GeometryMeshBuilder::Geometry106 Geometry() : count(0) {}
107
finishMeshBuilder::Geometry108 void finish(int iCount) {
109 MeshRange *range = count ? &ranges[count - 1] : NULL;
110
111 if (range) {
112 range->iCount = iCount - range->iStart;
113 if (!range->iCount)
114 count--;
115 }
116 }
117
validForTileMeshBuilder::Geometry118 bool validForTile(uint16 tile, uint16 clut) {
119 #ifdef SPLIT_BY_TILE
120 if (!count) return false;
121 MeshRange &range = ranges[count - 1];
122
123 return (tile == range.tile
124 #ifdef SPLIT_BY_CLUT
125 && clut == range.clut
126 #endif
127 );
128 #else
129 return count != 0;
130 #endif
131 }
132
getNextRangeMeshBuilder::Geometry133 MeshRange* getNextRange(int vStart, int iCount, uint16 tile, uint16 clut) {
134 MeshRange *range = count ? &ranges[count - 1] : NULL;
135
136 if (range)
137 range->iCount = iCount - range->iStart;
138
139 if (!range || range->iCount) {
140 ASSERT(count < COUNT(ranges));
141 range = &ranges[count++];
142 }
143
144 range->vStart = vStart;
145 range->iStart = iCount;
146 range->tile = tile;
147 range->clut = clut;
148
149 return range;
150 }
151 };
152
153 struct Dynamic {
154 uint16 count;
155 uint16 *faces;
156 };
157
158 struct RoomRange {
159 Geometry geometry[3]; // opaque, double-side alpha, additive
160 Dynamic dynamic[3]; // lists of dynamic polygons (with animated textures) like lava, waterfalls etc.
161 MeshRange sprites;
162 MeshRange waterVolume;
163 int split;
164 } *rooms;
165
166 struct ModelRange {
167 int parts[3][32];
168 Geometry geometry[3];
169 int vStart;
170 int vCount;
171 } *models;
172
173 // procedured
174 MeshRange shadowBlob;
175 MeshRange quad, circle, box;
176 MeshRange plane;
177
178 int transparent;
179
180 #ifdef SPLIT_BY_TILE
181 uint16 curTile, curClut;
182 #endif
183
184 enum {
185 BLEND_NONE = 1,
186 BLEND_ALPHA = 2,
187 BLEND_ADD = 4,
188 };
189
MeshBuilderMeshBuilder190 MeshBuilder(TR::Level *level, Texture *atlas) : atlas(atlas), level(level) {
191 dynMesh = new Mesh(NULL, COUNT(dynIndices), NULL, COUNT(dynVertices), 1, true);
192 dynRange.vStart = 0;
193 dynRange.iStart = 0;
194 dynMesh->initRange(dynRange);
195
196 // allocate room geometry ranges
197 rooms = new RoomRange[level->roomsCount];
198
199 int iCount = 0, vCount = 0;
200
201 // sort room faces by material
202 for (int i = 0; i < level->roomsCount; i++) {
203 TR::Room::Data &data = level->rooms[i].data;
204 sort(data.faces, data.fCount);
205 // sort room sprites by material
206 sort(data.sprites, data.sCount);
207 }
208
209 // sort mesh faces by material
210 for (int i = 0; i < level->meshesCount; i++) {
211 TR::Mesh &mesh = level->meshes[i];
212 sort(mesh.faces, mesh.fCount);
213 }
214
215 // get size of mesh for rooms (geometry & sprites)
216 int vStartRoom = vCount;
217
218 // pre-calculate water level for rooms
219 for (int i = 0; i < level->roomsCount; i++) {
220 TR::Room &room = level->rooms[i];
221 room.waterLevel[0] = room.waterLevel[1] = room.waterLevelSurface = TR::NO_WATER;
222 }
223
224 for (int j = 0; j < 2; j++) {
225 for (int i = 0; i < level->roomsCount; i++)
226 calcWaterLevel(i, level->state.flags.flipped);
227 level->flipMap();
228 }
229
230 // get reooms geometry info
231 for (int i = 0; i < level->roomsCount; i++) {
232 TR::Room &r = level->rooms[i];
233 TR::Room::Data &d = r.data;
234
235 int vStartCount = vCount;
236
237 iCount += (d.rCount * 6 + d.tCount * 3) * DOUBLE_SIDED;
238 vCount += (d.rCount * 4 + d.tCount * 3);
239
240 roomRemoveWaterSurfaces(r, iCount, vCount);
241
242 for (int j = 0; j < r.meshesCount; j++) {
243 TR::Room::Mesh &m = r.meshes[j];
244 TR::StaticMesh *s = &level->staticMeshes[m.meshIndex];
245 if (!level->meshOffsets[s->mesh]) continue;
246 TR::Mesh &mesh = level->meshes[level->meshOffsets[s->mesh]];
247
248 iCount += (mesh.rCount * 6 + mesh.tCount * 3) * DOUBLE_SIDED;
249 vCount += (mesh.rCount * 4 + mesh.tCount * 3);
250 }
251
252 #ifdef MERGE_SPRITES
253 iCount += d.sCount * 6;
254 vCount += d.sCount * 4;
255 #endif
256
257 if (vCount - vStartRoom > 0xFFFF) {
258 vStartRoom = vStartCount;
259 rooms[i].split = true;
260 } else
261 rooms[i].split = false;
262 }
263
264 // get models info
265 int vStartModel = vCount;
266 models = new ModelRange[level->modelsCount];
267 for (int i = 0; i < level->modelsCount; i++) {
268 models[i].vStart = vCount;
269 TR::Model &model = level->models[i];
270 for (int j = 0; j < model.mCount; j++) {
271 int index = level->meshOffsets[model.mStart + j];
272 if (!index && model.mStart + j > 0)
273 continue;
274 TR::Mesh &mesh = level->meshes[index];
275 iCount += (mesh.rCount * 6 + mesh.tCount * 3) * DOUBLE_SIDED;
276 vCount += (mesh.rCount * 4 + mesh.tCount * 3);
277 }
278 models[i].vCount = vCount - models[i].vStart;
279 models[i].vStart -= vStartModel;
280 }
281
282 // shadow blob mesh (8 triangles, 8 vertices)
283 iCount += 8 * 3 * 3;
284 vCount += 8 * 2 + 1;
285
286 // quad (post effect filter)
287 iCount += 6;
288 vCount += 4;
289
290 // circle
291 iCount += CIRCLE_SEGS * 3;
292 vCount += CIRCLE_SEGS + 1;
293
294 // box
295 const Index boxIndices[] = {
296 2, 1, 0, 3, 2, 0,
297 4, 5, 6, 4, 6, 7,
298 8, 9, 10, 8, 10, 11,
299 14, 13, 12, 15, 14, 12,
300 16, 17, 18, 16, 18, 19,
301 22, 21, 20, 23, 22, 20,
302 };
303
304 const short4 boxCoords[] = {
305 short4(-1, -1, 1, 0), short4( 1, -1, 1, 0), short4( 1, 1, 1, 0), short4(-1, 1, 1, 0),
306 short4( 1, 1, 1, 0), short4( 1, 1, -1, 0), short4( 1, -1, -1, 0), short4( 1, -1, 1, 0),
307 short4(-1, -1, -1, 0), short4( 1, -1, -1, 0), short4( 1, 1, -1, 0), short4(-1, 1, -1, 0),
308 short4(-1, -1, -1, 0), short4(-1, -1, 1, 0), short4(-1, 1, 1, 0), short4(-1, 1, -1, 0),
309 short4( 1, 1, 1, 0), short4(-1, 1, 1, 0), short4(-1, 1, -1, 0), short4( 1, 1, -1, 0),
310 short4(-1, -1, -1, 0), short4( 1, -1, -1, 0), short4( 1, -1, 1, 0), short4(-1, -1, 1, 0),
311 };
312
313 iCount += COUNT(boxIndices);
314 vCount += COUNT(boxCoords);
315
316 // detailed plane
317 #ifdef GENERATE_WATER_PLANE
318 iCount += SQR(PLANE_DETAIL * 2) * 6;
319 vCount += SQR(PLANE_DETAIL * 2 + 1);
320 #endif
321
322 // make meshes buffer (single vertex buffer object for all geometry & sprites on level)
323 Index *indices = new Index[iCount];
324 Vertex *vertices = new Vertex[vCount];
325 iCount = vCount = 0;
326 int aCount = 0;
327
328 // build rooms
329 vStartRoom = vCount;
330 aCount++;
331
332 for (int i = 0; i < level->roomsCount; i++) {
333 TR::Room &room = level->rooms[i];
334 TR::Room::Data &d = room.data;
335 RoomRange &range = rooms[i];
336
337 if (range.split) {
338 vStartRoom = vCount;
339 aCount++;
340 }
341
342 range.waterVolume.iCount = 0;
343 if (Core::settings.detail.water > Core::Settings::MEDIUM)
344 buildWaterVolume(i, indices, vertices, iCount, vCount, vStartRoom);
345
346 for (int transp = 0; transp < 3; transp++) { // opaque, opacity
347 int blendMask = getBlendMask(transp);
348
349 Geometry &geom = range.geometry[transp];
350
351 // room geometry
352 buildRoom(geom, range.dynamic + transp, blendMask, room, level, indices, vertices, iCount, vCount, vStartRoom);
353
354 // static meshes
355 for (int j = 0; j < room.meshesCount; j++) {
356 TR::Room::Mesh &m = room.meshes[j];
357 TR::StaticMesh *s = &level->staticMeshes[m.meshIndex];
358 if (!level->meshOffsets[s->mesh]) continue;
359 TR::Mesh &mesh = level->meshes[level->meshOffsets[s->mesh]];
360
361 int x = m.x - room.info.x;
362 int y = m.y;
363 int z = m.z - room.info.z;
364 int d = m.rotation.value / 0x4000;
365 buildMesh(geom, blendMask, mesh, level, indices, vertices, iCount, vCount, vStartRoom, 0, x, y, z, d, m.color, true, false);
366 }
367
368 geom.finish(iCount);
369 }
370
371 // rooms sprites
372 #ifdef MERGE_SPRITES
373 range.sprites.vStart = vStartRoom;
374 range.sprites.iStart = iCount;
375 for (int j = 0; j < d.sCount; j++) {
376 TR::Room::Data::Sprite &f = d.sprites[j];
377 TR::Room::Data::Vertex &v = d.vertices[f.vertexIndex];
378 TR::TextureInfo &sprite = level->spriteTextures[f.texture];
379
380 addSprite(indices, vertices, iCount, vCount, vStartRoom, v.pos.x, v.pos.y, v.pos.z, false, false, sprite, v.color, v.color);
381 }
382 range.sprites.iCount = iCount - range.sprites.iStart;
383 #else
384 range.sprites.iCount = d.sCount * 6;
385 #endif
386 }
387 ASSERT(vCount - vStartRoom <= 0xFFFF);
388
389 // build models geometry
390 vStartModel = vCount;
391 aCount++;
392
393 for (int i = 0; i < level->modelsCount; i++) {
394 TR::Model &model = level->models[i];
395 int vCountStart = vCount;
396
397 for (int transp = 0; transp < 3; transp++) {
398 Geometry &geom = models[i].geometry[transp];
399
400 int blendMask = getBlendMask(transp);
401
402 for (int j = 0; j < model.mCount; j++) {
403 #ifndef MERGE_MODELS
404 models[i].parts[transp][j] = geom.count;
405 #endif
406
407 bool forceOpaque = false;
408 TR::Entity::fixOpaque(model.type, forceOpaque);
409
410 int index = level->meshOffsets[model.mStart + j];
411 if (index || model.mStart + j <= 0) {
412 TR::Mesh &mesh = level->meshes[index];
413 #ifndef MERGE_MODELS
414 geom.getNextRange(vStartModel, iCount, 0xFFFF, 0xFFFF);
415 #endif
416 buildMesh(geom, blendMask, mesh, level, indices, vertices, iCount, vCount, vStartModel, j, 0, 0, 0, 0, COLOR_WHITE, false, forceOpaque);
417 }
418
419 #ifndef MERGE_MODELS
420 geom.finish(iCount);
421 models[i].parts[transp][j] = geom.count - models[i].parts[transp][j];
422 #endif
423 }
424
425 #ifdef MERGE_MODELS
426 geom.finish(iCount);
427 models[i].parts[transp][0] = geom.count;
428 #endif
429 }
430
431 //int transp = TR::Entity::fixTransp(model.type);
432
433 if (model.type == TR::Entity::SKY) {
434 ModelRange &m = models[i];
435 m.geometry[0].ranges[0].iCount = iCount - models[i].geometry[0].ranges[0].iStart;
436 m.geometry[1].ranges[0].iCount = 0;
437 m.geometry[2].ranges[0].iCount = 0;
438 // remove bottom triangles from skybox
439 //if (m.geometry[0].ranges[0].iCount && ((level.version & TR::VER_TR3)))
440 // m.geometry[0].ranges[0].iCount -= 16 * 3;
441 // rotate TR2 skybox
442 if (level->version & TR::VER_TR2) {
443 for (int j = vCountStart; j < vCount; j++) {
444 short4 &c = vertices[j].coord;
445 c = short4(c.x, -c.z, c.y, c.w);
446 }
447 }
448 }
449 }
450
451 weldSkinJoints(vertices + vStartModel, level->extra.laraSkin, level->extra.laraJoints);
452 weldSkinJoints(vertices + vStartModel, level->extra.braid, level->extra.braid);
453
454 //ASSERT(vCount - vStartModel <= 0xFFFF);
455
456 // build common primitives
457 int vStartCommon = vCount;
458 aCount++;
459
460 shadowBlob.vStart = vStartCommon;
461 shadowBlob.iStart = iCount;
462 shadowBlob.iCount = 8 * 3 * 3;
463 for (int i = 0; i < 9; i++) {
464 Vertex &v0 = vertices[vCount + i * 2 + 0];
465 v0.normal = short4( 0, -1, 0, 1 );
466 v0.texCoord = short4( whiteObject.texCoordAtlas[0].x, whiteObject.texCoordAtlas[0].y, 32767, 32767 );
467 v0.color = v0.light = ubyte4( 0, 0, 0, 0 );
468
469 if (i == 8) {
470 v0.coord = short4( 0, 0, 0, 0 );
471 break;
472 }
473
474 float a = i * (PI / 4.0f) + (PI / 8.0f);
475 float c = cosf(a);
476 float s = sinf(a);
477 short c0 = short(c * 256.0f);
478 short s0 = short(s * 256.0f);
479 short c1 = short(c * 512.0f);
480 short s1 = short(s * 512.0f);
481 v0.coord = short4( c0, 0, s0, 0 );
482
483 Vertex &v1 = vertices[vCount + i * 2 + 1];
484 v1 = v0;
485 v1.coord = short4( c1, 0, s1, 0 );
486 v1.color = v1.light = ubyte4( 255, 255, 255, 0 );
487
488 int idx = iCount + i * 3 * 3;
489 int j = ((i + 1) % 8) * 2;
490 indices[idx++] = i * 2;
491 indices[idx++] = 8 * 2;
492 indices[idx++] = j;
493
494 indices[idx++] = i * 2 + 1;
495 indices[idx++] = i * 2;
496 indices[idx++] = j;
497
498 indices[idx++] = i * 2 + 1;
499 indices[idx++] = j;
500 indices[idx++] = j + 1;
501 }
502 vCount += 8 * 2 + 1;
503 iCount += shadowBlob.iCount;
504
505 // quad
506 quad.vStart = vStartCommon;
507 quad.iStart = iCount;
508 quad.iCount = 2 * 3;
509
510 addQuad(indices, iCount, vCount, vStartCommon, vertices, &whiteSprite, false, false);
511 vertices[vCount + 0].coord = short4( -32767, 32767, 0, 1 );
512 vertices[vCount + 1].coord = short4( 32767, 32767, 0, 1 );
513 vertices[vCount + 2].coord = short4( 32767, -32767, 0, 1 );
514 vertices[vCount + 3].coord = short4( -32767, -32767, 0, 1 );
515
516 vertices[vCount + 0].texCoord = short4( 0, 32767, 0, 0 );
517 vertices[vCount + 1].texCoord = short4( 32767, 32767, 0, 0 );
518 vertices[vCount + 2].texCoord = short4( 32767, 0, 0, 0 );
519 vertices[vCount + 3].texCoord = short4( 0, 0, 0, 0 );
520
521 for (int i = 0; i < 4; i++) {
522 Vertex &v = vertices[vCount++];
523 v.normal = short4( 0, 0, 0, 0 );
524 v.color = ubyte4( 255, 255, 255, 255 );
525 v.light = ubyte4( 255, 255, 255, 255 );
526 }
527
528 // circle
529 circle.vStart = vStartCommon;
530 circle.iStart = iCount;
531 circle.iCount = CIRCLE_SEGS * 3;
532
533 vec2 pos(32767.0f, 0.0f);
534 vec2 cs(cosf(PI2 / CIRCLE_SEGS), sinf(PI2 / CIRCLE_SEGS));
535
536 int baseIdx = vCount - vStartCommon;
537 for (int i = 0; i < CIRCLE_SEGS; i++) {
538 Vertex &v = vertices[vCount + i];
539 pos.rotate(cs);
540 v.coord = short4( short(pos.x), short(pos.y), 0, 1 );
541 v.normal = short4( 0, 0, 0, 1 );
542 v.texCoord = short4( whiteSprite.texCoordAtlas[0].x, whiteSprite.texCoordAtlas[0].y, 32767, 32767 );
543 v.color = ubyte4( 255, 255, 255, 255 );
544 v.light = ubyte4( 255, 255, 255, 255 );
545
546 indices[iCount++] = baseIdx + i;
547 indices[iCount++] = baseIdx + (i + 1) % CIRCLE_SEGS;
548 indices[iCount++] = baseIdx + CIRCLE_SEGS;
549 }
550 vertices[vCount + CIRCLE_SEGS] = vertices[vCount];
551 vertices[vCount + CIRCLE_SEGS].coord = short4( 0, 0, 0, 1 );
552 vCount += CIRCLE_SEGS + 1;
553
554 // box
555 box.vStart = vStartCommon;
556 box.iStart = iCount;
557 box.iCount = COUNT(boxIndices);
558
559 baseIdx = vCount - vStartCommon;
560
561 for (int i = 0; i < COUNT(boxIndices); i++)
562 indices[iCount++] = baseIdx + boxIndices[i];
563
564 for (int i = 0; i < COUNT(boxCoords); i++) {
565 Vertex &v = vertices[vCount++];
566 v.coord = boxCoords[i];
567 v.normal = short4(0, 0, 0, 0);
568 v.texCoord = short4(0, 0, 0, 0);
569 v.color = ubyte4(255, 255, 255, 255);
570 v.light = ubyte4(255, 255, 255, 255);
571 }
572
573 // plane
574 #ifdef GENERATE_WATER_PLANE
575 plane.vStart = vStartCommon;
576 plane.iStart = iCount;
577 plane.iCount = SQR(PLANE_DETAIL * 2) * 6;
578
579 baseIdx = vCount - vStartCommon;
580 for (int16 j = -PLANE_DETAIL; j <= PLANE_DETAIL; j++)
581 for (int16 i = -PLANE_DETAIL; i <= PLANE_DETAIL; i++) {
582 vertices[vCount++].coord = short4( i, j, 0, 1 );
583 if (j < PLANE_DETAIL && i < PLANE_DETAIL) {
584 int idx = baseIdx + (j + PLANE_DETAIL) * (PLANE_DETAIL * 2 + 1) + i + PLANE_DETAIL;
585 indices[iCount + 0] = idx + PLANE_DETAIL * 2 + 1;
586 indices[iCount + 1] = idx + 1;
587 indices[iCount + 2] = idx;
588 indices[iCount + 3] = idx + PLANE_DETAIL * 2 + 2;
589 indices[iCount + 4] = idx + 1;
590 indices[iCount + 5] = idx + PLANE_DETAIL * 2 + 1;
591 iCount += 6;
592 }
593 }
594 ASSERT(vCount - vStartCommon <= 0xFFFF);
595 #else
596 plane.iCount = 0;
597 #endif
598
599 LOG("MegaMesh (i:%d v:%d a:%d, size:%d)\n", iCount, vCount, aCount, int(iCount * sizeof(Index) + vCount * sizeof(GAPI::Vertex)));
600
601 // compile buffer and ranges
602 mesh = new Mesh(indices, iCount, vertices, vCount, aCount, false);
603 delete[] indices;
604 delete[] vertices;
605
606 PROFILE_LABEL(BUFFER, mesh->ID[0], "Geometry indices");
607 PROFILE_LABEL(BUFFER, mesh->ID[1], "Geometry vertices");
608
609 // initialize Vertex Arrays
610 MeshRange rangeRoom;
611 rangeRoom.vStart = 0;
612 mesh->initRange(rangeRoom);
613 for (int i = 0; i < level->roomsCount; i++) {
614
615 if (rooms[i].split) {
616 ASSERT(rooms[i].geometry[0].count);
617 rangeRoom.vStart = rooms[i].geometry[0].ranges[0].vStart;
618 mesh->initRange(rangeRoom);
619 }
620
621 RoomRange &r = rooms[i];
622 for (int j = 0; j < 3; j++)
623 for (int k = 0; k < r.geometry[j].count; k++)
624 r.geometry[j].ranges[k].aIndex = rangeRoom.aIndex;
625
626 r.sprites.aIndex = rangeRoom.aIndex;
627 r.waterVolume.aIndex = rangeRoom.aIndex;
628 }
629
630 MeshRange rangeModel;
631 rangeModel.vStart = vStartModel;
632 mesh->initRange(rangeModel);
633 for (int i = 0; i < level->modelsCount; i++)
634 for (int j = 0; j < 3; j++) {
635 Geometry &geom = models[i].geometry[j];
636 for (int k = 0; k < geom.count; k++)
637 geom.ranges[k].aIndex = rangeModel.aIndex;
638 }
639
640 MeshRange rangeCommon;
641 rangeCommon.vStart = vStartCommon;
642 mesh->initRange(rangeCommon);
643 shadowBlob.aIndex = rangeCommon.aIndex;
644 quad.aIndex = rangeCommon.aIndex;
645 circle.aIndex = rangeCommon.aIndex;
646 plane.aIndex = rangeCommon.aIndex;
647 box.aIndex = rangeCommon.aIndex;
648 }
649
~MeshBuilderMeshBuilder650 ~MeshBuilder() {
651 for (int i = 0; i < level->roomsCount; i++)
652 for (int j = 0; j < COUNT(rooms[i].dynamic); j++)
653 delete[] rooms[i].dynamic[j].faces;
654
655 delete[] rooms;
656 delete[] models;
657 delete mesh;
658 delete dynMesh;
659 }
660
flipMapMeshBuilder661 void flipMap() {
662 for (int i = 0; i < level->roomsCount; i++)
663 if (level->rooms[i].alternateRoom > -1)
664 swap(rooms[i], rooms[level->rooms[i].alternateRoom]);
665 }
666
rotateMeshBuilder667 inline short4 rotate(const short4 &v, int dir) {
668 if (dir == 0) return v;
669 short4 res = v;
670
671 switch (dir) {
672 case 1 : res.x = v.z; res.z = -v.x; break;
673 case 2 : res.x = -v.x; res.z = -v.z; break;
674 case 3 : res.x = -v.z; res.z = v.x; break;
675 default : ASSERT(false);
676 }
677 return res;
678 }
679
transformMeshBuilder680 inline short4 transform(const short4 &v, int joint, int x, int y, int z, int dir) {
681 short4 res = rotate(v, dir);
682 res.x += x;
683 res.y += y;
684 res.z += z;
685 res.w = joint * 2;
686 return res;
687 }
688
isWaterSurfaceMeshBuilder689 bool isWaterSurface(int delta, int roomIndex, bool fromWater) {
690 if (roomIndex != TR::NO_ROOM && delta == 0) {
691 TR::Room &r = level->rooms[roomIndex];
692 if (r.flags.water ^ fromWater)
693 return true;
694 if (r.alternateRoom > -1 && level->rooms[r.alternateRoom].flags.water ^ fromWater)
695 return true;
696 }
697 return false;
698 }
699
weldSkinJointsMeshBuilder700 void weldSkinJoints(Vertex *vertices, int16 skinIndex, int16 jointsIndex) {
701 if (skinIndex == -1 || jointsIndex == -1) {
702 return;
703 }
704
705 ASSERT(level->models[skinIndex].mCount == level->models[jointsIndex].mCount);
706
707 const TR::Model *model = level->models + skinIndex;
708 const TR::Node *node = (TR::Node*)&level->nodesData[model->node];//(TR::Node*)level->nodesData + model->node;
709
710 int sIndex = 0;
711 short4 stack[16];
712 short4 pos(0, 0, 0, 0);
713 short4 jointsPos[MAX_JOINTS];
714
715 for (int i = 0; i < model->mCount; i++) {
716 if (i > 0 && node) {
717 const TR::Node &t = node[i - 1];
718 if (t.flags & 0x01) pos = stack[--sIndex];
719 if (t.flags & 0x02) stack[sIndex++] = pos;
720 pos.x += t.x;
721 pos.y += t.y;
722 pos.z += t.z;
723 }
724 jointsPos[i] = pos;
725 }
726
727 const ModelRange &rangeSkin = models[skinIndex];
728 const ModelRange &rangeJoints = models[jointsIndex];
729
730 #define COORD_FILL(VAR,RANGE)\
731 short4 *VAR = new short4[RANGE.vCount];\
732 for (int i = 0; i < RANGE.vCount; i++) {\
733 VAR[i] = vertices[RANGE.vStart + i].coord;\
734 int index = VAR[i].w / 2;\
735 VAR[i].x += jointsPos[index].x;\
736 VAR[i].y += jointsPos[index].y;\
737 VAR[i].z += jointsPos[index].z;\
738 }
739
740 COORD_FILL(vSkin, rangeSkin);
741 COORD_FILL(vJoints, rangeJoints);
742
743 // bruteforce :(
744 for (int j = 0; j < rangeJoints.vCount; j++) {
745 for (int i = 0; i < rangeSkin.vCount; i++) {
746 if (//vSkin[i].w < vJoints[j].w &&
747 abs(vSkin[i].x - vJoints[j].x) <= 1 &&
748 abs(vSkin[i].y - vJoints[j].y) <= 1 &&
749 abs(vSkin[i].z - vJoints[j].z) <= 1) { // compare position
750 vertices[rangeJoints.vStart + j].coord = vertices[rangeSkin.vStart + i].coord; // set bone index
751 vertices[rangeJoints.vStart + j].normal = vertices[rangeSkin.vStart + i].normal;
752 break;
753 }
754 }
755 }
756
757 delete[] vSkin;
758 delete[] vJoints;
759
760 #undef COORD_FILL
761 }
762
calcWaterLevelMeshBuilder763 int calcWaterLevel(int16 roomIndex, bool flip) {
764 TR::Room &room = level->rooms[roomIndex];
765
766 int32 &value = room.waterLevel[flip];
767
768 if (value != TR::NO_WATER)
769 return value;
770
771 if (room.flags.water) {
772 value = room.info.yBottom;
773
774 for (int z = 0; z < room.zSectors; z++)
775 for (int x = 0; x < room.xSectors; x++) {
776 TR::Room::Sector &s = room.sectors[x * room.zSectors + z];
777 if (level->getNextRoom(&s) != TR::NO_ROOM)
778 continue;
779 if (s.ceiling != TR::NO_FLOOR)
780 value = min( value, s.ceiling * 256 );
781 if (s.roomAbove != TR::NO_ROOM)
782 value = min( value, calcWaterLevel(s.roomAbove, flip) );
783 }
784
785 return value;
786 }
787
788 return room.info.yBottom;
789 }
790
roomRemoveWaterSurfacesMeshBuilder791 void roomRemoveWaterSurfaces(TR::Room &room, int &iCount, int &vCount) {
792 for (int i = 0; i < room.data.fCount; i++)
793 room.data.faces[i].water = false;
794
795 if (Core::settings.detail.water == Core::Settings::LOW)
796 return;
797
798 for (int i = 0; i < room.data.fCount; i++) {
799 TR::Face &f = room.data.faces[i];
800
801 short3 &a = room.data.vertices[f.vertices[0]].pos;
802 short3 &b = room.data.vertices[f.vertices[1]].pos;
803 short3 &c = room.data.vertices[f.vertices[2]].pos;
804
805 if (a.y != b.y || a.y != c.y) // skip non-horizontal or non-portal plane primitive
806 continue;
807
808 int sx = (int(a.x) + int(b.x) + int(c.x)) / 3 / 1024;
809 int sz = (int(a.z) + int(b.z) + int(c.z)) / 3 / 1024;
810
811 TR::Room::Sector &s = room.sectors[sx * room.zSectors + sz];
812
813 int yt = abs(a.y - s.ceiling * 256);
814 int yb = abs(s.floor * 256 - a.y);
815
816 if (yt > 0 && yb > 0) continue;
817
818 if (isWaterSurface(yt, s.roomAbove, room.flags.water) ||
819 isWaterSurface(yb, s.roomBelow, room.flags.water)) {
820 f.water = true;
821
822 room.waterLevelSurface = a.y;
823 if (f.triangle) {
824 iCount -= 3;
825 vCount -= 3;
826 } else {
827 iCount -= 6;
828 vCount -= 4;
829 }
830
831 // preserve indices & vertices for water volume
832 if (room.flags.water && Core::settings.detail.water > Core::Settings::MEDIUM) {
833 // water volume caps
834 iCount += (f.triangle ? 3 : 6) * 2;
835 vCount += (f.triangle ? 3 : 4) * 2;
836 // water volume bounds (reserved)
837 iCount += (f.triangle ? 3 : 4) * 6;
838 vCount += (f.triangle ? 3 : 4) * 4;
839 }
840 }
841 }
842 }
843
addUniqueVertexMeshBuilder844 Index addUniqueVertex(Array<short3> &vertices, short3 &v) {
845 for (int i = 0; i < vertices.length; i++) {
846 short3 &o = vertices[i];
847 if (o.x == v.x && o.y == v.y && o.z == v.z)
848 return i;
849 }
850 return vertices.push(v);
851 }
852
addUniqueEdgeMeshBuilder853 void addUniqueEdge(Array<Edge> &edges, Index a, Index b) {
854 for (int i = 0; i < edges.length; i++) {
855 Edge &e = edges[i];
856 if ((e.a == a && e.b == b) || (e.a == b && e.b == a)) {
857 edges.remove(i);
858 return;
859 }
860 }
861 edges.push(Edge(a, b));
862 }
863
buildWaterVolumeMeshBuilder864 void buildWaterVolume(int roomIndex, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart) {
865 TR::Room &room = level->rooms[roomIndex];
866 if (!room.flags.water) return;
867 MeshRange &range = rooms[roomIndex].waterVolume;
868
869 Array<Edge> wEdges(128);
870 Array<Index> wIndices(128);
871 Array<short3> wVertices(128);
872
873 for (int i = 0; i < room.data.fCount; i++) {
874 TR::Face &f = room.data.faces[i];
875 if (!f.water) continue;
876
877 Index idx[4];
878
879 idx[0] = addUniqueVertex(wVertices, room.data.vertices[f.vertices[0]].pos);
880 idx[1] = addUniqueVertex(wVertices, room.data.vertices[f.vertices[1]].pos);
881 idx[2] = addUniqueVertex(wVertices, room.data.vertices[f.vertices[2]].pos);
882
883 if (!f.triangle) {
884 idx[3] = addUniqueVertex(wVertices, room.data.vertices[f.vertices[3]].pos);
885
886 wIndices.push(idx[0]);
887 wIndices.push(idx[1]);
888 wIndices.push(idx[3]);
889
890 wIndices.push(idx[3]);
891 wIndices.push(idx[1]);
892 wIndices.push(idx[2]);
893
894 addUniqueEdge(wEdges, idx[0], idx[1]);
895 addUniqueEdge(wEdges, idx[1], idx[2]);
896 addUniqueEdge(wEdges, idx[2], idx[3]);
897 addUniqueEdge(wEdges, idx[3], idx[0]);
898 } else {
899 wIndices.push(idx[0]);
900 wIndices.push(idx[1]);
901 wIndices.push(idx[2]);
902
903 addUniqueEdge(wEdges, idx[0], idx[1]);
904 addUniqueEdge(wEdges, idx[1], idx[2]);
905 addUniqueEdge(wEdges, idx[2], idx[0]);
906 }
907 }
908
909 if (!wEdges.length) return;
910
911 Array<short3> wOffsets(wVertices.length);
912
913 for (int i = 0; i < wVertices.length; i++)
914 wOffsets.push(short3(0, WATER_VOLUME_OFFSET, 0));
915
916 for (int i = 0; i < wEdges.length; i++) {
917 Edge &e = wEdges[i];
918 short3 &a = wVertices[e.a];
919 short3 &b = wVertices[e.b];
920 int16 dx = a.z - b.z;
921 int16 dz = b.x - a.x;
922
923 short3 &ao = wOffsets[e.a];
924 ao.x = clamp(ao.x + dx, -WATER_VOLUME_OFFSET, WATER_VOLUME_OFFSET);
925 ao.z = clamp(ao.z + dz, -WATER_VOLUME_OFFSET, WATER_VOLUME_OFFSET);
926
927 short3 &bo = wOffsets[e.b];
928 bo.x = clamp(bo.x + dx, -WATER_VOLUME_OFFSET, WATER_VOLUME_OFFSET);
929 bo.z = clamp(bo.z + dz, -WATER_VOLUME_OFFSET, WATER_VOLUME_OFFSET);
930 }
931
932 range.vStart = vStart;
933 range.iCount = wIndices.length * 2 + wEdges.length * 6;
934 range.iStart = iCount;
935
936 for (int i = 0; i < wIndices.length; i += 3) {
937 indices[iCount++] = vCount + wIndices[i + 2];
938 indices[iCount++] = vCount + wIndices[i + 1];
939 indices[iCount++] = vCount + wIndices[i + 0];
940 }
941
942 for (int i = 0; i < wIndices.length; i++)
943 indices[iCount++] = vCount + wIndices[i] + wVertices.length;
944
945 for (int i = 0; i < wEdges.length; i++) {
946 Index a = wEdges[i].a;
947 Index b = wEdges[i].b;
948
949 indices[iCount++] = vCount + a;
950 indices[iCount++] = vCount + b;
951 indices[iCount++] = vCount + a + wVertices.length;
952
953 indices[iCount++] = vCount + b;
954 indices[iCount++] = vCount + b + wVertices.length;
955 indices[iCount++] = vCount + a + wVertices.length;
956 }
957
958 for (int i = 0; i < wVertices.length; i++) {
959 short3 &v = wVertices[i];
960 short3 &o = wOffsets[i];
961
962 v.x += o.x;
963 v.y += o.y;
964 v.z += o.z;
965
966 vertices[vCount++].coord = short4(v.x, v.y, v.z, 0);
967 }
968
969 for (int i = 0; i < wVertices.length; i++) {
970 short3 &v = wVertices[i];
971
972 int16 base = v.y;
973
974 v.y += WATER_VOLUME_HEIGHT - WATER_VOLUME_OFFSET - WATER_VOLUME_OFFSET;
975
976 const vec3 sectorOffsets[] = {
977 vec3(-8, 0, -8),
978 vec3( 8, 0, -8),
979 vec3( 8, 0, 8),
980 vec3(-8, 0, 8),
981 };
982
983 int16 floor = 32000;
984 for (int j = 0; j < 4; j++) {
985 vec3 pos = room.getOffset() + vec3(v.x, v.y, v.z) + sectorOffsets[j];
986 int16 rIndex = roomIndex;
987 TR::Room::Sector *sector = level->getSector(rIndex, pos);
988 if (sector->floor == TR::NO_FLOOR || !level->rooms[rIndex].flags.water) continue;
989 floor = min(floor, int16(level->getFloor(sector, pos)));
990 }
991
992 floor -= WATER_VOLUME_OFFSET * 3;
993
994 if (floor > base) {
995 v.y = min(v.y, floor);
996 }
997
998 vertices[vCount++].coord = short4(v.x, v.y, v.z, 0);
999 }
1000 }
1001
getBlendMaskMeshBuilder1002 inline int getBlendMask(int texAttribute) {
1003 ASSERT(texAttribute < 3);
1004 return 1 << texAttribute;
1005 }
1006
buildRoomMeshBuilder1007 void buildRoom(Geometry &geom, Dynamic *dyn, int blendMask, const TR::Room &room, TR::Level *level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart) {
1008 const TR::Room::Data &d = room.data;
1009
1010 if (dyn) {
1011 dyn->count = 0;
1012 dyn->faces = NULL;
1013 }
1014
1015 for (int j = 0; j < d.fCount; j++) {
1016 TR::Face &f = d.faces[j];
1017 ASSERT(!f.colored);
1018 ASSERT(f.flags.texture < level->objectTexturesCount);
1019 TR::TextureInfo &t = level->objectTextures[f.flags.texture];
1020
1021 if (f.water) continue;
1022
1023 CHECK_ROOM_NORMAL(f);
1024
1025 if (!(blendMask & getBlendMask(t.attribute)))
1026 continue;
1027
1028 if (dyn && t.animated) {
1029 ASSERT(dyn->count < 0xFFFF);
1030 dyn->count++;
1031 continue;
1032 }
1033
1034 if (!geom.validForTile(t.tile, t.clut))
1035 geom.getNextRange(vStart, iCount, t.tile, t.clut);
1036
1037 ADD_ROOM_FACE(indices, iCount, vCount, vStart, vertices, f, t);
1038 }
1039
1040 // if room has non-static polygons, fill the list of dynamic faces
1041 if (dyn && dyn->count) {
1042 dyn->faces = new uint16[dyn->count];
1043 dyn->count = 0;
1044 for (int j = 0; j < d.fCount; j++) {
1045 TR::Face &f = d.faces[j];
1046 TR::TextureInfo &t = level->objectTextures[f.flags.texture];
1047
1048 if (f.water) continue;
1049
1050 if (!(blendMask & getBlendMask(t.attribute)))
1051 continue;
1052
1053 if (t.animated)
1054 dyn->faces[dyn->count++] = j;
1055 }
1056 }
1057 }
1058
buildMeshMeshBuilder1059 bool buildMesh(Geometry &geom, int blendMask, const TR::Mesh &mesh, TR::Level *level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 joint, int x, int y, int z, int dir, const Color32 &light, bool useRoomTex, bool forceOpaque) {
1060 bool isOpaque = true;
1061
1062 for (int j = 0; j < mesh.fCount; j++) {
1063 TR::Face &f = mesh.faces[j];
1064 ASSERT(f.colored || f.flags.texture < level->objectTexturesCount);
1065 //if (level->version & TR::VER_PSX) {
1066 // f.colored = false; // PSX version has colored textures... not yet :)
1067 //}
1068 TR::TextureInfo &t = f.colored ? (useRoomTex ? whiteRoom : whiteObject) : level->objectTextures[f.flags.texture];
1069
1070 int texAttrib = forceOpaque ? 0 : t.attribute;
1071
1072 if (f.effects.additive) {
1073 texAttrib = 2;
1074 }
1075
1076 if (texAttrib != 0)
1077 isOpaque = false;
1078
1079 if (!(blendMask & getBlendMask(texAttrib)))
1080 continue;
1081
1082 if (!geom.validForTile(t.tile, t.clut))
1083 geom.getNextRange(vStart, iCount, t.tile, t.clut);
1084
1085 Color32 c = f.colored ? level->getColor(f.flags.value) : COLOR_WHITE;
1086
1087 addFace(indices, iCount, vCount, vStart, vertices, f, &t,
1088 mesh.vertices[f.vertices[0]].coord,
1089 mesh.vertices[f.vertices[1]].coord,
1090 mesh.vertices[f.vertices[2]].coord,
1091 mesh.vertices[f.vertices[3]].coord);
1092
1093 for (int k = 0; k < (f.triangle ? 3 : 4); k++) {
1094 TR::Mesh::Vertex &v = mesh.vertices[f.vertices[k]];
1095
1096 vertices[vCount].coord = transform(v.coord, joint, x, y, z, dir);
1097 vec3 n = vec3(v.normal.x, v.normal.y, v.normal.z).normal() * 32767.0f;
1098 v.normal = short4(short(n.x), short(n.y), short(n.z), f.triangle ? 1 : 0);
1099 vertices[vCount].normal = rotate(v.normal, dir);
1100 vertices[vCount].color = ubyte4( c.r, c.g, c.b, c.a );
1101 vertices[vCount].light = ubyte4( light.r, light.g, light.b, 255 );
1102
1103 vCount++;
1104 }
1105 }
1106
1107 return isOpaque;
1108 }
1109
addTexCoordMeshBuilder1110 void addTexCoord(Vertex *vertices, int vCount, TR::TextureInfo *tex, bool triangle, uint8 flip) {
1111 int count = triangle ? 3 : 4;
1112 for (int i = 0; i < count; i++) {
1113 Vertex &v = vertices[vCount + i];
1114 v.texCoord = short4( tex->texCoordAtlas[i].x, tex->texCoordAtlas[i].y, 32767, 32767 );
1115 }
1116
1117 if (((level->version & TR::VER_PSX)) && !triangle) // TODO: swap vertices instead of rectangle indices and vertices.texCoords (WRONG lighting in TR2!)
1118 swap(vertices[vCount + 2].texCoord, vertices[vCount + 3].texCoord);
1119
1120 if ((level->version & TR::VER_SAT)) {
1121 if (triangle) {
1122 /* transform Saturn's triangle texCoords by flip code
1123 |\
1124 flip 2, 6, 8, 12 - |_\
1125 _
1126 flip 0, 4, 10, 14 - | /
1127 |/
1128 */
1129 if (flip == 2 || flip == 6 || flip == 8 || flip == 12)
1130 vertices[vCount + 1].texCoord = vertices[vCount + 2].texCoord;
1131
1132 vertices[vCount + 2].texCoord.x = vertices[vCount + 0].texCoord.x;
1133
1134 if (flip == 10 || flip == 14) // flip diagonal
1135 swap(vertices[vCount + 1].texCoord, vertices[vCount + 2].texCoord);
1136
1137 if (flip == 2 || flip == 6) { // rotate
1138 swap(vertices[vCount + 0].texCoord, vertices[vCount + 2].texCoord);
1139 swap(vertices[vCount + 2].texCoord, vertices[vCount + 1].texCoord);
1140 }
1141
1142 if (flip == 8 || flip == 12) // flip vertical
1143 swap(vertices[vCount + 0].texCoord, vertices[vCount + 2].texCoord);
1144
1145 } else {
1146
1147 if (flip) { // flip horizontal
1148 swap(vertices[vCount + 0].texCoord, vertices[vCount + 1].texCoord);
1149 swap(vertices[vCount + 3].texCoord, vertices[vCount + 2].texCoord);
1150 }
1151
1152 }
1153 }
1154 }
1155
addTriangleMeshBuilder1156 void addTriangle(Index *indices, int &iCount, int vCount, int vStart, Vertex *vertices, TR::TextureInfo *tex, bool doubleSided, uint8 flip) {
1157 int vIndex = vCount - vStart;
1158
1159 indices[iCount + 0] = vIndex + 0;
1160 indices[iCount + 1] = vIndex + 1;
1161 indices[iCount + 2] = vIndex + 2;
1162
1163 iCount += 3;
1164
1165 if (doubleSided) {
1166 indices[iCount + 0] = vIndex + 2;
1167 indices[iCount + 1] = vIndex + 1;
1168 indices[iCount + 2] = vIndex + 0;
1169 iCount += 3;
1170 }
1171
1172 if (tex) addTexCoord(vertices, vCount, tex, true, flip);
1173 }
1174
addQuadMeshBuilder1175 void addQuad(Index *indices, int &iCount, int vCount, int vStart, Vertex *vertices, TR::TextureInfo *tex, bool doubleSided, uint8 flip) {
1176 int vIndex = vCount - vStart;
1177
1178 indices[iCount + 0] = vIndex + 0;
1179 indices[iCount + 1] = vIndex + 1;
1180 indices[iCount + 2] = vIndex + 2;
1181
1182 indices[iCount + 3] = vIndex + 0;
1183 indices[iCount + 4] = vIndex + 2;
1184 indices[iCount + 5] = vIndex + 3;
1185
1186 iCount += 6;
1187
1188 if (doubleSided) {
1189 indices[iCount + 0] = vIndex + 2;
1190 indices[iCount + 1] = vIndex + 1;
1191 indices[iCount + 2] = vIndex + 0;
1192
1193 indices[iCount + 3] = vIndex + 3;
1194 indices[iCount + 4] = vIndex + 2;
1195 indices[iCount + 5] = vIndex + 0;
1196
1197 iCount += 6;
1198 }
1199
1200 if (tex) addTexCoord(vertices, vCount, tex, false, flip);
1201 }
1202
addQuadMeshBuilder1203 void addQuad(Index *indices, int &iCount, int &vCount, int vStart, Vertex *vertices, TR::TextureInfo *tex, bool doubleSided, uint8 flip,
1204 const short3 &c0, const short3 &c1, const short3 &c2, const short3 &c3) {
1205 addQuad(indices, iCount, vCount, vStart, vertices, tex, doubleSided, flip);
1206
1207 // TODO: pre-calculate trapezoid ratio for room geometry
1208 vec3 a = c0 - c1;
1209 vec3 b = c3 - c2;
1210 vec3 c = c0 - c3;
1211 vec3 d = c1 - c2;
1212
1213 float aL = a.length();
1214 float bL = b.length();
1215 float cL = c.length();
1216 float dL = d.length();
1217
1218 float ab = a.dot(b) / (aL * bL);
1219 float cd = c.dot(d) / (cL * dL);
1220
1221 int16 tx = abs(vertices[vCount + 0].texCoord.x - vertices[vCount + 3].texCoord.x);
1222 int16 ty = abs(vertices[vCount + 0].texCoord.y - vertices[vCount + 3].texCoord.y);
1223
1224 if (ab > cd) {
1225 int k = (tx > ty) ? 3 : 2;
1226
1227 if (aL > bL)
1228 vertices[vCount + 2].texCoord[k] = vertices[vCount + 3].texCoord[k] = int16(bL / aL * 32767.0f);
1229 else
1230 vertices[vCount + 0].texCoord[k] = vertices[vCount + 1].texCoord[k] = int16(aL / bL * 32767.0f);
1231 } else {
1232 int k = (tx > ty) ? 2 : 3;
1233
1234 if (cL > dL) {
1235 vertices[vCount + 1].texCoord[k] = vertices[vCount + 2].texCoord[k] = int16(dL / cL * 32767.0f);
1236 } else
1237 vertices[vCount + 0].texCoord[k] = vertices[vCount + 3].texCoord[k] = int16(cL / dL * 32767.0f);
1238 }
1239 }
1240
1241
addFaceMeshBuilder1242 void addFace(Index *indices, int &iCount, int &vCount, int vStart, Vertex *vertices, const TR::Face &f, TR::TextureInfo *tex, const short3 &a, const short3 &b, const short3 &c, const short3 &d) {
1243 if (f.triangle)
1244 addTriangle(indices, iCount, vCount, vStart, vertices, tex, f.flags.doubleSided, f.flip);
1245 else
1246 addQuad(indices, iCount, vCount, vStart, vertices, tex, f.flags.doubleSided, f.flip, a, b, c, d);
1247 }
1248
1249
coordTransformMeshBuilder1250 short4 coordTransform(const vec3 ¢er, const vec3 &offset) {
1251 mat4 m = Core::mViewInv;
1252 m.setPos(center);
1253
1254 vec3 coord = m * offset;
1255 return short4(int16(coord.x), int16(coord.y), int16(coord.z), 0);
1256 }
1257
1258 void addSprite(Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 x, int16 y, int16 z, bool invertX, bool invertY, const TR::TextureInfo &sprite, const Color32 &tColor, const Color32 &bColor, bool expand = false) {
1259 addQuad(indices, iCount, vCount, vStart, NULL, NULL, false, false);
1260
1261 Vertex *quad = &vertices[vCount];
1262
1263 int16 x0, y0, x1, y1;
1264
1265 if (expand) {
1266 if (invertX) {
1267 x0 = x - int16(sprite.l);
1268 x1 = x - int16(sprite.r);
1269 } else {
1270 x0 = x + int16(sprite.l);
1271 x1 = x + int16(sprite.r);
1272 }
1273
1274 if (invertY) {
1275 y0 = y - int16(sprite.t);
1276 y1 = y - int16(sprite.b);
1277 } else {
1278 y0 = y + int16(sprite.t);
1279 y1 = y + int16(sprite.b);
1280 }
1281 } else {
1282 x0 = x1 = x;
1283 y0 = y1 = y;
1284 }
1285
1286 #ifndef MERGE_SPRITES
1287 if (!expand) {
1288 vec3 pos = vec3(float(x), float(y), float(z));
1289 quad[0].coord = coordTransform(pos, vec3( float(sprite.l), float(-sprite.t), 1 ));
1290 quad[1].coord = coordTransform(pos, vec3( float(sprite.r), float(-sprite.t), 1 ));
1291 quad[2].coord = coordTransform(pos, vec3( float(sprite.r), float(-sprite.b), 1 ));
1292 quad[3].coord = coordTransform(pos, vec3( float(sprite.l), float(-sprite.b), 1 ));
1293 } else
1294 #endif
1295 {
1296 quad[0].coord = short4( x0, y0, z, 1 );
1297 quad[1].coord = short4( x1, y0, z, 1 );
1298 quad[2].coord = short4( x1, y1, z, 1 );
1299 quad[3].coord = short4( x0, y1, z, 1 );
1300 }
1301
1302 quad[0].normal = quad[1].normal = quad[2].normal = quad[3].normal = short4( 0, 0, 0, 0 );
1303 quad[0].color = quad[1].color =
1304 quad[2].color = quad[3].color = ubyte4( 255, 255, 255, 255 );
1305 quad[0].light = quad[1].light = ubyte4( tColor.r, tColor.g, tColor.b, tColor.a );
1306 quad[2].light = quad[3].light = ubyte4( bColor.r, bColor.g, bColor.b, bColor.a );
1307
1308 quad[0].texCoord = short4( sprite.texCoordAtlas[0].x, sprite.texCoordAtlas[0].y, sprite.l, -sprite.t );
1309 quad[1].texCoord = short4( sprite.texCoordAtlas[1].x, sprite.texCoordAtlas[0].y, sprite.r, -sprite.t );
1310 quad[2].texCoord = short4( sprite.texCoordAtlas[1].x, sprite.texCoordAtlas[1].y, sprite.r, -sprite.b );
1311 quad[3].texCoord = short4( sprite.texCoordAtlas[0].x, sprite.texCoordAtlas[1].y, sprite.l, -sprite.b );
1312
1313 vCount += 4;
1314 }
1315
1316 void addDynBar(const TR::TextureInfo &tile, const vec2 &pos, const vec2 &size, uint32 color, uint32 color2 = 0) {
1317 dynCheck(1 * 6);
1318
1319 Index *indices = dynIndices;
1320 Vertex *vertices = dynVertices;
1321 int &iCount = dynICount;
1322 int &vCount = dynVCount;
1323
1324 addQuad(indices, iCount, vCount, 0, vertices, NULL, false, false);
1325
1326 int16 minX = int16(pos.x);
1327 int16 minY = int16(pos.y);
1328 int16 maxX = int16(size.x) + minX;
1329 int16 maxY = int16(size.y) + minY;
1330
1331 vertices[vCount + 0].coord = short4( minX, minY, 0, 1 );
1332 vertices[vCount + 1].coord = short4( maxX, minY, 0, 1 );
1333 vertices[vCount + 2].coord = short4( maxX, maxY, 0, 1 );
1334 vertices[vCount + 3].coord = short4( minX, maxY, 0, 1 );
1335
1336 for (int i = 0; i < 4; i++) {
1337 Vertex &v = vertices[vCount + i];
1338 v.normal = short4( 0, 0, 0, 0 );
1339 if (color2 != 0 && (i == 0 || i == 3))
1340 v.light.value = color2;
1341 else
1342 v.light.value = color;
1343
1344 short2 uv = tile.texCoordAtlas[i];
1345
1346 v.texCoord = short4( uv.x, uv.y, 32767, 32767 );
1347 }
1348
1349 vCount += 4;
1350 }
1351
addDynFrameMeshBuilder1352 void addDynFrame(const vec2 &pos, const vec2 &size, uint32 color1, uint32 color2) {
1353 dynCheck(4 * 6);
1354
1355 Index *indices = dynIndices;
1356 Vertex *vertices = dynVertices;
1357 int &iCount = dynICount;
1358 int &vCount = dynVCount;
1359
1360 short4 uv = short4( whiteSprite.texCoordAtlas[0].x, whiteSprite.texCoordAtlas[0].y, 32767, 32767 );
1361
1362 int16 minX = int16(pos.x);
1363 int16 minY = int16(pos.y);
1364 int16 maxX = int16(size.x) + minX;
1365 int16 maxY = int16(size.y) + minY;
1366 int16 s = 1;
1367
1368 vertices[vCount + 0].coord = short4( minX - s, minY - s, 0, 1 );
1369 vertices[vCount + 1].coord = short4( maxX + s, minY - s, 0, 1 );
1370 vertices[vCount + 2].coord = short4( maxX + s, minY + s, 0, 1 );
1371 vertices[vCount + 3].coord = short4( minX - s, minY + s, 0, 1 );
1372
1373 vertices[vCount + 4].coord = short4( minX - s, minY - s, 0, 1 );
1374 vertices[vCount + 5].coord = short4( minX + s, minY - s, 0, 1 );
1375 vertices[vCount + 6].coord = short4( minX + s, maxY + s, 0, 1 );
1376 vertices[vCount + 7].coord = short4( minX - s, maxY + s, 0, 1 );
1377
1378 for (int i = 0; i < 8; i++) {
1379 Vertex &v = vertices[vCount + i];
1380 v.normal = short4( 0, 0, 0, 0 );
1381 v.light.value = color1;
1382 v.texCoord = uv;
1383 }
1384
1385 addQuad(indices, iCount, vCount, 0, vertices, NULL, false, false); vCount += 4;
1386 addQuad(indices, iCount, vCount, 0, vertices, NULL, false, false); vCount += 4;
1387
1388 vertices[vCount + 0].coord = short4( minX + s, maxY - s, 0, 1 );
1389 vertices[vCount + 1].coord = short4( maxX + s, maxY - s, 0, 1 );
1390 vertices[vCount + 2].coord = short4( maxX + s, maxY + s, 0, 1 );
1391 vertices[vCount + 3].coord = short4( minX + s, maxY + s, 0, 1 );
1392
1393 vertices[vCount + 4].coord = short4( maxX - s, minY + s, 0, 1 );
1394 vertices[vCount + 5].coord = short4( maxX + s, minY + s, 0, 1 );
1395 vertices[vCount + 6].coord = short4( maxX + s, maxY + s, 0, 1 );
1396 vertices[vCount + 7].coord = short4( maxX - s, maxY + s, 0, 1 );
1397
1398 for (int i = 0; i < 8; i++) {
1399 Vertex &v = vertices[vCount + i];
1400 v.normal = short4( 0, 0, 0, 0 );
1401 v.light.value = color2;
1402 v.texCoord = uv;
1403 }
1404
1405 addQuad(indices, iCount, vCount, 0, vertices, NULL, false, false); vCount += 4;
1406 addQuad(indices, iCount, vCount, 0, vertices, NULL, false, false); vCount += 4;
1407 }
1408
renderBufferMeshBuilder1409 void renderBuffer(Index *indices, int iCount, Vertex *vertices, int vCount) {
1410 if (iCount <= 0) return;
1411
1412 dynRange.iStart = 0;
1413 dynRange.iCount = iCount;
1414
1415 dynMesh->update(indices, iCount, vertices, vCount);
1416 dynMesh->render(dynRange);
1417 }
1418
renderRoomGeometryMeshBuilder1419 void renderRoomGeometry(int roomIndex) {
1420 Geometry &geom = rooms[roomIndex].geometry[transparent];
1421 for (int i = 0; i < geom.count; i++) {
1422 MeshRange &range = geom.ranges[i];
1423
1424 #ifdef SPLIT_BY_TILE
1425 int clutOffset = level->rooms[roomIndex].flags.water ? 512 : 0;
1426 atlas->bindTile(range.tile, range.clut + clutOffset);
1427 #endif
1428
1429 mesh->render(range);
1430 }
1431
1432 Dynamic &dyn = rooms[roomIndex].dynamic[transparent];
1433 if (dyn.count) {
1434 #ifdef SPLIT_BY_TILE
1435 uint16 tile = 0xFFFF, clut = 0xFFFF;
1436 #endif
1437 int iCount = 0, vCount = 0, vStart = 0;
1438
1439 const TR::Room::Data &d = level->rooms[roomIndex].data;
1440 for (int i = 0; i < dyn.count; i++) {
1441 TR::Face &f = d.faces[dyn.faces[i]];
1442 TR::TextureInfo &t = level->objectTextures[f.flags.texture];
1443
1444 #ifdef SPLIT_BY_TILE
1445 if (iCount) {
1446 if (tile != t.tile
1447 #ifdef SPLIT_BY_CLUT
1448 || clut != t.clut
1449 #endif
1450 ) {
1451 atlas->bindTile(tile, clut);
1452 renderBuffer(dynIndices, iCount, dynVertices, vCount);
1453 tile = t.tile;
1454 clut = t.clut;
1455 iCount = 0;
1456 vCount = 0;
1457 }
1458 } else {
1459 tile = t.tile;
1460 clut = t.clut;
1461 }
1462 #endif
1463
1464 ADD_ROOM_FACE(dynIndices, iCount, vCount, vStart, dynVertices, f, t);
1465 }
1466
1467 if (iCount) {
1468 #ifdef SPLIT_BY_TILE
1469 atlas->bindTile(tile, clut);
1470 #endif
1471 renderBuffer(dynIndices, iCount, dynVertices, vCount);
1472 }
1473 }
1474 }
1475
dynBeginMeshBuilder1476 void dynBegin() {
1477 dynICount = 0;
1478 dynVCount = 0;
1479
1480 #ifdef SPLIT_BY_TILE
1481 curTile = 0xFFFF;
1482 curClut = 0xFFFF;
1483 #endif
1484 }
1485
dynEndMeshBuilder1486 void dynEnd() {
1487 if (dynICount) {
1488 renderBuffer(dynIndices, dynICount, dynVertices, dynVCount);
1489 }
1490 }
1491
dynCheckMeshBuilder1492 void dynCheck(int freeIndicesCount) {
1493 if (dynICount + freeIndicesCount > COUNT(dynIndices)) {
1494 dynEnd();
1495 dynBegin();
1496 }
1497 }
1498
1499 void addDynSprite(int spriteIndex, const short3 ¢er, bool invertX, bool invertY, const Color32 &tColor, const Color32 &bColor, bool expand = false) {
1500 dynCheck(1 * 6);
1501
1502 TR::TextureInfo &sprite = level->spriteTextures[spriteIndex];
1503
1504 #ifdef SPLIT_BY_TILE
1505 if (sprite.tile != curTile
1506 #ifdef SPLIT_BY_CLUT
1507 || sprite.clut != curClut
1508 #endif
1509 ) {
1510 dynEnd();
1511 dynBegin();
1512 curTile = sprite.tile;
1513 curClut = sprite.clut;
1514 atlas->bindTile(curTile, curClut);
1515 }
1516 #endif
1517
1518 addSprite(dynIndices, dynVertices, dynICount, dynVCount, 0, center.x, center.y, center.z, invertX, invertY, sprite, tColor, bColor, expand);
1519 }
1520
renderRoomSpritesMeshBuilder1521 void renderRoomSprites(int roomIndex) {
1522 #ifndef MERGE_SPRITES
1523 Core::mModel.identity();
1524 Core::mModel.setPos(Core::active.basis[0].pos);
1525
1526 dynBegin();
1527
1528 TR::Room::Data &d = level->rooms[roomIndex].data;
1529 for (int j = 0; j < d.sCount; j++) {
1530 TR::Room::Data::Sprite &f = d.sprites[j];
1531 TR::Room::Data::Vertex &v = d.vertices[f.vertexIndex];
1532 addDynSprite(f.texture, d.vertices[f.vertexIndex].pos, false, false, v.color, v.color);
1533 }
1534
1535 dynEnd();
1536 #else
1537 mesh->render(rooms[roomIndex].sprites);
1538 #endif
1539 }
1540
renderMeshMeshBuilder1541 void renderMesh(const MeshRange &range) {
1542 mesh->render(range);
1543 }
1544
1545 void renderModel(int modelIndex, bool underwater = false) {
1546 ASSERT((Core::pass != Core::passCompose && Core::pass != Core::passShadow && Core::pass != Core::passAmbient) ||
1547 level->models[modelIndex].mCount == Core::active.basisCount);
1548
1549 int part = 0;
1550
1551 Geometry &geom = models[modelIndex].geometry[transparent];
1552 #ifdef MERGE_MODELS
1553 int i = 0;
1554 #else
1555 for (int i = 0; i < level->models[modelIndex].mCount; i++)
1556 #endif
1557 {
1558 #ifndef MERGE_MODELS
1559 if (models[modelIndex].parts[transparent][i] == 0)
1560 continue;
1561
1562 Basis &basis = Core::active.basis[i];
1563 if (basis.w == 0.0f) {
1564 part += models[modelIndex].parts[transparent][i];
1565 continue;
1566 }
1567 #ifdef FFP
1568 Core::mModel.identity();
1569 Core::mModel.setRot(basis.rot);
1570 Core::mModel.setPos(basis.pos);
1571 #else
1572 Core::active.shader->setParam(uBasis, *(vec4*)&basis, 2);
1573 #endif
1574 #endif
1575
1576 for (int j = 0; j < models[modelIndex].parts[transparent][i]; j++) {
1577 MeshRange &range = geom.ranges[part++];
1578
1579 ASSERT(range.iCount);
1580
1581 #ifdef SPLIT_BY_TILE
1582 int clutOffset = underwater ? 512 : 0;
1583 atlas->bindTile(range.tile, range.clut + clutOffset);
1584 #endif
1585
1586 mesh->render(range);
1587 }
1588 }
1589 }
1590
renderShadowBlobMeshBuilder1591 void renderShadowBlob() {
1592 mesh->render(shadowBlob);
1593 }
1594
renderQuadMeshBuilder1595 void renderQuad() {
1596 mesh->render(quad);
1597 }
1598
renderCircleMeshBuilder1599 void renderCircle() {
1600 mesh->render(circle);
1601 }
1602
renderPlaneMeshBuilder1603 void renderPlane() {
1604 mesh->render(plane);
1605 }
1606
renderBoxMeshBuilder1607 void renderBox() {
1608 mesh->render(box);
1609 }
1610
renderWaterVolumeMeshBuilder1611 void renderWaterVolume(int roomIndex) {
1612 MeshRange &range = rooms[roomIndex].waterVolume;
1613 if (range.iCount)
1614 mesh->render(range);
1615 }
1616 };
1617
1618 #endif
1619