Ejemplo n.º 1
0
void MeshAlg::computeBounds(
    const Array<Vector3>&   vertexArray,
    AABox&                  box,
    Sphere&                 sphere) {

    Vector3 xmin, xmax, ymin, ymax, zmin, zmax;

    // FIRST PASS: find 6 minima/maxima points
    xmin.x = ymin.y = zmin.z = finf();
    xmax.x = ymax.y = zmax.z = -finf();

    for (int v = 0; v < vertexArray.size(); ++v) {
        const Vector3& vertex = vertexArray[v];

        if (vertex.x < xmin.x) {
    		xmin = vertex;
        }

        if (vertex.x > xmax.x) {
    		xmax = vertex;
        }

        if (vertex.y < ymin.y) {
    		ymin = vertex;
        }

        if (vertex.y > ymax.y) {
		    ymax = vertex;
        }

        if (vertex.z < zmin.z) {
		    zmin = vertex;
        }

        if (vertex.z > zmax.z) {
		    zmax = vertex;
        }
	}

    // Set points dia1 & dia2 to the maximally separated pair
    Vector3 dia1 = xmin;
    Vector3 dia2 = xmax;
    {
        // Set xspan = distance between the 2 points xmin & xmax (squared)
        double xspan = (xmax - xmin).squaredMagnitude();

        // Same for y & z spans
        double yspan = (ymax - ymin).squaredMagnitude();
        double zspan = (zmax - zmin).squaredMagnitude();

        double maxspan = xspan;

        if (yspan > maxspan) {
	        maxspan = yspan;
	        dia1    = ymin;
            dia2    = ymax;
	    }

        if (zspan > maxspan) {
            maxspan = zspan;
    	    dia1    = zmin;
            dia2    = zmax;
	    }
    }


    // dia1, dia2 is a diameter of initial sphere

    // calc initial center
    Vector3 center = (dia1 + dia2) / 2.0;

    // calculate initial radius^2 and radius
    Vector3 d = dia2 - sphere.center;

    double radSq = d.squaredMagnitude();
    double rad  = sqrt(radSq);

    // SECOND PASS: increment current sphere
    double old_to_p, old_to_new;

    for (int v = 0; v < vertexArray.size(); ++v) {
        const Vector3& vertex = vertexArray[v];

        d = vertex - center;

        double old_to_p_sq = d.squaredMagnitude();

    	// do r^2 test first
        if (old_to_p_sq > radSq) {
		 	// this point is outside of current sphere
    		old_to_p = sqrt(old_to_p_sq);

    		// calc radius of new sphere
		    rad = (rad + old_to_p) / 2.0;

            // for next r^2 compare
		    radSq = rad * rad; 	
		    old_to_new = old_to_p - rad;

		    // calc center of new sphere
            center = (rad * center + old_to_new * vertex) / old_to_p;
		}	
	}

	const Vector3 min(xmin.x, ymin.y, zmin.z);
	const Vector3 max(xmax.x, ymax.y, zmax.z);

        box = AABox(min, max);

	const float boxRadSq = (max - min).squaredMagnitude() * 0.25f;

	if (boxRadSq >= radSq){
            if (isNaN(center.x) || ! isFinite(rad)) {
                sphere = Sphere(Vector3::zero(), finf());
            } else {
                sphere = Sphere(center, rad);
            }
	} else {
            sphere = Sphere((max + min) * 0.5f, sqrt(boxRadSq));
	}
}
Ejemplo n.º 2
0
void VisibleEntity::onPose(Array<shared_ptr<Surface> >& surfaceArray) {

    // We have to pose in order to compute bounds that are used for selection in the editor
    // and collisions in simulation, so pose anyway if not visible,
    // but then roll back.
    debugAssert(isFinite(m_frame.translation.x));
    debugAssert(! isNaN(m_frame.rotation[0][0]));
    const int oldLen = surfaceArray.size();

    const bool boundsChangedSincePreviousFrame = poseModel(surfaceArray);

    // Compute bounds for objects that moved
    if (m_lastAABoxBounds.isEmpty() || boundsChangedSincePreviousFrame || (m_lastChangeTime > m_lastBoundsTime)) {

        m_lastSphereBounds = Sphere(m_frame.translation, 0);
        
        const CFrame& myFrameInverse = frame().inverse();

        m_lastObjectSpaceAABoxBounds = AABox::empty();
        m_lastBoxBoundArray.fastClear();

        // Look at all surfaces produced
        for (int i = oldLen; i < surfaceArray.size(); ++i) {
            AABox b;
            Sphere s;
            const shared_ptr<Surface>& surf = surfaceArray[i];

            // body to world transformation for the surface
            CoordinateFrame cframe;
            surf->getCoordinateFrame(cframe, false);
            debugAssertM(cframe.translation.x == cframe.translation.x, "NaN translation");


            surf->getObjectSpaceBoundingSphere(s);
            s = cframe.toWorldSpace(s);
            m_lastSphereBounds.radius = max(m_lastSphereBounds.radius,
                                            (s.center - m_lastSphereBounds.center).length() + s.radius);


            // Take the entity's frame out of consideration, so that we get tight AA bounds 
            // in the Entity's frame
            CFrame osFrame = myFrameInverse * cframe;

            surf->getObjectSpaceBoundingBox(b);

            m_lastBoxBoundArray.append(cframe.toWorldSpace(b));
            const Box& temp = osFrame.toWorldSpace(b);
            m_lastObjectSpaceAABoxBounds.merge(temp);
        }

        // Box can't represent an empty box, so we make empty boxes into real boxes with zero volume here
        if (m_lastObjectSpaceAABoxBounds.isEmpty()) {
            m_lastObjectSpaceAABoxBounds = AABox(Point3::zero());
            m_lastAABoxBounds = AABox(frame().translation);
        }

        m_lastBoxBounds = frame().toWorldSpace(m_lastObjectSpaceAABoxBounds);
        m_lastBoxBounds.getBounds(m_lastAABoxBounds);
        m_lastBoundsTime = System::time();
    }

    if (! m_visible) {
        // Discard my surfaces if I'm invisible; they were only needed for bounds
        surfaceArray.resize(oldLen, false);
    }
}
Ejemplo n.º 3
0
void MD2Model::Part::load(const std::string& filename, float resize) {

    resize *= 0.55f;

    // If models are being reloaded it is dangerous to trust the interpolation cache.
    interpolatedModel = NULL;

    alwaysAssertM(FileSystem::exists(filename), std::string("Can't find \"") + filename + "\"");

    setNormalTable();

    // Clear out
    reset();

    BinaryInput b(filename, G3D_LITTLE_ENDIAN);

    MD2ModelHeader header;

    header.deserialize(b);
    debugAssert(header.version == 8);
    debugAssert(header.numVertices <= 4096);

    keyFrame.resize(header.numFrames);
    Array<Vector3> frameMin;
    frameMin.resize(header.numFrames); 
    Array<Vector3> frameMax;
    frameMax.resize(header.numFrames);
    Array<double>  frameRad;
    frameRad.resize(header.numFrames);

    texCoordScale.x = 1.0f / header.skinWidth;
    texCoordScale.y = 1.0f / header.skinHeight;

    Vector3 min  = Vector3::inf();
    Vector3 max  = -Vector3::inf();
    double  rad  = 0;

    if (header.numVertices < 3) {
        Log::common()->printf("\n*****************\nWarning: \"%s\" is corrupted and is not being loaded.\n", filename.c_str());
        return;
    }

    loadTextureFilenames(b, header.numSkins, header.offsetSkins);

    for (int f = 0; f < keyFrame.size(); ++f) {
        MD2Frame md2Frame;

        b.setPosition(header.offsetFrames + f * header.frameSize);
        md2Frame.deserialize(b);

        // Read the vertices for the frame
        keyFrame[f].vertexArray.resize(header.numVertices);
        keyFrame[f].normalArray.resize(header.numVertices);

        // Per-pose bounds
        Vector3 min_1  = Vector3::inf();
        Vector3 max_1  = -Vector3::inf();
        double  rad_1  = 0;

        // Quake's axes are permuted and scaled
        double scale[3]   = {-.07, .07, -.07};
        int    permute[3] = {2, 0, 1};
        int v, i;
        for (v = 0; v < header.numVertices; ++v) {

            Vector3& vertex = keyFrame[f].vertexArray[v];
            for (i = 0; i < 3; ++i) {
                vertex[permute[i]] = (b.readUInt8() * md2Frame.scale[i] + md2Frame.translate[i]) * float(scale[permute[i]]);
            }

            vertex *= resize;

            uint8 normalIndex = b.readUInt8();
            debugAssertM(normalIndex < 162, "Illegal canonical normal index in file");
            keyFrame[f].normalArray[v] = iClamp(normalIndex, 0, 161);

            min_1 = min_1.min(vertex);
            max_1 = max_1.max(vertex);

            if (vertex.squaredMagnitude() > rad_1) {
                rad_1 = vertex.squaredMagnitude();
            }
        }

        frameMin[f] = min_1;
        frameMax[f] = max_1;
        frameRad[f] = sqrt(rad_1);

        min = min.min(min_1);
        max = max.max(max_1);

        if (rad_1 > rad) {
            rad = rad_1;
        }
    }

    // Compute per-animation bounds based on frame bounds
    for (int a = 0; a < JUMP; ++a) {
        const int first = animationTable[a].first;
        const int last  = animationTable[a].last;

        if ((first < header.numFrames) && (last < header.numFrames)) {
            Vector3 min = frameMin[first];
            Vector3 max = frameMax[first];
            double rad  = frameRad[first];

            for (int i = first + 1; i <= last; ++i) {
                min = min.min(frameMin[i]);
                max = max.max(frameMax[i]);
                rad = G3D::max(rad, frameRad[i]);
            }

            animationBoundingBox[a]    = AABox(min, max);

            // Sometimes the sphere bounding the box is tighter than the one we calculated.
            const float boxRadSq = (max-min).squaredMagnitude() * 0.25f;

            if (boxRadSq >= square(rad)) {
                animationBoundingSphere[a] = Sphere(Vector3::zero(), (float)rad);
            } else {
                animationBoundingSphere[a] = Sphere((max + min) * 0.5f, sqrt(boxRadSq));
            }

        } else {
            // This animation is not supported by this model
            animationBoundingBox[a]    = AABox(Vector3::zero(), Vector3::zero());
            animationBoundingSphere[a] = Sphere(Vector3::zero(), 0);
        }
    }

    animationBoundingBox[JUMP] = animationBoundingBox[JUMP_DOWN];
    animationBoundingSphere[JUMP] = animationBoundingSphere[JUMP_DOWN];

    boundingBox    = AABox(min, max);
    boundingSphere = Sphere(Vector3::zero(), (float)sqrt(rad));

    // Load the texture coords
    Array<Vector2int16> fileTexCoords;
    fileTexCoords.resize(header.numTexCoords);
    b.setPosition(header.offsetTexCoords);
    for (int t = 0; t < fileTexCoords.size(); ++t) {
        fileTexCoords[t].x = b.readUInt16();
        fileTexCoords[t].y = b.readUInt16();
    }

    // The indices for the texture coords (which don't match the
    // vertex indices originally).
    indexArray.resize(header.numTriangles * 3);
    Array<Vector2int16> index_texCoordArray;
    index_texCoordArray.resize(indexArray.size());

    // Read the triangles, reversing them to get triangle list order
    b.setPosition(header.offsetTriangles);
    for (int t = header.numTriangles - 1; t >= 0; --t) {

        for (int i = 2; i >= 0; --i) {
            indexArray[t * 3 + i] = b.readUInt16();
        }

        for (int i = 2; i >= 0; --i) {
            index_texCoordArray[t * 3 + i] = fileTexCoords[b.readUInt16()];
        }
    }

    computeTexCoords(index_texCoordArray);

    // Read the primitives
    {
        primitiveArray.clear();
        b.setPosition(header.offsetGlCommands);
        
        int n = b.readInt32();

        while (n != 0) {
            Primitive& primitive = primitiveArray.next();

            if (n > 0) {
                primitive.type = PrimitiveType::TRIANGLE_STRIP;
            } else {
                primitive.type = PrimitiveType::TRIANGLE_FAN;
                n = -n;
            }

            primitive.pvertexArray.resize(n);

            Array<Primitive::PVertex>&  pvertex = primitive.pvertexArray;

            for (int i = 0; i < pvertex.size(); ++i) {
                pvertex[i].texCoord.x = b.readFloat32();
                pvertex[i].texCoord.y = b.readFloat32();
                pvertex[i].index      = b.readInt32();
            }

            n = b.readInt32();
        }
    }


    MeshAlg::computeAdjacency(keyFrame[0].vertexArray, indexArray, faceArray, edgeArray, vertexArray);
    weldedFaceArray = faceArray;
    weldedEdgeArray = edgeArray;
    weldedVertexArray = vertexArray;
    MeshAlg::weldAdjacency(keyFrame[0].vertexArray, weldedFaceArray, weldedEdgeArray, weldedVertexArray);

    numBoundaryEdges = MeshAlg::countBoundaryEdges(edgeArray);
    numWeldedBoundaryEdges = MeshAlg::countBoundaryEdges(weldedEdgeArray);

    shared_ptr<VertexBuffer> indexBuffer = 
        VertexBuffer::create(indexArray.size() * sizeof(int), VertexBuffer::WRITE_ONCE);
    indexVAR = IndexStream(indexArray, indexBuffer);
}
Ejemplo n.º 4
0
void LoadGameObjectModelList()
{
    FILE* model_list_file = fopen((sWorld.GetDataPath() + "vmaps/" + VMAP::GAMEOBJECT_MODELS).c_str(), "rb");
    if (!model_list_file)
        return;

    uint32 name_length, displayId;
    char buff[500];
    while (!feof(model_list_file))
    {
        fread(&displayId, sizeof(uint32), 1, model_list_file);
        fread(&name_length, sizeof(uint32), 1, model_list_file);

        if (name_length >= sizeof(buff))
        {
            sLog.outDebug("File %s seems to be corrupted", VMAP::GAMEOBJECT_MODELS);
            break;
        }

        fread(&buff, sizeof(char), name_length, model_list_file);
        Vector3 v1, v2;
        fread(&v1, sizeof(Vector3), 1, model_list_file);
        fread(&v2, sizeof(Vector3), 1, model_list_file);

        model_list.insert(ModelList::value_type(displayId, GameobjectModelData(std::string(buff, name_length), AABox(v1, v2))));
    }
    fclose(model_list_file);
}
Ejemplo n.º 5
0
    //=================================================================
    bool TileAssembler::convertRawFile(const std::string& pModelFilename)
    {
        bool success = true;
        std::string filename = iSrcDir;
        if (filename.length() >0)
            filename.append("/");
        filename.append(pModelFilename);
        FILE *rf = fopen(filename.c_str(), "rb");

        if (!rf)
        {
            printf("ERROR: Can't open model file in form: %s",pModelFilename.c_str());
            printf("...                          or form: %s",filename.c_str() );
            return false;
        }

        char ident[8];

        int readOperation = 1;

        // temporary use defines to simplify read/check code (close file and return at fail)
        #define READ_OR_RETURN(V,S) if(fread((V), (S), 1, rf) != 1) { \
                                        fclose(rf); printf("readfail, op = %i\n", readOperation); return(false); }readOperation++;
        #define CMP_OR_RETURN(V,S)  if(strcmp((V),(S)) != 0)        { \
                                        fclose(rf); printf("cmpfail, %s!=%s\n", V, S);return(false); }

        READ_OR_RETURN(&ident, 8);
        CMP_OR_RETURN(ident, "VMAP003");

        // we have to read one int. This is needed during the export and we have to skip it here
        uint32 tempNVectors;
        READ_OR_RETURN(&tempNVectors, sizeof(tempNVectors));

        uint32 groups;
        uint32 RootWMOID;
        char blockId[5];
        blockId[4] = 0;
        int blocksize;

        READ_OR_RETURN(&groups, sizeof(uint32));
        READ_OR_RETURN(&RootWMOID, sizeof(uint32));

        std::vector<GroupModel> groupsArray;

        for (uint32 g=0; g<groups; ++g)
        {
            std::vector<MeshTriangle> triangles;
            std::vector<Vector3> vertexArray;

            uint32 mogpflags, GroupWMOID;
            READ_OR_RETURN(&mogpflags, sizeof(uint32));
            READ_OR_RETURN(&GroupWMOID, sizeof(uint32));

            float bbox1[3], bbox2[3];
            READ_OR_RETURN(bbox1, sizeof(float)*3);
            READ_OR_RETURN(bbox2, sizeof(float)*3);

            uint32 liquidflags;
            READ_OR_RETURN(&liquidflags, sizeof(uint32));

            // will this ever be used? what is it good for anyway??
            uint32 branches;
            READ_OR_RETURN(&blockId, 4);
            CMP_OR_RETURN(blockId, "GRP ");
            READ_OR_RETURN(&blocksize, sizeof(int));
            READ_OR_RETURN(&branches, sizeof(uint32));
            for (uint32 b=0; b<branches; ++b)
            {
                uint32 indexes;
                // indexes for each branch (not used jet)
                READ_OR_RETURN(&indexes, sizeof(uint32));
            }

            // ---- indexes
            READ_OR_RETURN(&blockId, 4);
            CMP_OR_RETURN(blockId, "INDX");
            READ_OR_RETURN(&blocksize, sizeof(int));
            uint32 nindexes;
            READ_OR_RETURN(&nindexes, sizeof(uint32));
            if (nindexes >0)
            {
                uint16 *indexarray = new uint16[nindexes];
                READ_OR_RETURN(indexarray, nindexes*sizeof(uint16));
                for (uint32 i=0; i<nindexes; i+=3)
                {
                    triangles.push_back(MeshTriangle(indexarray[i], indexarray[i+1], indexarray[i+2]));
                }
                delete[] indexarray;
            }

            // ---- vectors
            READ_OR_RETURN(&blockId, 4);
            CMP_OR_RETURN(blockId, "VERT");
            READ_OR_RETURN(&blocksize, sizeof(int));
            uint32 nvectors;
            READ_OR_RETURN(&nvectors, sizeof(uint32));

            if (nvectors >0)
            {
                float *vectorarray = new float[nvectors*3];
                READ_OR_RETURN(vectorarray, nvectors*sizeof(float)*3);
                for (uint32 i=0; i<nvectors; ++i)
                {
                    vertexArray.push_back( Vector3(vectorarray + 3*i) );
                }
                delete[] vectorarray;
            }
            // ----- liquid
            WmoLiquid *liquid = 0;
            if (liquidflags& 1)
            {
                WMOLiquidHeader hlq;
                READ_OR_RETURN(&blockId, 4);
                CMP_OR_RETURN(blockId, "LIQU");
                READ_OR_RETURN(&blocksize, sizeof(int));
                READ_OR_RETURN(&hlq, sizeof(WMOLiquidHeader));
                liquid = new WmoLiquid(hlq.xtiles, hlq.ytiles, Vector3(hlq.pos_x, hlq.pos_y, hlq.pos_z), hlq.type);
                uint32 size = hlq.xverts*hlq.yverts;
                READ_OR_RETURN(liquid->GetHeightStorage(), size*sizeof(float));
                size = hlq.xtiles*hlq.ytiles;
                READ_OR_RETURN(liquid->GetFlagsStorage(), size);
            }

            groupsArray.push_back(GroupModel(mogpflags, GroupWMOID, AABox(Vector3(bbox1), Vector3(bbox2))));
            groupsArray.back().setMeshData(vertexArray, triangles);
            groupsArray.back().setLiquidData(liquid);

            // drop of temporary use defines
            #undef READ_OR_RETURN
            #undef CMP_OR_RETURN
        }
        fclose(rf);

        // write WorldModel
        WorldModel model;
        model.setRootWmoID(RootWMOID);
        if (groupsArray.size())
        {
            model.setGroupModels(groupsArray);
            success = model.writeFile(iDestDir + "/" + pModelFilename + ".vmo");
        }

        //std::cout << "readRawFile2: '" << pModelFilename << "' tris: " << nElements << " nodes: " << nNodes << std::endl;
        return success;
    }
