models: reuse md2 skins in md5 models

This commit is contained in:
Denis Pauk 2024-01-30 01:16:49 +02:00
parent ca0e150232
commit ded6b9c858
4 changed files with 209 additions and 29 deletions

View file

@ -774,9 +774,13 @@ Mod_LoadModel_MD2(const char *mod_name, const void *buffer, int modfilelen,
for (i = 0; i < pheader->num_skins; i++)
{
char *skin;
skin = (char *)pheader + pheader->ofs_skins + i * MAX_SKINNAME;
skin[MAX_SKINNAME - 1] = 0;
R_Printf(PRINT_DEVELOPER, "%s: %s #%d: Should load external '%s'\n",
__func__, mod_name, i,
(char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME);
__func__, mod_name, i, skin);
}
*type = mod_alias;
@ -784,6 +788,48 @@ Mod_LoadModel_MD2(const char *mod_name, const void *buffer, int modfilelen,
return extradata;
}
static void
Mod_LoadSkinList_MD2(const char *mod_name, const void *buffer, int modfilelen,
char **skins, int *numskins)
{
dmdl_t pinmodel;
int i;
if (modfilelen < sizeof(pinmodel))
{
R_Printf(PRINT_ALL, "%s: %s has incorrect header size (%i should be %ld)",
__func__, mod_name, modfilelen, sizeof(pinmodel));
}
for (i=0 ; i<sizeof(dmdl_t)/sizeof(int) ; i++)
{
((int *)&pinmodel)[i] = LittleLong(((int *)buffer)[i]);
}
if (pinmodel.version != ALIAS_VERSION)
{
R_Printf(PRINT_ALL, "%s: %s has wrong version number (%i should be %i)",
__func__, mod_name, pinmodel.version, ALIAS_VERSION);
}
if (pinmodel.ofs_end < 0 || pinmodel.ofs_end > modfilelen)
{
R_Printf(PRINT_ALL, "%s: model %s file size(%d) too small, should be %d",
__func__, mod_name, modfilelen, pinmodel.ofs_end);
}
if (pinmodel.num_skins < 0)
{
R_Printf(PRINT_ALL, "%s: model %s file has incorrect skins count %d",
__func__, mod_name, pinmodel.num_skins);
}
*numskins = pinmodel.num_skins;
*skins = malloc(pinmodel.num_skins * MAX_SKINNAME);
memcpy(*skins, (char *)buffer + pinmodel.ofs_skins,
pinmodel.num_skins * MAX_SKINNAME);
}
/*
=============
@ -1360,6 +1406,19 @@ Mod_LoadMinMaxUpdate(const char *mod_name, vec3_t mins, vec3_t maxs, void *extra
}
}
static void
Mod_LoadSkinList(const char *mod_name, const void *buffer, int modfilelen,
char **skins, int *numskins)
{
switch (LittleLong(*(unsigned *)buffer))
{
case IDALIASHEADER:
Mod_LoadSkinList_MD2(mod_name, buffer, modfilelen,
skins, numskins);
break;
}
}
/*
=================
Mod_LoadModel
@ -1415,42 +1474,52 @@ Mod_LoadModel(const char *mod_name, const void *buffer, int modfilelen,
return extradata;
}
/* Add md5 to full file name */
static void
Mod_LoadFileInsertMD5(char *newname, const char *oldname, int size)
{
const char *filename;
filename = COM_SkipPath(oldname);
memset(newname, 0, size);
memcpy(newname, oldname, strlen(oldname) - strlen(filename));
Q_strlcat(newname, "md5/", size);
Q_strlcat(newname, filename, size);
}
static int
Mod_LoadFileMD5Merge(const char *namewe, void **buffer)
{
int fullsize, filesize_anim, filesize;
char *final_buffer = NULL;
void *anim_buffer = NULL;
int fullsize, filesize_anim, filesize, filesize_skins;
char *final_buffer = NULL, *skins_list = NULL;
void *anim_buffer = NULL, *skins_buffer = NULL;
qboolean md5path = false;
char newname[256];
/* search mesh file */
Q_strlcpy(newname, namewe, sizeof(newname));
Q_strlcat(newname, ".md5mesh", sizeof(newname));
filesize = ri.FS_LoadFile(newname, buffer);
#if 0
/* check overwrite file */
if (filesize <= 0)
{
const char *model_name;
char model_path[256];
char md5modelname[256];
model_name = COM_SkipPath(namewe);
memset(model_path, 0, sizeof(model_path));
memcpy(model_path, namewe, strlen(namewe) - strlen(model_name));
Mod_LoadFileInsertMD5(md5modelname, newname, sizeof(md5modelname));
Q_strlcpy(newname, model_path, sizeof(newname));
Q_strlcat(newname, "md5/", sizeof(newname));
Q_strlcat(newname, model_name, sizeof(newname));
Q_strlcat(newname, ".md5mesh", sizeof(newname));
filesize = ri.FS_LoadFile(newname, buffer);
filesize = ri.FS_LoadFile(md5modelname, buffer);
/* no replace file */
if (filesize <= 0)
{
return filesize;
}
}
#endif
md5path = true;
strcpy(newname, md5modelname);
}
/* search animation file */
memcpy(newname + strlen(newname) - strlen("mesh"), "anim", strlen("anim"));
filesize_anim = ri.FS_LoadFile(newname, &anim_buffer);
if (filesize_anim <= 0)
@ -1459,13 +1528,63 @@ Mod_LoadFileMD5Merge(const char *namewe, void **buffer)
return filesize;
}
/* search skins list */
Q_strlcpy(newname, namewe, sizeof(newname));
Q_strlcat(newname, ".md2", sizeof(newname));
filesize_skins = ri.FS_LoadFile(newname, &skins_buffer);
if (filesize_skins > 0)
{
char *skins = NULL;
int numskins = 0, i;
Mod_LoadSkinList(newname, skins_buffer, filesize_skins,
&skins, &numskins);
ri.FS_FreeFile(skins_buffer);
/*
* 20 -> numskins <num> | skin <num> "MAX_SKINNAME" + md5
*/
skins_list = malloc((numskins + 1) * (MAX_SKINNAME + 20));
sprintf(skins_list, "\nnumskins %d\n", numskins);
for(i = 0; i < numskins; i++)
{
char *skinname = skins + MAX_SKINNAME * i;
if (!md5path)
{
sprintf(skins_list + strlen(skins_list), "skin %d \"%s\"\n",
i, skinname);
}
else
{
char md5skinname[256];
Mod_LoadFileInsertMD5(md5skinname, skinname, sizeof(md5skinname));
sprintf(skins_list + strlen(skins_list), "skin %d \"%s\"\n",
i, md5skinname);
}
}
}
/* prepare final file */
fullsize = filesize + filesize_anim + 1;
if (skins_list)
{
fullsize += strlen(skins_list);
}
/* allocate new buffer, ERR_FATAL on alloc fail */
final_buffer = ri.FS_AllocFile(fullsize);
/* copy combined information */
memcpy(final_buffer, *buffer, filesize);
if (skins_list)
{
memcpy(final_buffer + filesize, skins_list, strlen(skins_list));
filesize += strlen(skins_list);
free(skins_list);
}
final_buffer[filesize] = 0;
memcpy(final_buffer + filesize + 1, anim_buffer, filesize_anim);

