Esempio n. 1
0
CMapArea* CMapAreaReader::read()
{
    CMapArea* ret = nullptr;
    try
    {
        atUint32 magic = base::readUint32();
        if (magic != 0xDEADD00D)
            THROW_INVALID_DATA_EXCEPTION_RETURN(nullptr, "Not a valid MAPA file got 0x%.8X", magic);
        CMapArea::Version version = (CMapArea::Version)base::readUint32();

        if (version != CMapArea::Version::MetroidPrime1 && version != CMapArea::Version::MetroidPrime2 && version != CMapArea::Version::MetroidPrime3)
            THROW_INVALID_DATA_EXCEPTION_RETURN(nullptr, "Only Metroid Prime 1-3 Minimaps are supported got version %i", (atUint32)version);

        ret = new CMapArea;

        CMaterial material;
        atUint32 materialFlags = 0;
        materialFlags |= 0x8;
        materialFlags |= 0x80;
        material.setMaterialFlags(materialFlags);
        atUint32 vertexAttributes = 0;
        vertexAttributes |= 3;
        material.setVertexAttributes(vertexAttributes);
        material.setBlendMode(EBlendMode::Zero, EBlendMode::One);

        STEVStage tevStage;
        tevStage.ColorInFlags = 0xE | (0xF << 5) | (0xF << 10) | (0xF << 15);
        tevStage.AlphaInFlags = 0x6 | (0x7 << 5) | (0x7 << 10) | (0x7 << 15);

        tevStage.ColorOpFlags = 0;
        tevStage.AlphaOpFlags = 0;
        tevStage.KonstColorIn  = 0x0C;
        tevStage.KonstAlphaIn  = 0x1C;

        material.addTevStage(tevStage, 0);

        ret->m_materialID = CMaterialCache::instance()->addMaterial(material);

        ret->m_unknown1 = base::readUint32();
        ret->m_unknown2 = base::readUint32();
        
        ret->m_boundingBox.readBoundingBox(*this);

        if (version != CMapArea::Version::MetroidPrime1)
        {
            base::readUint32();
            base::readUint32();
            base::readUint32();
            if (version == CMapArea::Version::MetroidPrime3)
                base::readUint32();
        }

        atUint32 poiCount    = base::readUint32();
        atUint32 vertexCount = base::readUint32();
        atUint32 detailCount = base::readUint32();
        atUint64 headerSize = base::position();

        if (version == CMapArea::Version::MetroidPrime3)
        {
            atUint32 stringLength = base::readUint32();
            base::readUint32();
            headerSize = base::position();
            if (stringLength > 0)
                base::readString(stringLength);
        }

        for (atUint32 i = 0; i < poiCount; i++)
        {
            SPointOfInterest pointOfInterest;
            if (version == CMapArea::Version::MetroidPrime3)
                pointOfInterest.unknown1 = readUint32();

            pointOfInterest.type = base::readUint32();
            pointOfInterest.unknown2 = base::readUint32();
            if (version != CMapArea::Version::MetroidPrime3)
            {
                pointOfInterest.unknown3 = base::readUint16();
                pointOfInterest.id = base::readUint16();
            }
            else
            {
                pointOfInterest.unknown4.readRGBA(*this);
            }
            base::seek(4); // padding;

            CMatrix3f transformBasis;
            CVector3f transformOrigin;
            for (atUint32 i = 0; i < 3; i++)
            {
                transformBasis[i].x = base::readFloat();
                transformBasis[i].y = base::readFloat();
                transformBasis[i].z = base::readFloat();
                transformOrigin[i] = base::readFloat();
            }
            pointOfInterest.transform = CTransform(transformBasis.transposed(), transformOrigin);

            base::seek(4*4); // padding;

            ret->m_pointsOfInterest.push_back(pointOfInterest);
        }

        for (atUint32 i = 0; i < vertexCount; ++i)
        {
            CVector3f vec(*this);
            ret->m_vertices.push_back(vec);
        }

        for (atUint32 i = 0; i < detailCount; i++)
        {
            SMapAreaDetail detail;
            detail.boundingBox.readBoundingBox(*this);

            atUint32 primDataStart = base::readUint32();
            atUint32 primDataEnd   = base::readUint32();
            atUint64 oldPos = base::position();

            base::seek(primDataStart + headerSize, Athena::SeekOrigin::Begin);

            atUint32 primitiveCount = base::readUint32();

            for (atUint32 j = 0; j < primitiveCount; j++)
            {
                SMapAreaPrimitive primitive;
                atUint32 type = base::readUint32();

                switch((EPrimitive)type)
                {
                    case EPrimitive::Quads:
                        primitive.type = GL_QUADS;
                        break;
                    case EPrimitive::Triangles:
                        primitive.type = GL_TRIANGLES;
                        break;
                    case EPrimitive::TriangleStrip:
                        primitive.type = GL_TRIANGLE_STRIP;
                        break;
                    case EPrimitive::TriangleFan:
                        primitive.type = GL_TRIANGLE_FAN;
                        break;
                    case EPrimitive::Lines:
                        primitive.type = GL_LINES;
                        break;
                    case EPrimitive::LineStrip:
                        primitive.type = GL_LINE_STRIP;
                        break;
                    case EPrimitive::Points:
                        primitive.type = GL_POINTS;
                        break;
                }

                atUint32 indexCount = base::readUint32();

                for (atUint32 k = 0; k < indexCount; ++k)
                {
                    atUint16 idx = (atUint16)base::readUByte();
                    primitive.indices.push_back(idx);
                }

                if (type != 0)
                {
                    //primitive.indices.push_back(0xFFFF);
                    detail.primitives.push_back(primitive);
                }
                base::seek((base::position() + 3) & ~3, Athena::SeekOrigin::Begin);
            }
            base::seek(primDataEnd + headerSize, Athena::SeekOrigin::Begin);

            atUint32 borderCount = base::readUint32();

            for (atUint32 j = 0; j < borderCount; j++)
            {
                SMapBorder border;
                atUint32 borderIndexCount = base::readUint32();
                for (atUint32 k = 0; k < borderIndexCount; ++k)
                {
                    atInt16 idx =(atInt16)base::readUByte();
                    border.indices.push_back(idx);
                }

                //border.indices.push_back(0xFFFF);
                detail.borders.push_back(border);
                base::seek((base::position() + 3) & ~3, Athena::SeekOrigin::Begin);
            }

            ret->m_details.push_back(detail);
            base::seek(oldPos, Athena::SeekOrigin::Begin);
        }
    }
    catch(...)
    {
        delete ret;
        ret = nullptr;
        throw;
    }

    return ret;
}