Beispiel #1
0
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);
}
Beispiel #2
0
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;
}
Beispiel #3
0
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);
    }
}
Beispiel #4
0
    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;
    }
Beispiel #5
0
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);
    }
}