Legends-of-Azeroth-Pandaria-5.4.8

Форк
0
1026 строк · 40.2 Кб
1
/*
2
 * Copyright (C) 2011-2016 Project SkyFire <http://www.projectskyfire.org/>
3
 * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
4
 * Copyright (C) 2005-2016 MaNGOS <http://getmangos.com/>
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License as published by the
8
 * Free Software Foundation; either version 3 of the License, or (at your
9
 * option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14
 * more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along
17
 * with this program. If not, see <http://www.gnu.org/licenses/>.
18
 */
19

20
#include "TerrainBuilder.h"
21
#include "PathCommon.h"
22
#include "MapBuilder.h"
23
#include "MapDefines.h"
24
#include "VMapManager2.h"
25
#include "MapDefines.h"
26
#include "MapTree.h"
27
#include "ModelInstance.h"
28
#include <vector>
29

30
#include "SharedDefines.h"
31

32
// ******************************************
33
// Map file format defines
34
// ******************************************
35
struct map_fileheader
36
{
37
    uint32 mapMagic;
38
    uint32 versionMagic;
39
    uint32 buildMagic;
40
    uint32 areaMapOffset;
41
    uint32 areaMapSize;
42
    uint32 heightMapOffset;
43
    uint32 heightMapSize;
44
    uint32 liquidMapOffset;
45
    uint32 liquidMapSize;
46
    uint32 holesOffset;
47
    uint32 holesSize;
48
};
49

50
#define MAP_HEIGHT_NO_HEIGHT  0x0001
51
#define MAP_HEIGHT_AS_INT16   0x0002
52
#define MAP_HEIGHT_AS_INT8    0x0004
53

54
struct map_heightHeader
55
{
56
    uint32 fourcc;
57
    uint32 flags;
58
    float  gridHeight;
59
    float  gridMaxHeight;
60
};
61

62
#define MAP_LIQUID_NO_TYPE    0x0001
63
#define MAP_LIQUID_NO_HEIGHT  0x0002
64

65
struct map_liquidHeader
66
{
67
    uint32 fourcc;
68
    uint8 flags;
69
    uint8 liquidFlags;
70
    uint16 liquidType;
71
    uint8  offsetX;
72
    uint8  offsetY;
73
    uint8  width;
74
    uint8  height;
75
    float  liquidLevel;
76
};
77

78
#define MAP_LIQUID_TYPE_NO_WATER    0x00
79
#define MAP_LIQUID_TYPE_WATER       0x01
80
#define MAP_LIQUID_TYPE_OCEAN       0x02
81
#define MAP_LIQUID_TYPE_MAGMA       0x04
82
#define MAP_LIQUID_TYPE_SLIME       0x08
83
#define MAP_LIQUID_TYPE_DARK_WATER  0x10
84
#define MAP_LIQUID_TYPE_WMO_WATER   0x20
85

86
// uint32 GetLiquidFlags(uint32 liquidType)
87
// {
88
//     // LiquidType.dbc
89
//     // Hardcoded for laziness' sake
90
//     static std::map<uint32, uint32> liquidEntryToLiquidType =
91
//     {
92
//         {   1, MAP_LIQUID_TYPE_WATER },
93
//         {   2, MAP_LIQUID_TYPE_OCEAN },
94
//         {   3, MAP_LIQUID_TYPE_MAGMA },
95
//         {   4, MAP_LIQUID_TYPE_SLIME },
96
//         {   5, MAP_LIQUID_TYPE_WATER },
97
//         {   6, MAP_LIQUID_TYPE_OCEAN },
98
//         {   7, MAP_LIQUID_TYPE_MAGMA },
99
//         {   8, MAP_LIQUID_TYPE_SLIME },
100
//         {   9, MAP_LIQUID_TYPE_WATER },
101
//         {  10, MAP_LIQUID_TYPE_OCEAN },
102
//         {  11, MAP_LIQUID_TYPE_MAGMA },
103
//         {  12, MAP_LIQUID_TYPE_SLIME },
104
//         {  13, MAP_LIQUID_TYPE_WATER },
105
//         {  14, MAP_LIQUID_TYPE_OCEAN },
106
//         {  15, MAP_LIQUID_TYPE_MAGMA },
107
//         {  17, MAP_LIQUID_TYPE_WATER },
108
//       //{  18, MAP_LIQUID_TYPE_OCEAN },
109
//         {  19, MAP_LIQUID_TYPE_MAGMA },
110
//         {  20, MAP_LIQUID_TYPE_SLIME },
111
//         {  21, MAP_LIQUID_TYPE_SLIME },
112
//         {  41, MAP_LIQUID_TYPE_WATER },
113
//         {  61, MAP_LIQUID_TYPE_WATER },
114
//         {  81, MAP_LIQUID_TYPE_WATER },
115
//         { 100, MAP_LIQUID_TYPE_OCEAN },
116
//         { 121, MAP_LIQUID_TYPE_MAGMA },
117
//         { 141, MAP_LIQUID_TYPE_MAGMA },
118
//         { 181, MAP_LIQUID_TYPE_WATER },
119
//     };
120
//     auto itr = liquidEntryToLiquidType.find(liquidType);
121
//     if (itr == liquidEntryToLiquidType.end())
122
//         std::abort();
123
//     return itr->second;
124
// }
125

126
uint32 GetLiquidFlags(uint32 liquidId);
127

