Tools for preprocessing data files from Quake to make them suitable for use on PS1 hardware
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

227 lines
6.0 KiB

#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#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;
}