Example #1
0
void ParticleSurface::sortAndUploadIndices(shared_ptr<ParticleSurface> particleSurface, const Vector3& csz) {
    ParticleSystem::s_sortArray.fastClear();
    
    shared_ptr<ParticleSystem::Block> block = particleSurface->m_block;
    shared_ptr<ParticleSystem> particleSystem = block->particleSystem.lock();
    for (int i = 0; i < particleSystem->m_particle.size(); ++i) {
        const ParticleSystem::Particle& particle = particleSystem->m_particle[i];
        CFrame cframe;
        particleSurface->getCoordinateFrame(cframe);
        const Point3& wsPosition = particleSystem->particlesAreInWorldSpace() ?
            particle.position :
            cframe.pointToWorldSpace(particle.position);
        const float particleCSZ = dot(wsPosition, csz);

        ParticleSystem::SortProxy proxy;
        proxy.index = block->startIndex + i;
        proxy.z = particleCSZ;
        ParticleSystem::s_sortArray.append(proxy);
    }
    ParticleSystem::s_sortArray.sort(SORT_DECREASING);
    ParticleSystem::ParticleBuffer& pBuffer = ParticleSystem::s_particleBuffer;
    bool needsReallocation = true;
    if (pBuffer.indexStream.valid() &&
        (pBuffer.indexStream.maxSize() >= size_t(ParticleSystem::s_sortArray.size()))) {
        needsReallocation = false;
    }

    if (needsReallocation) {
        int numToAllocate = ParticleSystem::s_sortArray.size() * 2;
        shared_ptr<VertexBuffer> vb = VertexBuffer::create(sizeof(int) * numToAllocate + 8);
        int ignored;
        pBuffer.indexStream = IndexStream(ignored, numToAllocate, vb);
    }
    static Array<int> sortedIndices;
    sortedIndices.fastClear();
    for (const ParticleSystem::SortProxy& p : ParticleSystem::s_sortArray) {
        sortedIndices.append(p.index);
    }
    pBuffer.indexStream.update(sortedIndices);
}
DirectionHistogram::DirectionHistogram(int numSlices, const Vector3& axis) : m_slices(numSlices) {
    alwaysAssertM(numSlices >= 4, "At least four slices required");

    // Turn on old hemisphere-only optimization
    const bool hemi = true;

    // Normalize
    const Vector3& Z = axis.direction();

    Vector3 X = (abs(Z.dot(Vector3::unitX())) <= 0.9f) ? Vector3::unitX() : Vector3::unitY();
    X = (X - Z * (Z.dot(X))).direction();
    const Vector3 Y = Z.cross(X);

    // Only generate upper hemisphere
    static const int P = m_slices;
    static const int T = hemi ? (m_slices / 2) : m_slices;
    const float thetaExtent = float( hemi ? G3D::halfPi() : G3D::pi() );

    for (int t = 0; t < T; ++t) {
        const float theta = t * thetaExtent / (T - 1.0f);
        const float z = cos(theta);
        const float r = sin(theta);

        const bool firstRow = (t == 0);
        const bool secondRow = (t == 1);
        const bool lastRow = ! hemi && (t == T - 1);

        for (int p = 0; p < P; ++p) {
            const float phi = p * float(G3D::twoPi()) / P;
            const float x = cos(phi) * r;
            const float y = sin(phi) * r;

            const bool unique = (! firstRow && ! lastRow) || (p == 0);
                
            // Only insert one vertex at each pole
            if (unique) {
                m_meshVertex.append(X * x + Y * y + Z * z);
            }

            const int i = m_meshVertex.size() - 1;
            // Index of the start of this row
            const int rowStart  = ((i - 1) / P) * P + 1;
            const int colOffset = i - rowStart;

            if (firstRow) {
                // (First row generates no quads)
            } else if (secondRow) {                
                // Degnererate north pole
                m_meshIndex.append(0, 0, i, rowStart + (colOffset + 1) % P);

            } else if (lastRow) {
                // Degenerate south pole
                m_meshIndex.append(i, i, i - p - 1, i - p - 2);

            } else {

                m_meshIndex.append(
                    i - P, 
                    i, 
                    rowStart + (colOffset + 1) % P, 
                    rowStart + ((colOffset + 1) % P) - P);
            }
        }
    }

    m_bucket.resize(m_meshVertex.size());
    reset();

    // We initially accumulate areas and then invert them in a follow-up pass
    m_invArea.resize(m_meshIndex.size());
    // Zero the array
    System::memset(m_invArea.getCArray(), 0, sizeof(float) * m_invArea.size());

    CPUVertexArray vertexArray;
    // Create triTree
    {
        
        vertexArray.hasTangent     = false;
        vertexArray.hasTexCoord0   = false;
        
        for(int i = 0; i < m_meshVertex.size(); ++i){
            CPUVertexArray::Vertex v;
            v.position = m_meshVertex[i];
            v.normal   = m_meshVertex[i];
            vertexArray.vertex.append(v);
        }


        Array<Tri> triArray;
        for (int q = 0; q < m_meshIndex.size(); q += 4) {
            const int i0 = m_meshIndex[q];
            const int i1 = m_meshIndex[q + 1];
            const int i2 = m_meshIndex[q + 2];
            const int i3 = m_meshIndex[q + 3];
            
            // Create two tris for each quad
            // Wind backwards; these tris have to face inward

            const Proxy<Material>::Ref vii(VertexIndexIndex::create(q));
            
            Tri A(i0, i3, i2, vertexArray, vii);
            Tri B(i0, i2, i1, vertexArray, vii);

            triArray.append(A);
            triArray.append(B);

            // Attribute the area of the surrounding quads to each vertex.  If we don't do this, then
            // vertices near the equator will recieve only half of the correct probability.
            float area = A.area() + B.area();
            m_invArea[i0] += area;
            m_invArea[i1] += area;
            m_invArea[i2] += area;
            m_invArea[i3] += area;
        }
        
        m_tree.setContents(triArray, vertexArray);
        //ASKMORGAN
        vertexArray.vertex.clear();

        for (int i = 0; i < m_invArea.size(); ++i) {
            // Multiply by a small number to keep these from getting too large
            m_invArea[i] = 0.001f / m_invArea[i];
        }
    }

    shared_ptr<VertexBuffer> dataArea = VertexBuffer::create(sizeof(Vector3) * m_meshVertex.size(),
        VertexBuffer::WRITE_EVERY_FEW_FRAMES);
    m_gpuMeshVertex = AttributeArray(m_meshVertex, dataArea);

    shared_ptr<VertexBuffer> indexArea = VertexBuffer::create(sizeof(int) * m_meshIndex.size(), 
        VertexBuffer::WRITE_ONCE);
    m_gpuMeshIndex = IndexStream(m_meshIndex, indexArea);

    m_dirty = false;
}
Example #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);
}