128
namespace MMAP
129
{
130

131
    uint32 const MAP_VERSION_MAGIC = 10;
132

133
    TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ }
134
    TerrainBuilder::~TerrainBuilder() { }
135

136
    /**************************************************************************/
137
    void TerrainBuilder::getLoopVars(Spot portion, int &loopStart, int &loopEnd, int &loopInc)
138
    {
139
        switch (portion)
140
        {
141
            case ENTIRE:
142
                loopStart = 0;
143
                loopEnd = V8_SIZE_SQ;
144
                loopInc = 1;
145
                break;
146
            case TOP:
147
                loopStart = 0;
148
                loopEnd = V8_SIZE;
149
                loopInc = 1;
150
                break;
151
            case LEFT:
152
                loopStart = 0;
153
                loopEnd = V8_SIZE_SQ - V8_SIZE + 1;
154
                loopInc = V8_SIZE;
155
                break;
156
            case RIGHT:
157
                loopStart = V8_SIZE - 1;
158
                loopEnd = V8_SIZE_SQ;
159
                loopInc = V8_SIZE;
160
                break;
161
            case BOTTOM:
162
                loopStart = V8_SIZE_SQ - V8_SIZE;
163
                loopEnd = V8_SIZE_SQ;
164
                loopInc = 1;
165
                break;
166
        }
167
    }
168

169
    /**************************************************************************/
170
    void TerrainBuilder::loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData)
171
    {
172
        if (loadMap(mapID, tileX, tileY, meshData, ENTIRE))
173
        {
174
            loadMap(mapID, tileX+1, tileY, meshData, LEFT);
175
            loadMap(mapID, tileX-1, tileY, meshData, RIGHT);
176
            loadMap(mapID, tileX, tileY+1, meshData, TOP);
177
            loadMap(mapID, tileX, tileY-1, meshData, BOTTOM);
178
        }
179
    }
180

181
    /**************************************************************************/
182
    bool TerrainBuilder::loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, Spot portion)
