void MapChunk::initStrip() { strip = new StripType[768]; //! \todo figure out exact length of strip needed StripType* s = strip; for (int x = 0; x<8; ++x) { for (int y = 0; y<8; ++y) { if (isHole(x / 2, y / 2)) continue; *s++ = indexLoD(y, x); //9 *s++ = indexNoLoD(y, x); //0 *s++ = indexNoLoD(y + 1, x); //17 *s++ = indexLoD(y, x); //9 *s++ = indexNoLoD(y + 1, x); //17 *s++ = indexNoLoD(y + 1, x + 1); //18 *s++ = indexLoD(y, x); //9 *s++ = indexNoLoD(y + 1, x + 1); //18 *s++ = indexNoLoD(y, x + 1); //1 *s++ = indexLoD(y, x); //9 *s++ = indexNoLoD(y, x + 1); //1 *s++ = indexNoLoD(y, x); //0 } } striplen = static_cast<int>(s - strip); }
float GridMap::getHeightFromFloat(float x, float y) const { if (!m_V8 || !m_V9) return INVALID_HEIGHT_VALUE; x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); int x_int = (int)x; int y_int = (int)y; x -= x_int; y -= y_int; x_int &= (MAP_RESOLUTION - 1); y_int &= (MAP_RESOLUTION - 1); if (isHole(x_int, y_int)) return INVALID_HEIGHT_VALUE; // Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid // +--------------> X // | h1-------h2 Coordinates is: // | | \ 1 / | h1 0,0 // | | \ / | h2 0,1 // | | 2 h5 3 | h3 1,0 // | | / \ | h4 1,1 // | | / 4 \ | h5 1/2,1/2 // | h3-------h4 // V Y // For find height need // 1 - detect triangle // 2 - solve linear equation from triangle points // Calculate coefficients for solve h = a*x + b*y + c float a,b,c; // Select triangle: if (x+y < 1) { if (x > y) { // 1 triangle (h1, h2, h5 points) float h1 = m_V9[(x_int )*129 + y_int]; float h2 = m_V9[(x_int+1)*129 + y_int]; float h5 = 2 * m_V8[x_int*128 + y_int]; a = h2-h1; b = h5-h1-h2; c = h1; } else { // 2 triangle (h1, h3, h5 points) float h1 = m_V9[x_int*129 + y_int ]; float h3 = m_V9[x_int*129 + y_int+1]; float h5 = 2 * m_V8[x_int*128 + y_int]; a = h5 - h1 - h3; b = h3 - h1; c = h1; } } else { if (x > y) { // 3 triangle (h2, h4, h5 points) float h2 = m_V9[(x_int+1)*129 + y_int ]; float h4 = m_V9[(x_int+1)*129 + y_int+1]; float h5 = 2 * m_V8[x_int*128 + y_int]; a = h2 + h4 - h5; b = h4 - h2; c = h5 - h4; } else { // 4 triangle (h3, h4, h5 points) float h3 = m_V9[(x_int )*129 + y_int+1]; float h4 = m_V9[(x_int+1)*129 + y_int+1]; float h5 = 2 * m_V8[x_int*128 + y_int]; a = h4 - h3; b = h3 + h4 - h5; c = h5 - h4; } } // Calculate height return a * x + b * y + c; }
inline void LoadMapChunk(MPQFile & mf, chunk*_chunk) { float h; uint32 fourcc; uint32 size; MapChunkHeader header; mf.seekRelative(4); mf.read(&size, 4); size_t lastpos = mf.getPos() + size; mf.read(&header, 0x80); _chunk->area_id =header.areaid ; _chunk->flag =0; float xbase = header.xpos; float ybase = header.ypos; float zbase = header.zpos; zbase = TILESIZE*32-zbase; xbase = TILESIZE*32-xbase; if(wmoc.x >xbase)wmoc.x =xbase; if(wmoc.z >zbase)wmoc.z =zbase; int chunkflags = header.flags; float zmin=999999999.0f; float zmax=-999999999.0f; //must be there, bl!zz uses some crazy format int nTextures; while (mf.getPos() < lastpos) { mf.read(&fourcc,4); mf.read(&size, 4); //if(size!=580) // printf("\n sz=%d",size); size_t nextpos = mf.getPos() + size; if(fourcc==0x4d435654) // MCVT { for (int j=0; j<17; j++) for (int i=0; i<((j%2)?8:9); i++) { mf.read(&h,4); float z=h+ybase; if (j%2) { if(isHole(header.holes,i,j)) _chunk->v8[i][j/2] = -1000; else _chunk->v8[i][j/2] = z; } else { if(isHole(header.holes,i,j)) _chunk->v9[i][j/2] = -1000; else _chunk->v9[i][j/2] = z; } if(z>zmax)zmax=z; //if(z<zmin)zmin=z; } } else if(fourcc==0x4d434e52) // MCNR { nextpos = mf.getPos() + 0x1C0; // size fix } else if(fourcc==0x4d434c51) // MCLQ { // liquid / water level //bool haswater; char fcc1[5]; mf.read(fcc1,4); flipcc(fcc1); fcc1[4]=0; if (!strcmp(fcc1,"MCSE")) { for(int i=0;i<9;i++) for(int j=0;j<9;j++) _chunk->waterlevel[i][j]=-999999; // no liquid/water } else { float maxheight; mf.read(&maxheight, 4); for(int j=0;j<9;j++) for(int i=0;i<9;i++) { mf.read(&h, 4); mf.read(&h, 4); if(h > maxheight) _chunk->waterlevel[i][j]=-999999; else _chunk->waterlevel[i][j]=h; } if(chunkflags & 4 || chunkflags & 8) _chunk->flag |=1; if(chunkflags & 16) _chunk->flag |=2; } break; } else if (fourcc==0x4d434c59) // MCLY { // texture info nTextures = (int)size; } else if (fourcc==0x4d43414c) // MCAL { if (nTextures<=0) continue; } mf.seek(nextpos); } }
bool TileBuilder::loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, Spot portion) { char mapFileName[255]; sprintf(mapFileName, "maps/%03u%02u%02u.map", mapID, tileY, tileX); FILE* mapFile = fopen(mapFileName, "rb"); if(!mapFile) return true; GridMapFileHeader fheader; fread(&fheader, sizeof(GridMapFileHeader), 1, mapFile); if(fheader.versionMagic != *((uint32 const*)(MAP_VERSION_MAGIC))) { fclose(mapFile); printf("%s is the wrong version, please extract new .map files\n", mapFileName); return false; } GridMapHeightHeader hheader; fseek(mapFile, fheader.heightMapOffset, SEEK_SET); fread(&hheader, sizeof(GridMapHeightHeader), 1, mapFile); bool haveTerrain = !(hheader.flags & MAP_HEIGHT_NO_HEIGHT); bool haveLiquid = fheader.liquidMapOffset && !m_skipLiquid; // no data in this map file if(!haveTerrain && !haveLiquid) { fclose(mapFile); return true; } // data used later uint16 holes[16][16]; uint8* liquid_type = 0; G3D::Array<int> ltriangles; G3D::Array<int> ttriangles; // terrain data if(haveTerrain) { int i; float heightMultiplier; float V9[V9_SIZE_SQ], V8[V8_SIZE_SQ]; if(hheader.flags & MAP_HEIGHT_AS_INT8) { uint8 v9[V9_SIZE_SQ]; uint8 v8[V8_SIZE_SQ]; fread(v9, sizeof(uint8), V9_SIZE_SQ, mapFile); fread(v8, sizeof(uint8), V8_SIZE_SQ, mapFile); heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 255; for(i = 0; i < V9_SIZE_SQ; ++i) V9[i] = (float)v9[i]*heightMultiplier + hheader.gridHeight; if(m_hiResHeightMaps) for(i = 0; i < V8_SIZE_SQ; ++i) V8[i] = (float)v8[i]*heightMultiplier + hheader.gridHeight; } else if(hheader.flags & MAP_HEIGHT_AS_INT16) { uint16 v9[V9_SIZE_SQ]; uint16 v8[V8_SIZE_SQ]; fread(v9, sizeof(uint16), V9_SIZE_SQ, mapFile); fread(v8, sizeof(uint16), V8_SIZE_SQ, mapFile); heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 65535; for(i = 0; i < V9_SIZE_SQ; ++i) V9[i] = (float)v9[i]*heightMultiplier + hheader.gridHeight; if(m_hiResHeightMaps) for(i = 0; i < V8_SIZE_SQ; ++i) V8[i] = (float)v8[i]*heightMultiplier + hheader.gridHeight; } else { fread(V9, sizeof(float), V9_SIZE_SQ, mapFile); if(m_hiResHeightMaps) fread(V8, sizeof(float), V8_SIZE_SQ, mapFile); } // hole data memset(holes, 0, fheader.holesSize); fseek(mapFile, fheader.holesOffset, SEEK_SET); fread(holes, fheader.holesSize, 1, mapFile); int count = meshData.solidVerts.size() / 3; float xoffset = (float(tileX)-32)*GRID_SIZE; float yoffset = (float(tileY)-32)*GRID_SIZE; float coord[3]; for(i = 0; i < V9_SIZE_SQ; ++i) { getHeightCoord(i, GRID_V9, xoffset, yoffset, coord, V9); meshData.solidVerts.append(coord[0]); meshData.solidVerts.append(coord[2]); meshData.solidVerts.append(coord[1]); } if(m_hiResHeightMaps) for(i = 0; i < V8_SIZE_SQ; ++i) { getHeightCoord(i, GRID_V8, xoffset, yoffset, coord, V8); meshData.solidVerts.append(coord[0]); meshData.solidVerts.append(coord[2]); meshData.solidVerts.append(coord[1]); } int triInc, j, indices[3], loopStart, loopEnd, loopInc; getLoopVars(portion, loopStart, loopEnd, loopInc); triInc = m_hiResHeightMaps ? 1 : BOTTOM-TOP; for(i = loopStart; i < loopEnd; i+=loopInc) for(j = TOP; j <= BOTTOM; j+=triInc) { getHeightTriangle(i, Spot(j), indices); ttriangles.append(indices[2] + count); ttriangles.append(indices[1] + count); ttriangles.append(indices[0] + count); } } // liquid data if(haveLiquid) { do { GridMapLiquidHeader lheader; fseek(mapFile, fheader.liquidMapOffset, SEEK_SET); fread(&lheader, sizeof(GridMapLiquidHeader), 1, mapFile); float* liquid_map = 0; if (!(lheader.flags & MAP_LIQUID_NO_TYPE)) { liquid_type = new uint8 [16*16]; fread(liquid_type, sizeof(uint8), 16*16, mapFile); } if (!(lheader.flags & MAP_LIQUID_NO_HEIGHT)) { liquid_map = new float [lheader.width*lheader.height]; fread(liquid_map, sizeof(float), lheader.width*lheader.height, mapFile); } if(!liquid_type && !liquid_map) break; int count = meshData.liquidVerts.size() / 3; float xoffset = (float(tileX)-32)*GRID_SIZE; float yoffset = (float(tileY)-32)*GRID_SIZE; float coord[3]; int row, col; // generate coordinates if (!(lheader.flags & MAP_LIQUID_NO_HEIGHT)) { int j = 0; for(int i = 0; i < V9_SIZE_SQ; ++i) { row = i / V9_SIZE; col = i % V9_SIZE; if((row < (lheader.offsetY) || row >= (lheader.offsetY + lheader.height)) || (col < (lheader.offsetX) || col >= (lheader.offsetX + lheader.width))) { // dummy vert using invalid height meshData.liquidVerts.append((xoffset+col*GRID_PART_SIZE)*-1, -500.f, (yoffset+row*GRID_PART_SIZE)*-1); continue; } getLiquidCoord(i, j, xoffset, yoffset, coord, liquid_map); meshData.liquidVerts.append(coord[0]); meshData.liquidVerts.append(coord[2]); meshData.liquidVerts.append(coord[1]); j++; } } else { for(int i = 0; i < V9_SIZE_SQ; ++i) { row = i / V9_SIZE; col = i % V9_SIZE; meshData.liquidVerts.append((xoffset+col*GRID_PART_SIZE)*-1, lheader.liquidLevel, (yoffset+row*GRID_PART_SIZE)*-1); } } delete [] liquid_map; int indices[3], loopStart, loopEnd, loopInc, triInc; getLoopVars(portion, loopStart, loopEnd, loopInc); triInc = BOTTOM-TOP; // generate triangles for(int i = loopStart; i < loopEnd; i+=loopInc) for(int j = TOP; j <= BOTTOM; j+= triInc) { getHeightTriangle(i, Spot(j), indices, true); ltriangles.append(indices[2] + count); ltriangles.append(indices[1] + count); ltriangles.append(indices[0] + count); } }while(0); } fclose(mapFile); // now that we have gathered the data, we can figure out which parts to keep: // liquid above ground // ground above any liquid type // ground below <1.5 yard of water int loopStart, loopEnd, loopInc, tTriCount; bool useTerrain, useLiquid; float* lverts = meshData.liquidVerts.getCArray(); float* tverts = meshData.solidVerts.getCArray(); int* ltris = ltriangles.getCArray(); int* ttris = ttriangles.getCArray(); getLoopVars(portion, loopStart, loopEnd, loopInc); tTriCount = m_hiResHeightMaps ? 4 : 2; if(ltriangles.size() || ttriangles.size()) { for(int i = loopStart; i < loopEnd; i+=loopInc) { for(int j = 0; j < 2; ++j) { // default is true, will change to false if needed useTerrain = true; useLiquid = true; uint8 liquidType; // if there is no liquid, don't use liquid if(!liquid_type || !meshData.liquidVerts.size() || !ltriangles.size()) useLiquid = false; else { liquidType = getLiquidType(i, (const uint8 (*)[16])liquid_type); switch(liquidType) { case 0: // unknown liquid gets no terrain type liquidType = 0; break; case MAP_LIQUID_TYPE_WATER: case MAP_LIQUID_TYPE_OCEAN: // merge different types of water liquidType = NAV_WATER; break; case MAP_LIQUID_TYPE_MAGMA: liquidType = NAV_MAGMA; break; case MAP_LIQUID_TYPE_SLIME: liquidType = NAV_SLIME; break; case MAP_LIQUID_TYPE_DARK_WATER: // players should not be here, so logically neither should creatures useTerrain = false; useLiquid = false; break; } } // if there is no terrain, don't use terrain if(!ttriangles.size()) useTerrain = false; // liquid is rendered as quads. If any triangle has invalid height, // don't render any of the triangles in that quad // contrib/extractor uses -500.0 for invalid height if(useLiquid) if((&lverts[ltris[0]*3])[1] == -500.f || (&lverts[ltris[1]*3])[1] == -500.f || (&lverts[ltris[2]*3])[1] == -500.f) { useLiquid = false; } // if there is a hole here, don't use the terrain if(useTerrain) useTerrain = !isHole(i, holes); if(useTerrain && useLiquid) { // get the indexes of the corners of the quad int idx1, idx2, idx3; if(j == 0) { idx1 = 0; idx2 = 1; idx3 = tTriCount; // accesses index from next triangle on low res } else { idx1 = 0; idx2 = 3*tTriCount/2-2; idx3 = 3*tTriCount/2-1; } if(useTerrain && (&lverts[ltris[0]*3])[1] - 1.5f > (&tverts[ttris[idx1]*3])[1] && (&lverts[ltris[1]*3])[1] - 1.5f > (&tverts[ttris[idx2]*3])[1] && (&lverts[ltris[2]*3])[1] - 1.5f > (&tverts[ttris[idx3]*3])[1]) useTerrain = false; // if the whole terrain triangle is 1.5yds under liquid, don't use it else if(useLiquid && (&lverts[ltris[0]*3])[1] < (&tverts[ttris[idx1]*3])[1] && (&lverts[ltris[1]*3])[1] < (&tverts[ttris[idx2]*3])[1] && (&lverts[ltris[2]*3])[1] < (&tverts[ttris[idx3]*3])[1]) useLiquid = false; // if the whole liquid triangle is under terrain, don't use it } if(useLiquid) { meshData.liquidType.append(liquidType); for(int k = 0; k < 3; ++k) meshData.liquidTris.append(ltris[k]); } if(useTerrain) for(int k = 0; k < 3*tTriCount/2; ++k) meshData.solidTris.append(ttris[k]); // advance to next set of triangles ltris += 3; ttris += 3*tTriCount/2; } } } delete [] liquid_type; return true; }
inline void LoadMapChunk(MPQFile &mf, chunk *_chunk) { float h; uint32 fourcc; uint32 size; MapChunkHeader header; mf.seekRelative(4); mf.read(&size, 4); size_t lastpos = mf.getPos() + size; mf.read(&header, 0x80); // what if header size got changed? _chunk->area_id = header.areaid; float xbase = header.xpos; float ybase = header.ypos; float zbase = header.zpos; zbase = TILESIZE * 32 - zbase; xbase = TILESIZE * 32 - xbase; if(wmoc.x > xbase) wmoc.x = xbase; if(wmoc.z > zbase) wmoc.z = zbase; int chunkflags = header.flags; //printf("LMC: flags %X\n", chunkflags); float zmin = 999999999.0f; float zmax = -999999999.0f; // must be there, bl!zz uses some crazy format while (mf.getPos() < lastpos) { mf.read(&fourcc, 4); mf.read(&size, 4); size_t nextpos = mf.getPos() + size; if(fourcc == 0x4d435654) // MCVT { for (int j = 0; j < 17; ++j) { for (int i = 0; i < ((j % 2) ? 8 : 9); ++i) { mf.read(&h, 4); float z = h + ybase; if (j % 2) { if(isHole(header.holes, i, j)) _chunk->v8[i][j / 2] = -1000; else _chunk->v8[i][j / 2] = z; } else { if(isHole(header.holes, i, j)) _chunk->v9[i][j / 2] = -1000; else _chunk->v9[i][j / 2] = z; } if(z > zmax) zmax = z; //if(z < zmin) zmin = z; } } } else if(fourcc == 0x4d434e52) // MCNR { nextpos = mf.getPos() + 0x1C0; // size fix } else if(fourcc == 0x4d434c51) // MCLQ { // liquid / water level char fcc1[5]; mf.read(fcc1, 4); flipcc(fcc1); fcc1[4] = 0; float *ChunkLiqHeight = new float[81]; if (!strcmp(fcc1, "MCSE")) { for(int j = 0; j < 81; ++j) { ChunkLiqHeight[j] = -999999; // no liquid/water } } else { float maxheight; mf.read(&maxheight, 4); for(int j = 0; j < 81; ++j) { LiqData liq; mf.read(&liq, 8); if(liq.height > maxheight) ChunkLiqHeight[j] = -999999; else ChunkLiqHeight[j] = h; } if(chunkflags & 4 || chunkflags & 8) MapLiqFlag[chunk_num] |= 1; // water if(chunkflags & 16) MapLiqFlag[chunk_num] |= 2; // magma/slime } if(!(chunk_num % 16)) m = 1024 * (chunk_num / 16); k = m + (chunk_num % 16) * 8; for(int p = 0; p < 72; p += 9) { for(int s = 0; s < 8; ++s) { MapLiqHeight[k] = ChunkLiqHeight[p + s]; ++k; } k = k + 120; } delete []ChunkLiqHeight; break; } mf.seek(nextpos); } }