Merge branch 'animated-textures-with-model-features' into 'next'

Animated model textures

See merge request STJr/SRB2!2489
This commit is contained in:
kaldrum 2025-03-20 23:33:46 +00:00
commit 8820304cc5
15 changed files with 2077 additions and 921 deletions

View file

@ -47,7 +47,7 @@ EXPORT void HWRAPI(ClearMipMapCache) (void);
EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value);
//Hurdler: added for new development
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface);
EXPORT void HWRAPI(DrawModel) (model_t *model, float frameIndex, float duration, float tics, float nextFrameIndex, float frameIndexStep, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface);
EXPORT void HWRAPI(CreateModelVBOs) (model_t *model);
EXPORT void HWRAPI(SetTransform) (FTransform *ptransform);
EXPORT INT32 HWRAPI(GetTextureUsed) (void);

File diff suppressed because it is too large Load diff

View file

@ -23,13 +23,12 @@
typedef struct
{
size_t index;
char filename[32];
float scale;
float offset;
model_t *model;
void *grpatch;
boolean notexturefile; // true if texture file was not found
void *blendgrpatch;
boolean noblendfile; // true if blend texture file was not found
boolean found;
boolean error;

View file

@ -231,20 +231,12 @@ typedef struct
} md2frame_t;
// Load the model
model_t *MD2_LoadModel(const char *fileName, int ztag, boolean useFloat)
model_t *MD2_LoadModel(char *buffer, int ztag, boolean useFloat)
{
FILE *f;
model_t *retModel = NULL;
md2header_t *header;
size_t fileLen;
int i, j;
size_t namelen;
char *texturefilename;
const char *texPos;
char *buffer;
const float WUNITS = 1.0f;
float dataScale = WUNITS;
@ -271,49 +263,8 @@ model_t *MD2_LoadModel(const char *fileName, int ztag, boolean useFloat)
useFloat = true;
f = fopen(fileName, "rb");
if (!f)
return NULL;
retModel = (model_t*)Z_Calloc(sizeof(model_t), ztag, 0);
//size_t fileLen;
//int i, j;
//size_t namelen;
//char *texturefilename;
texPos = strchr(fileName, '/');
if (texPos)
{
texPos++;
namelen = strlen(texPos) + 1;
texturefilename = (char*)Z_Malloc(namelen, PU_CACHE, 0);
strcpy(texturefilename, texPos);
}
else
{
namelen = strlen(fileName) + 1;
texturefilename = (char*)Z_Malloc(namelen, PU_CACHE, 0);
strcpy(texturefilename, fileName);
}
texturefilename[namelen - 2] = 'z';
texturefilename[namelen - 3] = 'u';
texturefilename[namelen - 4] = 'b';
// find length of file
fseek(f, 0, SEEK_END);
fileLen = ftell(f);
fseek(f, 0, SEEK_SET);
// read in file
buffer = malloc(fileLen);
if (fread(buffer, fileLen, 1, f)) { } // squash ignored fread error
fclose(f);
// get pointer to file header
header = (md2header_t*)buffer;
@ -571,6 +522,5 @@ model_t *MD2_LoadModel(const char *fileName, int ztag, boolean useFloat)
}
}
free(buffer);
return retModel;
}

View file

@ -14,6 +14,6 @@
#include "../doomtype.h"
// Load the Model
model_t *MD2_LoadModel(const char *fileName, int ztag, boolean useFloat);
model_t *MD2_LoadModel(char *buffer, int ztag, boolean useFloat);
#endif

View file

@ -144,20 +144,17 @@ static void LatLngInit(void)
static boolean latlnginit = false;
model_t *MD3_LoadModel(const char *fileName, int ztag, boolean useFloat)
model_t *MD3_LoadModel(char *buffer, 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)
{
@ -165,25 +162,8 @@ model_t *MD3_LoadModel(const char *fileName, int ztag, boolean useFloat)
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;
@ -516,7 +496,5 @@ model_t *MD3_LoadModel(const char *fileName, int ztag, boolean useFloat)
}*/
free(buffer);
return retModel;
}

View file

@ -14,6 +14,6 @@
#include "../doomtype.h"
// Load the Model
model_t *MD3_LoadModel(const char *fileName, int ztag, boolean useFloat);
model_t *MD3_LoadModel(char *buffer, int ztag, boolean useFloat);
#endif

File diff suppressed because it is too large Load diff

View file