183
    {
184
        char mapFileName[255];
185
        sprintf(mapFileName, "maps/%04u_%02u_%02u.map", mapID, tileY, tileX);
186

187
        FILE* mapFile = fopen(mapFileName, "rb");
188
        if (!mapFile)
189
            return false;
190

191
        map_fileheader fheader;
192
        if (fread(&fheader, sizeof(map_fileheader), 1, mapFile) != 1 ||
193
            fheader.versionMagic != MAP_VERSION_MAGIC)
194
        {
195
            fclose(mapFile);
196
            printf("%s is the wrong version, please extract new .map files\n", mapFileName);
197
            return false;
198
        }
199

200
        map_heightHeader hheader;
201
        fseek(mapFile, fheader.heightMapOffset, SEEK_SET);
202

203
        bool haveTerrain = false;
204
        bool haveLiquid = false;
205
        if (fread(&hheader, sizeof(map_heightHeader), 1, mapFile) == 1)
206
        {
207
            haveTerrain = !(hheader.flags & MAP_HEIGHT_NO_HEIGHT);
208
            haveLiquid = fheader.liquidMapOffset && !m_skipLiquid;
209
        }
210

211
        // no data in this map file
212
        if (!haveTerrain && !haveLiquid)
213
        {
214
            fclose(mapFile);
215
            return false;
216
        }
217

218
        // data used later
219
        uint16 holes[16][16];
220
        memset(holes, 0, sizeof(holes));
221
        uint16 liquid_entry[16][16];
222
        memset(liquid_entry, 0, sizeof(liquid_entry));
223
        uint8 liquid_flags[16][16];
224
        memset(liquid_flags, 0, sizeof(liquid_flags));
225
        G3D::Array<int> ltriangles;
226
        G3D::Array<int> ttriangles;
227

228
        // terrain data
229
        if (haveTerrain)
230
        {
231
            float heightMultiplier;
232
            float V9[V9_SIZE_SQ], V8[V8_SIZE_SQ];
233
            int expected = V9_SIZE_SQ + V8_SIZE_SQ;
234

235
            if (hheader.flags & MAP_HEIGHT_AS_INT8)
236
            {
237
                uint8 v9[V9_SIZE_SQ];
238
                uint8 v8[V8_SIZE_SQ];
239
                int count = 0;
240
                count += fread(v9, sizeof(uint8), V9_SIZE_SQ, mapFile);
241
                count += fread(v8, sizeof(uint8), V8_SIZE_SQ, mapFile);
242
                if (count != expected)
243
                    printf("TerrainBuilder::loadMap: Failed to read some data expected %d, read %d\n", expected, count);
244

245
                heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 255;
246

247
                for (int i = 0; i < V9_SIZE_SQ; ++i)
248
                    V9[i] = (float)v9[i]*heightMultiplier + hheader.gridHeight;
249

250
                for (int i = 0; i < V8_SIZE_SQ; ++i)
251
                    V8[i] = (float)v8[i]*heightMultiplier + hheader.gridHeight;
252
            }
253
            else if (hheader.flags & MAP_HEIGHT_AS_INT16)
254
            {
255
                uint16 v9[V9_SIZE_SQ];
256
                uint16 v8[V8_SIZE_SQ];
257
                int count = 0;
258
                count += fread(v9, sizeof(uint16), V9_SIZE_SQ, mapFile);
259
                count += fread(v8, sizeof(uint16), V8_SIZE_SQ, mapFile);
260
                if (count != expected)
261
                    printf("TerrainBuilder::loadMap: Failed to read some data expected %d, read %d\n", expected, count);
262

263
                heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 65535;
264

265
                for (int i = 0; i < V9_SIZE_SQ; ++i)
266
                    V9[i] = (float)v9[i]*heightMultiplier + hheader.gridHeight;
267

268
                for (int i = 0; i < V8_SIZE_SQ; ++i)
269
                    V8[i] = (float)v8[i]*heightMultiplier + hheader.gridHeight;
270
            }
271
            else
272
            {
273
                int count = 0;
274
                count += fread(V9, sizeof(float), V9_SIZE_SQ, mapFile);
275
                count += fread(V8, sizeof(float), V8_SIZE_SQ, mapFile);
276
                if (count != expected)
277
                    printf("TerrainBuilder::loadMap: Failed to read some data expected %d, read %d\n", expected, count);
278
            }
279

280
            // hole data
281
            if (fheader.holesSize != 0)
282
            {
283
                memset(holes, 0, fheader.holesSize);
284
                fseek(mapFile, fheader.holesOffset, SEEK_SET);
285
                if (fread(holes, fheader.holesSize, 1, mapFile) != 1)
286
                    printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
287
            }
288

289
            int count = meshData.solidVerts.size() / 3;
290
            float xoffset = (float(tileX)-32)*GRID_SIZE;
291
            float yoffset = (float(tileY)-32)*GRID_SIZE;
292

293
            float coord[3];
294

295
            for (int i = 0; i < V9_SIZE_SQ; ++i)
296
            {
297
                getHeightCoord(i, GRID_V9, xoffset, yoffset, coord, V9);
298
                meshData.solidVerts.append(coord[0]);
299
                meshData.solidVerts.append(coord[2]);
300
                meshData.solidVerts.append(coord[1]);
301
            }
302

303
            for (int i = 0; i < V8_SIZE_SQ; ++i)
304
            {
305
                getHeightCoord(i, GRID_V8, xoffset, yoffset, coord, V8);
306
                meshData.solidVerts.append(coord[0]);
307
                meshData.solidVerts.append(coord[2]);
308
                meshData.solidVerts.append(coord[1]);
309
            }
310

311
            int indices[] = { 0, 0, 0 };
312
            int loopStart = 0, loopEnd = 0, loopInc = 0;
313
            getLoopVars(portion, loopStart, loopEnd, loopInc);
314
            for (int i = loopStart; i < loopEnd; i+=loopInc)
315
                for (int j = TOP; j <= BOTTOM; j+=1)
316
                {
317
                    getHeightTriangle(i, Spot(j), indices);
318
                    ttriangles.append(indices[2] + count);
319
                    ttriangles.append(indices[1] + count);
320
                    ttriangles.append(indices[0] + count);
321
                }
322
        }
323

324
        // liquid data
325
        if (haveLiquid)
326
        {
327
            map_liquidHeader lheader;
328
            fseek(mapFile, fheader.liquidMapOffset, SEEK_SET);
329
            if (fread(&lheader, sizeof(map_liquidHeader), 1, mapFile) != 1)
330
                printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
331

332
            float* liquid_map = nullptr;
333

334
            if (!(lheader.flags & MAP_LIQUID_NO_TYPE))
335
            {
336
                if (fread(liquid_entry, sizeof(liquid_entry), 1, mapFile) != 1)
337
                    printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
338
                if (fread(liquid_flags, sizeof(liquid_flags), 1, mapFile) != 1)
339
                    printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");                
340
            }
341
            else
342
            {
343
                std::fill_n(&liquid_entry[0][0], 16 * 16, lheader.liquidType);
344
                std::fill_n(&liquid_flags[0][0], 16 * 16, lheader.liquidFlags);
345
            }
346

347
            if (!(lheader.flags & MAP_LIQUID_NO_HEIGHT))
348
            {
349
                uint32 toRead = lheader.width * lheader.height;
350
                liquid_map = new float [toRead];
351
                if (fread(liquid_map, sizeof(float), toRead, mapFile) != toRead)
352
                {
353
                    printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
354
                    delete[] liquid_map;
355
                    liquid_map = nullptr;
356
                }                
357
            }
358

359
            int count = meshData.liquidVerts.size() / 3;
360
            float xoffset = (float(tileX)-32)*GRID_SIZE;
361
            float yoffset = (float(tileY)-32)*GRID_SIZE;
362

363
            float coord[3];
364
            int row, col;
365

366
            // generate coordinates
367
            if (!(lheader.flags & MAP_LIQUID_NO_HEIGHT))
368
            {
369
                int j = 0;
370
                for (int i = 0; i < V9_SIZE_SQ; ++i)
371
                {
372
                    row = i / V9_SIZE;
373
                    col = i % V9_SIZE;
374

375
                    if (row < lheader.offsetY || row >= lheader.offsetY + lheader.height ||
376
                        col < lheader.offsetX || col >= lheader.offsetX + lheader.width)
377
                    {
378
                        // dummy vert using invalid height
379
                        meshData.liquidVerts.append((xoffset+col*GRID_PART_SIZE)*-1, INVALID_MAP_LIQ_HEIGHT, (yoffset+row*GRID_PART_SIZE)*-1);
380
                        continue;
381
                    }
382

383
                    getLiquidCoord(i, j, xoffset, yoffset, coord, liquid_map);
384
                    meshData.liquidVerts.append(coord[0]);
385
                    meshData.liquidVerts.append(coord[2]);
386
                    meshData.liquidVerts.append(coord[1]);
387
                    j++;
388
                }
389
            }
390
            else
391
            {
392
                for (int i = 0; i < V9_SIZE_SQ; ++i)
393
                {
394
                    row = i / V9_SIZE;
395
                    col = i % V9_SIZE;
396
                    meshData.liquidVerts.append((xoffset+col*GRID_PART_SIZE)*-1, lheader.liquidLevel, (yoffset+row*GRID_PART_SIZE)*-1);
397
                }
398
            }
399

400
            delete [] liquid_map;
401

402
            int indices[] = { 0, 0, 0 };
403
            int loopStart = 0, loopEnd = 0, loopInc = 0, triInc = BOTTOM-TOP;
404
            getLoopVars(portion, loopStart, loopEnd, loopInc);
405

406
            // generate triangles
407
            for (int i = loopStart; i < loopEnd; i += loopInc)
408
            {
409
                for (int j = TOP; j <= BOTTOM; j+= triInc)
410
                {
411
                    getHeightTriangle(i, Spot(j), indices, true);
412
                    ltriangles.append(indices[2] + count);
413
                    ltriangles.append(indices[1] + count);
414
                    ltriangles.append(indices[0] + count);
415
                }                
416
            }
417
        }
418

419
        fclose(mapFile);
420

421
        // now that we have gathered the data, we can figure out which parts to keep:
422
        // liquid above ground, ground above liquid
423
        int loopStart = 0, loopEnd = 0, loopInc = 0, tTriCount = 4;
424
        bool useTerrain, useLiquid;
425

426
        float* lverts = meshData.liquidVerts.getCArray();
427
        int* ltris = ltriangles.getCArray();
428

429
        float* tverts = meshData.solidVerts.getCArray();
430
        int* ttris = ttriangles.getCArray();
431

432
        if ((ltriangles.size() + ttriangles.size()) == 0)
433
            return false;
434

435
        // make a copy of liquid vertices
436
        // used to pad right-bottom frame due to lost vertex data at extraction
437
        float* lverts_copy = nullptr;
438
        if (meshData.liquidVerts.size())
439
        {
440
            lverts_copy = new float[meshData.liquidVerts.size()];
441
            memcpy(lverts_copy, lverts, sizeof(float)*meshData.liquidVerts.size());
442
        }
443

444
        getLoopVars(portion, loopStart, loopEnd, loopInc);
445
        for (int i = loopStart; i < loopEnd; i+=loopInc)
446
        {
447
            for (int j = 0; j < 2; ++j)
448
            {
449
                // default is true, will change to false if needed
450
                useTerrain = true;
451
                useLiquid = true;
452
                uint8 liquidType = MAP_LIQUID_TYPE_NO_WATER;
453

454
                // if there is no liquid, don't use liquid
455
                if (!meshData.liquidVerts.size() || !ltriangles.size())
456
                    useLiquid = false;
457
                else
458
                {
459
                    liquidType = getLiquidType(i, liquid_flags);
460
                    switch (liquidType)
461
                    {
462
                        default:
463
                            useLiquid = false;
464
                            break;
465
                        case MAP_LIQUID_TYPE_WATER:
466
                        case MAP_LIQUID_TYPE_OCEAN:
467
                            // merge different types of water
468
                            liquidType = NAV_WATER;
469
                            break;
470
                        case MAP_LIQUID_TYPE_MAGMA:
471
                            liquidType = NAV_MAGMA;
472
                            break;
473
                        case MAP_LIQUID_TYPE_SLIME:
474
                            liquidType = NAV_SLIME;
475
                            break;
476
                        case MAP_LIQUID_TYPE_DARK_WATER:
477
                            // players should not be here, so logically neither should creatures
478
                            useTerrain = false;
479
                            useLiquid = false;
480
                            break;
481
                    }
482
                }
483
                // useLiquid = false; // Liquid pathfinding works absolutely abysmally, instead preventing all transitions between ground and water. Triangles generated for ADT water are also royally screwed up
484

485
                // if there is no terrain, don't use terrain
486
                if (!ttriangles.size())
487
                    useTerrain = false;
488

489
                // while extracting ADT data we are losing right-bottom vertices
490
                // this code adds fair approximation of lost data
491
                if (useLiquid)
492
                {
493
                    float quadHeight = 0;
494
                    uint32 validCount = 0;
495
                    for(uint32 idx = 0; idx < 3; idx++)
496
                    {
497
                        float h = lverts_copy[ltris[idx]*3 + 1];
498
                        if (h != INVALID_MAP_LIQ_HEIGHT && h < INVALID_MAP_LIQ_HEIGHT_MAX)
499
                        {
500
                            quadHeight += h;
501
                            validCount++;
502
                        }
503
                    }
504

505
                    // update vertex height data
506
                    if (validCount > 0 && validCount < 3)
507
                    {
508
                        quadHeight /= validCount;
509
                        for(uint32 idx = 0; idx < 3; idx++)
510
                        {
511
                            float h = lverts[ltris[idx]*3 + 1];
512
                            if (h == INVALID_MAP_LIQ_HEIGHT || h > INVALID_MAP_LIQ_HEIGHT_MAX)
513
                                lverts[ltris[idx]*3 + 1] = quadHeight;
514
                        }
515
                    }
516

517
                    // no valid vertexes - don't use this poly at all
518
                    if (validCount == 0)
519
                        useLiquid = false;
520
                }
521

522
                // if there is a hole here, don't use the terrain
523
                if (useTerrain && fheader.holesSize != 0)
524
                    useTerrain = !isHole(i, holes);
525

526
                // we use only one terrain kind per quad - pick higher one
527
                if (useTerrain && useLiquid)
528
                {
529
                    float minLLevel = INVALID_MAP_LIQ_HEIGHT_MAX;
530
                    float maxLLevel = INVALID_MAP_LIQ_HEIGHT;
531
                    for(uint32 x = 0; x < 3; x++)
532
                    {
533
                        float h = lverts[ltris[x]*3 + 1];
534
                        if (minLLevel > h)
535
                            minLLevel = h;
536

537
                        if (maxLLevel < h)
538
                            maxLLevel = h;
539
                    }
540

541
                    float maxTLevel = INVALID_MAP_LIQ_HEIGHT;
542
                    float minTLevel = INVALID_MAP_LIQ_HEIGHT_MAX;
543
                    for(uint32 x = 0; x < 6; x++)
544
                    {
545
                        float h = tverts[ttris[x]*3 + 1];
546
                        if (maxTLevel < h)
547
                            maxTLevel = h;
548

549
                        if (minTLevel > h)
550
                            minTLevel = h;
551
                    }
552

553
                    // terrain under the liquid?
554
                    if (minLLevel > maxTLevel)
555
                        useTerrain = false;
556

557
                    //liquid under the terrain?
558
                    if (minTLevel > maxLLevel)
559
                        useLiquid = false;
560
                }
561

562
                // store the result
563
                if (useLiquid)
564
                {
565
                    meshData.liquidType.append(liquidType);
566
                    for (int k = 0; k < 3; ++k)
567
                        meshData.liquidTris.append(ltris[k]);
568
                }
569

570
                if (useTerrain)
571
                    for (int k = 0; k < 3*tTriCount/2; ++k)
572
                        meshData.solidTris.append(ttris[k]);
573

574
                // advance to next set of triangles
575
                ltris += 3;
576
                ttris += 3*tTriCount/2;
577
            }
578
        }
579

580
        if (lverts_copy)
581
            delete [] lverts_copy;
582

583
        // hardcoded hack? todo
584
        // if (mapID == 562 && tileX == 31 && tileY == 20)
585
        // {
586
        //     auto appendTriangle = [&](float x, float y, float z)
587
        //     {
588
        //         meshData.solidVerts.append(y);
589
        //         meshData.solidVerts.append(z);
590
        //         meshData.solidVerts.append(x);
591
        //     };
592
        //     int offset = meshData.solidVerts.size() / 3;
593
        //     appendTriangle(6243.723145f, 266.888031f, 11.087075f);
594
        //     appendTriangle(6242.431641f, 267.910858f, 11.131095f);
595
        //     appendTriangle(6245.623047f, 272.175842f, 11.213024f);
596
        //     appendTriangle(6246.949707f, 270.999542f, 11.237248f);
597
        //     meshData.solidTris.append(offset + 2);
598
        //     meshData.solidTris.append(offset + 1);
599
        //     meshData.solidTris.append(offset + 0);
600
        //     meshData.solidTris.append(offset + 3);
601
        //     meshData.solidTris.append(offset + 2);
602
        //     meshData.solidTris.append(offset + 0);
603

604
        //     offset = meshData.solidVerts.size() / 3;
605
        //     appendTriangle(6234.996582f, 255.983063f, 11.099862f);
606
        //     appendTriangle(6231.778809f, 252.019989f, 11.046977f);
607
        //     appendTriangle(6230.504395f, 253.067917f, 11.187262f);
608
        //     appendTriangle(6233.755859f, 257.066101f, 11.118346f);
609
        //     meshData.solidTris.append(offset + 2);
610
        //     meshData.solidTris.append(offset + 1);
611
        //     meshData.solidTris.append(offset + 0);
612
        //     meshData.solidTris.append(offset + 3);
613
        //     meshData.solidTris.append(offset + 2);
614
        //     meshData.solidTris.append(offset + 0);
615
        // }
616

617
        return meshData.solidTris.size() || meshData.liquidTris.size();
618
    }
