예제 #1
0
    void MapBuilder::buildTile(int mapID, int tileX, int tileY, dtNavMesh* navMesh)
    {
        MeshData meshData;

        // get heightmap data
        m_terrainBuilder->loadMap(mapID, tileX, tileY, meshData, m_magic);

        // get model data
        m_terrainBuilder->loadVMap(mapID, tileY, tileX, meshData);

        // if there is no data, give up now
        if (!meshData.solidVerts.size() && !meshData.liquidVerts.size())
            { return; }

        // remove unused vertices
        TerrainBuilder::cleanVertices(meshData.solidVerts, meshData.solidTris);
        TerrainBuilder::cleanVertices(meshData.liquidVerts, meshData.liquidTris);

        // gather all mesh data for final data check, and bounds calculation
        G3D::Array<float> allVerts;
        allVerts.append(meshData.liquidVerts);
        allVerts.append(meshData.solidVerts);

        if (!allVerts.size())
            { return; }

        // get bounds of current tile
        float bmin[3], bmax[3];
        getTileBounds(tileX, tileY, allVerts.getCArray(), allVerts.size() / 3, bmin, bmax);

        m_terrainBuilder->loadOffMeshConnections(mapID, tileX, tileY, meshData, m_offMeshFilePath);

        printf(" Building map %03u - Tile [%02u,%02u]\n", mapID, tileX, tileY);
        buildMoveMapTile(mapID, tileX, tileY, meshData, bmin, bmax, navMesh);
    }
예제 #2
0
    void IntermediateValues::generateRealObj(uint32 mapID, uint32 tileX, uint32 tileY, MeshData meshData)
    {
        char objFileName[255];
        sprintf(objFileName, "meshes/map%03u.obj", mapID);

        FILE* objFile = fopen(objFileName, "wb");
        if (!objFile)
        {
            char message[1024];
            sprintf(message, "Failed to open %s for writing!\n", objFileName);
            perror(message);
            return;
        }

        G3D::Array<float> allVerts;
        G3D::Array<int> allTris;

        allTris.append(meshData.liquidTris);
        allVerts.append(meshData.liquidVerts);
        TerrainBuilder::copyIndices(allTris, meshData.solidTris, allVerts.size() / 3);
        allVerts.append(meshData.solidVerts);

        float* verts = allVerts.getCArray();
        int* tris = allTris.getCArray();

        for (int i = 0; i < allVerts.size() / 3; i++)
            fprintf(objFile, "v %f %f %f\n", verts[i*3], verts[i*3 + 1], verts[i*3 + 2]);

        for (int i = 0; i < allTris.size() / 3; i++)
            fprintf(objFile, "f %i %i %i\n", tris[i*3] + 1, tris[i*3 + 1] + 1, tris[i*3 + 2] + 1);

        fclose(objFile);
    }
예제 #3
0
    void IntermediateValues::generateObjFile(uint32 mapID, uint32 tileX, uint32 tileY, MeshData meshData)
    {
        generateRealObj(mapID, tileX, tileY, meshData);

        char tileString[25];
        sprintf(tileString, "[%02u,%02u]: ", tileY, tileX);
        printf("%sWriting debug output...                       \r", tileString);

        char objFileName[255];
        sprintf(objFileName, "meshes/%03u.map", mapID);

        FILE* objFile = fopen(objFileName, "wb");
        if (!objFile)
        {
            char message[1024];
            sprintf(message, "Failed to open %s for writing!\n", objFileName);
            perror(message);
            return;
        }

        char b = '\0';
        fwrite(&b, sizeof(char), 1, objFile);
        fclose(objFile);

        sprintf(objFileName, "meshes/%03u%02u%02u.mesh", mapID, tileY, tileX);
        objFile = fopen(objFileName, "wb");
        if (!objFile)
        {
            char message[1024];
            sprintf(message, "Failed to open %s for writing!\n", objFileName);
            perror(message);
            return;
        }

        G3D::Array<float> allVerts;
        G3D::Array<int> allTris;

        allTris.append(meshData.liquidTris);
        allVerts.append(meshData.liquidVerts);
        TerrainBuilder::copyIndices(allTris, meshData.solidTris, allVerts.size() / 3);
        allVerts.append(meshData.solidVerts);

        float* verts = allVerts.getCArray();
        int vertCount = allVerts.size() / 3;
        int* tris = allTris.getCArray();
        int triCount = allTris.size() / 3;

        fwrite(&vertCount, sizeof(int), 1, objFile);
        fwrite(verts, sizeof(float), vertCount*3, objFile);
        fflush(objFile);

        fwrite(&triCount, sizeof(int), 1, objFile);
        fwrite(tris, sizeof(int), triCount*3, objFile);
        fflush(objFile);

        fclose(objFile);
    }
예제 #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;
    }