Ejemplo n.º 6
0
    void TileAssembler::exportGameobjectModels()
    {
        FILE* model_list = fopen((iSrcDir + "/" + "temp_gameobject_models").c_str(), "rb");
        if (!model_list)
            return;

        FILE* model_list_copy = fopen((iDestDir + "/" + GAMEOBJECT_MODELS).c_str(), "wb");
        if (!model_list_copy)
        {
            fclose(model_list);
            return;
        }

        uint32 name_length, displayId;
        char buff[500];
        while (true)
        {
            if (fread(&displayId, sizeof(uint32), 1, model_list) != 1)
                if (feof(model_list))   // EOF flag is only set after failed reading attempt
                    break;

            if (fread(&name_length, sizeof(uint32), 1, model_list) != 1
                || name_length >= sizeof(buff)
                || fread(&buff, sizeof(char), name_length, model_list) != name_length)
            {
                std::cout << "\nFile 'temp_gameobject_models' seems to be corrupted" << std::endl;
                break;
            }

            std::string model_name(buff, name_length);

            WorldModel_Raw raw_model;
            if (!raw_model.Read((iSrcDir + "/" + model_name).c_str()) )
                continue;

            spawnedModelFiles.insert(model_name);
            AABox bounds;
            bool boundEmpty = true;
            for (uint32 g = 0; g < raw_model.groupsArray.size(); ++g)
            {
                std::vector<Vector3>& vertices = raw_model.groupsArray[g].vertexArray;

                uint32 nvectors = vertices.size();
                for (uint32 i = 0; i < nvectors; ++i)
                {
                    Vector3& v = vertices[i];
                    if (boundEmpty)
                        bounds = AABox(v, v), boundEmpty = false;
                    else
                        bounds.merge(v);
                }
            }

            fwrite(&displayId, sizeof(uint32), 1, model_list_copy);
            fwrite(&name_length, sizeof(uint32), 1, model_list_copy);
            fwrite(&buff, sizeof(char), name_length, model_list_copy);
            fwrite(&bounds.low(), sizeof(Vector3), 1, model_list_copy);
            fwrite(&bounds.high(), sizeof(Vector3), 1, model_list_copy);
        }

        fclose(model_list);
        fclose(model_list_copy);
    }