619

620
    /**************************************************************************/
621
    void TerrainBuilder::getHeightCoord(int index, Grid grid, float xOffset, float yOffset, float* coord, float* v)
622
    {
623
        // wow coords: x, y, height
624
        // coord is mirroed about the horizontal axes
625
        switch (grid)
626
        {
627
        case GRID_V9:
628
            coord[0] = (xOffset + index%(V9_SIZE)*GRID_PART_SIZE) * -1.f;
629
            coord[1] = (yOffset + (int)(index/(V9_SIZE))*GRID_PART_SIZE) * -1.f;
630
            coord[2] = v[index];
631
            break;
632
        case GRID_V8:
633
            coord[0] = (xOffset + index%(V8_SIZE)*GRID_PART_SIZE + GRID_PART_SIZE/2.f) * -1.f;
634
            coord[1] = (yOffset + (int)(index/(V8_SIZE))*GRID_PART_SIZE + GRID_PART_SIZE/2.f) * -1.f;
635
            coord[2] = v[index];
636
            break;
637
        }
638
    }
639

640
    /**************************************************************************/
641
    void TerrainBuilder::getHeightTriangle(int square, Spot triangle, int* indices, bool liquid/* = false*/)
642
    {
643
        int rowOffset = square/V8_SIZE;
644
        if (!liquid)
645
            switch (triangle)
646
        {
647
            case TOP:
648
                indices[0] = square+rowOffset;                  //           0-----1 .... 128
649
                indices[1] = square+1+rowOffset;                //           |\ T /|
650
                indices[2] = (V9_SIZE_SQ)+square;               //           | \ / |
651
                break;                                          //           |L 0 R| .. 127
652
            case LEFT:                                          //           | / \ |
653
                indices[0] = square+rowOffset;                  //           |/ B \|
654
                indices[1] = (V9_SIZE_SQ)+square;               //          129---130 ... 386
655
                indices[2] = square+V9_SIZE+rowOffset;          //           |\   /|
656
                break;                                          //           | \ / |
657
            case RIGHT:                                         //           | 128 | .. 255
658
                indices[0] = square+1+rowOffset;                //           | / \ |
659
                indices[1] = square+V9_SIZE+1+rowOffset;        //           |/   \|
660
                indices[2] = (V9_SIZE_SQ)+square;               //          258---259 ... 515
661
                break;
662
            case BOTTOM:
663
                indices[0] = (V9_SIZE_SQ)+square;
664
                indices[1] = square+V9_SIZE+1+rowOffset;
665
                indices[2] = square+V9_SIZE+rowOffset;
666
                break;
667
            default: break;
668
        }
669
        else
670
            switch (triangle)
671
        {                                                           //           0-----1 .... 128
672
            case TOP:                                               //           |\    |
673
                indices[0] = square+rowOffset;                      //           | \ T |
674
                indices[1] = square+1+rowOffset;                    //           |  \  |
675
                indices[2] = square+V9_SIZE+1+rowOffset;            //           | B \ |
676
                break;                                              //           |    \|
677
            case BOTTOM:                                            //          129---130 ... 386
678
                indices[0] = square+rowOffset;                      //           |\    |
679
                indices[1] = square+V9_SIZE+1+rowOffset;            //           | \   |
680
                indices[2] = square+V9_SIZE+rowOffset;              //           |  \  |
681
                break;                                              //           |   \ |
682
            default: break;                                         //           |    \|
683
        }                                                           //          258---259 ... 515
684

685
    }
