#include #include #include #include "mdl.h" #include "ps1mdl.h" #define PALETTE_SIZE 256 #define NUMVERTEXNORMALS 162 static double anorms[NUMVERTEXNORMALS][3] = { #include "../anorms.h" }; int convertPalette(const char* lmpFile) { FILE* fp; const short palette_size = PALETTE_SIZE; unsigned char palette[PALETTE_SIZE * 3]; fopen_s(&fp, lmpFile, "rb"); if (fp == NULL) return 0; fread(palette, sizeof(unsigned char) * 3, PALETTE_SIZE, fp); fclose(fp); int file_size = PALETTE_SIZE * 4 + 24, tmp; fopen_s(&fp, "quake.pal", "wb"); if (fp == NULL) return 0; fwrite("RIFF", sizeof(char), 4, fp); tmp = file_size - 8; fwrite(&tmp, sizeof(int), 1, fp); fwrite("PAL data", sizeof(char), 8, fp); tmp = file_size - 20; fwrite(&tmp, sizeof(int), 1, fp); fwrite("\000\003", sizeof(char), 2, fp); fwrite(&palette_size, sizeof(short), 1, fp); for (int i = 0; i < PALETTE_SIZE; ++i) { fwrite(palette + i * 3, 3, 1, fp); fwrite("\000", sizeof(char), 1, fp); } tmp = 1337; fwrite(&tmp, sizeof(int), 1, fp); fclose(fp); return 1; } static void toFixedVector(const vec3_t inVec, int outVec[3]) { const int scale = 1 << 12; outVec[0] = (int)(inVec[0] * scale); outVec[1] = (int)(inVec[1] * scale); outVec[2] = (int)(inVec[2] * scale); } int convertModel(const char* outFile, const mdl_header_t* inHeader, const mdl_texcoord_t* inTexCoords, const mdl_triangle_t* inTriangles, const mdl_frame_t* inFrames) { FILE* fout; fopen_s(&fout, outFile, "wb"); if (fout == NULL) return 0; // Header ps1mdl_header_t outHeader; outHeader.ident = inHeader->ident; outHeader.version = inHeader->version; toFixedVector(inHeader->scale, outHeader.scale); toFixedVector(inHeader->translate, outHeader.translate); outHeader.skinWidth = (unsigned short)inHeader->skinwidth; outHeader.skinHeight = (unsigned short)inHeader->skinheight; outHeader.vertexCount = (unsigned short)inHeader->num_verts; outHeader.triangleCount = (unsigned short)inHeader->num_tris; outHeader.frameCount = (unsigned short)inHeader->num_frames; outHeader.pad = 0; fwrite(&outHeader, sizeof(ps1mdl_header_t), 1, fout); // Texture coordinates for (int i = 0; i < inHeader->num_verts; ++i) { ps1mdl_texcoord_t outTexCoord; outTexCoord.onSeam = (short)(inTexCoords[i].onseam != 0); outTexCoord.u = (short)inTexCoords[i].s; outTexCoord.v = (short)inTexCoords[i].t; fwrite(&outTexCoord, sizeof(ps1mdl_texcoord_t), 1, fout); } // Triangles for (int i = 0; i < inHeader->num_tris; ++i) { ps1mdl_triangle_t outTriangle; outTriangle.frontFace = (short)(inTriangles[i].facesfront != 0); outTriangle.vertexIndex[0] = (unsigned short)inTriangles[i].vertex[0]; outTriangle.vertexIndex[1] = (unsigned short)inTriangles[i].vertex[1]; outTriangle.vertexIndex[2] = (unsigned short)inTriangles[i].vertex[2]; fwrite(&outTriangle, sizeof(ps1mdl_triangle_t), 1, fout); } // Vertices for (int frameIdx = 0; frameIdx < inHeader->num_frames; ++frameIdx) { for (int i = 0; i < inHeader->num_verts; ++i) { mdl_vertex_t* inVert = &inFrames[frameIdx].frame.verts[i]; ps1mdl_vertex_t outVertex; outVertex.position[0] = inVert->v[0]; outVertex.position[1] = inVert->v[1]; outVertex.position[2] = inVert->v[2]; outVertex.normalIndex = inVert->normalIndex; fwrite(&outVertex, sizeof(ps1mdl_vertex_t), 1, fout); } } fclose(fout); return 1; } void exportNormals() { FILE* fout; fopen_s(&fout, "ps1anorms.h", "w"); if (fout == NULL) return; for (int i = 0; i < NUMVERTEXNORMALS; ++i) { int x = (int)(anorms[i][0] * 4096); int y = (int)(anorms[i][1] * 4096); int z = (int)(anorms[i][2] * 4096); fprintf(fout, "{%d, %d, %d, 0},\n", x, y, z); } fclose(fout); } int main(int argc, char** argv) { FILE* f; mdl_header_t header; char path[_MAX_PATH]; convertPalette(argv[1]); exportNormals(); fopen_s(&f, argv[2], "rb"); if (f == NULL) return 1; fread(&header, sizeof(mdl_header_t), 1, f); printf("Header model identifier: %d, version: %d\n", header.ident, header.version); // Skins printf("Reading %d skins of size: %dx%d\n", header.num_skins, header.skinwidth, header.skinheight); size_t skinSize = header.skinwidth * header.skinheight * sizeof(unsigned char); unsigned char* buf = (unsigned char*)malloc(skinSize); if (!buf) { fclose(f); return 1; } for (int i = 0; i < header.num_skins; ++i) { int group; fread(&group, sizeof(int), 1, f); if (group) { int numPics; fread(&numPics, sizeof(int), 1, f); fseek(f, numPics * sizeof(float) + numPics * skinSize, SEEK_CUR); } else { fread(buf, sizeof(unsigned char), skinSize, f); FILE* fout; sprintf_s(path, _MAX_PATH, "skin_%d_%dx%d.raw", i, header.skinwidth, header.skinheight); fopen_s(&fout, path, "wb"); if (fout == NULL) continue; fwrite(buf, sizeof(unsigned char), skinSize, fout); fclose(fout); } } free(buf); printf("Reading geometry data for %d vertices, %d triangles, %d frames\n", header.num_verts, header.num_tris, header.num_frames); // Texcoords & triangles (vertex indices) mdl_texcoord_t* texCoords = (mdl_texcoord_t*)malloc(sizeof(mdl_texcoord_t) * header.num_verts); mdl_triangle_t* triangles = (mdl_triangle_t*)malloc(sizeof(mdl_triangle_t) * header.num_tris); fread(texCoords, sizeof(mdl_texcoord_t), header.num_verts, f); fread(triangles, sizeof(mdl_triangle_t), header.num_tris, f); // Frames (vertex data) mdl_frame_t* frames = (mdl_frame_t*)malloc(sizeof(mdl_frame_t) * header.num_frames); for (int i = 0; i < header.num_frames; ++i) { frames[i].frame.verts = (mdl_vertex_t*)malloc(sizeof(mdl_vertex_t) * header.num_verts); fread(&frames[i].type, sizeof(int), 1, f); fread(&frames[i].frame.bboxmin, sizeof(mdl_vertex_t), 1, f); fread(&frames[i].frame.bboxmax, sizeof(mdl_vertex_t), 1, f); fread(frames[i].frame.name, sizeof(char), 16, f); fread(frames[i].frame.verts, sizeof(mdl_vertex_t), header.num_verts, f); } fclose(f); // Write simplified model file for PS1 if (!convertModel(argv[3], &header, texCoords, triangles, frames)) return 1; return 0; }