mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2024-12-23 11:10:56 +00:00
522 lines
14 KiB
C
522 lines
14 KiB
C
/*
|
|
From the 'Wizard2' engine by Spaddlewit Inc. ( http://www.spaddlewit.com )
|
|
An experimental work-in-progress.
|
|
|
|
Donated to Sonic Team Junior and adapted to work with
|
|
Sonic Robo Blast 2. The license of this code matches whatever
|
|
the licensing is for Sonic Robo Blast 2.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "../doomdef.h"
|
|
#include "hw_md3load.h"
|
|
#include "hw_model.h"
|
|
#include "../z_zone.h"
|
|
|
|
typedef struct
|
|
{
|
|
int ident; // A "magic number" that's used to identify the .md3 file
|
|
int version; // The version of the file, always 15
|
|
char name[64];
|
|
int flags;
|
|
int numFrames; // Number of frames
|
|
int numTags;
|
|
int numSurfaces;
|
|
int numSkins; // Number of skins with the model
|
|
int offsetFrames;
|
|
int offsetTags;
|
|
int offsetSurfaces;
|
|
int offsetEnd; // Offset, in bytes from the start of the file, to the end of the file (filesize)
|
|
} md3modelHeader;
|
|
|
|
typedef struct
|
|
{
|
|
float minBounds[3]; // First corner of the bounding box
|
|
float maxBounds[3]; // Second corner of the bounding box
|
|
float localOrigin[3]; // Local origin, usually (0, 0, 0)
|
|
float radius; // Radius of bounding sphere
|
|
char name[16]; // Name of frame
|
|
} md3Frame;
|
|
|
|
typedef struct
|
|
{
|
|
char name[64]; // Name of tag
|
|
float origin[3]; // Coordinates of tag
|
|
float axis[9]; // Orientation of tag object
|
|
} md3Tag;
|
|
|
|
typedef struct
|
|
{
|
|
int ident;
|
|
char name[64]; // Name of this surface
|
|
int flags;
|
|
int numFrames; // # of keyframes
|
|
int numShaders; // # of shaders
|
|
int numVerts; // # of vertices
|
|
int numTriangles; // # of triangles
|
|
int offsetTriangles; // Relative offset from start of this struct to where the list of Triangles start
|
|
int offsetShaders; // Relative offset from start of this struct to where the list of Shaders start
|
|
int offsetST; // Relative offset from start of this struct to where the list of tex coords start
|
|
int offsetXYZNormal; // Relative offset from start of this struct to where the list of vertices start
|
|
int offsetEnd; // Relative offset from start of this struct to where this surface ends
|
|
} md3Surface;
|
|
|
|
typedef struct
|
|
{
|
|
char name[64]; // Name of this shader
|
|
int shaderIndex; // Shader index number
|
|
} md3Shader;
|
|
|
|
typedef struct
|
|
{
|
|
int index[3]; // List of offset values into the list of Vertex objects that constitute the corners of the Triangle object.
|
|
} md3Triangle;
|
|
|
|
typedef struct
|
|
{
|
|
float st[2];
|
|
} md3TexCoord;
|
|
|
|
typedef struct
|
|
{
|
|
short x, y, z, n;
|
|
} md3Vertex;
|
|
|
|
static float latlnglookup[256][256][3];
|
|
|
|
static void GetNormalFromLatLong(short latlng, float *out)
|
|
{
|
|
float *lookup = latlnglookup[(unsigned char)(latlng >> 8)][(unsigned char)(latlng & 255)];
|
|
|
|
out[0] = *lookup++;
|
|
out[1] = *lookup++;
|
|
out[2] = *lookup++;
|
|
}
|
|
|
|
#if 0
|
|
static void NormalToLatLng(float *n, short *out)
|
|
{
|
|
// Special cases
|
|
if (0.0f == n[0] && 0.0f == n[1])
|
|
{
|
|
if (n[2] > 0.0f)
|
|
*out = 0;
|
|
else
|
|
*out = 128;
|
|
}
|
|
else
|
|
{
|
|
char x, y;
|
|
|
|
x = (char)(57.2957795f * (atan2(n[1], n[0])) * (255.0f / 360.0f));
|
|
y = (char)(57.2957795f * (acos(n[2])) * (255.0f / 360.0f));
|
|
|
|
*out = (x << 8) + y;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static inline void LatLngToNormal(short n, float *out)
|
|
{
|
|
const float PI = (3.1415926535897932384626433832795f);
|
|
float lat = (float)(n >> 8);
|
|
float lng = (float)(n & 255);
|
|
|
|
lat *= PI / 128.0f;
|
|
lng *= PI / 128.0f;
|
|
|
|
out[0] = cosf(lat) * sinf(lng);
|
|
out[1] = sinf(lat) * sinf(lng);
|
|
out[2] = cosf(lng);
|
|
}
|
|
|
|
static void LatLngInit(void)
|
|
{
|
|
int i, j;
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
for (j = 0; j < 256; j++)
|
|
LatLngToNormal((short)((i << 8) + j), latlnglookup[i][j]);
|
|
}
|
|
}
|
|
|
|
static boolean latlnginit = false;
|
|
|
|
model_t *MD3_LoadModel(const char *fileName, int ztag, boolean useFloat)
|
|
{
|
|
const float WUNITS = 1.0f;
|
|
model_t *retModel = NULL;
|
|
md3Frame *frames = NULL;
|
|
char *fname = NULL;
|
|
md3modelHeader *mdh;
|
|
long fileLen;
|
|
long fileReadLen;
|
|
char *buffer;
|
|
int surfEnd;
|
|
int i, t;
|
|
int matCount;
|
|
FILE *f;
|
|
|
|
if (!latlnginit)
|
|
{
|
|
LatLngInit();
|
|
latlnginit = true;
|
|
}
|
|
|
|
f = fopen(fileName, "rb");
|
|
|
|
if (!f)
|
|
return NULL;
|
|
|
|
retModel = (model_t*)Z_Calloc(sizeof(model_t), ztag, 0);
|
|
|
|
// find length of file
|
|
fseek(f, 0, SEEK_END);
|
|
fileLen = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
|
|
// read in file
|
|
buffer = malloc(fileLen);
|
|
fileReadLen = fread(buffer, fileLen, 1, f);
|
|
fclose(f);
|
|
|
|
(void)fileReadLen; // intentionally ignore return value, per buildbot
|
|
|
|
// get pointer to file header
|
|
mdh = (md3modelHeader*)buffer;
|
|
|
|
retModel->numMeshes = mdh->numSurfaces;
|
|
|
|
retModel->numMaterials = 0;
|
|
surfEnd = 0;
|
|
for (i = 0; i < mdh->numSurfaces; i++)
|
|
{
|
|
md3Surface *mdS = (md3Surface*)&buffer[mdh->offsetSurfaces];
|
|
surfEnd += mdS->offsetEnd;
|
|
|
|
retModel->numMaterials += mdS->numShaders;
|
|
}
|
|
|
|
// Initialize materials
|
|
if (retModel->numMaterials <= 0) // Always at least one skin, duh
|
|
retModel->numMaterials = 1;
|
|
|
|
retModel->materials = (material_t*)Z_Calloc(sizeof(material_t)*retModel->numMaterials, ztag, 0);
|
|
|
|
for (t = 0; t < retModel->numMaterials; t++)
|
|
{
|
|
retModel->materials[t].ambient[0] = 0.3686f;
|
|
retModel->materials[t].ambient[1] = 0.3684f;
|
|
retModel->materials[t].ambient[2] = 0.3684f;
|
|
retModel->materials[t].ambient[3] = 1.0f;
|
|
retModel->materials[t].diffuse[0] = 0.8863f;
|
|
retModel->materials[t].diffuse[1] = 0.8850f;
|
|
retModel->materials[t].diffuse[2] = 0.8850f;
|
|
retModel->materials[t].diffuse[3] = 1.0f;
|
|
retModel->materials[t].emissive[0] = 0.0f;
|
|
retModel->materials[t].emissive[1] = 0.0f;
|
|
retModel->materials[t].emissive[2] = 0.0f;
|
|
retModel->materials[t].emissive[3] = 1.0f;
|
|
retModel->materials[t].specular[0] = 0.4902f;
|
|
retModel->materials[t].specular[1] = 0.4887f;
|
|
retModel->materials[t].specular[2] = 0.4887f;
|
|
retModel->materials[t].specular[3] = 1.0f;
|
|
retModel->materials[t].shininess = 25.0f;
|
|
retModel->materials[t].spheremap = false;
|
|
}
|
|
|
|
retModel->meshes = (mesh_t*)Z_Calloc(sizeof(mesh_t)*retModel->numMeshes, ztag, 0);
|
|
|
|
frames = (md3Frame*)&buffer[mdh->offsetFrames];
|
|
retModel->framenames = (char*)Z_Calloc(mdh->numFrames*16, ztag, 0);
|
|
fname = retModel->framenames;
|
|
for (i = 0; i < mdh->numFrames; i++)
|
|
{
|
|
memcpy(fname, frames->name, 16);
|
|
fname += 16;
|
|
frames++;
|
|
}
|
|
|
|
matCount = 0;
|
|
for (i = 0, surfEnd = 0; i < mdh->numSurfaces; i++)
|
|
{
|
|
int j;
|
|
md3Shader *mdShader;
|
|
md3Surface *mdS = (md3Surface*)&buffer[mdh->offsetSurfaces + surfEnd];
|
|
surfEnd += mdS->offsetEnd;
|
|
|
|
mdShader = (md3Shader*)((char*)mdS + mdS->offsetShaders);
|
|
|
|
for (j = 0; j < mdS->numShaders; j++, matCount++)
|
|
{
|
|
size_t len = strlen(mdShader[j].name);
|
|
mdShader[j].name[len-1] = 'z';
|
|
mdShader[j].name[len-2] = 'u';
|
|
mdShader[j].name[len-3] = 'b';
|
|
|
|
// Load material
|
|
/* retModel->materials[matCount].texture = Texture::ReadTexture(mdShader[j].name, ZT_TEXTURE);
|
|
|
|
if (!systemSucks)
|
|
{
|
|
// Check for a normal map...??
|
|
char openfilename[1024];
|
|
char normalMapName[1024];
|
|
strcpy(normalMapName, mdShader[j].name);
|
|
len = strlen(normalMapName);
|
|
char *ptr = &normalMapName[len];
|
|
ptr--; // z
|
|
ptr--; // u
|
|
ptr--; // b
|
|
ptr--; // .
|
|
*ptr++ = '_';
|
|
*ptr++ = 'n';
|
|
*ptr++ = '.';
|
|
*ptr++ = 'b';
|
|
*ptr++ = 'u';
|
|
*ptr++ = 'z';
|
|
*ptr++ = '\0';
|
|
|
|
sprintf(openfilename, "%s/%s", "textures", normalMapName);
|
|
// Convert backslashes to forward slashes
|
|
for (int k = 0; k < 1024; k++)
|
|
{
|
|
if (openfilename[k] == '\0')
|
|
break;
|
|
|
|
if (openfilename[k] == '\\')
|
|
openfilename[k] = '/';
|
|
}
|
|
|
|
Resource::resource_t *res = Resource::Open(openfilename);
|
|
if (res)
|
|
{
|
|
Resource::Close(res);
|
|
retModel->materials[matCount].lightmap = Texture::ReadTexture(normalMapName, ZT_TEXTURE);
|
|
}
|
|
}*/
|
|
}
|
|
|
|
retModel->meshes[i].numFrames = mdS->numFrames;
|
|
retModel->meshes[i].numTriangles = mdS->numTriangles;
|
|
|
|
if (!useFloat) // 'tinyframe' mode with indices
|
|
{
|
|
float tempNormal[3];
|
|
float *uvptr;
|
|
md3TexCoord *mdST;
|
|
unsigned short *indexptr;
|
|
md3Triangle *mdT;
|
|
|
|
retModel->meshes[i].tinyframes = (tinyframe_t*)Z_Calloc(sizeof(tinyframe_t)*mdS->numFrames, ztag, 0);
|
|
retModel->meshes[i].numVertices = mdS->numVerts;
|
|
retModel->meshes[i].uvs = (float*)Z_Malloc(sizeof(float)*2*mdS->numVerts, ztag, 0);
|
|
for (j = 0; j < mdS->numFrames; j++)
|
|
{
|
|
short *vertptr;
|
|
char *normptr;
|
|
// char *tanptr;
|
|
int k;
|
|
md3Vertex *mdV = (md3Vertex*)((char*)mdS + mdS->offsetXYZNormal + (mdS->numVerts*j*sizeof(md3Vertex)));
|
|
retModel->meshes[i].tinyframes[j].vertices = (short*)Z_Malloc(sizeof(short)*3*mdS->numVerts, ztag, 0);
|
|
retModel->meshes[i].tinyframes[j].normals = (char*)Z_Malloc(sizeof(char)*3*mdS->numVerts, ztag, 0);
|
|
|
|
// if (retModel->materials[0].lightmap)
|
|
// retModel->meshes[i].tinyframes[j].tangents = (char*)malloc(sizeof(char));//(char*)Z_Malloc(sizeof(char)*3*mdS->numVerts, ztag);
|
|
retModel->meshes[i].indices = (unsigned short*)Z_Malloc(sizeof(unsigned short) * 3 * mdS->numTriangles, ztag, 0);
|
|
vertptr = retModel->meshes[i].tinyframes[j].vertices;
|
|
normptr = retModel->meshes[i].tinyframes[j].normals;
|
|
|
|
// tanptr = retModel->meshes[i].tinyframes[j].tangents;
|
|
retModel->meshes[i].tinyframes[j].material = &retModel->materials[i];
|
|
|
|
for (k = 0; k < mdS->numVerts; k++)
|
|
{
|
|
// Vertex
|
|
*vertptr = mdV[k].x;
|
|
vertptr++;
|
|
*vertptr = mdV[k].z;
|
|
vertptr++;
|
|
*vertptr = 1.0f - mdV[k].y;
|
|
vertptr++;
|
|
|
|
// Normal
|
|
GetNormalFromLatLong(mdV[k].n, tempNormal);
|
|
*normptr = (char)(tempNormal[0] * 127);
|
|
normptr++;
|
|
*normptr = (char)(tempNormal[2] * 127);
|
|
normptr++;
|
|
*normptr = (char)(tempNormal[1] * 127);
|
|
normptr++;
|
|
}
|
|
}
|
|
|
|
uvptr = (float*)retModel->meshes[i].uvs;
|
|
mdST = (md3TexCoord*)((char*)mdS + mdS->offsetST);
|
|
for (j = 0; j < mdS->numVerts; j++)
|
|
{
|
|
*uvptr = mdST[j].st[0];
|
|
uvptr++;
|
|
*uvptr = mdST[j].st[1];
|
|
uvptr++;
|
|
}
|
|
|
|
indexptr = retModel->meshes[i].indices;
|
|
mdT = (md3Triangle*)((char*)mdS + mdS->offsetTriangles);
|
|
for (j = 0; j < mdS->numTriangles; j++, mdT++)
|
|
{
|
|
// Indices
|
|
*indexptr = (unsigned short)mdT->index[0];
|
|
indexptr++;
|
|
*indexptr = (unsigned short)mdT->index[1];
|
|
indexptr++;
|
|
*indexptr = (unsigned short)mdT->index[2];
|
|
indexptr++;
|
|
}
|
|
}
|
|
else // Traditional full-float loading method
|
|
{
|
|
float dataScale = 0.015624f * WUNITS;
|
|
float tempNormal[3];
|
|
md3TexCoord *mdST;
|
|
md3Triangle *mdT;
|
|
float *uvptr;
|
|
int k;
|
|
|
|
retModel->meshes[i].numVertices = mdS->numTriangles * 3;//mdS->numVerts;
|
|
retModel->meshes[i].frames = (mdlframe_t*)Z_Calloc(sizeof(mdlframe_t)*mdS->numFrames, ztag, 0);
|
|
retModel->meshes[i].uvs = (float*)Z_Malloc(sizeof(float)*2*mdS->numTriangles*3, ztag, 0);
|
|
|
|
for (j = 0; j < mdS->numFrames; j++)
|
|
{
|
|
float *vertptr;
|
|
float *normptr;
|
|
md3Vertex *mdV = (md3Vertex*)((char*)mdS + mdS->offsetXYZNormal + (mdS->numVerts*j*sizeof(md3Vertex)));
|
|
retModel->meshes[i].frames[j].vertices = (float*)Z_Malloc(sizeof(float)*3*mdS->numTriangles*3, ztag, 0);
|
|
retModel->meshes[i].frames[j].normals = (float*)Z_Malloc(sizeof(float)*3*mdS->numTriangles*3, ztag, 0);
|
|
// if (retModel->materials[i].lightmap)
|
|
// retModel->meshes[i].frames[j].tangents = (float*)malloc(sizeof(float));//(float*)Z_Malloc(sizeof(float)*3*mdS->numTriangles*3, ztag);
|
|
vertptr = retModel->meshes[i].frames[j].vertices;
|
|
normptr = retModel->meshes[i].frames[j].normals;
|
|
retModel->meshes[i].frames[j].material = &retModel->materials[i];
|
|
|
|
mdT = (md3Triangle*)((char*)mdS + mdS->offsetTriangles);
|
|
|
|
for (k = 0; k < mdS->numTriangles; k++)
|
|
{
|
|
// Vertex 1
|
|
*vertptr = mdV[mdT->index[0]].x * dataScale;
|
|
vertptr++;
|
|
*vertptr = mdV[mdT->index[0]].z * dataScale;
|
|
vertptr++;
|
|
*vertptr = 1.0f - mdV[mdT->index[0]].y * dataScale;
|
|
vertptr++;
|
|
|
|
GetNormalFromLatLong(mdV[mdT->index[0]].n, tempNormal);
|
|
*normptr = tempNormal[0];
|
|
normptr++;
|
|
*normptr = tempNormal[2];
|
|
normptr++;
|
|
*normptr = tempNormal[1];
|
|
normptr++;
|
|
|
|
// Vertex 2
|
|
*vertptr = mdV[mdT->index[1]].x * dataScale;
|
|
vertptr++;
|
|
*vertptr = mdV[mdT->index[1]].z * dataScale;
|
|
vertptr++;
|
|
*vertptr = 1.0f - mdV[mdT->index[1]].y * dataScale;
|
|
vertptr++;
|
|
|
|
GetNormalFromLatLong(mdV[mdT->index[1]].n, tempNormal);
|
|
*normptr = tempNormal[0];
|
|
normptr++;
|
|
*normptr = tempNormal[2];
|
|
normptr++;
|
|
*normptr = tempNormal[1];
|
|
normptr++;
|
|
|
|
// Vertex 3
|
|
*vertptr = mdV[mdT->index[2]].x * dataScale;
|
|
vertptr++;
|
|
*vertptr = mdV[mdT->index[2]].z * dataScale;
|
|
vertptr++;
|
|
*vertptr = 1.0f - mdV[mdT->index[2]].y * dataScale;
|
|
vertptr++;
|
|
|
|
GetNormalFromLatLong(mdV[mdT->index[2]].n, tempNormal);
|
|
*normptr = tempNormal[0];
|
|
normptr++;
|
|
*normptr = tempNormal[2];
|
|
normptr++;
|
|
*normptr = tempNormal[1];
|
|
normptr++;
|
|
|
|
mdT++; // Advance to next triangle
|
|
}
|
|
}
|
|
|
|
mdST = (md3TexCoord*)((char*)mdS + mdS->offsetST);
|
|
uvptr = (float*)retModel->meshes[i].uvs;
|
|
mdT = (md3Triangle*)((char*)mdS + mdS->offsetTriangles);
|
|
|
|
for (k = 0; k < mdS->numTriangles; k++)
|
|
{
|
|
*uvptr = mdST[mdT->index[0]].st[0];
|
|
uvptr++;
|
|
*uvptr = mdST[mdT->index[0]].st[1];
|
|
uvptr++;
|
|
|
|
*uvptr = mdST[mdT->index[1]].st[0];
|
|
uvptr++;
|
|
*uvptr = mdST[mdT->index[1]].st[1];
|
|
uvptr++;
|
|
|
|
*uvptr = mdST[mdT->index[2]].st[0];
|
|
uvptr++;
|
|
*uvptr = mdST[mdT->index[2]].st[1];
|
|
uvptr++;
|
|
|
|
mdT++; // Advance to next triangle
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
// Tags?
|
|
retModel->numTags = mdh->numTags;
|
|
retModel->maxNumFrames = mdh->numFrames;
|
|
retModel->tags = (tag_t*)Z_Calloc(sizeof(tag_t) * retModel->numTags * mdh->numFrames, ztag);
|
|
md3Tag *mdTag = (md3Tag*)&buffer[mdh->offsetTags];
|
|
tag_t *curTag = retModel->tags;
|
|
for (i = 0; i < mdh->numFrames; i++)
|
|
{
|
|
int j;
|
|
for (j = 0; j < retModel->numTags; j++, mdTag++)
|
|
{
|
|
strcpys(curTag->name, mdTag->name, sizeof(curTag->name) / sizeof(char));
|
|
curTag->transform.m[0][0] = mdTag->axis[0];
|
|
curTag->transform.m[0][1] = mdTag->axis[1];
|
|
curTag->transform.m[0][2] = mdTag->axis[2];
|
|
curTag->transform.m[1][0] = mdTag->axis[3];
|
|
curTag->transform.m[1][1] = mdTag->axis[4];
|
|
curTag->transform.m[1][2] = mdTag->axis[5];
|
|
curTag->transform.m[2][0] = mdTag->axis[6];
|
|
curTag->transform.m[2][1] = mdTag->axis[7];
|
|
curTag->transform.m[2][2] = mdTag->axis[8];
|
|
curTag->transform.m[3][0] = mdTag->origin[0] * WUNITS;
|
|
curTag->transform.m[3][1] = mdTag->origin[1] * WUNITS;
|
|
curTag->transform.m[3][2] = mdTag->origin[2] * WUNITS;
|
|
curTag->transform.m[3][3] = 1.0f;
|
|
|
|
Matrix::Rotate(&curTag->transform, 90.0f, &Vector::Xaxis);
|
|
curTag++;
|
|
}
|
|
}*/
|
|
|
|
|
|
free(buffer);
|
|
|
|
return retModel;
|
|
}
|