686

687
    /**************************************************************************/
688
    void TerrainBuilder::getLiquidCoord(int index, int index2, float xOffset, float yOffset, float* coord, float* v)
689
    {
690
        // wow coords: x, y, height
691
        // coord is mirroed about the horizontal axes
692
        coord[0] = (xOffset + index%(V9_SIZE)*GRID_PART_SIZE) * -1.f;
693
        coord[1] = (yOffset + (int)(index/(V9_SIZE))*GRID_PART_SIZE) * -1.f;
694
        coord[2] = v[index2];
695
    }
696

697
    static uint16 holetab_h[4] = {0x1111, 0x2222, 0x4444, 0x8888};
698
    static uint16 holetab_v[4] = {0x000F, 0x00F0, 0x0F00, 0xF000};
699

700
    /**************************************************************************/
701
    bool TerrainBuilder::isHole(int square, const uint16 holes[16][16])
702
    {
703
        int row = square / 128;
704
        int col = square % 128;
705
        int cellRow = row / 8;     // 8 squares per cell
706
        int cellCol = col / 8;
707
        int holeRow = row % 8 / 2;
708
        int holeCol = (square - (row * 128 + cellCol * 8)) / 2;
709

710
        uint16 hole = holes[cellRow][cellCol];
711

712
        return (hole & holetab_h[holeCol] & holetab_v[holeRow]) != 0;
713
    }