Ejemplo n.º 7
0
 AABox CinderGraphicItem::bounding_aabox() const {
     return AABox(position() + scale(), position() - scale());
 }
Ejemplo n.º 8
0
    bool TileAssembler::calculateTransformedBound(ModelSpawn &spawn)
    {
        std::string modelFilename = iSrcDir + "/" + spawn.name;
        ModelPosition modelPosition;
        modelPosition.iDir = spawn.iRot;
        modelPosition.iScale = spawn.iScale;
        modelPosition.init();

        FILE *rf = fopen(modelFilename.c_str(), "rb");
        if (!rf)
        {
            printf("ERROR: Can't open model file: %s\n", modelFilename.c_str());
            return false;
        }

        AABox modelBound;
        bool boundEmpty=true;
        char ident[8];

        int readOperation = 1;

        // temporary use defines to simplify read/check code (close file and return at fail)
        #define READ_OR_RETURN(V,S) if(fread((V), (S), 1, rf) != 1) { \
                                        fclose(rf); printf("readfail, op = %i\n", readOperation); return(false); }readOperation++;
        #define CMP_OR_RETURN(V,S)  if(strcmp((V),(S)) != 0)        { \
                                        fclose(rf); printf("cmpfail, %s!=%s\n", V, S);return(false); }

        READ_OR_RETURN(&ident, 8);
        CMP_OR_RETURN(ident, "VMAP003");

        // we have to read one int. This is needed during the export and we have to skip it here
        uint32 tempNVectors;
        READ_OR_RETURN(&tempNVectors, sizeof(tempNVectors));

        uint32 groups, wmoRootId;
        char blockId[5];
        blockId[4] = 0;
        int blocksize;
        float *vectorarray = 0;

        READ_OR_RETURN(&groups, sizeof(uint32));
        READ_OR_RETURN(&wmoRootId, sizeof(uint32));
        if (groups != 1) printf("Warning: '%s' does not seem to be a M2 model!\n", modelFilename.c_str());

        for (uint32 g=0; g<groups; ++g) // should be only one for M2 files...
        {
            fseek(rf, 3*sizeof(uint32) + 6*sizeof(float), SEEK_CUR);

            READ_OR_RETURN(&blockId, 4);
            CMP_OR_RETURN(blockId, "GRP ");
            READ_OR_RETURN(&blocksize, sizeof(int));
            fseek(rf, blocksize, SEEK_CUR);

            // ---- indexes
            READ_OR_RETURN(&blockId, 4);
            CMP_OR_RETURN(blockId, "INDX");
            READ_OR_RETURN(&blocksize, sizeof(int));
            fseek(rf, blocksize, SEEK_CUR);

            // ---- vectors
            READ_OR_RETURN(&blockId, 4);
            CMP_OR_RETURN(blockId, "VERT");
            READ_OR_RETURN(&blocksize, sizeof(int));
            uint32 nvectors;
            READ_OR_RETURN(&nvectors, sizeof(uint32));

            if (nvectors >0)
            {
                vectorarray = new float[nvectors*3];
                READ_OR_RETURN(vectorarray, nvectors*sizeof(float)*3);
            }
            else
            {
                std::cout << "error: model '" << spawn.name << "' has no geometry!" << std::endl;
                return false;
            }

            for (uint32 i=0, indexNo=0; indexNo<nvectors; indexNo++, i+=3)
            {
                Vector3 v = Vector3(vectorarray[i+0], vectorarray[i+1], vectorarray[i+2]);
                v = modelPosition.transform(v);

                if (boundEmpty)
                    modelBound = AABox(v, v), boundEmpty=false;
                else
                    modelBound.merge(v);
            }
            delete[] vectorarray;
            // drop of temporary use defines
            #undef READ_OR_RETURN
            #undef CMP_OR_RETURN
        }
        spawn.iBound = modelBound + spawn.iPos;
        spawn.flags |= MOD_HAS_BOUND;
        fclose(rf);
        return true;
    }
