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 &center, 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 &center, 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