714

715
    /**************************************************************************/
716
    uint8 TerrainBuilder::getLiquidType(int square, const uint8 liquid_type[16][16])
717
    {
718
        int row = square / 128;
719
        int col = square % 128;
720
        int cellRow = row / 8;     // 8 squares per cell
721
        int cellCol = col / 8;
722

723
        return liquid_type[cellRow][cellCol];
724
    }
725

726
    /**************************************************************************/
727
    bool TerrainBuilder::loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData)
728
    {
729
        VMapManager2* vmapManager = new VMapManager2();
730
        int result = vmapManager->loadMap("vmaps", mapID, tileX, tileY);
731
        bool retval = false;
732

733
        do
734
        {
735
            if (result == VMAP_LOAD_RESULT_ERROR)
736
                break;
737

738
            InstanceTreeMap instanceTrees;
739
            ((VMapManager2*)vmapManager)->getInstanceMapTree(instanceTrees);
740

741
            if (!instanceTrees[mapID])
742
                break;
743

744
            ModelInstance* models = nullptr;
745
            uint32 count = 0;
746
            instanceTrees[mapID]->getModelInstances(models, count);
747

748
            if (!models)
749
                break;
750

751
            for (uint32 i = 0; i < count; ++i)
752
            {
753
                ModelInstance instance = models[i];
754

755
                // model instances exist in tree even though there are instances of that model in this tile
756
                WorldModel* worldModel = instance.getWorldModel();
757
                if (!worldModel)
758
                    continue;
759

760
                // now we have a model to add to the meshdata
761
                retval = true;
762

763
                std::vector<GroupModel> groupModels;
764
                worldModel->getGroupModels(groupModels);
765

766
                // all M2s need to have triangle indices reversed
767
                bool isM2 = instance.name.find(".m2") != std::string::npos || instance.name.find(".M2") != std::string::npos;
768

769
                // transform data
770
                float scale = instance.iScale;
771
                G3D::Matrix3 rotation = G3D::Matrix3::fromEulerAnglesXYZ(G3D::pi()*instance.iRot.z / -180.f, G3D::pi() * instance.iRot.x / -180.f, G3D::pi() * instance.iRot.y / -180.f);
772
                G3D::Vector3 position = instance.iPos;
773
                position.x -= 32 * GRID_SIZE;
774
                position.y -= 32 * GRID_SIZE;
775

776
                for (std::vector<GroupModel>::iterator it = groupModels.begin(); it != groupModels.end(); ++it)
777
                {
778
                    std::vector<G3D::Vector3> tempVertices;
779
                    std::vector<G3D::Vector3> transformedVertices;
780
                    std::vector<MeshTriangle> tempTriangles;
781
                    WmoLiquid* liquid = nullptr;
782

783
                    it->getMeshData(tempVertices, tempTriangles, liquid);
784

785
                    // first handle collision mesh
786
                    transform(tempVertices, transformedVertices, scale, rotation, position);
787

788
                    int offset = meshData.solidVerts.size() / 3;
789

790
                    copyVertices(transformedVertices, meshData.solidVerts);
791
                    copyIndices(tempTriangles, meshData.solidTris, offset, isM2);
792

793
                    // now handle liquid data
794
                    if (liquid && liquid->GetFlagsStorage())
795
                    {
796
                        std::vector<G3D::Vector3> liqVerts;
797
                        std::vector<int> liqTris;
798
                        uint32 tilesX, tilesY, vertsX, vertsY;
799
                        G3D::Vector3 corner;
800
                        liquid->getPosInfo(tilesX, tilesY, corner);
801
                        vertsX = tilesX + 1;
802
                        vertsY = tilesY + 1;
803
                        uint8* flags = liquid->GetFlagsStorage();
804
                        float* data = liquid->GetHeightStorage();
805
                        uint8 type = NAV_AREA_EMPTY;
806

807
                        // convert liquid type to NavTerrain
808
                        uint32 liquidFlags = GetLiquidFlags(liquid->GetType());
809
                        if ((liquidFlags & (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN)) != 0)
810
                            type = NAV_AREA_WATER;
811
                        else if ((liquidFlags & (MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME)) != 0)
812
                            type = NAV_AREA_MAGMA_SLIME;
813

814
                        // indexing is weird...
815
                        // after a lot of trial and error, this is what works:
816
                        // vertex = y*vertsX+x
817
                        // tile   = x*tilesY+y
818
                        // flag   = y*tilesY+x
819

820
                        G3D::Vector3 vert;
821
                        for (uint32 x = 0; x < vertsX; ++x)
822
                        {
823
                            for (uint32 y = 0; y < vertsY; ++y)
824
                            {
825
                                vert = G3D::Vector3(corner.x + x * GRID_PART_SIZE, corner.y + y * GRID_PART_SIZE, data[y*vertsX + x]);
826
                                vert = vert * rotation * scale + position;
827
                                vert.x *= -1.f;
828
                                vert.y *= -1.f;
829
                                liqVerts.push_back(vert);
830
                            }
831
                        }
832

833
                        int idx1, idx2, idx3, idx4;
834
                        uint32 square;
835
                        for (uint32 x = 0; x < tilesX; ++x)
836
                        {
837
                            for (uint32 y = 0; y < tilesY; ++y)
838
                            {
839
                                if ((flags[x + y*tilesX] & 0x0f) != 0x0f)
840
                                {
841
                                    square = x * tilesY + y;
842
                                    idx1 = square + x;
843
                                    idx2 = square + 1 + x;
844
                                    idx3 = square + tilesY + 1 + 1 + x;
845
                                    idx4 = square + tilesY + 1 + x;
846

847
                                    // top triangle
848
                                    liqTris.push_back(idx3);
849
                                    liqTris.push_back(idx2);
850
                                    liqTris.push_back(idx1);
851
                                    // bottom triangle
852
                                    liqTris.push_back(idx4);
853
                                    liqTris.push_back(idx3);
854
                                    liqTris.push_back(idx1);
855
                                }
856
                            }
857
                        }
858

859
                        uint32 liqOffset = meshData.liquidVerts.size() / 3;
860
                        for (uint32 j = 0; j < liqVerts.size(); ++j)
861
                            meshData.liquidVerts.append(liqVerts[j].y, liqVerts[j].z, liqVerts[j].x);
862

863
                        for (uint32 j = 0; j < liqTris.size() / 3; ++j)
864
                        {
865
                            meshData.liquidTris.append(liqTris[j * 3 + 1] + liqOffset, liqTris[j * 3 + 2] + liqOffset, liqTris[j * 3] + liqOffset);
866
                            meshData.liquidType.append(type);
867
                        }
868
                    }
869
                }
870
            }
871
        }
872
        while (false);
873

874
        vmapManager->unloadMap(mapID, tileX, tileY);
875
        delete vmapManager;
876

877
        return retval;
878
    }