View file

@ -103,12 +103,14 @@ typedef struct md5_model_s
md5_frame_t *skelFrames;
int *vertexIndices;
vec2_t *st;
char *skins;
int num_frames;
int num_joints;
int num_meshes;
int num_verts;
int num_tris;
int num_skins;
int frameRate;
} md5_model_t;
@ -569,6 +571,58 @@ ReadMD5Model(const char *buffer, size_t size)
return NULL;
}
}
else if (sscanf(buff, "numskins %d", &mdl->num_skins) == 1)
{
if (mdl->num_skins > 0)
{
mdl->skins = malloc(mdl->num_skins * MAX_SKINNAME);
memset(mdl->skins, 0, mdl->num_skins * MAX_SKINNAME);
}
}
else if (strncmp (buff, "skin ", 5) == 0)
{
const char *token;
char *line;
int pos;
line = buff + 5;
token = COM_Parse(&line);
pos = (int)strtol(token, (char **)NULL, 10);
if (pos < mdl->num_skins)
{
int quote = 0, j = 0;
char *skinname;
skinname = mdl->skins + pos * MAX_SKINNAME;
/* Copy the shader name whithout the quote marks */
while (*line)
{
if (*line == '"')
{
quote++;
if (quote >= 2)
{
break;
}
}
else if (quote == 1)
{
if ((j >= (MAX_SKINNAME - 1)))
{
break;
}
skinname[j] = *line;
j ++;
}
line ++;
}
}
}
else if (sscanf(buff, "numJoints %d", &mdl->num_joints) == 1)
{
if (mdl->num_joints > 0)
@ -753,6 +807,12 @@ FreeModelMd5(md5_model_t *mdl)
mdl->baseSkel = NULL;
}
if (mdl->skins)
{
free(mdl->skins);
mdl->skins = NULL;
}
if (mdl->meshes)
{
/* Free mesh data */
@ -1050,7 +1110,7 @@ Mod_LoadModel_MD5(const char *mod_name, const void *buffer, int modfilelen,
int framesize = sizeof(daliasxframe_t) + sizeof(dxtrivertx_t) * num_verts;
int ofs_skins = sizeof(dmdx_t);
int ofs_frames = ofs_skins + md5file->num_meshes * MAX_SKINNAME;
int ofs_frames = ofs_skins + md5file->num_skins * MAX_SKINNAME;
int ofs_glcmds = ofs_frames + framesize * md5file->num_frames;
int ofs_meshes = ofs_glcmds + num_glcmds * sizeof(int);
int ofs_tris = ofs_meshes + md5file->num_tris * sizeof(dtriangle_t);
@ -1059,7 +1119,7 @@ Mod_LoadModel_MD5(const char *mod_name, const void *buffer, int modfilelen,
dmdx_t *pheader = NULL;
*numskins = md5file->num_meshes;
*numskins = md5file->num_skins;
extradata = Hunk_Begin(ofs_end + Q_max(*numskins, MAX_MD2SKINS) * sizeof(struct image_s *));
pheader = Hunk_Alloc(ofs_end);
*skins = Hunk_Alloc((*numskins) * sizeof(struct image_s *));
@ -1139,18 +1199,19 @@ Mod_LoadModel_MD5(const char *mod_name, const void *buffer, int modfilelen,
num_tris += md5file->meshes[i].num_tris; // vertexIndices
}
memset((char *)pheader + pheader->ofs_skins, 0,
/* register all skins */
memcpy((char *)pheader + pheader->ofs_skins, md5file->skins,
pheader->num_skins * MAX_SKINNAME);
/* use meshes names as replacement for skins */
for (i = 0; i < pheader->num_skins; i++)
{
strncpy((char *)pheader + pheader->ofs_skins + i * MAX_SKINNAME,
md5file->meshes[i].shader, MAX_SKINNAME - 1);
char *skin;
skin = (char *)pheader + pheader->ofs_skins + i * MAX_SKINNAME;
skin[MAX_SKINNAME - 1] = 0;
R_Printf(PRINT_DEVELOPER, "%s: %s #%d: Should load external '%s'\n",
__func__, mod_name, i,
(char *)pheader + pheader->ofs_skins + i * MAX_SKINNAME);
__func__, mod_name, i, skin);
}
if (md5file)

View file

@ -143,7 +143,7 @@ LoadPCX(const char *origname, byte **pic, byte **palette, int *width, int *heigh
if (!raw || len < sizeof(pcx_t))
{
R_Printf(PRINT_DEVELOPER, "Bad pcx file %s\n", filename);
R_Printf(PRINT_DEVELOPER, "Bad pcx file %s, length %d\n", filename, len);
return;
}

View file

@ -421,7 +421,7 @@ FS_FOpenFile(const char *rawname, fileHandle_t *f, qboolean gamedir_only)
// Evil hack for maps.lst and players/
// TODO: A flag to ignore paks would be better
if ((strcmp(fs_gamedirvar->string, "") == 0) && search->pack) {
if ((strcmp(name, "maps.lst") == 0)|| (strncmp(name, "players/", 8) == 0)) {
if ((strcmp(name, "maps.lst") == 0) || (strncmp(name, "players/", 8) == 0)) {
continue;
}
}