Ejemplo n.º 9
0
void Capsule::getBounds(AABox& out) const {
    Vector3 min = p1.min(p2) - (Vector3(1, 1, 1) * _radius);
    Vector3 max = p1.max(p2) + (Vector3(1, 1, 1) * _radius);

    out = AABox(min, max);
}
Ejemplo n.º 10
0
void Sphere::getBounds(AABox& out) const {
    Vector3 extent(radius, radius, radius);
    out = AABox(center - extent, center + extent);
}
Ejemplo n.º 11
0
OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData* packetData,
                                                                    EncodeBitstreamParams& params) const {

    OctreeElement::AppendState appendElementState = OctreeElement::COMPLETED; // assume the best...

    // first, check the params.extraEncodeData to see if there's any partial re-encode data for this element
    OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData;
    EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData = NULL;
    bool hadElementExtraData = false;
    if (extraEncodeData && extraEncodeData->contains(this)) {
        entityTreeElementExtraEncodeData =
            static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);
        hadElementExtraData = true;
    } else {
        // if there wasn't one already, then create one
        entityTreeElementExtraEncodeData = new EntityTreeElementExtraEncodeData();
        entityTreeElementExtraEncodeData->elementCompleted = !hasContent();

        for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
            EntityTreeElementPointer child = getChildAtIndex(i);
            if (!child) {
                entityTreeElementExtraEncodeData->childCompleted[i] = true; // if no child exists, it is completed
            } else {
                if (child->hasEntities()) {
                    entityTreeElementExtraEncodeData->childCompleted[i] = false;
                } else {
                    // if the child doesn't have enities, it is completed
                    entityTreeElementExtraEncodeData->childCompleted[i] = true;
                }
            }
        }
        forEachEntity([&](EntityItemPointer entity) {
            entityTreeElementExtraEncodeData->entities.insert(entity->getEntityItemID(), entity->getEntityProperties(params));
        });
    }

    //assert(extraEncodeData);
    //assert(extraEncodeData->contains(this));
    //entityTreeElementExtraEncodeData = static_cast<EntityTreeElementExtraEncodeData*>((*extraEncodeData)[this]);

    LevelDetails elementLevel = packetData->startLevel();

    // write our entities out... first determine which of the entities are in view based on our params
    uint16_t numberOfEntities = 0;
    uint16_t actualNumberOfEntities = 0;
    int numberOfEntitiesOffset = 0;
    withReadLock([&] {
        QVector<uint16_t> indexesOfEntitiesToInclude;

        // It's possible that our element has been previous completed. In this case we'll simply not include any of our
        // entities for encoding. This is needed because we encode the element data at the "parent" level, and so we
        // need to handle the case where our sibling elements need encoding but we don't.
        if (!entityTreeElementExtraEncodeData->elementCompleted) {
            for (uint16_t i = 0; i < _entityItems.size(); i++) {
                EntityItemPointer entity = _entityItems[i];
                bool includeThisEntity = true;

                if (!params.forceSendScene && entity->getLastChangedOnServer() < params.lastViewFrustumSent) {
                    includeThisEntity = false;
                }

                if (hadElementExtraData) {
                    includeThisEntity = includeThisEntity &&
                        entityTreeElementExtraEncodeData->entities.contains(entity->getEntityItemID());
                }

                if (includeThisEntity || params.recurseEverything) {

                    // we want to use the maximum possible box for this, so that we don't have to worry about the nuance of
                    // simulation changing what's visible. consider the case where the entity contains an angular velocity
                    // the entity may not be in view and then in view a frame later, let the client side handle it's view
                    // frustum culling on rendering.
                    bool success;
                    AACube entityCube = entity->getQueryAACube(success);
                    if (!success || !params.viewFrustum.cubeIntersectsKeyhole(entityCube)) {
                        includeThisEntity = false; // out of view, don't include it
                    } else {
                        // Check the size of the entity, it's possible that a "too small to see" entity is included in a
                        // larger octree cell because of its position (for example if it crosses the boundary of a cell it
                        // pops to the next higher cell. So we want to check to see that the entity is large enough to be seen
                        // before we consider including it.
                        success = true;
                        // we can't cull a parent-entity by its dimensions because the child may be larger.  we need to
                        // avoid sending details about a child but not the parent.  the parent's queryAACube should have
                        // been adjusted to encompass the queryAACube of the child.
                        AABox entityBounds = entity->hasChildren() ? AABox(entityCube) : entity->getAABox(success);
                        if (!success) {
                            // if this entity is a child of an avatar, the entity-server wont be able to determine its
                            // AABox.  If this happens, fall back to the queryAACube.
                            entityBounds = AABox(entityCube);
                        }
                        auto renderAccuracy = calculateRenderAccuracy(params.viewFrustum.getPosition(),
                                                                      entityBounds,
                                                                      params.octreeElementSizeScale,
                                                                      params.boundaryLevelAdjust);
                        if (renderAccuracy <= 0.0f) {
                            includeThisEntity = false; // too small, don't include it

                            #ifdef WANT_LOD_DEBUGGING
                            qDebug() << "skipping entity - TOO SMALL - \n"
                                     << "......id:" << entity->getID() << "\n"
                                     << "....name:" << entity->getName() << "\n"
                                     << "..bounds:" << entityBounds << "\n"
                                     << "....cell:" << getAACube();
                            #endif
                        }
                    }
                }

                if (includeThisEntity) {
                    #ifdef WANT_LOD_DEBUGGING
                    qDebug() << "including entity - \n"
                        << "......id:" << entity->getID() << "\n"
                        << "....name:" << entity->getName() << "\n"
                        << "....cell:" << getAACube();
                    #endif
                    indexesOfEntitiesToInclude << i;
                    numberOfEntities++;
                } else {
                    // if the extra data included this entity, and we've decided to not include the entity, then
                    // we can treat it as if it was completed.
                    entityTreeElementExtraEncodeData->entities.remove(entity->getEntityItemID());
                }
            }
        }

        numberOfEntitiesOffset = packetData->getUncompressedByteOffset();
        bool successAppendEntityCount = packetData->appendValue(numberOfEntities);

        if (successAppendEntityCount) {
            foreach(uint16_t i, indexesOfEntitiesToInclude) {
                EntityItemPointer entity = _entityItems[i];
                LevelDetails entityLevel = packetData->startLevel();
                OctreeElement::AppendState appendEntityState = entity->appendEntityData(packetData,
                    params, entityTreeElementExtraEncodeData);

                // If none of this entity data was able to be appended, then discard it
                // and don't include it in our entity count
                if (appendEntityState == OctreeElement::NONE) {
                    packetData->discardLevel(entityLevel);
                } else {
                    // If either ALL or some of it got appended, then end the level (commit it)
                    // and include the entity in our final count of entities
                    packetData->endLevel(entityLevel);
                    actualNumberOfEntities++;
                }

                // If the entity item got completely appended, then we can remove it from the extra encode data
                if (appendEntityState == OctreeElement::COMPLETED) {
                    entityTreeElementExtraEncodeData->entities.remove(entity->getEntityItemID());
                }

                // If any part of the entity items didn't fit, then the element is considered partial
                // NOTE: if the entity item didn't fit or only partially fit, then the entity item should have
                // added itself to the extra encode data.
                if (appendEntityState != OctreeElement::COMPLETED) {
                    appendElementState = OctreeElement::PARTIAL;
                }
            }
        } else {
Ejemplo n.º 12
0
bool MeshDefFragment::unpack(WLDReader *s)
{
    uint16_t vertexCount, texCoordsCount, normalCount, colorCount, polyCount;
    uint16_t vertexPieceCount, polyTexCount, vertexTexCount, scaleFactor;
    s->unpackField('I', &m_flags);
    s->unpackReference(&m_palette);
    s->unpackArray("R", 3, m_ref);
    s->unpackArray("f", 3, &m_center);
    s->unpackArray("I", 3, &m_param2);
    s->unpackField('f', &m_maxDist);
    // This is not always defined, we will calculate it later on.
    s->unpackArray("f", 3, &m_boundsAA.low);
    s->unpackArray("f", 3, &m_boundsAA.high);
    s->unpackFields("hhhhhhhhhh", &vertexCount, &texCoordsCount, &normalCount,
                 &colorCount, &polyCount, &vertexPieceCount, &polyTexCount,
                 &vertexTexCount, &m_size9, &scaleFactor);

    float scale = 1.0 / float(1 << scaleFactor);
    int16_t vertex[3], texCoord[2];
    int8_t normal[3], color[4];
    uint16_t polygon[4], vertexPiece[2], polyTex[2], vertexTex[2];
    s->unpackStruct("hhh", vertex);
    vec3 scaledVertex = vec3(vertex[0] * scale, vertex[1] * scale, vertex[2] * scale);
    m_boundsAA = AABox(scaledVertex, scaledVertex);
    m_vertices.append(scaledVertex);
    for(uint16_t i = 1; i < vertexCount; i++)
    {
        s->unpackStruct("hhh", vertex);
        scaledVertex = vec3(vertex[0] * scale, vertex[1] * scale, vertex[2] * scale);
        m_boundsAA.extendTo(scaledVertex);
        m_vertices.append(scaledVertex);
    }
    for(uint16_t i = 0; i < texCoordsCount; i++)
    {
        s->unpackStruct("hh", texCoord);
        m_texCoords.append(vec2((texCoord[0] / 256.0), (texCoord[1] / 256.0)));
    }
    for(uint16_t i = 0; i < normalCount; i++)
    {
        s->unpackStruct("bbb", normal);
        m_normals.append(vec3(normal[0] / 127.0, normal[1] / 127.0, normal[2] / 127.0));
    }
    for(uint16_t i = 0; i < colorCount; i++)
    {
        s->unpackStruct("BBBB", color);
        m_colors.append(qRgba(color[0], color[1], color[2], color[3]));
    }
    for(uint16_t i = 0; i < polyCount; i++)
    {
        s->unpackStruct("HHHH", polygon);
        m_polygonFlags.append(polygon[0]);
        m_indices.append(polygon[1]);
        m_indices.append(polygon[2]);
        m_indices.append(polygon[3]);
    }
    for(uint16_t i = 0; i < vertexPieceCount; i++)
    {
        s->unpackStruct("HH", vertexPiece);
        m_vertexPieces.append(vec2us(vertexPiece[0], vertexPiece[1]));
    }
    for(uint16_t i = 0; i < polyTexCount; i++)
    {
        s->unpackStruct("HH", polyTex);
        m_polygonsByTex.append(vec2us(polyTex[0], polyTex[1]));
    }
    for(uint16_t i = 0; i < vertexTexCount; i++)
    {
        s->unpackStruct("HH", vertexTex);
        m_verticesByTex.append(vec2us(vertexTex[0], vertexTex[1]));
    }
    return true;
}
Ejemplo n.º 13
0
  /*
   * Tries to load vmap and tilemap for a gridtile and creates a navmesh for it.
   *
   */
  bool
  ModelContainerView::generateMoveMapForTile (int pMapId, int x, int y)
  {
        bool result = iVMapManager.loadMap (gVMapDataDir.c_str (), pMapId, x, y) == VMAP_LOAD_RESULT_OK;
        if (result == VMAP_LOAD_RESULT_OK)
        {
            //VMap loaded. Add data from vmap to global Triangle-Array
            parseVMap (pMapId, x, y);
        }
        // Add data from Height-Map to global Triangle-Array
        generateHeightMap(pMapId,x,y);
        // We will now add all triangles inside the given zone to the vectormap.
        // We could also do additional checks here.
        double x_max = (32-x)*SIZE_OF_GRIDS + 50;
        double y_max = (32-y)*SIZE_OF_GRIDS + 50;
        double x_min = x_max - SIZE_OF_GRIDS - 100;
        double y_min = y_max - SIZE_OF_GRIDS - 100;
        Vector3 low = Vector3(x_min,y_min,-inf());
        Vector3 high = Vector3(x_max,y_max,inf());
        AABox checkBox = AABox(low,high);
        AABox check;
        Triangle t;
        //each triangle has mangos format.
        for (int i = 0; i < globalTriangleArray.size(); i++) {
            t = globalTriangleArray[i];
            t.getBounds(check);
            if (checkBox.contains(check)) {
                // Write it down in detour format.
                iGlobArray.append(t.vertex(0).y,t.vertex(0).z,t.vertex(0).x);
                iGlobArray.append(t.vertex(1).y,t.vertex(1).z,t.vertex(1).x);
                iGlobArray.append(t.vertex(2).y,t.vertex(2).z,t.vertex(2).x);
            }
                
        }
        if (iGlobArray.size() == 0) {
            printf("No models - check your mmap.datadir in your config");
            return true;
        }

        if(gMakeObjFile)
            debugGenerateObjFile(); // create obj file for Recast Demo viewer
        //return true;
        float bmin[3], bmax[3];
        /*
         * The format looks like this
         * Verticle = float[3]
         * Triangle = Verticle[3]
         * So there are
         * array.size() floats
         * that means there are
         * nverts = array.size()/3 Verticles
         * that means there are
         * ntris = nverts/3
         */
         //array/3 verticles
        const int nverts = iGlobArray.size()/3; // because 1 vert is 3 float.
        // -> vert = float[3]
        const float* verts = iGlobArray.getCArray();
        rcCalcBounds(verts,nverts,bmin,bmax);
        // nverts/3 triangles
        // -> Triangle = vert[3] = float[9]
        int* tris = new int[nverts];// because 1 triangle is 3 verts
        for (int i = 0; i< nverts; i++)
            tris[i] = i;
        /* tris[i] = 1,2,3;4,5,6;7,8,9;
         *
         */
        const int ntris = (nverts/3);
	rcConfig m_cfg;
	//
	// Step 1. Initialize build config.
	//

	// Init build configuration from GUI
	memset(&m_cfg, 0, sizeof(m_cfg));
        // Change config settings here!
	m_cfg.cs = 0.3f;
	m_cfg.ch = 0.2f;
	m_cfg.walkableSlopeAngle = 50.0f;
	m_cfg.walkableHeight = 10;
	m_cfg.walkableClimb = 4;
	m_cfg.walkableRadius = 2;
	m_cfg.maxEdgeLen = (int)(12 / 0.3f);
	m_cfg.maxSimplificationError = 1.3f;
	m_cfg.minRegionSize = (int)rcSqr(50);
	m_cfg.mergeRegionSize = (int)rcSqr(20);
	m_cfg.maxVertsPerPoly = (int)6;
	m_cfg.detailSampleDist = 1.8f;
	m_cfg.detailSampleMaxError = 0.2f * 1;
        bool m_keepInterResults = false;
        printf("CellSize        : %.2f\n",m_cfg.cs);
        printf("CellHeight      : %.2f\n",m_cfg.ch);
        printf("WalkableSlope   : %.2f\n",m_cfg.walkableSlopeAngle);
        printf("WalkableHeight  : %i\n",m_cfg.walkableHeight);
        printf("walkableClimb   : %i\n",m_cfg.walkableClimb);
        printf("walkableRadius  : %i\n",m_cfg.walkableRadius);
        printf("maxEdgeLen      : %i\n",m_cfg.maxEdgeLen);
        printf("maxSimplific.Er.: %.2f\n",m_cfg.maxSimplificationError);
        printf("minRegionSize   : %i\n",m_cfg.minRegionSize);
        printf("mergedRegSize   : %i\n",m_cfg.mergeRegionSize);
        printf("maxVertsPerPoly : %i\n",m_cfg.maxVertsPerPoly);
        printf("detailSampledist: %.2f\n",m_cfg.detailSampleDist);
        printf("det.Samp.max.err: %.2f\n",m_cfg.detailSampleMaxError);
	// Set the area where the navigation will be build.
	// Here the bounds of the input mesh are used, but the
	// area could be specified by an user defined box, etc.
	vcopy(m_cfg.bmin, bmin);
	vcopy(m_cfg.bmax, bmax);
	rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, &m_cfg.width, &m_cfg.height);

	//
	// Step 2. Rasterize input polygon soup.
	//

	// Allocate voxel heighfield where we rasterize our input data to.
	rcHeightfield* m_solid = new rcHeightfield;
	if (!m_solid)
	{
		printf("buildNavigation: Out of memory 'solid'.\n");
		return false;
	}
	if (!rcCreateHeightfield(*m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch))
	{
		printf("buildNavigation: Could not create solid heightfield.\n");
		return false;
	}

	// Allocate array that can hold triangle flags.
	// If you have multiple meshes you need to process, allocate
	// and array which can hold the max number of triangles you need to process.
	unsigned char* m_triflags = new unsigned char[ntris];
	if (!m_triflags)
	{
		printf("buildNavigation: Out of memory 'triangleFlags' (%d).\n", ntris);
		return false;
	}

	// Find triangles which are walkable based on their slope and rasterize them.
	// If your input data is multiple meshes, you can transform them here, calculate
	// the flags for each of the meshes and rasterize them.
	memset(m_triflags, 0, ntris*sizeof(unsigned char));
	rcMarkWalkableTriangles(m_cfg.walkableSlopeAngle, verts, nverts, tris, ntris, m_triflags);
	rcRasterizeTriangles(verts, nverts, tris, m_triflags, ntris, *m_solid, m_cfg.walkableClimb);

    // should delete [] verts?  - probably not, this is just pointer to data in a G3D Array
    // should delete [] tris?

	if (!m_keepInterResults)
	{
		delete [] m_triflags;
		m_triflags = 0;
	}

	//
	// Step 3. Filter walkables surfaces.
	//

	// Once all geoemtry is rasterized, we do initial pass of filtering to
	// remove unwanted overhangs caused by the conservative rasterization
	// as well as filter spans where the character cannot possibly stand.
	rcFilterLowHangingWalkableObstacles(m_cfg.walkableClimb, *m_solid);
	rcFilterLedgeSpans(m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid);
	rcFilterWalkableLowHeightSpans(m_cfg.walkableHeight, *m_solid);


	//
	// Step 4. Partition walkable surface to simple regions.
	//

	// Compact the heightfield so that it is faster to handle from now on.
	// This will result more cache coherent data as well as the neighbours
	// between walkable cells will be calculated.
	rcCompactHeightfield* m_chf = new rcCompactHeightfield;
	if (!m_chf)
	{
		printf("buildNavigation: Out of memory 'chf'.\n");
		return false;
	}
	if (!rcBuildCompactHeightfield(m_cfg.walkableHeight, m_cfg.walkableClimb, RC_WALKABLE, *m_solid, *m_chf))
	{
		printf( "buildNavigation: Could not build compact data.\n");
		return false;
	}

	if (!m_keepInterResults)
	{
		delete m_solid;
		m_solid = 0;
	}

	// Erode the walkable area by agent radius.
	if (!rcErodeArea(RC_WALKABLE_AREA, m_cfg.walkableRadius, *m_chf))
	{
		printf("buildNavigation: Could not erode.\n");
		return false;
	}

	// (Optional) Mark areas.
	//const ConvexVolume* vols = m_geom->getConvexVolumes();
	//for (int i  = 0; i < m_geom->getConvexVolumeCount(); ++i)
	//	rcMarkConvexPolyArea(vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (unsigned char)vols[i].area, *m_chf);

	// Prepare for region partitioning, by calculating distance field along the walkable surface.
	if (!rcBuildDistanceField(*m_chf))
	{
		printf("buildNavigation: Could not build distance field.\n");
		return false;
	}

	// Partition the walkable surface into simple regions without holes.
	if (!rcBuildRegions(*m_chf, m_cfg.borderSize, m_cfg.minRegionSize, m_cfg.mergeRegionSize))
	{
		printf("buildNavigation: Could not build regions.\n");
	}

	//
	// Step 5. Trace and simplify region contours.
	//

	// Create contours.
	rcContourSet* m_cset = new rcContourSet;
	if (!m_cset)
	{
		printf("buildNavigation: Out of memory 'cset'.\n");
		return false;
	}
	if (!rcBuildContours(*m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, *m_cset))
	{
		printf("buildNavigation: Could not create contours.\n");
		return false;
	}

	//
	// Step 6. Build polygons mesh from contours.
	//

	// Build polygon navmesh from the contours.
	rcPolyMesh* m_pmesh = new rcPolyMesh;
	if (!m_pmesh)
	{
		printf("buildNavigation: Out of memory 'pmesh'.\n");
		return false;
	}
	if (!rcBuildPolyMesh(*m_cset, m_cfg.maxVertsPerPoly, *m_pmesh))
	{
		printf( "buildNavigation: Could not triangulate contours.\n");
		return false;
	}

	//
	// Step 7. Create detail mesh which allows to access approximate height on each polygon.
	//

	rcPolyMeshDetail* m_dmesh = new rcPolyMeshDetail;
	if (!m_dmesh)
	{
		printf("buildNavigation: Out of memory 'pmdtl'.\n");
		return false;
	}

	if (!rcBuildPolyMeshDetail(*m_pmesh, *m_chf, m_cfg.detailSampleDist, m_cfg.detailSampleMaxError, *m_dmesh))
	{
		printf("buildNavigation: Could not build detail mesh.\n");
	}

	if (!m_keepInterResults)
	{
		delete m_chf;
		m_chf = 0;
		delete m_cset;
		m_cset = 0;
	}

	// At this point the navigation mesh data is ready, you can access it from m_pmesh.
	// See duDebugDrawPolyMesh or dtCreateNavMeshData as examples how to access the data.

	//
	// (Optional) Step 8. Create Detour data from Recast poly mesh.
	//

	// The GUI may allow more max points per polygon than Detour can handle.
	// Only build the detour navmesh if we do not exceed the limit.
	if (m_cfg.maxVertsPerPoly <= DT_VERTS_PER_POLYGON)
	{
		unsigned char* navData = 0;
		int navDataSize = 0;
                // Update poly flags from areas.
		for (int i = 0; i < m_pmesh->npolys; ++i)
		{
                    // for now all generated navmesh is walkable by everyone.
                    // else there will be no pathfinding at all!
                    m_pmesh->flags[i] = RC_WALKABLE_AREA;
		}

		dtNavMeshCreateParams params;
		memset(&params, 0, sizeof(params));
		params.verts = m_pmesh->verts;
		params.vertCount = m_pmesh->nverts;
		params.polys = m_pmesh->polys;
		params.polyAreas = m_pmesh->areas;
		params.polyFlags = m_pmesh->flags;
		params.polyCount = m_pmesh->npolys;
		params.nvp = m_pmesh->nvp;
		params.detailMeshes = m_dmesh->meshes;
		params.detailVerts = m_dmesh->verts;
		params.detailVertsCount = m_dmesh->nverts;
		params.detailTris = m_dmesh->tris;
		params.detailTriCount = m_dmesh->ntris;
		params.offMeshConVerts = 0;
		params.offMeshConRad = 0;
		params.offMeshConDir = 0;
		params.offMeshConAreas = 0;
		params.offMeshConFlags = 0;
		params.offMeshConCount = 0;
		params.walkableHeight = 2.0f;
		params.walkableRadius = 0.6f;
		params.walkableClimb = 0.9f;
		vcopy(params.bmin, m_pmesh->bmin);
		vcopy(params.bmax, m_pmesh->bmax);
		params.cs = m_cfg.cs;
		params.ch = m_cfg.ch;
		printf("vertcount       : %05u\n",params.vertCount);
                printf("polycount       : %05u\n",params.polyCount);
                printf("detailVertsCount: %05u\n",params.detailVertsCount);
                printf("detailTriCount  : %05u\n",params.detailTriCount);
                printf("walkableClimb   : %.2f\n",params.walkableClimb);
                printf("walkableRadius  : %.2f\n",params.walkableRadius);
                printf("walkableHeight  : %.2f\n",params.walkableHeight);
		if (!dtCreateNavMeshData(&params, &navData, &navDataSize))
		{
			printf("Could not build Detour navmesh.\n");
			return false;
		}
                // navData now contains the MoveMap
                printf("Generated Navigation Mesh! Size: %i bytes/ %i kB / %i MB\n",navDataSize,navDataSize/1024,navDataSize/(1024*1024));
                char tmp[14];
                sprintf(tmp, "%03u%02u%02u.mmap",iMap,ix,iy);
                std::string savefilepath = gMMapDataDir + "/" + tmp;
                ofstream inf( savefilepath.c_str(),ofstream::binary );
                if( inf )
                {
                        inf.write( (char*)( &navData[0] ), navDataSize ) ;
                }
                printf("MoveMap saved under %s\n", savefilepath.c_str());
                delete [] navData;
        }
       // debugLoadNavMesh();
        return (result);
  }
Ejemplo n.º 14
0
AABox GlyphFace::getBoundingBox() const {
    double e = 100*EPSILON;
    return bboxToWorld(AABox(Vector(glyph->xMin, glyph->yMin, -e),
                             Vector(glyph->xMax, glyph->yMax, e)));
}
Ejemplo n.º 15
0
AABox ExtrudedLine::getBoundingBox() const {
    double e = 100*EPSILON;
    return bboxToWorld(AABox(Vector(c1[0]-e, c1[1]-e, -EPSILON), 
                             Vector(c2[0]+e, c2[1]+e, 1+EPSILON)));
}