879

880
    /**************************************************************************/
881
    void TerrainBuilder::transform(std::vector<G3D::Vector3> &source, std::vector<G3D::Vector3> &transformedVertices, float scale, G3D::Matrix3 &rotation, G3D::Vector3 &position)
882
    {
883
        for (std::vector<G3D::Vector3>::iterator it = source.begin(); it != source.end(); ++it)
884
        {
885
            // apply tranform, then mirror along the horizontal axes
886
            G3D::Vector3 v((*it) * rotation * scale + position);
887
            v.x *= -1.f;
888
            v.y *= -1.f;
889
            transformedVertices.push_back(v);
890
        }
891
    }
892

893
    /**************************************************************************/
894
    void TerrainBuilder::copyVertices(std::vector<G3D::Vector3> &source, G3D::Array<float> &dest)
895
    {
896
        for (std::vector<G3D::Vector3>::iterator it = source.begin(); it != source.end(); ++it)
897
        {
898
            dest.push_back((*it).y);
899
            dest.push_back((*it).z);
900
            dest.push_back((*it).x);
901
        }
902
    }
903

904
    /**************************************************************************/
905
    void TerrainBuilder::copyIndices(std::vector<MeshTriangle> &source, G3D::Array<int> &dest, int offset, bool flip)
906
    {
907
        if (flip)
908
        {
909
            for (std::vector<MeshTriangle>::iterator it = source.begin(); it != source.end(); ++it)
910
            {
911
                dest.push_back((*it).idx2+offset);
912
                dest.push_back((*it).idx1+offset);
913
                dest.push_back((*it).idx0+offset);
914
            }
915
        }
916
        else
917
        {
918
            for (std::vector<MeshTriangle>::iterator it = source.begin(); it != source.end(); ++it)
919
            {
920
                dest.push_back((*it).idx0+offset);
921
                dest.push_back((*it).idx1+offset);
922
                dest.push_back((*it).idx2+offset);
923
            }
924
        }
925
    }