@ -10,7 +10,9 @@
#ifndef _HW_MODEL_H_
#define _HW_MODEL_H_
#include "hw_glob.h"
#include "../doomtype.h"
#include "../w_wad.h"
typedef struct
{
@ -78,13 +80,44 @@ typedef struct tag_s
// matrix_t transform;
} tag_t;
#define MODEL_INTERPOLATION_FLAG "+i"
#define MODEL_INTERPOLATION_FLAG 'i'
#define MODEL_EXTEND_FLAG 'e'
#define MODEL_0ANGLE_FLAG 'o'
#define MODEL_NO_0ANGLE_FLAG 'n'
typedef enum
{
MODEL_TYPE_NONE,
MODEL_TYPE_ZIP,
MODEL_TYPE_MD3,
MODEL_TYPE_MD3S,
MODEL_TYPE_MD2,
MODEL_TYPE_MD2S
} modeltype_t;
typedef enum //results from the LoadModelTextures function
{
TEXLOAD_NONE,
TEXLOAD_TEXTURE,
TEXLOAD_BLEND,
} modeltexload_t;
typedef struct
{
patch_t **patches;
UINT8 *frames;
UINT8 numtextures;
} textureframe_t;
typedef struct
{
INT32 frames[256];
UINT8 numframes;
boolean interpolate;
boolean extend;
signed char zeroangle;
textureframe_t textures;
textureframe_t blends;
} modelspr2frames_t;
typedef struct model_s
@ -98,11 +131,20 @@ typedef struct model_s
int numTags;
tag_t *tags;
int startFrame; //starting frame for non-spr2 models, can be used in order to allow multiple sprites to be contained in one md3
char *frameNames;
boolean interpolate[256];
signed char zeroangle[256];
playersprite_t numspr2;
modelspr2frames_t *spr2frames;
modelspr2frames_t *superspr2frames;
textureframe_t *textures;
textureframe_t *blends;
UINT8 numtextures;
UINT8 numblends;
// the max_s and max_t values that the uvs are currently adjusted to
// (if a sprite is used as a texture)
float max_s;
@ -119,15 +161,17 @@ extern model_t *modelHead;
void HWR_ReloadModels(void);
tag_t *GetTagByName(model_t *model, char *name, int frame);
model_t *LoadModel(const char *filename, int ztag);
model_t *LoadModel(const char *filename, int ztag, size_t spriteModelIndex);
void UnloadModel(model_t *model);
modeltype_t GetModelType(const char *name, boolean printfail);
void Optimize(model_t *model);
void LoadModelInterpolationSettings(model_t *model);
void LoadModelSettings(model_t *model, size_t spriteModelIndex);
void LoadModelSprite2(model_t *model);
void GenerateVertexNormals(model_t *model);
void GeneratePolygonNormals(model_t *model, int ztag);
void CreateVBOTiny(mesh_t *mesh, tinyframe_t *frame);
void CreateVBO(mesh_t *mesh, mdlframe_t *frame);
void DeleteVBOs(model_t *model);
modeltexload_t LoadModelTextures(const char *filename, model_t *model, wadfile_t *zip, size_t spriteModelIndex);
#endif

View file

