int main() { char* sourcePath = openGMFFile(); char* outputPath = saveGMFFile(); source = fopen(sourcePath, "rb"); output = fopen(outputPath, "w"); if (source == 0 || output == 0) { printf("No file selected, exiting."); return 1; } char *header = getBytes(3); if(strncmp(header, "GMI", 3)) { printf("This is not a valid binary GMF file!\n"); return 1; } printf("Decompiling GMI...\n\n"); delete header; int gmfVersion = getInteger(); fprintf(output, "GMA\n"); fprintf(output, "*GABRIEL_ASCIIEXPORT\t%i\n", gmfVersion); while(!feof(source)) { char* objectType = getBytesNF(8); // Model Type if (!memcmp(objectType, "\x01\x00\x00\x00\x00\x00\x00\x00", 8) || !memcmp(objectType, "\x03\x00\x00\x00\x00\x00\x00\x00", 8) || !memcmp(objectType, "\x02\x00\x00\x00\x00\x00\x00\x00", 8)) { if (!memcmp(objectType, "\x03\x00\x00\x00\x00\x00\x00\x00", 8) || !memcmp(objectType, "\x02\x00\x00\x00\x00\x00\x00\x00", 8)) isRA1 = 1; else isRA1 = 0; getBytes(8); int type = getInteger(); if (type == 15) { fprintf(output, "*MODEL_TYPE\tBasic Model\n"); } else { printf("Unknown Model Type: %d\n", type); return 1; } } // Scene Info else if (!memcmp(objectType, "\x01\x00\x00\x00\x02\x00\x00\x00", 8)) { readSceneInfo(); } // Material Info else if (!memcmp(objectType, "\x07\x00\x00\x00\x02\x00\x00\x00", 8)) { readMaterialList(0); } //Object List else if (!memcmp(objectType, "\x12\x00\x00\x00\x02\x00\x00\x00", 8)) { readObjectList(0); } else { getBytes(8); if (fgetc(source) == EOF) break; printf("Object type unknown!\n"); debugHex(objectType, 8); MessageBox(NULL, "Error! Unknown Object Type!\n","Decompilation unsuccessfull!", MB_OK | MB_ICONWARNING); return 1; } } printf("Decompiled sucessfully!\n"); MessageBox(NULL, "Binary GMF decompiled sucessfully!" ,"Decompilation successfull!", MB_OK); return 0; }
GeometryPtr LoaderDFF::readGeometry(const RWBStream &stream) { auto geomStream = stream.getInnerStream(); auto geomStructID = geomStream.getNextChunk(); if (geomStructID != CHUNK_STRUCT) { throw DFFLoaderException("Geometry missing struct chunk"); } auto geom = std::make_shared<Geometry>(); char *headerPtr = geomStream.getCursor(); geom->flags = *(std::uint16_t *)headerPtr; headerPtr += sizeof(std::uint16_t); /*unsigned short numUVs = *(std::uint8_t*)headerPtr;*/ headerPtr += sizeof(std::uint8_t); /*unsigned short moreFlags = *(std::uint8_t*)headerPtr;*/ headerPtr += sizeof(std::uint8_t); unsigned int numTris = *(std::uint32_t *)headerPtr; headerPtr += sizeof(std::uint32_t); unsigned int numVerts = *(std::uint32_t *)headerPtr; headerPtr += sizeof(std::uint32_t); /*unsigned int numFrames = *(std::uint32_t*)headerPtr;*/ headerPtr += sizeof(std::uint32_t); std::vector<GeometryVertex> verts; verts.resize(numVerts); if (geomStream.getChunkVersion() < 0x1003FFFF) { headerPtr += sizeof(RW::BSGeometryColor); } /// @todo extract magic numbers. if ((geom->flags & 8) == 8) { for (size_t v = 0; v < numVerts; ++v) { verts[v].colour = *(glm::u8vec4 *)headerPtr; headerPtr += sizeof(glm::u8vec4); } } else { for (size_t v = 0; v < numVerts; ++v) { verts[v].colour = {255, 255, 255, 255}; } } if ((geom->flags & 4) == 4 || (geom->flags & 128) == 128) { for (size_t v = 0; v < numVerts; ++v) { verts[v].texcoord = *(glm::vec2 *)headerPtr; headerPtr += sizeof(glm::vec2); } } // Grab indicies data to generate normals (if applicable). RW::BSGeometryTriangle *triangles = (RW::BSGeometryTriangle *)headerPtr; headerPtr += sizeof(RW::BSGeometryTriangle) * numTris; geom->geometryBounds = *(RW::BSGeometryBounds *)headerPtr; geom->geometryBounds.radius = std::abs(geom->geometryBounds.radius); headerPtr += sizeof(RW::BSGeometryBounds); for (size_t v = 0; v < numVerts; ++v) { verts[v].position = *(glm::vec3 *)headerPtr; headerPtr += sizeof(glm::vec3); } if ((geom->flags & 16) == 16) { for (size_t v = 0; v < numVerts; ++v) { verts[v].normal = *(glm::vec3 *)headerPtr; headerPtr += sizeof(glm::vec3); } } else { // Use triangle data to calculate normals for each vert. for (size_t t = 0; t < numTris; ++t) { auto &triangle = triangles[t]; auto &A = verts[triangle.first]; auto &B = verts[triangle.second]; auto &C = verts[triangle.third]; auto normal = glm::normalize( glm::cross(C.position - A.position, B.position - A.position)); A.normal = normal; B.normal = normal; C.normal = normal; } } // Process the geometry child sections for (auto chunkID = geomStream.getNextChunk(); chunkID != 0; chunkID = geomStream.getNextChunk()) { switch (chunkID) { case CHUNK_MATERIALLIST: readMaterialList(geom, geomStream); break; case CHUNK_EXTENSION: readGeometryExtension(geom, geomStream); break; default: break; } } geom->dbuff.setFaceType(geom->facetype == Geometry::Triangles ? GL_TRIANGLES : GL_TRIANGLE_STRIP); geom->gbuff.uploadVertices(verts); geom->dbuff.addGeometry(&geom->gbuff); glGenBuffers(1, &geom->EBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geom->EBO); size_t icount = std::accumulate( geom->subgeom.begin(), geom->subgeom.end(), 0u, [](size_t a, const SubGeometry &b) { return a + b.numIndices; }); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * icount, 0, GL_STATIC_DRAW); for (auto &sg : geom->subgeom) { glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, sg.start * sizeof(uint32_t), sizeof(uint32_t) * sg.numIndices, sg.indices.data()); } return geom; }
int decompile(HWND parent, const LPWSTR sourcePath, const LPWSTR outputPath) { isRA1 = 0; _wfopen_s(&source, sourcePath, L"rb"); _wfopen_s(&output, outputPath, L"w"); if (source == 0 || output == 0) { myprintf("No file selected."); return 1; } char *header = getBytes(3); if(strncmp(header, "GMI", 3)) { myprintf("This is not a valid binary GMF file!\n"); return 1; } free(header); myprintf("Decompiling GMI...\n\n"); int gmfVersion = getInteger(); fprintf(output, "GMA\n"); fprintf(output, "*GABRIEL_ASCIIEXPORT\t%i\n", gmfVersion); while(!feof(source)) { char* objectType = getBytesNF(8); // Model Type if (!memcmp(objectType, "\x01\x00\x00\x00\x00\x00\x00\x00", 8) || !memcmp(objectType, "\x03\x00\x00\x00\x00\x00\x00\x00", 8) || !memcmp(objectType, "\x02\x00\x00\x00\x00\x00\x00\x00", 8)) { if (!memcmp(objectType, "\x03\x00\x00\x00\x00\x00\x00\x00", 8) || !memcmp(objectType, "\x02\x00\x00\x00\x00\x00\x00\x00", 8)) isRA1 = 1; else isRA1 = 0; free(getBytes(8)); int type = getInteger(); if (type == 15) { fprintf(output, "*MODEL_TYPE\tBasic Model\n"); } else { myprintf("Unknown Model Type: %d\n", type); return 1; } } // Scene Info else if (!memcmp(objectType, "\x01\x00\x00\x00\x02\x00\x00\x00", 8)) { readSceneInfo(); } // Material Info else if (!memcmp(objectType, "\x07\x00\x00\x00\x02\x00\x00\x00", 8)) { readMaterialList(0); } //Object List else if (!memcmp(objectType, "\x12\x00\x00\x00\x02\x00\x00\x00", 8)) { readObjectList(0); } else { free(getBytes(8)); if (fgetc(source) == EOF) break; myprintf("Object type unknown!\n"); debugHex(objectType, 8); MessageBox(parent, L"Error! Unknown Object Type!\n",L"Decompilation unsuccessfull!", MB_OK | MB_ICONWARNING); free(objectType); return 1; } free(objectType); } myprintf("Decompiled sucessfully!\n"); MessageBox(parent, L"Binary GMF decompiled sucessfully!" ,L"Decompilation successfull!", MB_OK); fclose(source); fclose(output); return 0; }
int readMaterial() { printInt(8); printInt(2); //Placeholder for length printBytes("\xFF\xFF\xFF\xFF", 4); int beginningOffset = ftell(output); readNothing("*MATERIAL"); openBracket(); int matRefNo = readInt("*MATERIAL_REF_NO"); char* matName = readString("*MATERIAL_NAME"); char* matClass = readString("*MATERIAL_CLASS"); char* matAmbient = readRGB("*MATERIAL_AMBIENT"); char* matDiffuse = readRGB("*MATERIAL_DIFFUSE"); char* matSpecular = readRGB("*MATERIAL_SPECULAR"); float matShine = readFloat("*MATERIAL_SHINE"); float matShineStrength = readFloat("*MATERIAL_SHINESTRENGTH"); float matTransparency = readFloat("*MATERIAL_TRANSPARENCY"); /*float matTransparency; bracketize(); char* buffer = (char*) malloc(sizeof(char)* 24); int offset = ftell(input);*/ float matWireSize = readFloat("*MATERIAL_WIRESIZE"); char* matShading = readString("*MATERIAL_SHADING"); float matXPFallof = readFloat("*MATERIAL_XP_FALLOF"); float matSelfIllum = readFloat("*MATERIAL_SELFILLUM"); char* matFallof = readString("*MATERIAL_FALLOF"); char* matXPType = readString("*MATERIAL_XP_TYPE"); printInt(matRefNo); printString(matName); printString(matClass); printBytes(matAmbient, 4); printBytes(matDiffuse, 4); printBytes(matSpecular, 4); printFloat(matShine); printFloat(matShineStrength); printFloat(matTransparency); printFloat(matWireSize); if(!strncmp(matShading, "Blinn", 5)) printInt(12); else printInt(0); printFloat(matXPFallof); printFloat(matSelfIllum); if(!strncmp(matFallof, "In", 2)) printInt(1); else printInt(0); if(!strncmp(matXPType, "Filter", 6)) printInt(1); else printInt(0); char* nextType = (char*)malloc(sizeof(char)*32); int numMaterials = 0; int numTextures = 0; int tParsed = 0; int mParsed = 0; while(1) { int currentOffset = ftell(input); fscanf(input, "%s\n", nextType); if(!strncmp(nextType, "*TEXTURE_LIST", 14) && tParsed == 0) { //Placeholder for number of textures int numTexturesOffset = ftell(output); printBytes("\xDE\xAD\xBE\xEF", 4); numTextures += readTextureList(); int afterTextureList = ftell(output); fseek(output, numTexturesOffset, 0); printInt(numTextures); fseek(output, afterTextureList, 0); mParsed = 1; } else if(tParsed == 0) { tParsed = 1; printInt(0); } if(!strncmp(nextType, "*MATERIAL_LIST", 14) && mParsed == 0) { //Placeholder for number of textures int numMaterialsOffset = ftell(output); printBytes("\xDE\xAD\xBE\xEF", 4); numMaterials += readMaterialList(); int afterMaterialList = ftell(output); fseek(output, numMaterialsOffset, 0); printInt(numMaterials); fseek(output, afterMaterialList, 0); mParsed = 1; } else if (mParsed == 0) { mParsed = 1; printInt(0); } if(!strncmp(nextType, "}", 1)) { fseek(input, currentOffset, 0); break; } } closeBracket(); int endOffset = ftell(output); int size = endOffset - beginningOffset; fseek(output, beginningOffset - 4, 0); printInt(size); fseek(output, endOffset, 0); return 0; }