926

927
    /**************************************************************************/
928
    void TerrainBuilder::copyIndices(G3D::Array<int> &source, G3D::Array<int> &dest, int offset)
929
    {
930
        int* src = source.getCArray();
931
        for (int32 i = 0; i < source.size(); ++i)
932
            dest.append(src[i] + offset);
933
    }
934

935
    /**************************************************************************/
936
    void TerrainBuilder::cleanVertices(G3D::Array<float> &verts, G3D::Array<int> &tris)
937
    {
938
        std::map<int, int> vertMap;
939

940
        int* t = tris.getCArray();
941
        float* v = verts.getCArray();
942

943
        G3D::Array<float> cleanVerts;
944
        int index, count = 0;
945
        // collect all the vertex indices from triangle
946
        for (int i = 0; i < tris.size(); ++i)
947
        {
948
            if (vertMap.find(t[i]) != vertMap.end())
949
                continue;
950
            std::pair<int, int> val;
951
            val.first = t[i];
952

953
            index = val.first;
954
            val.second = count;
955

956
            vertMap.insert(val);
957
            cleanVerts.append(v[index * 3], v[index * 3 + 1], v[index * 3 + 2]);
958
            count++;
959
        }
960

961
        verts.fastClear();
962
        verts.append(cleanVerts);
963
        cleanVerts.clear();
964

965
        // update triangles to use new indices
966
        for (int i = 0; i < tris.size(); ++i)
967
        {
968
            std::map<int, int>::iterator it;
969
            if ((it = vertMap.find(t[i])) == vertMap.end())
970
                continue;
971

972
            t[i] = (*it).second;
973
        }
974

975
        vertMap.clear();
976
    }
977

978
    /**************************************************************************/
979
    void TerrainBuilder::loadOffMeshConnections(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, const char* offMeshFilePath)
980
    {
981
        // no meshfile input given?
982
        if (offMeshFilePath == nullptr)
983
            return;
984

985
        FILE* fp = fopen(offMeshFilePath, "rb");
986
        if (!fp)
987
        {
988
            printf(" loadOffMeshConnections:: input file %s not found!\n", offMeshFilePath);
989
            return;
990
        }
991

992
        // pretty silly thing, as we parse entire file and load only the tile we need
993
        // but we don't expect this file to be too large
994
        char* buf = new char[512];
995
        while(fgets(buf, 512, fp))
996
        {
997
            float p0[3], p1[3];
998
            uint32 mid, tx, ty;
999
            float size;
1000
            if (sscanf(buf, "%u %u,%u (%f %f %f) (%f %f %f) %f", &mid, &tx, &ty,
1001
                &p0[0], &p0[1], &p0[2], &p1[0], &p1[1], &p1[2], &size) != 10)
1002
                continue;
1003

1004
            if (mapID == mid && tileX == tx && tileY == ty)
1005
            {
1006
                meshData.offMeshConnections.append(p0[1]);
1007
                meshData.offMeshConnections.append(p0[2]);
1008
                meshData.offMeshConnections.append(p0[0]);
1009

1010
                meshData.offMeshConnections.append(p1[1]);
1011
                meshData.offMeshConnections.append(p1[2]);
1012
                meshData.offMeshConnections.append(p1[0]);
1013

1014
                meshData.offMeshConnectionDirs.append(1);          // 1 - both direction, 0 - one sided
1015
                meshData.offMeshConnectionRads.append(size);       // agent size equivalent
1016
                // can be used same way as polygon flags
1017
                meshData.offMeshConnectionsAreas.append((unsigned char)0xFF);
1018
                meshData.offMeshConnectionsFlags.append((unsigned short)0xFF);  // all movement masks can make this path
1019
            }
1020

1021
        }
1022

1023
        delete [] buf;
1024
        fclose(fp);
1025
    }
1026
}
1027

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.