@ -2462,7 +2462,7 @@ EXPORT void HWRAPI(CreateModelVBOs) (model_t *model)
#define BUFFER_OFFSET(i) ((void*)(i))
static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
static void DrawModelEx(model_t *model, float frameIndex, float duration, float tics, float nextFrameIndex, float frameIndexStep, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
{
static GLRGBAFloat poly = {0,0,0,0};
static GLRGBAFloat tint = {0,0,0,0};
@ -2630,11 +2630,40 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float
if (useTinyFrames)
{
tinyframe_t *frame = &mesh->tinyframes[frameIndex % mesh->numFrames];
UINT32 idx = frameIndex;
UINT32 nidx;
float offset = frameIndex - idx;
float step = fabsf(frameIndexStep) * pol;
tinyframe_t *frame = &mesh->tinyframes[idx];
tinyframe_t *nextframe = NULL;
if (nextFrameIndex != -1)
nextframe = &mesh->tinyframes[nextFrameIndex % mesh->numFrames];
if (nextFrameIndex > -1.0f)
{
nidx = nextFrameIndex;
if (nextFrameIndex >= mesh->numFrames)
{
if (model->startFrame)
nidx = model->startFrame;
else
nidx = 0;
}
if (frameIndexStep > 1.0f) //extend the animation beyond the normal allotted amount within the same amount of time, and interpolate
{
idx = ((frameIndex + step >= frameIndex + frameIndexStep) ? nidx : frameIndex + step);
frame = &mesh->tinyframes[idx];
if (nextFrameIndex <= frameIndex && (frameIndex + step >= frameIndex + frameIndexStep - 1))
nextframe = &mesh->tinyframes[nidx];
else
nextframe = &mesh->tinyframes[idx + 1];
}
else if (frameIndexStep < -1.0f) //dont interpolate, still extend
{
idx = ((frameIndex + step >= frameIndex + (-1 * frameIndexStep)) ? nidx : frameIndex + step);
frame = &mesh->tinyframes[idx];
}
else
nextframe = &mesh->tinyframes[nidx];
}
if (!nextframe || fpclassify(pol) == FP_ZERO)
{
@ -2661,17 +2690,21 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float
short *vertPtr;
char *normPtr;
int j = 0;
float inter = pol;
// Dangit, I soooo want to do this in a GLSL shader...
AllocLerpTinyBuffer(mesh->numVertices * sizeof(short) * 3);
vertPtr = vertTinyBuffer;
normPtr = normTinyBuffer;
inter = fmodf(offset + step, 1.0f);
inter = (inter <= 0) ? 1.0f : inter;
for (j = 0; j < mesh->numVertices * 3; j++)
{
// Interpolate
*vertPtr++ = (short)(frame->vertices[j] + (pol * (nextframe->vertices[j] - frame->vertices[j])));
*normPtr++ = (char)(frame->normals[j] + (pol * (nextframe->normals[j] - frame->normals[j])));
*vertPtr++ = (short)(frame->vertices[j] + (inter * (nextframe->vertices[j] - frame->vertices[j])));
*normPtr++ = (char)(frame->normals[j] + (inter * (nextframe->normals[j] - frame->normals[j])));
}
pglVertexPointer(3, GL_SHORT, 0, vertTinyBuffer);
@ -2682,11 +2715,40 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float
}
else
{
mdlframe_t *frame = &mesh->frames[frameIndex % mesh->numFrames];
UINT32 idx = frameIndex;
UINT32 nidx;
float offset = frameIndex - idx;
float step = fabsf(frameIndexStep) * pol;
mdlframe_t *frame = &mesh->frames[idx];
mdlframe_t *nextframe = NULL;
if (nextFrameIndex != -1)
nextframe = &mesh->frames[nextFrameIndex % mesh->numFrames];
if (nextFrameIndex > -1.0f)
{
nidx = nextFrameIndex;
if (nextFrameIndex >= mesh->numFrames)
{
if (model->startFrame)
nidx = model->startFrame;
else
nidx = 0;
}
if (frameIndexStep > 1.0f) //extend the animation beyond the normal allotted amount within the same amount of time, and interpolate
{
idx = ((frameIndex + step >= frameIndex + frameIndexStep) ? nidx : frameIndex + step);
frame = &mesh->frames[idx];
if (nextFrameIndex <= frameIndex && (frameIndex + step >= frameIndex + frameIndexStep - 1))
nextframe = &mesh->frames[nidx];
else
nextframe = &mesh->frames[idx + 1];
}
else if (frameIndexStep < -1.0f) //dont interpolate, still extend
{
idx = ((frameIndex + step >= frameIndex + (-1 * frameIndexStep)) ? nidx : frameIndex + step);
frame = &mesh->frames[idx];
}
else
nextframe = &mesh->frames[nidx];
}
if (!nextframe || fpclassify(pol) == FP_ZERO)
{
@ -2715,6 +2777,7 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float
float *vertPtr;
float *normPtr;
int j = 0;
float inter = pol;
// Dangit, I soooo want to do this in a GLSL shader...
AllocLerpBuffer(mesh->numVertices * sizeof(float) * 3);
@ -2722,11 +2785,14 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float
normPtr = normBuffer;
//int j = 0;
inter = fmodf(offset + step, 1.0f);
inter = (inter <= 0) ? 1.0f : inter;
for (j = 0; j < mesh->numVertices * 3; j++)
{
// Interpolate
*vertPtr++ = frame->vertices[j] + (pol * (nextframe->vertices[j] - frame->vertices[j]));
*normPtr++ = frame->normals[j] + (pol * (nextframe->normals[j] - frame->normals[j]));
*vertPtr++ = frame->vertices[j] + (inter * (nextframe->vertices[j] - frame->vertices[j]));
*normPtr++ = frame->normals[j] + (inter * (nextframe->normals[j] - frame->normals[j]));
}
pglVertexPointer(3, GL_FLOAT, 0, vertBuffer);
@ -2756,9 +2822,9 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float
// -----------------+
// HWRAPI DrawModel : Draw a model
// -----------------+
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
EXPORT void HWRAPI(DrawModel) (model_t *model, float frameIndex, float duration, float tics, float nextFrameIndex, float frameIndexStep, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
{
DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, hscale, vscale, flipped, hflipped, Surface);
DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, frameIndexStep, pos, hscale, vscale, flipped, hflipped, Surface);
}
// -----------------+

View file

@ -828,18 +828,18 @@ state_t states[NUMSTATES] =
// c:
{SPR_PLAY, SPR2_TAL0|FF_SPR2MIDSTART, 5, {NULL}, 0, 0, S_TAILSOVERLAY_STAND, 0}, // S_TAILSOVERLAY_STAND
{SPR_PLAY, SPR2_TAL1|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_0DEGREES, 0}, // S_TAILSOVERLAY_0DEGREES
{SPR_PLAY, SPR2_TAL2|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PLUS30DEGREES, 0}, // S_TAILSOVERLAY_PLUS30DEGREES
{SPR_PLAY, SPR2_TAL3|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PLUS60DEGREES, 0}, // S_TAILSOVERLAY_PLUS60DEGREES
{SPR_PLAY, SPR2_TAL4|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_MINUS30DEGREES, 0}, // S_TAILSOVERLAY_MINUS30DEGREES
{SPR_PLAY, SPR2_TAL5|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_MINUS60DEGREES, 0}, // S_TAILSOVERLAY_MINUS60DEGREES
{SPR_PLAY, SPR2_TAL6|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_RUN, 0}, // S_TAILSOVERLAY_RUN
{SPR_PLAY, SPR2_TAL1|FF_SPR2MIDSTART, 4, {NULL}, 0, 0, S_TAILSOVERLAY_0DEGREES, 0}, // S_TAILSOVERLAY_0DEGREES
{SPR_PLAY, SPR2_TAL2|FF_SPR2MIDSTART, 4, {NULL}, 0, 0, S_TAILSOVERLAY_PLUS30DEGREES, 0}, // S_TAILSOVERLAY_PLUS30DEGREES
{SPR_PLAY, SPR2_TAL3|FF_SPR2MIDSTART, 4, {NULL}, 0, 0, S_TAILSOVERLAY_PLUS60DEGREES, 0}, // S_TAILSOVERLAY_PLUS60DEGREES
{SPR_PLAY, SPR2_TAL4|FF_SPR2MIDSTART, 4, {NULL}, 0, 0, S_TAILSOVERLAY_MINUS30DEGREES, 0}, // S_TAILSOVERLAY_MINUS30DEGREES
{SPR_PLAY, SPR2_TAL5|FF_SPR2MIDSTART, 4, {NULL}, 0, 0, S_TAILSOVERLAY_MINUS60DEGREES, 0}, // S_TAILSOVERLAY_MINUS60DEGREES
{SPR_PLAY, SPR2_TAL6|FF_SPR2MIDSTART, 2, {NULL}, 0, 0, S_TAILSOVERLAY_RUN, 0}, // S_TAILSOVERLAY_RUN
{SPR_PLAY, SPR2_TAL7|FF_SPR2MIDSTART, 4, {NULL}, 0, 0, S_TAILSOVERLAY_FLY, 0}, // S_TAILSOVERLAY_FLY
{SPR_PLAY, SPR2_TAL8|FF_SPR2MIDSTART, 4, {NULL}, 0, 0, S_TAILSOVERLAY_TIRE, 0}, // S_TAILSOVERLAY_TIRE
{SPR_PLAY, SPR2_TAL9|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PAIN, 0}, // S_TAILSOVERLAY_PAIN
{SPR_PLAY, SPR2_TALA|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_GASP, 0}, // S_TAILSOVERLAY_GASP
{SPR_PLAY, SPR2_TALB , 35, {NULL}, 0, 0, S_TAILSOVERLAY_EDGE, 0}, // S_TAILSOVERLAY_EDGE
{SPR_PLAY, SPR2_TALC|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_DASH, 0}, // S_TAILSOVERLAY_DASH
{SPR_PLAY, SPR2_TAL9|FF_SPR2MIDSTART, 4, {NULL}, 0, 0, S_TAILSOVERLAY_PAIN, 0}, // S_TAILSOVERLAY_PAIN
{SPR_PLAY, SPR2_TALA|FF_SPR2MIDSTART, 4, {NULL}, 0, 0, S_TAILSOVERLAY_GASP, 0}, // S_TAILSOVERLAY_GASP
{SPR_PLAY, SPR2_TALB , 12, {NULL}, 0, 0, S_TAILSOVERLAY_EDGE, 0}, // S_TAILSOVERLAY_EDGE
{SPR_PLAY, SPR2_TALC|FF_SPR2MIDSTART, 2, {NULL}, 0, 0, S_TAILSOVERLAY_DASH, 0}, // S_TAILSOVERLAY_DASH
// [:
{SPR_JETF, 3|FF_ANIMATE|FF_FULLBRIGHT, 2, {NULL}, 1, 1, S_JETFUME1, 0}, // S_JETFUMEFLASH

View file

@ -915,14 +915,8 @@ boolean Picture_IsLumpPNG(const UINT8 *d, size_t s)
/*#if PNG_LIBPNG_VER_DLLNUM < 14
typedef PNG_CONST png_byte *png_const_bytep;
#endif*/
typedef struct
{
const UINT8 *buffer;
UINT32 size;
UINT32 position;
} png_io_t;
static void PNG_IOReader(png_structp png_ptr, png_bytep data, png_size_t length)
void PNG_IOReader(png_structp png_ptr, png_bytep data, png_size_t length)
{
png_io_t *f = png_get_io_ptr(png_ptr);
if (length > (f->size - f->position))

View file

@ -17,6 +17,28 @@
#include "r_defs.h"
#include "doomdef.h"
#ifdef HAVE_PNG
#ifndef _MSC_VER
#ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE
#endif
#endif
#ifndef _LFS64_LARGEFILE
#define _LFS64_LARGEFILE
#endif
#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 0
#endif
#include "png.h"
#ifndef PNG_READ_SUPPORTED
#undef HAVE_PNG
#endif
#endif
typedef enum
{
PICFMT_NONE = 0,
@ -78,6 +100,8 @@ void *Picture_GetPatchPixel(
void *Picture_TextureToFlat(size_t texnum);
void PNG_IOReader(png_structp png_ptr, png_bytep data, png_size_t length);
INT32 Picture_FormatBPP(pictureformat_t format);
boolean Picture_IsPatchFormat(pictureformat_t format);
boolean Picture_IsInternalPatchFormat(pictureformat_t format);
@ -118,6 +142,13 @@ void *Picture_PNGConvert(
pictureflags_t flags);
boolean Picture_PNGDimensions(UINT8 *png, INT32 *width, INT32 *height, INT16 *topoffset, INT16 *leftoffset, size_t size);
typedef struct
{
const UINT8 *buffer;
UINT32 size;
UINT32 position;
} png_io_t;
#define PICTURE_PNG_USELOOKUP
#endif

View file

@ -121,22 +121,7 @@ void W_Shutdown(void)
while (numwadfiles--)
{
wadfile_t *wad = wadfiles[numwadfiles];
if (wad->handle)
fclose(wad->handle);
Z_Free(wad->filename);
if (wad->path)
Z_Free(wad->path);
while (wad->numlumps--)
{
if (wad->lumpinfo[wad->numlumps].diskpath)
Z_Free(wad->lumpinfo[wad->numlumps].diskpath);
Z_Free(wad->lumpinfo[wad->numlumps].longname);
Z_Free(wad->lumpinfo[wad->numlumps].fullname);
}
Z_Free(wad->lumpinfo);
Z_Free(wad);
W_DeleteResourceFile(wad);
}
Z_Free(wadfiles);
@ -338,11 +323,36 @@ static void W_InvalidateLumpnumCache(void)
memset(lumpnumcache, 0, sizeof (lumpnumcache));
}
/** Detect a file type.
* \todo Actually detect the wad/pkzip headers and whatnot, instead of just checking the extensions.
*/
static restype_t ResourceFileDetect (const char* filename)
static boolean MagicIsWAD(char id[4])
{
// Very likely a wad
if (!memcmp(id, "IWAD", 4) || !memcmp(id, "PWAD", 4) || !memcmp(id, "ZWAD", 4) || !memcmp(id, "SDLL", 4))
return true;
return false;
}
/** Detect a file type.
*/
static restype_t ResourceFileDetect (FILE* handle, const char* filename)
{
char id[4];
size_t read;
// Read the first four bytes, then seek back
read = fread(&id, 1, sizeof id, handle);
fseek(handle, 0, SEEK_SET);
if (read >= sizeof id)
{
if (MagicIsWAD(id))
return RET_WAD;
// Seems to be a zip (so, a pk3)
else if (!memcmp(id, "PK\x03\x04", 4))
return RET_PK3;
}
if (!stricmp(&filename[strlen(filename) - 4], ".pk3"))
return RET_PK3;
if (!stricmp(&filename[strlen(filename) - 4], ".soc"))
@ -402,9 +412,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
if (memcmp(header.identification, "ZWAD", 4) == 0)
compressed = 1;
else if (memcmp(header.identification, "IWAD", 4) != 0
&& memcmp(header.identification, "PWAD", 4) != 0
&& memcmp(header.identification, "SDLL", 4) != 0)
else if (!MagicIsWAD(header.identification))
{
CONS_Alert(CONS_ERROR, M_GetText("Invalid WAD header\n"));
return NULL;
@ -921,7 +929,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
}
#endif
switch(type = ResourceFileDetect(filename))
switch(type = ResourceFileDetect(handle, filename))
{
case RET_SOC:
lumpinfo = ResGetLumpsStandalone(handle, &numlumps, "OBJCTCFG");
@ -1018,6 +1026,391 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
return wadfile->numlumps;
}
wadfile_t *W_LoadResourceFile(const char *filename)
{
FILE *handle;
lumpinfo_t *lumpinfo = NULL;
restype_t type;
UINT16 numlumps = 0;
// open wad file
if ((handle = fopen(filename, "rb")) == NULL)
{
CONS_Printf(M_GetText("Errors occurred while loading %s.\n"), filename);
return NULL;
}
switch (type = ResourceFileDetect(handle, filename))
{
case RET_PK3:
lumpinfo = ResGetLumpsZip(handle, &numlumps);
break;
case RET_WAD:
lumpinfo = ResGetLumpsWad(handle, &numlumps, filename);
break;
default:
CONS_Alert(CONS_ERROR, "Unsupported file format\n");
}
if (lumpinfo == NULL)
{
fclose(handle);
CONS_Printf(M_GetText("Errors occurred while loading %s.\n"), filename);
return NULL;
}
wadfile_t *wadfile = Z_Malloc(sizeof (*wadfile), PU_STATIC, NULL);
wadfile->filename = Z_StrDup(filename);
wadfile->path = NULL;
wadfile->type = type;
wadfile->handle = handle;
wadfile->numlumps = numlumps;
wadfile->foldercount = 0;
wadfile->lumpinfo = lumpinfo;
wadfile->important = false;
fseek(handle, 0, SEEK_END);
wadfile->filesize = (unsigned)ftell(handle);
// Irrelevant.
memset(wadfile->md5sum, 0x00, 16);
Z_Calloc(numlumps * sizeof (*wadfile->lumpcache), PU_STATIC, &wadfile->lumpcache);
Z_Calloc(numlumps * sizeof (*wadfile->patchcache), PU_STATIC, &wadfile->patchcache);
return wadfile;
}
void W_DeleteResourceFile(wadfile_t *wad)
{
if (!wad)
return;
if (wad->handle)
fclose(wad->handle);
Z_Free(wad->filename);
if (wad->path)
Z_Free(wad->path);
while (wad->numlumps--)
{
Z_Free(wad->lumpcache[wad->numlumps]);
if (wad->patchcache[wad->numlumps])
Patch_Free(wad->patchcache[wad->numlumps]);
if (wad->lumpinfo[wad->numlumps].diskpath)
Z_Free(wad->lumpinfo[wad->numlumps].diskpath);
Z_Free(wad->lumpinfo[wad->numlumps].longname);
Z_Free(wad->lumpinfo[wad->numlumps].fullname);
}
Z_Free(wad->lumpcache);
Z_Free(wad->patchcache);
Z_Free(wad->lumpinfo);
Z_Free(wad);
}
UINT16 Resource_CheckNumForName(wadfile_t *wad, const char *name)
{
lumpinfo_t *lump_p = wad->lumpinfo;
for (UINT16 i = 0; i < wad->numlumps; i++, lump_p++)
if (!strcmp(lump_p->fullname, name))
return i;
// not found.
return INT16_MAX;
}
void *Resource_CacheLumpNum(wadfile_t *wad, UINT16 lump, INT32 tag)
{
if (lump >= wad->numlumps)
return NULL;
lumpcache_t *lumpcache = wad->lumpcache;
if (!lumpcache[lump])
{
void *ptr = Z_Malloc(Resource_LumpLength(wad, lump), tag, &lumpcache[lump]);
Resource_ReadLumpHeader(wad, lump, ptr, 0, 0); // read the lump in full
}
else
Z_ChangeTag(lumpcache[lump], tag);
return lumpcache[lump];
}
void *Resource_CacheLumpName(wadfile_t *wad, const char *name, INT32 tag)
{
UINT16 lumpnum = Resource_CheckNumForName(wad, name);
if (lumpnum == INT16_MAX)
{
CONS_Alert(CONS_ERROR, "Resource file %s does not contain any lump named %s\n", wad->filename, name);
return NULL;
}
return Resource_CacheLumpNum(wad, lumpnum, tag);
}
boolean Resource_LumpExists(wadfile_t *wad, const char *name)
{
return Resource_CheckNumForName(wad, name) != INT16_MAX;
}
size_t Resource_LumpLength(wadfile_t *wad, UINT16 lump)
{
lumpinfo_t *l;
if (lump >= wad->numlumps)
return 0;
l = wad->lumpinfo + lump;
// Open the external file for this lump, if the WAD is a folder.
if (wad->type == RET_FOLDER)
{
// pathisdirectory calls stat, so if anything wrong has happened,
// this is the time to be aware of it.
INT32 stat = pathisdirectory(l->diskpath);
if (stat < 0)
{
#ifndef AVOID_ERRNO
if (direrror == ENOENT)
I_Error("W_LumpLengthPwad: file %s doesn't exist", l->diskpath);
else
I_Error("W_LumpLengthPwad: could not stat %s: %s", l->diskpath, strerror(direrror));
#else
I_Error("W_LumpLengthPwad: could not access %s", l->diskpath);
#endif
}
else if (stat == 1) // Path is a folder.
return 0;
else
{
FILE *handle = fopen(l->diskpath, "rb");
if (handle == NULL)
I_Error("W_LumpLengthPwad: could not open file %s", l->diskpath);
fseek(handle, 0, SEEK_END);
l->size = l->disksize = ftell(handle);
fclose(handle);
}
}
return l->size;
}
size_t Resource_ReadLumpHeader(wadfile_t *wad, UINT16 lump, void *dest, size_t size, size_t offset)
{
size_t lumpsize, bytesread;
lumpinfo_t *l;
FILE *handle = NULL;
if (lump >= wad->numlumps)
return 0;
l = wad->lumpinfo + lump;
// Open the external file for this lump, if the WAD is a folder.
if (wad->type == RET_FOLDER)
{
// pathisdirectory calls stat, so if anything wrong has happened,
// this is the time to be aware of it.
INT32 stat = pathisdirectory(l->diskpath);
if (stat < 0)
{
#ifndef AVOID_ERRNO
if (direrror == ENOENT)
I_Error("Resource_ReadLumpHeader: file %s doesn't exist", l->diskpath);
else
I_Error("Resource_ReadLumpHeader: could not stat %s: %s", l->diskpath, strerror(direrror));
#else
I_Error("Resource_ReadLumpHeader: could not access %s", l->diskpath);
#endif
}
else if (stat == 1) // Path is a folder.
return 0;
else
{
handle = fopen(l->diskpath, "rb");
if (handle == NULL)
I_Error("Resource_ReadLumpHeader: could not open file %s", l->diskpath);
// Find length of file
fseek(handle, 0, SEEK_END);
l->size = l->disksize = ftell(handle);
}
}
lumpsize = wad->lumpinfo[lump].size;
// empty resource (usually markers like S_START, F_END ..)
if (!lumpsize || lumpsize < offset)
{
if (wad->type == RET_FOLDER)
fclose(handle);
return 0;
}
// zero size means read all the lump
if (!size || size + offset > lumpsize)
size = lumpsize - offset;
// Let's get the raw lump data.
// We setup the desired file handle to read the lump data.
if (wad->type != RET_FOLDER)
handle = wad->handle;
fseek(handle, (long)(l->position + offset), SEEK_SET);
// But let's not copy it yet. We support different compression formats on lumps, so we need to take that into account.
switch (wad->lumpinfo[lump].compression)
{
case CM_NOCOMPRESSION: // If it's uncompressed, we directly write the data into our destination, and return the bytes read.
bytesread = fread(dest, 1, size, handle);
if (wad->type == RET_FOLDER)
fclose(handle);
#ifdef NO_PNG_LUMPS
if (Picture_IsLumpPNG((UINT8 *)dest, bytesread))
Picture_ThrowPNGError(l->fullname, wad->filename);
#endif
return bytesread;
case CM_LZF: // Is it LZF compressed? Used by ZWADs.
{
#ifdef ZWAD
char *rawData; // The lump's raw data.
char *decData; // Lump's decompressed real data.
size_t retval; // Helper var, lzf_decompress returns 0 when an error occurs.
rawData = Z_Malloc(l->disksize, PU_STATIC, NULL);
decData = Z_Malloc(l->size, PU_STATIC, NULL);
if (fread(rawData, 1, l->disksize, handle) < l->disksize)
I_Error("wad %s, lump %d: cannot read compressed data", wad->filename, lump);
retval = lzf_decompress(rawData, l->disksize, decData, l->size);
#ifndef AVOID_ERRNO
if (retval == 0) // If this was returned, check if errno was set
{
// errno is a global var set by the lzf functions when something goes wrong.
if (errno == E2BIG)
I_Error("wad %s, lump %d: compressed data too big (bigger than %s)", wad->filename, lump, sizeu1(l->size));
else if (errno == EINVAL)
I_Error("wad %s, lump %d: invalid compressed data", wad->filename, lump);
}
// Otherwise, fall back on below error (if zero was actually the correct size then ???)
#endif
if (retval != l->size)
{
I_Error("wad %s, lump %d: decompressed to wrong number of bytes (expected %s, got %s)", wad->filename, lump, sizeu1(l->size), sizeu2(retval));
}
if (!decData) // Did we get no data at all?
return 0;
M_Memcpy(dest, decData + offset, size);
Z_Free(rawData);
Z_Free(decData);
#ifdef NO_PNG_LUMPS
if (Picture_IsLumpPNG((UINT8 *)dest, size))
Picture_ThrowPNGError(l->fullname, wad->filename);
#endif
return size;
#else
//I_Error("ZWAD files not supported on this platform.");
return 0;
#endif
}
#ifdef HAVE_ZLIB
case CM_DEFLATE: // Is it compressed via DEFLATE? Very common in ZIPs/PK3s, also what most doom-related editors support.
{
UINT8 *rawData; // The lump's raw data.
UINT8 *decData; // Lump's decompressed real data.
int zErr; // Helper var.
z_stream strm;
unsigned long rawSize = l->disksize;
unsigned long decSize = l->size;
rawData = Z_Malloc(rawSize, PU_STATIC, NULL);
decData = Z_Malloc(decSize, PU_STATIC, NULL);
if (fread(rawData, 1, rawSize, handle) < rawSize)
I_Error("wad %s, lump %d: cannot read compressed data", wad->filename, lump);
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.total_in = strm.avail_in = rawSize;
strm.total_out = strm.avail_out = decSize;
strm.next_in = rawData;
strm.next_out = decData;
zErr = inflateInit2(&strm, -15);
if (zErr == Z_OK)
{
zErr = inflate(&strm, Z_FINISH);
if (zErr == Z_STREAM_END)
{
M_Memcpy(dest, decData, size);
}
else
{
size = 0;
zerr(zErr);
}
(void)inflateEnd(&strm);
}
else
{
size = 0;
zerr(zErr);
}
Z_Free(rawData);
Z_Free(decData);
#ifdef NO_PNG_LUMPS
if (Picture_IsLumpPNG((UINT8 *)dest, size))
Picture_ThrowPNGError(l->fullname, wad->filename);
#endif
return size;
}
#endif
default:
I_Error("wad %s, lump %d: unsupported compression type!", wad->filename, lump);
}
return 0;
}
UINT16 Resource_CheckNumForFolderStartPK3(wadfile_t *wad, const char *name, UINT16 startlump){
size_t name_length;
INT32 i;
lumpinfo_t *lump_p = wad->lumpinfo + startlump;
name_length = strlen(name);
for (i = startlump; i < wad->numlumps; i++, lump_p++)
{
if (strnicmp(name, lump_p->fullname, name_length) == 0)
{
/* SLADE is special and puts a single directory entry. Skip that. */
if (strlen(lump_p->fullname) == name_length)
i++;
return i;
}
}
return INT16_MAX;
}
UINT16 Resource_CheckNumForFolderEndPK3(wadfile_t *wad, const char *name, UINT16 startlump){
INT32 i;
lumpinfo_t *lump_p = wad->lumpinfo + startlump;
for (i = startlump; i < wad->numlumps; i++, lump_p++)
{
if (strnicmp(name, lump_p->fullname, strlen(name)))
break;
}
return i;
}
//
// Loads a folder as a WAD.
//
@ -1326,21 +1719,7 @@ W_CheckNumForMarkerStartPwad (const char *name, UINT16 wad, UINT16 startlump)
// Look for the first lump from a folder.
UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump)
{
size_t name_length;
INT32 i;
lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
name_length = strlen(name);
for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
{
if (strnicmp(name, lump_p->fullname, name_length) == 0)
{
/* SLADE is special and puts a single directory entry. Skip that. */
if (strlen(lump_p->fullname) == name_length)
i++;
return i;
}
}
return INT16_MAX;
return Resource_CheckNumForFolderStartPK3(wadfiles[wad], name, startlump);
}
// In a PK3 type of resource file, it looks for the next lumpinfo entry that doesn't share the specified pathfile.
@ -1348,14 +1727,7 @@ UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlum
// Returns the position of the lumpinfo entry.
UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump)
{
INT32 i;
lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
{
if (strnicmp(name, lump_p->fullname, strlen(name)))
break;
}
return i;
return Resource_CheckNumForFolderEndPK3(wadfiles[wad], name, startlump);
}
char *W_GetLumpFolderPathPK3(UINT16 wad, UINT16 lump)
@ -1902,46 +2274,10 @@ UINT8 W_LumpExists(const char *name)
size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump)
{
lumpinfo_t *l;
if (!TestValidLump(wad, lump))
return 0;
l = wadfiles[wad]->lumpinfo + lump;
// Open the external file for this lump, if the WAD is a folder.
if (wadfiles[wad]->type == RET_FOLDER)
{
// pathisdirectory calls stat, so if anything wrong has happened,
// this is the time to be aware of it.
INT32 stat = pathisdirectory(l->diskpath);
if (stat < 0)
{
#ifndef AVOID_ERRNO
if (direrror == ENOENT)
I_Error("W_LumpLengthPwad: file %s doesn't exist", l->diskpath);
else
I_Error("W_LumpLengthPwad: could not stat %s: %s", l->diskpath, strerror(direrror));
#else
I_Error("W_LumpLengthPwad: could not access %s", l->diskpath);
#endif
}
else if (stat == 1) // Path is a folder.
return 0;
else
{
FILE *handle = fopen(l->diskpath, "rb");
if (handle == NULL)
I_Error("W_LumpLengthPwad: could not open file %s", l->diskpath);
fseek(handle, 0, SEEK_END);
l->size = l->disksize = ftell(handle);
fclose(handle);
}
}
return l->size;
return Resource_LumpLength(wadfiles[wad], lump);
}
/** Returns the buffer size needed to load the given lump.
@ -2032,174 +2368,10 @@ void zerr(int ret)
*/
size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, size_t offset)
{
size_t lumpsize, bytesread;
lumpinfo_t *l;
FILE *handle = NULL;
if (!TestValidLump(wad, lump))
return 0;
l = wadfiles[wad]->lumpinfo + lump;
// Open the external file for this lump, if the WAD is a folder.
if (wadfiles[wad]->type == RET_FOLDER)
{
// pathisdirectory calls stat, so if anything wrong has happened,
// this is the time to be aware of it.
INT32 stat = pathisdirectory(l->diskpath);
if (stat < 0)
{
#ifndef AVOID_ERRNO
if (direrror == ENOENT)
I_Error("W_ReadLumpHeaderPwad: file %s doesn't exist", l->diskpath);
else
I_Error("W_ReadLumpHeaderPwad: could not stat %s: %s", l->diskpath, strerror(direrror));
#else
I_Error("W_ReadLumpHeaderPwad: could not access %s", l->diskpath);
#endif
}
else if (stat == 1) // Path is a folder.
return 0;
else
{
handle = fopen(l->diskpath, "rb");
if (handle == NULL)
I_Error("W_ReadLumpHeaderPwad: could not open file %s", l->diskpath);
// Find length of file
fseek(handle, 0, SEEK_END);
l->size = l->disksize = ftell(handle);
}
}
lumpsize = wadfiles[wad]->lumpinfo[lump].size;
// empty resource (usually markers like S_START, F_END ..)
if (!lumpsize || lumpsize<offset)
{
if (wadfiles[wad]->type == RET_FOLDER)
fclose(handle);
return 0;
}
// zero size means read all the lump
if (!size || size+offset > lumpsize)
size = lumpsize - offset;
// Let's get the raw lump data.
// We setup the desired file handle to read the lump data.
if (wadfiles[wad]->type != RET_FOLDER)
handle = wadfiles[wad]->handle;
fseek(handle, (long)(l->position + offset), SEEK_SET);
// But let's not copy it yet. We support different compression formats on lumps, so we need to take that into account.
switch(wadfiles[wad]->lumpinfo[lump].compression)
{
case CM_NOCOMPRESSION: // If it's uncompressed, we directly write the data into our destination, and return the bytes read.
bytesread = fread(dest, 1, size, handle);
if (wadfiles[wad]->type == RET_FOLDER)
fclose(handle);
return bytesread;
case CM_LZF: // Is it LZF compressed? Used by ZWADs.
{
#ifdef ZWAD
char *rawData; // The lump's raw data.
char *decData; // Lump's decompressed real data.
size_t retval; // Helper var, lzf_decompress returns 0 when an error occurs.
rawData = Z_Malloc(l->disksize, PU_STATIC, NULL);
decData = Z_Malloc(l->size, PU_STATIC, NULL);
if (fread(rawData, 1, l->disksize, handle) < l->disksize)
I_Error("wad %d, lump %d: cannot read compressed data", wad, lump);
retval = lzf_decompress(rawData, l->disksize, decData, l->size);
#ifndef AVOID_ERRNO
if (retval == 0) // If this was returned, check if errno was set
{
// errno is a global var set by the lzf functions when something goes wrong.
if (errno == E2BIG)
I_Error("wad %d, lump %d: compressed data too big (bigger than %s)", wad, lump, sizeu1(l->size));
else if (errno == EINVAL)
I_Error("wad %d, lump %d: invalid compressed data", wad, lump);
}
// Otherwise, fall back on below error (if zero was actually the correct size then ???)
#endif
if (retval != l->size)
{
I_Error("wad %d, lump %d: decompressed to wrong number of bytes (expected %s, got %s)", wad, lump, sizeu1(l->size), sizeu2(retval));
}
if (!decData) // Did we get no data at all?
return 0;
M_Memcpy(dest, decData + offset, size);
Z_Free(rawData);
Z_Free(decData);
return size;
#else
//I_Error("ZWAD files not supported on this platform.");
return 0;
#endif
}
#ifdef HAVE_ZLIB
case CM_DEFLATE: // Is it compressed via DEFLATE? Very common in ZIPs/PK3s, also what most doom-related editors support.
{
UINT8 *rawData; // The lump's raw data.
UINT8 *decData; // Lump's decompressed real data.
int zErr; // Helper var.
z_stream strm;
unsigned long rawSize = l->disksize;
unsigned long decSize = l->size;
rawData = Z_Malloc(rawSize, PU_STATIC, NULL);
decData = Z_Malloc(decSize, PU_STATIC, NULL);
if (fread(rawData, 1, rawSize, handle) < rawSize)
I_Error("wad %d, lump %d: cannot read compressed data", wad, lump);
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.total_in = strm.avail_in = rawSize;
strm.total_out = strm.avail_out = decSize;
strm.next_in = rawData;
strm.next_out = decData;
zErr = inflateInit2(&strm, -15);
if (zErr == Z_OK)
{
zErr = inflate(&strm, Z_FINISH);
if (zErr == Z_STREAM_END)
{
M_Memcpy(dest, decData, size);
}
else
{
size = 0;
zerr(zErr);
}
(void)inflateEnd(&strm);
}
else
{
size = 0;
zerr(zErr);
}
Z_Free(rawData);
Z_Free(decData);
return size;
}
#endif
default:
I_Error("wad %d, lump %d: unsupported compression type!", wad, lump);
}
return 0;
return Resource_ReadLumpHeader(wadfiles[wad], lump, dest, size, offset);
}
size_t W_ReadLumpHeader(lumpnum_t lumpnum, void *dest, size_t size, size_t offset)
@ -2229,21 +2401,10 @@ void W_ReadLumpPwad(UINT16 wad, UINT16 lump, void *dest)
// ==========================================================================
void *W_CacheLumpNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
{
lumpcache_t *lumpcache;
if (!TestValidLump(wad,lump))
return NULL;
lumpcache = wadfiles[wad]->lumpcache;
if (!lumpcache[lump])
{
void *ptr = Z_Malloc(W_LumpLengthPwad(wad, lump), tag, &lumpcache[lump]);
W_ReadLumpHeaderPwad(wad, lump, ptr, 0, 0); // read the lump in full
}
else
Z_ChangeTag(lumpcache[lump], tag);
return lumpcache[lump];
return Resource_CacheLumpNum(wadfiles[wad], lump, tag);
}
void *W_CacheLumpNum(lumpnum_t lumpnum, INT32 tag)

View file

@ -160,6 +160,12 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup);
// Adds a folder as a file
UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup);
// Loads a wadfile, but doesn't add it to the active wad files.
wadfile_t *W_LoadResourceFile(const char *filename);
// Deletes a wadfile.
void W_DeleteResourceFile(wadfile_t *wad);
// W_InitMultipleFiles exits if a file was not found, but not if all is okay.
void W_InitMultipleFiles(addfilelist_t *list);
@ -168,6 +174,15 @@ void W_InitMultipleFiles(addfilelist_t *list);
INT32 W_IsPathToFolderValid(const char *path);
char *W_GetFullFolderPath(const char *path);
UINT16 Resource_CheckNumForName(wadfile_t *wad, const char *name);
void *Resource_CacheLumpNum(wadfile_t *wad, UINT16 lump, INT32 tag);
void *Resource_CacheLumpName(wadfile_t *wad, const char *name, INT32 tag);
boolean Resource_LumpExists(wadfile_t *wad, const char *name);
size_t Resource_LumpLength(wadfile_t *wad, UINT16 lump);
size_t Resource_ReadLumpHeader(wadfile_t *wad, UINT16 lump, void *dest, size_t size, size_t offset);
UINT16 Resource_CheckNumForFolderStartPK3(wadfile_t *wad, const char *name, UINT16 startlump);
UINT16 Resource_CheckNumForFolderEndPK3(wadfile_t *wad, const char *name, UINT16 startlump);
const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump);
const char *W_CheckNameForNum(lumpnum_t lumpnum);