From 2bce4961703a81359071bee0d2318dcd94b7d8a8 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Fri, 19 Apr 2024 06:23:19 -0500 Subject: [PATCH 01/30] ? --- src/hardware/hw_drv.h | 2 +- src/hardware/hw_md2.c | 112 ++++++++++++++++++++++--------- src/hardware/hw_model.c | 103 +++++++++++++++++++--------- src/hardware/hw_model.h | 13 +++- src/hardware/r_opengl/r_opengl.c | 82 +++++++++++++++++++--- 5 files changed, 236 insertions(+), 76 deletions(-) diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 45ee2933a..02448b0c8 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -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); diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 0bb8de851..31b483a86 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -92,14 +92,14 @@ static void md2_freeModel (model_t *model) // load model // // Hurdler: the current path is the Legacy.exe path -static model_t *md2_readModel(const char *filename) +static model_t *md2_readModel(const char *filename, size_t spriteModelIndex) { //Filename checking fixed ~Monster Iestyn and Golden if (FIL_FileExists(va("%s"PATHSEP"%s", srb2home, filename))) - return LoadModel(va("%s"PATHSEP"%s", srb2home, filename), PU_STATIC); + return LoadModel(va("%s"PATHSEP"%s", srb2home, filename), PU_STATIC, spriteModelIndex); if (FIL_FileExists(va("%s"PATHSEP"%s", srb2path, filename))) - return LoadModel(va("%s"PATHSEP"%s", srb2path, filename), PU_STATIC); + return LoadModel(va("%s"PATHSEP"%s", srb2path, filename), PU_STATIC, spriteModelIndex); return NULL; } @@ -1064,7 +1064,7 @@ static boolean HWR_CanInterpolateModel(mobj_t *mobj, model_t *model) { if (cv_glmodelinterpolation.value == 2) // Always interpolate return true; - return model->interpolate[(mobj->frame & FF_FRAMEMASK)]; + return model->interpolate[(mobj->frame & FF_FRAMEMASK) + model->startFrame]; } static boolean HWR_CanInterpolateSprite2(modelspr2frames_t *spr2frame) @@ -1093,19 +1093,22 @@ static modelspr2frames_t *HWR_GetModelSprite2Frames(md2_t *md2, UINT16 spr2) return &md2->model->superspr2frames[spr2]; } - if (md2->model->spr2frames) + if (md2->model->spr2frames[spr2].numframes) return &md2->model->spr2frames[spr2]; return NULL; } -static modelspr2frames_t *HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT16 spr2, player_t *player) +static modelspr2frames_t *HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT16 spr2, player_t *player, UINT16 *spr2out) { UINT16 super = 0; UINT8 i = 0; if (!md2 || !md2->model || !skin) + { + *spr2out = 0; return HWR_GetModelSprite2Frames(md2, 0); + } while (!HWR_GetModelSprite2Frames(md2, spr2) && spr2 != SPR2_STND @@ -1144,7 +1147,7 @@ static modelspr2frames_t *HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT16 s if (i >= 32) // probably an infinite loop... spr2 = 0; - + *spr2out = spr2; return HWR_GetModelSprite2Frames(md2, spr2); } @@ -1199,8 +1202,9 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) md2_t *md2; char filename[64]; - INT32 frame = 0; - INT32 nextFrame = -1; + float frame = 0.0f; + float nextFrame = -1.0f; + float frameStep = 1.0f; modelspr2frames_t *spr2frames = NULL; FTransform p; FSurfaceInfo Surf; @@ -1269,8 +1273,10 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(spr->mobj)); const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !R_ThingHorizontallyFlipped(spr->mobj)); spritedef_t *sprdef; + UINT16 spr2; spriteframe_t *sprframe; INT32 mod; + INT8 zeroangle; interpmobjstate_t interp; if (R_UsingFrameInterpolation() && !paused) @@ -1351,7 +1357,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) { //CONS_Debug(DBG_RENDER, "Loading model... (%s)", sprnames[spr->mobj->sprite]); sprintf(filename, "models/%s", md2->filename); - md2->model = md2_readModel(filename); + md2->model = md2_readModel(filename, spr->mobj->sprite); if (md2->model) { @@ -1438,23 +1444,34 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) frame = (spr->mobj->frame & FF_FRAMEMASK); if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) - spr2frames = HWR_GetModelSprite2(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player); + { + spr2 = 0; //need this for setting the mod correctly when spr2defaults stuff happens + spr2frames = HWR_GetModelSprite2(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player, &spr2); + } if (spr2frames) { + spritedef_t *defaultdef = P_GetSkinSpritedef(spr->mobj->skin, spr2); mod = spr2frames->numframes; -#ifndef DONTHIDEDIFFANIMLENGTH // by default, different anim length is masked by the mod - if (mod > (INT32)sprdef->numframes) - mod = sprdef->numframes; -#endif + + if (mod > (INT32)defaultdef->numframes) + { + frameStep = (float)mod/defaultdef->numframes; + if (!spr2frames->extend) + mod = defaultdef->numframes; + else if (defaultdef->numframes < sprdef->numframes) + mod = defaultdef->numframes; + } + if (!mod) mod = 1; - frame = spr2frames->frames[frame % mod]; + frame = spr2frames->frames[0] + (fmodf(frame, mod) * frameStep); } else { - mod = md2->model->meshes[0].numFrames; + mod = md2->model->meshes[0].numFrames - md2->model->startFrame; if (!mod) mod = 1; + frame = fmodf(frame, mod) + md2->model->startFrame; } #ifdef USE_MODEL_NEXTFRAME @@ -1463,11 +1480,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) #define INTERPOLERATION_LIMIT (TICRATE * 0.25f) - if (cv_glmodelinterpolation.value && tics <= durs && tics <= INTERPOLERATION_LIMIT) + if (cv_glmodelinterpolation.value && tics <= durs) { - if (durs > INTERPOLERATION_LIMIT) - durs = INTERPOLERATION_LIMIT; - if (spr2frames) { UINT16 next_spr2 = P_GetStateSprite2(&states[spr->mobj->state->nextstate]); @@ -1481,37 +1495,69 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) && states[spr->mobj->state->nextstate].sprite == SPR_PLAY && ((P_GetSkinSprite2(spr->mobj->skin, next_spr2, spr->mobj->player) == spr->mobj->sprite2))))) { - nextFrame = (spr->mobj->frame & FF_FRAMEMASK) + 1; - if (nextFrame >= mod) + nextFrame = 1.0f + (spr->mobj->frame & FF_FRAMEMASK); + if (nextFrame * frameStep >= mod) { if (spr->mobj->state->frame & FF_SPR2ENDSTATE) nextFrame--; else - nextFrame = 0; + nextFrame = 0.0f; } - if (frame || !(spr->mobj->state->frame & FF_SPR2ENDSTATE)) - nextFrame = spr2frames->frames[nextFrame]; + if ((INT32)frame || !(spr->mobj->state->frame & FF_SPR2ENDSTATE)) + nextFrame = spr2frames->frames[0] + (fmodf(nextFrame, mod) * frameStep); else - nextFrame = -1; + nextFrame = -1.0f; } } - else if (HWR_CanInterpolateModel(spr->mobj, md2->model)) + else if (HWR_CanInterpolateModel(spr->mobj, md2->model) && tics <= INTERPOLERATION_LIMIT) { + if (durs > INTERPOLERATION_LIMIT) + durs = INTERPOLERATION_LIMIT; + //this only applies now to non-player models, as the extend frames would allow someone to create a similar effect manually + // frames are handled differently for states with FF_ANIMATE, so get the next frame differently for the interpolation if (spr->mobj->frame & FF_ANIMATE) { nextFrame = (spr->mobj->frame & FF_FRAMEMASK) + 1; if (nextFrame >= (INT32)(spr->mobj->state->var1 + (spr->mobj->state->frame & FF_FRAMEMASK))) - nextFrame = (spr->mobj->state->frame & FF_FRAMEMASK) % mod; + nextFrame = (spr->mobj->state->frame & FF_FRAMEMASK) % mod + md2->model->startFrame; } else { if (spr->mobj->state->nextstate != S_NULL && states[spr->mobj->state->nextstate].sprite != SPR_NULL && !(spr->mobj->player && (spr->mobj->state->nextstate == S_PLAY_WAIT) && spr->mobj->state == &states[S_PLAY_STND])) - nextFrame = (states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK) % mod; + nextFrame = (states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK) % mod + md2->model->startFrame; } } } + if (spr2frames){ + if ((!HWR_CanInterpolateSprite2(spr2frames)|| !cv_glmodelinterpolation.value) && spr2frames->extend) + { + + UINT16 next_spr2 = P_GetStateSprite2(&states[spr->mobj->state->nextstate]); + next_spr2 = P_ApplySuperFlagToSprite2(next_spr2, spr->mobj); + if (spr->mobj->frame & FF_ANIMATE + || (spr->mobj->state->nextstate != S_NULL + && states[spr->mobj->state->nextstate].sprite == SPR_PLAY + && ((P_GetSkinSprite2(spr->mobj->skin, next_spr2, spr->mobj->player) == spr->mobj->sprite2)))) + { + nextFrame = 1.0f + (spr->mobj->frame & FF_FRAMEMASK); + if (nextFrame * frameStep >= mod) + { + if (spr->mobj->state->frame & FF_SPR2ENDSTATE) + nextFrame--; + else + nextFrame = 0.0f; + } + if ((INT32)frame || !(spr->mobj->state->frame & FF_SPR2ENDSTATE)) + nextFrame = spr2frames->frames[0] + (fmodf(nextFrame, mod) * frameStep); + else + nextFrame = -1.0f; + frameStep *= -1.0f; //use negative framestep to indicate extend without interpolation (also keeps value) + } + } + + } #undef INTERPOLERATION_LIMIT #endif @@ -1528,7 +1574,9 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) sprframe = &sprdef->spriteframes[spr->mobj->frame & FF_FRAMEMASK]; - if (sprframe->rotate || papersprite) + zeroangle = spr2frames ? spr2frames->zeroangle : md2->model->zeroangle[(spr->mobj->frame & FF_FRAMEMASK) + md2->model->startFrame]; + + if ((sprframe->rotate || papersprite || zeroangle == -1) && zeroangle != 1) { fixed_t anglef = AngleFixed(interp.angle); @@ -1589,7 +1637,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) p.y += ox * gl_viewcos; p.z += oy; - HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, md2->scale * xs, md2->scale * ys, flip, hflip, &Surf); + HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, frameStep, &p, md2->scale * xs, md2->scale * ys, flip, hflip, &Surf); } } diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index 5856473e4..81c4c3cc3 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -145,7 +145,7 @@ tag_t *GetTagByName(model_t *model, char *name, int frame) // // Load a model and convert it to the internal format. // -model_t *LoadModel(const char *filename, int ztag) +model_t *LoadModel(const char *filename, int ztag, size_t spriteModelIndex) { model_t *model; @@ -197,7 +197,7 @@ model_t *LoadModel(const char *filename, int ztag) GeneratePolygonNormals(model, ztag); LoadModelSprite2(model); if (!model->spr2frames) - LoadModelInterpolationSettings(model); + LoadModelSettings(model, spriteModelIndex); // Default material properties for (i = 0 ; i < model->numMaterials; i++) @@ -245,47 +245,70 @@ void HWR_ReloadModels(void) for (i = 0; i < numsprites; i++) { if (md2_models[i].model) - LoadModelInterpolationSettings(md2_models[i].model); + LoadModelSettings(md2_models[i].model, i); } } -void LoadModelInterpolationSettings(model_t *model) +void LoadModelSettings(model_t *model, size_t spriteModelIndex) { INT32 i; + INT32 start = -1; INT32 numframes = model->meshes[0].numFrames; char *framename = model->frameNames; if (!framename) return; - #define GET_OFFSET \ - memcpy(&interpolation_flag, framename + offset, 2); \ - model->interpolate[i] = (!memcmp(interpolation_flag, MODEL_INTERPOLATION_FLAG, 2)); - for (i = 0; i < numframes; i++) { - int offset = (strlen(framename) - 4); - char interpolation_flag[3]; - memset(&interpolation_flag, 0x00, 3); - - // find the +i on the frame name - // ANIM+i00 - // so the offset is (frame name length - 4) - GET_OFFSET; - - // maybe the frame had three digits? - // ANIM+i000 - // so the offset is (frame name length - 5) - if (!model->interpolate[i]) + char name[5]; + memset(&name, 0x00, 5); + memcpy(&name, framename, 4); + for (size_t j = 0; j < NUMSPRITES; j++) { - offset--; - GET_OFFSET; + if (!memcmp(sprnames[j], name, 5)) + { + if (&md2_models[j] == &md2_models[spriteModelIndex]) + { + start = i; + break; + } + } } - + if (start != -1) + break; framename += 16; } + start = (start == -1)? 0 : start; + model->startFrame = start; + framename = model->frameNames + 16 * start; + for (i = start; i < numframes; i++) + { + //int offset = (strlen(framename) - 4); + char *modelframeflags = framename + 4; + //char name[5]; + char flags[4]; + memset(&flags, 0x00, 4); + memcpy(&flags, modelframeflags, 3); + model->interpolate[i] = false; + model->zeroangle[i] = 0; - #undef GET_OFFSET + if (flags[0] == '+') + { + for (int j = 1; j < 2; j++) + { + if (flags[j] == MODEL_INTERPOLATION_FLAG) + model->interpolate[i] = true; + else if (flags[j] == MODEL_0ANGLE_FLAG) + model->zeroangle[i] = 1; + else if (flags[j] == MODEL_NO_0ANGLE_FLAG) + model->zeroangle[i] = -1; + else + break; + } + } + framename += 16; + } } void LoadModelSprite2(model_t *model) @@ -303,15 +326,17 @@ void LoadModelSprite2(model_t *model) { char prefix[6]; char name[5]; - char interpolation_flag[3]; + char flags[5]; char framechars[4]; UINT8 frame = 0; UINT8 spr2idx; boolean interpolate = false; + boolean extend = false; //allow animation to go over default sprite length + INT8 zeroangle = 0; //-1 remove all, 0 follow sprites, 1 force all memset(&prefix, 0x00, 6); memset(&name, 0x00, 5); - memset(&interpolation_flag, 0x00, 3); + memset(&flags, 0x00, 5); memset(&framechars, 0x00, 4); if (strlen(framename) >= 9) @@ -323,11 +348,24 @@ void LoadModelSprite2(model_t *model) memcpy(&name, modelframename, 4); modelframename += 4; // Oh look - memcpy(&interpolation_flag, modelframename, 2); - if (!memcmp(interpolation_flag, MODEL_INTERPOLATION_FLAG, 2)) + memcpy(&flags, modelframename, 4); + if (flags[0] == '+') { - interpolate = true; - modelframename += 2; + modelframename++; + for (int j = 1; j < 4; j++) + { + if (flags[j] == MODEL_INTERPOLATION_FLAG) + interpolate = true; + else if (flags[j] == MODEL_EXTEND_FLAG) + extend = true; + else if (flags[j] == MODEL_0ANGLE_FLAG) + zeroangle = 1; + else if (flags[j] == MODEL_NO_0ANGLE_FLAG) + zeroangle = -1; + else + break; + modelframename++; + } } memcpy(&framechars, modelframename, 3); @@ -363,6 +401,9 @@ void LoadModelSprite2(model_t *model) } frames[spr2idx].frames[frame] = i; frames[spr2idx].interpolate = interpolate; + frames[spr2idx].extend = extend; + frames[spr2idx].zeroangle = zeroangle; + break; } spr2idx++; diff --git a/src/hardware/hw_model.h b/src/hardware/hw_model.h index 5eb649b17..a4ee11b3e 100644 --- a/src/hardware/hw_model.h +++ b/src/hardware/hw_model.h @@ -78,13 +78,18 @@ 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 struct { INT32 frames[256]; UINT8 numframes; boolean interpolate; + boolean extend; + INT8 zeroangle; } modelspr2frames_t; typedef struct model_s @@ -98,8 +103,10 @@ 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]; + INT8 zeroangle[256]; modelspr2frames_t *spr2frames; modelspr2frames_t *superspr2frames; @@ -119,10 +126,10 @@ 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); 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); diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 75a92c2fb..208e698ae 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -2464,7 +2464,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}; @@ -2632,11 +2632,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) { @@ -2669,6 +2698,9 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float vertPtr = vertTinyBuffer; normPtr = normTinyBuffer; + pol = fmodf(offset + step, 1.0f); + pol = (pol <= 0) ? 1.0f : pol; + for (j = 0; j < mesh->numVertices * 3; j++) { // Interpolate @@ -2684,11 +2716,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) { @@ -2724,6 +2785,9 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float normPtr = normBuffer; //int j = 0; + pol = fmodf(offset + step, 1.0f); + pol = (pol <= 0) ? 1.0f : pol; + for (j = 0; j < mesh->numVertices * 3; j++) { // Interpolate @@ -2758,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); } // -----------------+ From 4df41ccf4d92874845d88efc13213c8d0eb37d69 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Sat, 20 Apr 2024 17:20:06 -0500 Subject: [PATCH 02/30] fixed compiler compat errors, support for long sprite names --- src/hardware/hw_md2.c | 9 +++-- src/hardware/hw_model.c | 90 ++++++++++++++++++++++++----------------- src/hardware/hw_model.h | 4 +- 3 files changed, 59 insertions(+), 44 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 31b483a86..a27af39ea 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1276,7 +1276,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) UINT16 spr2; spriteframe_t *sprframe; INT32 mod; - INT8 zeroangle; + signed char zeroangle; interpmobjstate_t interp; if (R_UsingFrameInterpolation() && !paused) @@ -1518,15 +1518,16 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) // frames are handled differently for states with FF_ANIMATE, so get the next frame differently for the interpolation if (spr->mobj->frame & FF_ANIMATE) { - nextFrame = (spr->mobj->frame & FF_FRAMEMASK) + 1; + nextFrame = fmodf((spr->mobj->frame & FF_FRAMEMASK) + 1, mod); if (nextFrame >= (INT32)(spr->mobj->state->var1 + (spr->mobj->state->frame & FF_FRAMEMASK))) - nextFrame = (spr->mobj->state->frame & FF_FRAMEMASK) % mod + md2->model->startFrame; + nextFrame = fmodf((spr->mobj->state->frame & FF_FRAMEMASK), mod); + nextFrame += md2->model->startFrame; } else { if (spr->mobj->state->nextstate != S_NULL && states[spr->mobj->state->nextstate].sprite != SPR_NULL && !(spr->mobj->player && (spr->mobj->state->nextstate == S_PLAY_WAIT) && spr->mobj->state == &states[S_PLAY_STND])) - nextFrame = (states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK) % mod + md2->model->startFrame; + nextFrame = fmodf((states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK), mod) + md2->model->startFrame; } } } diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index 81c4c3cc3..83cff73f2 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -252,63 +252,77 @@ void HWR_ReloadModels(void) void LoadModelSettings(model_t *model, size_t spriteModelIndex) { INT32 i; + INT32 count = 0; INT32 start = -1; INT32 numframes = model->meshes[0].numFrames; char *framename = model->frameNames; + char namechars; + char lastframename[16]; + memset(&lastframename, 0x00, 16); + memcpy(&lastframename, framename, 16); if (!framename) return; for (i = 0; i < numframes; i++) { - char name[5]; - memset(&name, 0x00, 5); - memcpy(&name, framename, 4); - for (size_t j = 0; j < NUMSPRITES; j++) + model->interpolate[i] = false; + model->zeroangle[i] = 0; + count++; + namechars = strlen(framename);//framename can only be up to 16 chars so for very long sprite names this will just not work (current/default still will) + namechars-= 1 + floor(log10(count));//get digits of frame so they can be ignored + //theres a padded 0 for counts under 10, but this can be useful for determining if a '+' suffix is added and the count needs to be reset + if (memcmp(framename, &lastframename, namechars)) + count = 0; + else if (count != atoi(framename + namechars + ((log10(count) < 2)? 0 : 1)))//if the counts dont match, set to 0 (should only happen if the frames are named really weirdly) + count = 0; + namechars = strlen(framename) - 1 - (log10(count) < 2 ? 2 : floor(log10(count))); + for (int j = 0; j < namechars; j++) { - if (!memcmp(sprnames[j], name, 5)) + if (*(framename + j) == '+') //should add frame flags regardless of name prefix { - if (&md2_models[j] == &md2_models[spriteModelIndex]) + namechars = j; + char flags[4]; + memset(&flags, 0x00, 4); + memcpy(&flags, framename + j, 3); + for (int l = 1; l < 3; l ++) { - start = i; - break; + if (flags[l] == MODEL_INTERPOLATION_FLAG){ + model->interpolate[i] = true; + } + //model->interpolate[i] = true; + else if (flags[l] == MODEL_0ANGLE_FLAG) + model->zeroangle[i] = 1; + else if (flags[l] == MODEL_NO_0ANGLE_FLAG) + model->zeroangle[i] = -1; + else + break; + } + break; + } + } + if (start == -1){ + for (size_t k = 0; k < NUMSPRITES; k++)//numsprites? + { + + if (!memcmp(sprnames[k], framename, namechars)) + { + if (&md2_models[k] == &md2_models[spriteModelIndex]) + { + start = i; + break; + } } } } - if (start != -1) - break; + memset(&lastframename, 0x00, 16); + memcpy(&lastframename, framename, 16); + namechars = 0; framename += 16; } start = (start == -1)? 0 : start; model->startFrame = start; framename = model->frameNames + 16 * start; - for (i = start; i < numframes; i++) - { - //int offset = (strlen(framename) - 4); - char *modelframeflags = framename + 4; - //char name[5]; - char flags[4]; - memset(&flags, 0x00, 4); - memcpy(&flags, modelframeflags, 3); - model->interpolate[i] = false; - model->zeroangle[i] = 0; - - if (flags[0] == '+') - { - for (int j = 1; j < 2; j++) - { - if (flags[j] == MODEL_INTERPOLATION_FLAG) - model->interpolate[i] = true; - else if (flags[j] == MODEL_0ANGLE_FLAG) - model->zeroangle[i] = 1; - else if (flags[j] == MODEL_NO_0ANGLE_FLAG) - model->zeroangle[i] = -1; - else - break; - } - } - framename += 16; - } } void LoadModelSprite2(model_t *model) @@ -332,7 +346,7 @@ void LoadModelSprite2(model_t *model) UINT8 spr2idx; boolean interpolate = false; boolean extend = false; //allow animation to go over default sprite length - INT8 zeroangle = 0; //-1 remove all, 0 follow sprites, 1 force all + char zeroangle = 0; //-1 remove all, 0 follow sprites, 1 force all memset(&prefix, 0x00, 6); memset(&name, 0x00, 5); diff --git a/src/hardware/hw_model.h b/src/hardware/hw_model.h index a4ee11b3e..64c4b367a 100644 --- a/src/hardware/hw_model.h +++ b/src/hardware/hw_model.h @@ -89,7 +89,7 @@ typedef struct UINT8 numframes; boolean interpolate; boolean extend; - INT8 zeroangle; + signed char zeroangle; } modelspr2frames_t; typedef struct model_s @@ -106,7 +106,7 @@ typedef struct model_s 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]; - INT8 zeroangle[256]; + signed char zeroangle[256]; modelspr2frames_t *spr2frames; modelspr2frames_t *superspr2frames; From 36bcf2c6dbb1384930b874e3314cc8d4ee7dc795 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Sat, 20 Apr 2024 18:14:19 -0500 Subject: [PATCH 03/30] one last thing --- src/hardware/hw_md2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index a27af39ea..8c6a67357 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1273,7 +1273,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(spr->mobj)); const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !R_ThingHorizontallyFlipped(spr->mobj)); spritedef_t *sprdef; - UINT16 spr2; + UINT16 spr2 = 0; spriteframe_t *sprframe; INT32 mod; signed char zeroangle; @@ -1445,7 +1445,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) frame = (spr->mobj->frame & FF_FRAMEMASK); if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) { - spr2 = 0; //need this for setting the mod correctly when spr2defaults stuff happens + //spr2 = 0; //need this for setting the mod correctly when spr2defaults stuff happens spr2frames = HWR_GetModelSprite2(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player, &spr2); } if (spr2frames) From 7bca1a47ea6dfa57c624e7e42a1416fba423a7bd Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Tue, 23 Apr 2024 04:31:03 -0500 Subject: [PATCH 04/30] Fixed interpolation getting distorted as mesh objects are iterated --- src/hardware/hw_model.c | 4 +--- src/hardware/r_opengl/r_opengl.c | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index 83cff73f2..e5d3aa900 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -287,10 +287,8 @@ void LoadModelSettings(model_t *model, size_t spriteModelIndex) memcpy(&flags, framename + j, 3); for (int l = 1; l < 3; l ++) { - if (flags[l] == MODEL_INTERPOLATION_FLAG){ + if (flags[l] == MODEL_INTERPOLATION_FLAG) model->interpolate[i] = true; - } - //model->interpolate[i] = true; else if (flags[l] == MODEL_0ANGLE_FLAG) model->zeroangle[i] = 1; else if (flags[l] == MODEL_NO_0ANGLE_FLAG) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 208e698ae..739907199 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -2692,20 +2692,21 @@ static void DrawModelEx(model_t *model, float 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; - pol = fmodf(offset + step, 1.0f); - pol = (pol <= 0) ? 1.0f : pol; + 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); @@ -2778,6 +2779,7 @@ static void DrawModelEx(model_t *model, float 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); @@ -2785,14 +2787,14 @@ static void DrawModelEx(model_t *model, float frameIndex, float duration, float normPtr = normBuffer; //int j = 0; - pol = fmodf(offset + step, 1.0f); - pol = (pol <= 0) ? 1.0f : pol; + 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); From c64832e3792416c10537e873918c1bd8b58f1444 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Tue, 23 Apr 2024 15:00:45 -0500 Subject: [PATCH 05/30] test at making available frames tied to mobj states only for spr2s, instead of existing sprite spr2s --- src/hardware/hw_md2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 8c6a67357..acd97da00 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1446,7 +1446,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) { //spr2 = 0; //need this for setting the mod correctly when spr2defaults stuff happens - spr2frames = HWR_GetModelSprite2(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player, &spr2); + spr2frames = HWR_GetModelSprite2(md2, spr->mobj->skin, P_GetStateSprite2(spr->mobj->state), spr->mobj->player, &spr2); } if (spr2frames) { @@ -1493,7 +1493,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) && (spr->mobj->frame & FF_ANIMATE || (spr->mobj->state->nextstate != S_NULL && states[spr->mobj->state->nextstate].sprite == SPR_PLAY - && ((P_GetSkinSprite2(spr->mobj->skin, next_spr2, spr->mobj->player) == spr->mobj->sprite2))))) + && ((next_spr2 == P_ApplySuperFlagToSprite2(P_GetStateSprite2(spr->mobj->state), spr->mobj)))))) { nextFrame = 1.0f + (spr->mobj->frame & FF_FRAMEMASK); if (nextFrame * frameStep >= mod) @@ -1540,7 +1540,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) if (spr->mobj->frame & FF_ANIMATE || (spr->mobj->state->nextstate != S_NULL && states[spr->mobj->state->nextstate].sprite == SPR_PLAY - && ((P_GetSkinSprite2(spr->mobj->skin, next_spr2, spr->mobj->player) == spr->mobj->sprite2)))) + && ((next_spr2 == P_ApplySuperFlagToSprite2(P_GetStateSprite2(spr->mobj->state), spr->mobj))))) { nextFrame = 1.0f + (spr->mobj->frame & FF_FRAMEMASK); if (nextFrame * frameStep >= mod) From 4935072898b274e6dfcfc1b60502da0e1791a035 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Tue, 23 Apr 2024 16:57:42 -0500 Subject: [PATCH 06/30] fixed state checks for spr2 frames not included in the sprites, very hacky way to keep extended model interpolation working at 35 fps --- src/hardware/hw_md2.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index acd97da00..74ecffd3e 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -39,6 +39,7 @@ #include "../r_things.h" #include "../r_draw.h" #include "../p_tick.h" +#include "../i_time.h" //uhhh #include "hw_model.h" #include "hw_main.h" @@ -1099,16 +1100,13 @@ static modelspr2frames_t *HWR_GetModelSprite2Frames(md2_t *md2, UINT16 spr2) return NULL; } -static modelspr2frames_t *HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT16 spr2, player_t *player, UINT16 *spr2out) +static UINT16 HWR_GetModelSprite2Num(md2_t *md2, skin_t *skin, UINT16 spr2, player_t *player) { UINT16 super = 0; UINT8 i = 0; if (!md2 || !md2->model || !skin) - { - *spr2out = 0; - return HWR_GetModelSprite2Frames(md2, 0); - } + return 0; while (!HWR_GetModelSprite2Frames(md2, spr2) && spr2 != SPR2_STND @@ -1147,8 +1145,7 @@ static modelspr2frames_t *HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT16 s if (i >= 32) // probably an infinite loop... spr2 = 0; - *spr2out = spr2; - return HWR_GetModelSprite2Frames(md2, spr2); + return spr2; } // Adjust texture coords of model to fit into a patch's max_s and max_t @@ -1445,8 +1442,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) frame = (spr->mobj->frame & FF_FRAMEMASK); if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) { - //spr2 = 0; //need this for setting the mod correctly when spr2defaults stuff happens - spr2frames = HWR_GetModelSprite2(md2, spr->mobj->skin, P_GetStateSprite2(spr->mobj->state), spr->mobj->player, &spr2); + spr2 = HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player); //need this for setting the mod correctly when spr2defaults stuff happens + spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, P_GetStateSprite2(spr->mobj->state), spr->mobj->player)); } if (spr2frames) { @@ -1475,8 +1472,11 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) } #ifdef USE_MODEL_NEXTFRAME - // Interpolate the model interpolation. (lol) - tics -= FixedToFloat(rendertimefrac); + // Interpolate the model interpolation. (lol?) + if (spr2frames->extend && (!(paused || P_AutoPause())) && !hu_stopped) + tics -= FixedToFloat(g_time.timefrac); //this feels extremely bad and hacky, if theres a better way to still get intermediates at 35 fps please lmk + else + tics -= FixedToFloat(rendertimefrac); #define INTERPOLERATION_LIMIT (TICRATE * 0.25f) From ebfb6a768e5192b4e81124bb9976c79616041d3f Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Tue, 23 Apr 2024 17:09:26 -0500 Subject: [PATCH 07/30] oops --- src/hardware/hw_md2.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 74ecffd3e..8ef226768 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1473,8 +1473,11 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) #ifdef USE_MODEL_NEXTFRAME // Interpolate the model interpolation. (lol?) - if (spr2frames->extend && (!(paused || P_AutoPause())) && !hu_stopped) - tics -= FixedToFloat(g_time.timefrac); //this feels extremely bad and hacky, if theres a better way to still get intermediates at 35 fps please lmk + if (spr2frames) + { + if (spr2frames->extend && (!(paused || P_AutoPause())) && !hu_stopped) + tics -= FixedToFloat(g_time.timefrac); //this feels extremely bad and hacky, if theres a better way to still get intermediates at 35 fps please lmk + } else tics -= FixedToFloat(rendertimefrac); From 89614c78a933a61c7236e20ac2e820d03f37ce29 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Tue, 23 Apr 2024 18:33:50 -0500 Subject: [PATCH 08/30] fix ghostmobjs --- src/hardware/hw_md2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 8ef226768..4f88dfe76 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1443,7 +1443,10 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) { spr2 = HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player); //need this for setting the mod correctly when spr2defaults stuff happens - spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, P_GetStateSprite2(spr->mobj->state), spr->mobj->player)); + if (spr->mobj->type == MT_PLAYER) + spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, P_GetStateSprite2(spr->mobj->state), spr->mobj->player)); + else + spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr2, spr->mobj->player)); } if (spr2frames) { From 88706ff7771d11e1e1f661c85fd46ac26ed63559 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Wed, 24 Apr 2024 00:08:58 -0500 Subject: [PATCH 09/30] fixed a super dumb problem --- src/hardware/hw_md2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 4f88dfe76..8cdad3d45 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1444,7 +1444,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) { spr2 = HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player); //need this for setting the mod correctly when spr2defaults stuff happens if (spr->mobj->type == MT_PLAYER) - spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, P_GetStateSprite2(spr->mobj->state), spr->mobj->player)); + spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, P_ApplySuperFlagToSprite2(P_GetStateSprite2(spr->mobj->state), spr->mobj), spr->mobj->player)); else spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr2, spr->mobj->player)); } From c29439fd51448b4bcb01671ee849080729669cc0 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Sun, 16 Jun 2024 21:58:19 -0700 Subject: [PATCH 10/30] fix crash when loading models without valid spr2frames --- src/hardware/hw_md2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index de3cb2a17..02a35129d 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1105,7 +1105,7 @@ static UINT16 HWR_GetModelSprite2Num(md2_t *md2, skin_t *skin, UINT16 spr2, play UINT16 super = 0; UINT8 i = 0; - if (!md2 || !md2->model || !skin) + if (!md2 || !md2->model || !md2->model->spr2frames || !skin) return 0; while (!HWR_GetModelSprite2Frames(md2, spr2) @@ -1443,7 +1443,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) sprdef = &sprites[spr->mobj->sprite]; frame = (spr->mobj->frame & FF_FRAMEMASK); - if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) + if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY && md2->model->spr2frames) { spr2 = HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player); //need this for setting the mod correctly when spr2defaults stuff happens if (spr->mobj->type == MT_PLAYER) From be89051ccfb91ff3d110660ddd9921a3e3e5fbaf Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Sun, 16 Jun 2024 19:29:28 -0700 Subject: [PATCH 11/30] animtextures progress --- src/hardware/hw_md2.c | 31 +- src/hardware/hw_md2.h | 1 + src/hardware/hw_md2load.c | 53 +-- src/hardware/hw_md2load.h | 2 +- src/hardware/hw_md3load.c | 24 +- src/hardware/hw_md3load.h | 2 +- src/hardware/hw_model.c | 426 ++++++++++++++++++++++-- src/hardware/hw_model.h | 22 ++ src/w_wad.c | 683 +++++++++++++++++++++++--------------- src/w_wad.h | 15 + 10 files changed, 868 insertions(+), 391 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 02a35129d..8e2dd7d0d 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -151,7 +151,7 @@ static void PNG_warn(png_structp PNG, png_const_charp pngtext) CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext); } -static GLTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_t *grpatch) +GLTextureFormat_t PNG_Load(const UINT8 *source, size_t source_size, int *w, int *h, GLPatch_t *grpatch) { png_structp png_ptr; png_infop png_info_ptr; @@ -162,28 +162,13 @@ static GLTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_ jmp_buf jmpbuf; #endif #endif - volatile png_FILE_p png_FILE; - //Filename checking fixed ~Monster Iestyn and Golden - char *pngfilename = va("%s"PATHSEP"models"PATHSEP"%s", srb2home, filename); - - FIL_ForceExtension(pngfilename, ".png"); - png_FILE = fopen(pngfilename, "rb"); - if (!png_FILE) - { - pngfilename = va("%s"PATHSEP"models"PATHSEP"%s", srb2path, filename); - FIL_ForceExtension(pngfilename, ".png"); - png_FILE = fopen(pngfilename, "rb"); - //CONS_Debug(DBG_RENDER, "M_SavePNG: Error on opening %s for loading\n", filename); - if (!png_FILE) - return 0; - } + png_io_t png_io; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, PNG_error, PNG_warn); if (!png_ptr) { CONS_Debug(DBG_RENDER, "PNG_Load: Error on initialize libpng\n"); - fclose(png_FILE); return 0; } @@ -192,7 +177,6 @@ static GLTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_ { CONS_Debug(DBG_RENDER, "PNG_Load: Error on allocate for libpng\n"); png_destroy_read_struct(&png_ptr, NULL, NULL); - fclose(png_FILE); return 0; } @@ -204,7 +188,6 @@ static GLTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_ { //CONS_Debug(DBG_RENDER, "libpng load error on %s\n", filename); png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); - fclose(png_FILE); Z_Free(grpatch->mipmap->data); return 0; } @@ -212,7 +195,10 @@ static GLTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_ png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf); #endif - png_init_io(png_ptr, png_FILE); + png_io.buffer = source; + png_io.size = source_size; + png_io.position = 0; + png_set_read_fn(png_ptr, &png_io, PNG_IOReader); #ifdef PNG_SET_USER_LIMITS_SUPPORTED png_set_user_limits(png_ptr, 2048, 2048); @@ -256,7 +242,6 @@ static GLTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_ png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); - fclose(png_FILE); *w = (int)width; *h = (int)height; return GL_TEXFMT_RGBA; @@ -494,6 +479,7 @@ void HWR_InitModels(void) for (i = 0; i < NUMSPRITES; i++) { + md2_models[i].index = i; md2_models[i].scale = -1.0f; md2_models[i].model = NULL; md2_models[i].grpatch = NULL; @@ -531,6 +517,7 @@ void HWR_LoadModels(void) for (s = 0; s < numskins; s++) { + md2_playermodels[s].index = s; md2_playermodels[s].scale = -1.0f; md2_playermodels[s].model = NULL; md2_playermodels[s].grpatch = NULL; @@ -1357,7 +1344,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) { //CONS_Debug(DBG_RENDER, "Loading model... (%s)", sprnames[spr->mobj->sprite]); sprintf(filename, "models/%s", md2->filename); - md2->model = md2_readModel(filename, spr->mobj->sprite); + md2->model = md2_readModel(filename, md2->index); if (md2->model) { diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h index 473f21cb7..34b302ea0 100644 --- a/src/hardware/hw_md2.h +++ b/src/hardware/hw_md2.h @@ -23,6 +23,7 @@ typedef struct { + size_t index; char filename[32]; float scale; float offset; diff --git a/src/hardware/hw_md2load.c b/src/hardware/hw_md2load.c index ce8eb35f3..7a6ddb0d7 100644 --- a/src/hardware/hw_md2load.c +++ b/src/hardware/hw_md2load.c @@ -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(const 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; diff --git a/src/hardware/hw_md2load.h b/src/hardware/hw_md2load.h index 1662d6471..62e440569 100644 --- a/src/hardware/hw_md2load.h +++ b/src/hardware/hw_md2load.h @@ -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(const char *buffer, int ztag, boolean useFloat); #endif diff --git a/src/hardware/hw_md3load.c b/src/hardware/hw_md3load.c index eccc48424..a31e9222c 100644 --- a/src/hardware/hw_md3load.c +++ b/src/hardware/hw_md3load.c @@ -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(const 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; diff --git a/src/hardware/hw_md3load.h b/src/hardware/hw_md3load.h index c0e0522ff..c07950d12 100644 --- a/src/hardware/hw_md3load.h +++ b/src/hardware/hw_md3load.h @@ -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(const char *buffer, int ztag, boolean useFloat); #endif diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index e5d3aa900..84997637d 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -10,8 +10,10 @@ #include "../doomdef.h" #include "../doomtype.h" #include "../info.h" +#include "../r_picformats.h" #include "../r_skins.h" #include "../r_state.h" +#include "../r_things.h" #include "../z_zone.h" #include "hw_model.h" #include "hw_md2load.h" @@ -19,6 +21,9 @@ #include "hw_md2.h" #include "../u_list.h" #include +#include "../w_wad.h" + + static float PI = (3.1415926535897932384626433832795f); static float U_Deg2Rad(float deg) @@ -140,6 +145,73 @@ tag_t *GetTagByName(model_t *model, char *name, int frame) return NULL; } +typedef enum +{ + MODEL_TYPE_ZIP, + MODEL_TYPE_MD3, + MODEL_TYPE_MD3S, + MODEL_TYPE_MD2, + MODEL_TYPE_MD2S +} modeltype_t; + +static modeltype_t GetModelType(const char *name, boolean printfail) +{ + const char *extension = NULL; + int i; + //Check magic number instead of extension for zipped models, so they can be called whatever (useful to prevent people from accidentally unzipping an individual model) + char id[4]; + size_t read; + + if (FIL_FileExists(name)) //wont work when this is called on lumps, so just move on to basic file extension checking + { + FILE *f = fopen(name, "rb"); + read = fread(&id, 1, sizeof id, f); + fclose(f); + + if (read >= sizeof(id)) + if (!memcmp(id, "PK\x03\x04", 4)) + return MODEL_TYPE_ZIP; + } + + for (i = (int)strlen(name)-1; i >= 0; i--) + { + if (name[i] != '.') + continue; + + extension = &name[i]; + break; + } + + if (!extension) + { + if (printfail) + CONS_Printf("Model %s is lacking a file extension, unable to determine type!\n", name); + return NULL; + } + else if (!strcmp(extension, ".md3")) + { + return MODEL_TYPE_MD3; + } + else if (!strcmp(extension, ".md3s")) // MD3 that will be converted in memory to use full floats + { + return MODEL_TYPE_MD3S; + } + else if (!strcmp(extension, ".md2")) + { + return MODEL_TYPE_MD2; + } + else if (!strcmp(extension, ".md2s")) + { + return MODEL_TYPE_MD2S; + } + else + { + if (printfail) + CONS_Printf("Unknown model format: %s\n", extension); + return NULL; + } +} + // // LoadModel // @@ -148,51 +220,71 @@ tag_t *GetTagByName(model_t *model, char *name, int frame) model_t *LoadModel(const char *filename, int ztag, size_t spriteModelIndex) { model_t *model; - - // What type of file? - const char *extension = NULL; + + wadfile_t *zip = NULL; + char *buffer; + modeltype_t type; int i; - for (i = (int)strlen(filename)-1; i >= 0; i--) - { - if (filename[i] != '.') - continue; - extension = &filename[i]; - break; - } - - if (!extension) - { - CONS_Printf("Model %s is lacking a file extension, unable to determine type!\n", filename); + type = GetModelType(filename, true); + + if (type == NULL) return NULL; - } - if (!strcmp(extension, ".md3")) + if (type == MODEL_TYPE_ZIP) { - if (!(model = MD3_LoadModel(filename, ztag, false))) + zip = W_LoadResourceFile(filename); + if (zip == NULL) + { + CONS_Printf("Failed loading model zip archive %s\n", filename); return NULL; - } - else if (!strcmp(extension, ".md3s")) // MD3 that will be converted in memory to use full floats - { - if (!(model = MD3_LoadModel(filename, ztag, true))) - return NULL; - } - else if (!strcmp(extension, ".md2")) - { - if (!(model = MD2_LoadModel(filename, ztag, false))) - return NULL; - } - else if (!strcmp(extension, ".md2s")) - { - if (!(model = MD2_LoadModel(filename, ztag, true))) + } + + for (i = zip->numlumps - 1; i >= 0; i--) + { + type = GetModelType(zip->lumpinfo[i].fullname, false); + if (type != NULL) + break; + } + if (type == NULL) + { + CONS_Printf("MD3/MD2 not found in zip archive %s\n", filename); + W_DeleteResourceFile(zip); return NULL; + } + buffer = Resource_CacheLumpNum(zip, i, PU_STATIC); } else { - CONS_Printf("Unknown model format: %s\n", extension); - return NULL; + FILE *f = fopen(filename, "rb"); + if (!f) + return NULL; + + // find length of file + fseek(f, 0, SEEK_END); + size_t fileLen = ftell(f); + fseek(f, 0, SEEK_SET); + + + // read in file + buffer = ZZ_Alloc(fileLen); + fread(buffer, fileLen, 1, f); + fclose(f); } + if (type == MODEL_TYPE_MD3 || type == MODEL_TYPE_MD3S) + { + if (!(model = MD3_LoadModel(buffer, ztag, type == MODEL_TYPE_MD3S))) + return NULL; + } + else if (type == MODEL_TYPE_MD2 || type == MODEL_TYPE_MD2S) + { + if (!(model = MD2_LoadModel(buffer, ztag, type == MODEL_TYPE_MD2S))) + return NULL; + } + + Z_Free(buffer); + Optimize(model); GeneratePolygonNormals(model, ztag); LoadModelSprite2(model); @@ -434,6 +526,274 @@ void LoadModelSprite2(model_t *model) model->superspr2frames = superspr2frames; } +boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT16 endlump, model_t *model, boolean blend, size_t spriteModelIndex) +{ + int i; + char prefix[MAXSPRITENAME + 1]; + UINT8 *buffer; + size_t size; + + + if (spriteModelIndex != NULL) + /* + regular sprite model loading, use sprite name + frame char + ex: THOKA for first frame of the thok, THOK0 for 27th + uses r_things.h Char2Frame for this, parity with sprite naming conventions + */ + { + textureframe_t *texarray; + textureframe_t texarraybuffer[256]; + UINT8 texloaded = 0; + strcpy(prefix, sprnames[spriteModelIndex]); + + for (i = startlump; i < endlump; i++) + { + lumpinfo_t lumpinfo = zip->lumpinfo[i]; + if (!strnicmp(prefix, lumpinfo.longname, strlen(prefix))) + //create textureframe_ts that only contain a single texture, put them all in the textures/blends field of the model_t + { + char frame = lumpinfo.longname[strlen(lumpinfo.longname) - 1]; + UINT8 framenum = R_Char2Frame(frame); + if (framenum > 63) + continue; + + buffer = Resource_CacheLumpNum(zip, i, PU_STATIC); + size = Resource_LumpLength(zip, i, PU_STATIC); + + textureframe_t texframe; + texframe.numtextures = 1; + + GLPatch_t **patcharray = ZZ_Alloc(sizeof(GLPatch_t*)); + GLPatch_t *grpatch = ZZ_Alloc(sizeof(GLPatch_t)); + //make grpatch here + patcharray[0] = grpatch; + texframe.grpatches = patcharray; + UINT8 *frames = ZZ_Alloc(sizeof(UINT8)); + frames[0] = framenum; + texframe.frames = frames; + + texarraybuffer[texloaded] = texframe; + texloaded++; + } + } + + texarray = ZZ_Alloc(sizeof(textureframe_t) * texloaded); + memcpy(texarray, texarraybuffer, sizeof(textureframe_t) * texloaded); + + if (blend) + { + model->blends = texarray; + model->numblends = texloaded; + } + else + { + model->textures = texarray; + model->numtextures = texloaded; + } + } + else if (model->spr2frames) + /* + spr2 model loading, use spr2 name + number + ex: WALK1 for first frame of walk, WALK16 for 16th + different from normal sprite naming due to it being possible to extend spr2 animations beyond normal frame limits + */ + { + //first, load the default textures. the regular default must exist, but the super does not + textureframe_t *texarray = ZZ_Alloc(sizeof(textureframe_t)); + textureframe_t defaults; + GLPatch_t *default; + GLPatch_t *superdefault; + GLPatch_t **defaultpatches; + UINT8 *defaultframes; + int numdefaults = 1; + + UINT8 lumpnum; + + if (blend) + { + lumpnum = Resource_CheckNumForName(zip, "Blend/DEFAULT.png"); + buffer = Resource_CacheLumpNum(zip, lumpnum, PU_STATIC); + size = Resource_LumpLength(zip, lumpnum); + //load png to default + + if (!(lumpnum = Resource_CheckNumForName(zip, "Blend/Super/DEFAULT.png") == INT16_MAX)) + { + superdefault = ZZ_Alloc(sizeof(GLPatch_t)); + + buffer = Resource_CacheLumpNum(zip, lumpnum, PU_STATIC); + size = Resource_LumpLength(zip, lumpnum); + if (Picture_IsLumpPNG(buffer, size)) + { + + } + //load png to superdefault + free(buffer); + numdefaults = 2; + } + + defaultpatches = ZZ_Alloc(sizeof(GLPatch_t*) * numdefaults); + defaultframes = ZZ_Alloc(sizeof(UINT8) * numdefaults); + defaultpatches[0] = default; + defaultframes[0] = 0; + + if (numdefaults > 1) + { + defaultpatches[1] = superdefault; + defaultframes[1] = 1; + } + + texarray[0] = defaults; + model->blends = texarray; + model->numblends = 1; + } + else + { + lumpnum = Resource_CheckNumForName(zip, "Textures/DEFAULT.png"); + buffer = Resource_CacheLumpNum(zip, lumpnum, PU_STATIC); + size = Resource_LumpLength(zip, lumpnum); + //load png to default + + if (!(lumpnum = Resource_CheckNumForName(zip, "Textures/Super/DEFAULT.png") == INT16_MAX)) + { + superdefault = ZZ_Alloc(sizeof(GLPatch_t)); + + buffer = Resource_CacheLumpNum(zip, lumpnum, PU_STATIC); + size = Resource_LumpLength(zip, lumpnum); + //load png to superdefault + numdefaults = 2; + } + + defaultpatches = ZZ_Alloc(sizeof(GLPatch_t*) * numdefaults); + defaultframes = ZZ_Alloc(sizeof(UINT8) * numdefaults); + defaultpatches[0] = default; + defaultframes[0] = 0; + + if (numdefaults > 1) + { + defaultpatches[1] = superdefault; + defaultframes[1] = 1; + } + + texarray[0] = defaults; + model->textures = texarray; + model->numtextures = 1; + } + + //load the rest of the textures, also figure out which ones are super frames + UINT16 superstart, superend; + superstart = Resource_CheckNumForFolderStartPK3(zip, "Textures/Super", startlump); + superend = Resource_CheckNumForFolderEndPK3(zip, "Textures/Super", startlump); + if (blend) + { + superstart = Resource_CheckNumForFolderStartPK3(zip, "Blend/Super", startlump); + superend = Resource_CheckNumForFolderEndPK3(zip, "Blend/Super", startlump); + } + + for (int s = 0; s < free_spr2; s++) + //create a textureframe_t for each spr2, which hold as many textures as provided. each goes into the corresponding modelspr2frames_t + { + GLPatch_t *grbuffer[256]; + GLPatch_t *supergrbuffer[256]; + UINT8 framebuffer[256]; + UINT8 superframebuffer[256]; + UINT8 numtextures = 0; + UINT8 numsupertextures = 0; + + strcpy(prefix, spr2names[s]); + for (i = startlump; i < endlump; i++) + { + boolean super = false; + if (i >= superstart && i < superend) + super = true; + lumpinfo_t lumpinfo = zip->lumpinfo[i]; + if (!strnicmp(prefix, lumpinfo.longname, strlen(prefix))) + { + char frame[4]; + strcpy(frame, lumpinfo.longname + 4); + int framenum = atoi(frame) - 1; + if (framenum < 0 || framenum > 255) + continue; + + buffer = Resource_CacheLumpNum(zip, i, PU_STATIC); + if (super) + { + //supergrpatches[numsupertextures] = + superframebuffer[numsupertextures] = framenum; + numsupertextures++; + } + else + { + //grpatches[numtextures] = + framebuffer[numtextures] = framenum; + numtextures++; + } + } + } + + if (numtextures) + { + GLPatch_t **grpatches = ZZ_Alloc(sizeof(GLPatch_t*) * numtextures); + memcpy(grpatches, grbuffer, sizeof(GLPatch_t) * numtextures); + + UINT8 *frames = ZZ_Alloc(sizeof(UINT8) * numtextures); + memcpy(frames, framebuffer, sizeof(UINT8) * numtextures); + + textureframe_t texframe = {grpatches, frames, numtextures}; + + if (blend) + model->spr2frames[s].blends = texframe; + else + model->spr2frames[s].textures = texframe; + } + + if (numsupertextures) + { + GLPatch_t **grpatches = ZZ_Alloc(sizeof(GLPatch_t*) * numsupertextures); + memcpy(grpatches, supergrbuffer, sizeof(GLPatch_t) * numsupertextures); + + UINT8 *frames = ZZ_Alloc(sizeof(UINT8) * numsupertextures); + memcpy(frames, superframebuffer, sizeof(UINT8) * numsupertextures); + + textureframe_t texframe = {grpatches, frames, numsupertextures}; + + if (blend) + model->superspr2frames[s].blends = texframe; + else + model->superspr2frames[s].textures = texframe; + } + } + } +} + +modeltexload_t LoadModelTextures(const char *filename, model_t *model, wadfile_t *zip, size_t spriteModelIndex) +{ + modeltexload_t filesloaded = TEXLOAD_NONE; + + if (zip) //zip, can support animated textures + { + if (Resource_LumpExists(zip, "Textures/DEFAULT.png"))//required for anything else, last-resort fallback texture for everything + { + UINT16 startlump, endlump; + startlump = Resource_CheckNumForFolderStartPK3(zip, "Textures", startlump); + endlump = Resource_CheckNumForFolderEndPK3(zip, "Textures", startlump); + AssignZippedModelTextures(zip, startlump, endlump, model, false, spriteModelIndex); + filesloaded = TEXLOAD_TEXTURE; + if (Resource_LumpExists(zip, "Blend/DEFAULT.png")) //same thing + { + startlump = Resource_CheckNumForFolderStartPK3(zip, "Blend", startlump); + endlump = Resource_CheckNumForFolderEndPK3(zip, "Blend", startlump); + AssignZippedModelTextures(zip, startlump, endlump, model, true, spriteModelIndex); + filesloaded = TEXLOAD_BLEND; + } + } + return filesloaded; + } + else //normal md3/2, default back to normal texture loading + { + + } +} + // // GenerateVertexNormals // diff --git a/src/hardware/hw_model.h b/src/hardware/hw_model.h index 64c4b367a..7fdb2b6a5 100644 --- a/src/hardware/hw_model.h +++ b/src/hardware/hw_model.h @@ -83,6 +83,20 @@ typedef struct tag_s #define MODEL_0ANGLE_FLAG 'o' #define MODEL_NO_0ANGLE_FLAG 'n' +typedef enum //results from the LoadModelTexture function +{ + TEXLOAD_NONE, + TEXLOAD_TEXTURE, + TEXLOAD_BLEND, +} modeltexload_t; + +typedef struct +{ + void **grpatches; + UINT8 *frames; + UINT8 numtextures; +} textureframe_t; + typedef struct { INT32 frames[256]; @@ -90,6 +104,8 @@ typedef struct boolean interpolate; boolean extend; signed char zeroangle; + textureframe_t textures; + textureframe_t blends; } modelspr2frames_t; typedef struct model_s @@ -110,6 +126,11 @@ typedef struct model_s 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; @@ -136,5 +157,6 @@ 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); +model_t *LoadModelZip(const char *filename, int ztag); #endif diff --git a/src/w_wad.c b/src/w_wad.c index cc7cdc201..011b50c7c 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -120,22 +120,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); @@ -339,11 +324,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")) @@ -403,9 +413,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; @@ -922,7 +930,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"); @@ -1015,6 +1023,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++; + break; + } + } + return i; +} + +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. // @@ -1318,21 +1711,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++; - break; - } - } - return i; + 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. @@ -1340,14 +1719,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) @@ -1887,46 +2259,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. @@ -2017,174 +2353,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 || lumpsizetype == 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) @@ -2214,21 +2386,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) diff --git a/src/w_wad.h b/src/w_wad.h index 3dcb9b6e8..fce1d0e9c 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -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); From 104977b90b59c9549f504690c309d23fcaad5142 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Sat, 22 Jun 2024 04:34:31 -0700 Subject: [PATCH 12/30] almost works --- src/hardware/hw_md2.c | 710 ++++++++++++------------------ src/hardware/hw_md2.h | 2 - src/hardware/hw_md2load.c | 2 +- src/hardware/hw_md2load.h | 2 +- src/hardware/hw_md3load.c | 2 +- src/hardware/hw_md3load.h | 2 +- src/hardware/hw_model.c | 899 +++++++++++++++++++++++++++++++------- src/hardware/hw_model.h | 19 +- src/r_picformats.c | 8 +- src/r_picformats.h | 31 ++ 10 files changed, 1059 insertions(+), 618 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 8e2dd7d0d..4a00f2c02 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -44,30 +44,6 @@ #include "hw_main.h" #include "../v_video.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 - #if PNG_LIBPNG_VER < 100207 - //#undef HAVE_PNG - #endif -#endif #ifndef errno #include "errno.h" @@ -97,10 +73,14 @@ static model_t *md2_readModel(const char *filename, size_t spriteModelIndex) { //Filename checking fixed ~Monster Iestyn and Golden if (FIL_FileExists(va("%s"PATHSEP"%s", srb2home, filename))) + { return LoadModel(va("%s"PATHSEP"%s", srb2home, filename), PU_STATIC, spriteModelIndex); + } if (FIL_FileExists(va("%s"PATHSEP"%s", srb2path, filename))) + { return LoadModel(va("%s"PATHSEP"%s", srb2path, filename), PU_STATIC, spriteModelIndex); + } return NULL; } @@ -139,335 +119,136 @@ static inline void md2_printModelInfo (model_t *model) #endif } -#ifdef HAVE_PNG -static void PNG_error(png_structp PNG, png_const_charp pngtext) +// -----------------+e +// md2_loadTexture : Download a pcx or png texture for models +// -----------------+ + +static void md2_loadTextures(const char *filename, md2_t *md2) { - CONS_Debug(DBG_RENDER, "libpng error at %p: %s", PNG, pngtext); - //I_Error("libpng error at %p: %s", PNG, pngtext); -} - -static void PNG_warn(png_structp PNG, png_const_charp pngtext) -{ - CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext); -} - -GLTextureFormat_t PNG_Load(const UINT8 *source, size_t source_size, int *w, int *h, GLPatch_t *grpatch) -{ - png_structp png_ptr; - png_infop png_info_ptr; - png_uint_32 width, height; - int bit_depth, color_type; -#ifdef PNG_SETJMP_SUPPORTED -#ifdef USE_FAR_KEYWORD - jmp_buf jmpbuf; -#endif -#endif - png_io_t png_io; - - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, - PNG_error, PNG_warn); - if (!png_ptr) + modeltype_t type; + wadfile_t *zip = NULL; + modeltexload_t texload = TEXLOAD_NONE; + patch_t *patch; + GLPatch_t *hwpatch; + char *pathname = va("%s"PATHSEP"%s", srb2home, filename); + if ((type = GetModelType(pathname, false)) != MODEL_TYPE_NONE) { - CONS_Debug(DBG_RENDER, "PNG_Load: Error on initialize libpng\n"); - return 0; - } - - png_info_ptr = png_create_info_struct(png_ptr); - if (!png_info_ptr) - { - CONS_Debug(DBG_RENDER, "PNG_Load: Error on allocate for libpng\n"); - png_destroy_read_struct(&png_ptr, NULL, NULL); - return 0; - } - -#ifdef USE_FAR_KEYWORD - if (setjmp(jmpbuf)) -#else - if (setjmp(png_jmpbuf(png_ptr))) -#endif - { - //CONS_Debug(DBG_RENDER, "libpng load error on %s\n", filename); - png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); - Z_Free(grpatch->mipmap->data); - return 0; - } -#ifdef USE_FAR_KEYWORD - png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf); -#endif - - png_io.buffer = source; - png_io.size = source_size; - png_io.position = 0; - png_set_read_fn(png_ptr, &png_io, PNG_IOReader); - -#ifdef PNG_SET_USER_LIMITS_SUPPORTED - png_set_user_limits(png_ptr, 2048, 2048); -#endif - - png_read_info(png_ptr, png_info_ptr); - - png_get_IHDR(png_ptr, png_info_ptr, &width, &height, &bit_depth, &color_type, - NULL, NULL, NULL); - - if (bit_depth == 16) - png_set_strip_16(png_ptr); - - if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png_ptr); - else if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(png_ptr); - - if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_tRNS)) - png_set_tRNS_to_alpha(png_ptr); - else if (color_type != PNG_COLOR_TYPE_RGB_ALPHA && color_type != PNG_COLOR_TYPE_GRAY_ALPHA) - { -#if PNG_LIBPNG_VER < 10207 - png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); -#else - png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); -#endif - } - - png_read_update_info(png_ptr, png_info_ptr); - - { - png_uint_32 i, pitch = png_get_rowbytes(png_ptr, png_info_ptr); - png_bytep PNG_image = Z_Malloc(pitch*height, PU_HWRMODELTEXTURE, &grpatch->mipmap->data); - png_bytepp row_pointers = png_malloc(png_ptr, height * sizeof (png_bytep)); - for (i = 0; i < height; i++) - row_pointers[i] = PNG_image + i*pitch; - png_read_image(png_ptr, row_pointers); - png_free(png_ptr, (png_voidp)row_pointers); - } - - png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); - - *w = (int)width; - *h = (int)height; - return GL_TEXFMT_RGBA; -} -#endif - -typedef struct -{ - UINT8 manufacturer; - UINT8 version; - UINT8 encoding; - UINT8 bitsPerPixel; - INT16 xmin; - INT16 ymin; - INT16 xmax; - INT16 ymax; - INT16 hDpi; - INT16 vDpi; - UINT8 colorMap[48]; - UINT8 reserved; - UINT8 numPlanes; - INT16 bytesPerLine; - INT16 paletteInfo; - INT16 hScreenSize; - INT16 vScreenSize; - UINT8 filler[54]; -} PcxHeader; - -static GLTextureFormat_t PCX_Load(const char *filename, int *w, int *h, - GLPatch_t *grpatch) -{ - PcxHeader header; -#define PALSIZE 768 - UINT8 palette[PALSIZE]; - const UINT8 *pal; - RGBA_t *image; - size_t pw, ph, size, ptr = 0; - INT32 ch, rep; - FILE *file; - //Filename checking fixed ~Monster Iestyn and Golden - char *pcxfilename = va("%s"PATHSEP"models"PATHSEP"%s", srb2home, filename); - - FIL_ForceExtension(pcxfilename, ".pcx"); - file = fopen(pcxfilename, "rb"); - if (!file) - { - pcxfilename = va("%s"PATHSEP"models"PATHSEP"%s", srb2path, filename); - FIL_ForceExtension(pcxfilename, ".pcx"); - file = fopen(pcxfilename, "rb"); - if (!file) - return 0; - } - - if (fread(&header, sizeof (PcxHeader), 1, file) != 1) - { - fclose(file); - return 0; - } - - if (header.bitsPerPixel != 8) - { - fclose(file); - return 0; - } - - fseek(file, -PALSIZE, SEEK_END); - - pw = *w = header.xmax - header.xmin + 1; - ph = *h = header.ymax - header.ymin + 1; - image = Z_Malloc(pw*ph*4, PU_HWRMODELTEXTURE, &grpatch->mipmap->data); - - if (fread(palette, sizeof (UINT8), PALSIZE, file) != PALSIZE) - { - Z_Free(image); - fclose(file); - return 0; - } - fseek(file, sizeof (PcxHeader), SEEK_SET); - - size = pw * ph; - while (ptr < size) - { - ch = fgetc(file); //Hurdler: beurk - if (ch >= 192) + if (type == MODEL_TYPE_ZIP) { - rep = ch - 192; - ch = fgetc(file); + zip = W_LoadResourceFile(pathname); + } + texload = LoadModelTextures(pathname, md2->model, zip, md2->index); + } + else + { + pathname = va("%s"PATHSEP"%s", srb2path, filename); + if ((type = GetModelType(pathname, true)) != MODEL_TYPE_NONE) + { + if (type == MODEL_TYPE_ZIP) + zip = W_LoadResourceFile(pathname); + texload = LoadModelTextures(pathname, md2->model, zip, md2->index); + } + } + if (zip) + W_DeleteResourceFile(zip); + if (texload < TEXLOAD_BLEND) + md2->noblendfile = true; + if (texload == TEXLOAD_NONE) + md2->notexturefile = true; + + if (texload >= TEXLOAD_TEXTURE) + { + patch = md2->model->textures[0].patches[0]; //default frame of spr2 or first frame of sprite model or generated patch if no texture is found + hwpatch = patch->hardware; + HWD.pfnSetTexture(hwpatch->mipmap); + } +} +static patch_t *md2_getSpriteModelTexture(model_t *model, UINT8 frame, boolean blend) +{ + patch_t *patch; + textureframe_t *texframe; + UINT8 numtexs; + UINT8 closestframe = 0, closestframeindex = 0; + + texframe = model->textures; + numtexs = model->numtextures; + if (blend) + { + texframe = model->blends; + numtexs = model->numblends; + } + for (int i = 0; i < numtexs; i++) //look for closest frame to target, must be before if not the exact frame. unlike the spr2 version, this loop should always find something, as a first texture is required + { + if (texframe[i].frames[0] == frame) + { + closestframe = texframe[i].frames[0]; + closestframeindex = i; + break; + } + else if (!closestframe && texframe[i].frames[0] < frame) + { + closestframe = texframe[i].frames[0]; + closestframeindex = i; + } + else if (texframe[i].frames[0] > closestframe && texframe[i].frames[0] < frame) + { + closestframe = texframe[i].frames[0]; + closestframeindex = i; + } + } + + patch = texframe[closestframeindex].patches[0]; + return patch; +} + +static patch_t *md2_getSprite2ModelTexture(model_t *model, modelspr2frames_t *spr2frames, UINT8 frame, boolean super, boolean blend) +{ + patch_t *patch; + textureframe_t texframe; + UINT8 closestframe = 0, closestframeindex = 0; + + texframe = spr2frames->textures; + if (blend) + texframe = spr2frames->blends; + + for (int i = 0; i < texframe.numtextures; i++) //look for closest frame to target, must be before if not the exact frame + { + if (texframe.frames[i] == frame) + { + closestframe = texframe.frames[i]; + closestframeindex = i; + break; + } + else if (!closestframe && texframe.frames[i] < frame) + { + closestframe = texframe.frames[i]; + closestframeindex = i; + } + else if (texframe.frames[i] > closestframe && texframe.frames[i] < frame) + { + closestframe = texframe.frames[i]; + closestframeindex = i; + } + } + if (closestframe) + { + patch = texframe.patches[closestframeindex]; + } + else //default + { + UINT8 defaultframe; + if (blend) + { + defaultframe = (super && model->blends[0].numtextures > 1) ? 1 : 0; //if super default exists and using super frames, use it. otherwise use the normal default + patch = model->blends[0].patches[defaultframe]; } else { - rep = 1; - } - while (rep--) - { - pal = palette + ch*3; - image[ptr].s.red = *pal++; - image[ptr].s.green = *pal++; - image[ptr].s.blue = *pal++; - image[ptr].s.alpha = 0xFF; - ptr++; + defaultframe = (super && model->textures[0].numtextures > 1) ? 1 : 0; + patch = model->textures[0].patches[(UINT8)super]; } } - fclose(file); - return GL_TEXFMT_RGBA; -} - -// -----------------+ -// md2_loadTexture : Download a pcx or png texture for models -// -----------------+ -static void md2_loadTexture(md2_t *model) -{ - patch_t *patch; - GLPatch_t *grPatch = NULL; - const char *filename = model->filename; - - if (model->grpatch) - { - patch = model->grpatch; - grPatch = (GLPatch_t *)(patch->hardware); - if (grPatch) - Z_Free(grPatch->mipmap->data); - } - else - model->grpatch = patch = Patch_Create(0, 0); - - if (!patch->hardware) - Patch_AllocateHardwarePatch(patch); - - if (grPatch == NULL) - grPatch = (GLPatch_t *)(patch->hardware); - - if (!grPatch->mipmap->downloaded && !grPatch->mipmap->data) - { - int w = 0, h = 0; - -#ifdef HAVE_PNG - grPatch->mipmap->format = PNG_Load(filename, &w, &h, grPatch); - if (grPatch->mipmap->format == 0) -#endif - grPatch->mipmap->format = PCX_Load(filename, &w, &h, grPatch); - if (grPatch->mipmap->format == 0) - { - model->notexturefile = true; // mark it so its not searched for again repeatedly - return; - } - - grPatch->mipmap->downloaded = 0; - grPatch->mipmap->flags = 0; - - patch->width = (INT16)w; - patch->height = (INT16)h; - grPatch->mipmap->width = (UINT16)w; - grPatch->mipmap->height = (UINT16)h; - - // for palette rendering, color cube is applied in post-processing instead of here - if (!HWR_ShouldUsePaletteRendering()) - { - UINT32 size; - RGBA_t *image; - // Lactozilla: Apply colour cube - image = grPatch->mipmap->data; - size = w*h; - while (size--) - { - V_CubeApply(&image->s.red, &image->s.green, &image->s.blue); - image++; - } - } - } - HWD.pfnSetTexture(grPatch->mipmap); -} - -// -----------------+ -// md2_loadBlendTexture : Download a pcx or png texture for blending MD2 models -// -----------------+ -static void md2_loadBlendTexture(md2_t *model) -{ - patch_t *patch; - GLPatch_t *grPatch = NULL; - char *filename = Z_Malloc(strlen(model->filename)+7, PU_STATIC, NULL); - - strcpy(filename, model->filename); - FIL_ForceExtension(filename, "_blend.png"); - - if (model->blendgrpatch) - { - patch = model->blendgrpatch; - grPatch = (GLPatch_t *)(patch->hardware); - if (grPatch) - Z_Free(grPatch->mipmap->data); - } - else - model->blendgrpatch = patch = Patch_Create(0, 0); - - if (!patch->hardware) - Patch_AllocateHardwarePatch(patch); - - if (grPatch == NULL) - grPatch = (GLPatch_t *)(patch->hardware); - - if (!grPatch->mipmap->downloaded && !grPatch->mipmap->data) - { - int w = 0, h = 0; -#ifdef HAVE_PNG - grPatch->mipmap->format = PNG_Load(filename, &w, &h, grPatch); - if (grPatch->mipmap->format == 0) -#endif - grPatch->mipmap->format = PCX_Load(filename, &w, &h, grPatch); - if (grPatch->mipmap->format == 0) - { - model->noblendfile = true; // mark it so its not searched for again repeatedly - Z_Free(filename); - return; - } - - grPatch->mipmap->downloaded = 0; - grPatch->mipmap->flags = 0; - - patch->width = (INT16)w; - patch->height = (INT16)h; - grPatch->mipmap->width = (UINT16)w; - grPatch->mipmap->height = (UINT16)h; - } - HWD.pfnSetTexture(grPatch->mipmap); // We do need to do this so that it can be cleared and knows to recreate it when necessary - - Z_Free(filename); + return patch; } // Don't spam the console, or the OS with fopen requests! @@ -482,7 +263,6 @@ void HWR_InitModels(void) md2_models[i].index = i; md2_models[i].scale = -1.0f; md2_models[i].model = NULL; - md2_models[i].grpatch = NULL; md2_models[i].notexturefile = false; md2_models[i].noblendfile = false; md2_models[i].found = false; @@ -517,10 +297,9 @@ void HWR_LoadModels(void) for (s = 0; s < numskins; s++) { - md2_playermodels[s].index = s; + md2_playermodels[s].index = 0; md2_playermodels[s].scale = -1.0f; md2_playermodels[s].model = NULL; - md2_playermodels[s].grpatch = NULL; md2_playermodels[s].notexturefile = false; md2_playermodels[s].noblendfile = false; md2_playermodels[s].found = false; @@ -1184,12 +963,13 @@ static void adjustTextureCoords(model_t *model, patch_t *patch) // HWR_DrawModel // + boolean HWR_DrawModel(gl_vissprite_t *spr) { md2_t *md2; char filename[64]; - float frame = 0.0f; + float frame, offsetframe = 0.0f; float nextFrame = -1.0f; float frameStep = 1.0f; modelspr2frames_t *spr2frames = NULL; @@ -1252,7 +1032,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) // Look at HWR_ProjectSprite for more { - patch_t *gpatch, *blendgpatch; + patch_t *patch = NULL, *blendpatch = NULL; GLPatch_t *hwrPatch = NULL, *hwrBlendPatch = NULL; float durs = (float)spr->mobj->state->tics; float tics = (float)spr->mobj->tics; @@ -1296,8 +1076,11 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) // don't forget to enable the depth test because we can't do this // like before: model polygons are not sorted - // 1. load model+texture if not already loaded - // 2. draw model with correct position, rotation,... + // 1. load model if not already loaded + // 2. preliminary texture loading if not already loaded + // 3. draw model with correct position, rotation,... + // 4. use frame information to pick correct texture + if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) // Use the player MD2 list if the mobj has a skin and is using the player sprites { UINT8 skinnum = ((skin_t*)spr->mobj->skin)->skinnum; @@ -1308,56 +1091,17 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) md2 = &md2_models[spr->mobj->sprite]; } - // texture loading before model init, so it knows if sprite graphics are used, which - // means that texture coordinates have to be adjusted - gpatch = md2->grpatch; - if (gpatch) - hwrPatch = ((GLPatch_t *)gpatch->hardware); - - if (!gpatch || !hwrPatch - || ((!hwrPatch->mipmap->format || !hwrPatch->mipmap->downloaded) && !md2->notexturefile)) - md2_loadTexture(md2); - - // Load it again, because it isn't being loaded into gpatch after md2_loadtexture... - gpatch = md2->grpatch; - if (gpatch) - hwrPatch = ((GLPatch_t *)gpatch->hardware); - - // Load blend texture - blendgpatch = md2->blendgrpatch; - if (blendgpatch) - hwrBlendPatch = ((GLPatch_t *)blendgpatch->hardware); - - if ((gpatch && hwrPatch && hwrPatch->mipmap->format) // don't load the blend texture if the base texture isn't available - && (!blendgpatch || !hwrBlendPatch - || ((!hwrBlendPatch->mipmap->format || !hwrBlendPatch->mipmap->downloaded) && !md2->noblendfile))) - md2_loadBlendTexture(md2); - - // Load it again, because it isn't being loaded into blendgpatch after md2_loadblendtexture... - blendgpatch = md2->blendgrpatch; - if (blendgpatch) - hwrBlendPatch = ((GLPatch_t *)blendgpatch->hardware); + sprintf(filename, "models/%s", md2->filename); if (md2->error) return false; // we already failed loading this before :( if (!md2->model) { //CONS_Debug(DBG_RENDER, "Loading model... (%s)", sprnames[spr->mobj->sprite]); - sprintf(filename, "models/%s", md2->filename); md2->model = md2_readModel(filename, md2->index); if (md2->model) - { md2_printModelInfo(md2->model); - // If model uses sprite patch as texture, then - // adjust texture coordinates to take power of two textures into account - if (!gpatch || !hwrPatch->mipmap->format) - adjustTextureCoords(md2->model, spr->gpatch); - // note down the max_s and max_t that end up in the VBO - md2->model->vbo_max_s = md2->model->max_s; - md2->model->vbo_max_t = md2->model->max_t; - HWD.pfnCreateModelVBOs(md2->model); - } else { //CONS_Debug(DBG_RENDER, " FAILED\n"); @@ -1365,57 +1109,63 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) return false; } } - - //HWD.pfnSetBlend(blend); // This seems to actually break translucency? - //Hurdler: arf, I don't like that implementation at all... too much crappy - - if (gpatch && hwrPatch && hwrPatch->mipmap->format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture + + if (md2->model->textures == NULL && !md2->notexturefile) + md2_loadTextures(filename, md2); + + if (md2->model->textures != NULL && !md2->notexturefile) + patch = md2->model->textures[0].patches[0]; //default or first frame, guaranteed unless there are loading issues + + if (patch) { - INT32 skinnum = TC_DEFAULT; - - if ((spr->mobj->flags & (MF_ENEMY|MF_BOSS)) && (spr->mobj->flags2 & MF2_FRET) && !(spr->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" + hwrPatch = (GLPatch_t*)patch->hardware; + if (!md2->notexturefile) { - if (spr->mobj->type == MT_CYBRAKDEMON || spr->mobj->colorized) - skinnum = TC_ALLWHITE; - else if (spr->mobj->type == MT_METALSONIC_BATTLE) - skinnum = TC_METALSONIC; - else - skinnum = TC_BOSS; - } - else if ((skincolornum_t)spr->mobj->color != SKINCOLOR_NONE) - { - if (spr->mobj->colorized) - skinnum = TC_RAINBOW; - else if (spr->mobj->player && spr->mobj->player->dashmode >= DASHMODE_THRESHOLD - && (spr->mobj->player->charflags & SF_DASHMODE) - && ((leveltime/2) & 1)) + if (!hwrPatch) { - if (spr->mobj->player->charflags & SF_MACHINE) - skinnum = TC_DASHMODE; - else - skinnum = TC_RAINBOW; + CONS_Printf("loadtex1\n"); + md2_loadTextures(filename, md2); + } + else if (!hwrPatch->mipmap->format || !hwrPatch->mipmap->downloaded) + { + CONS_Printf("loadtex2\n"); + md2_loadTextures(filename, md2); } - else if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) - skinnum = ((skin_t*)spr->mobj->skin)->skinnum; - else - skinnum = TC_DEFAULT; } + } + + if (md2->model->textures != NULL && !md2->notexturefile) + patch = md2->model->textures[0].patches[0]; + if (patch) + hwrPatch = (GLPatch_t*)patch->hardware; - // Translation or skin number found - HWR_GetBlendedTexture(gpatch, blendgpatch, skinnum, spr->colormap, (skincolornum_t)spr->mobj->color); - } - else // Sprite + if (!hwrPatch) { - // Check if sprite dimensions are different from previously used sprite. - // If so, uvs need to be readjusted. - // Comparing floats with the != operator here should be okay because they - // are just copies of glpatches' max_s and max_t values. - // Instead of the != operator, memcmp is used to avoid a compiler warning. - if (memcmp(&(hwrPatch->max_s), &(md2->model->max_s), sizeof(md2->model->max_s)) != 0 || - memcmp(&(hwrPatch->max_t), &(md2->model->max_t), sizeof(md2->model->max_t)) != 0) - adjustTextureCoords(md2->model, spr->gpatch); - HWR_GetMappedPatch(spr->gpatch, spr->colormap); + md2->notexturefile = true; + md2->noblendfile = true; } + else if (!hwrPatch->mipmap->format || !hwrPatch->mipmap->downloaded) + { + md2->notexturefile = true; + md2->noblendfile = true; + } + + //load blend texture. this gets loaded at the same time as the rest of the textures (and only if the first texture was successful), so it should either be there or not + if (!md2->notexturefile && md2->model->blends != NULL && !md2->noblendfile) + blendpatch = md2->model->blends[0].patches[0]; + if (blendpatch) + hwrBlendPatch = (GLPatch_t*)blendpatch->hardware; + + if (!hwrBlendPatch) + md2->noblendfile = true; + else if(!hwrBlendPatch->mipmap->format) + md2->noblendfile = true; + + if (md2->notexturefile) + adjustTextureCoords(md2->model, spr->gpatch); + md2->model->vbo_max_s = md2->model->max_s; + md2->model->vbo_max_t = md2->model->max_t; + HWD.pfnCreateModelVBOs(md2->model); if (spr->mobj->frame & FF_ANIMATE) { @@ -1454,14 +1204,16 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) if (!mod) mod = 1; - frame = spr2frames->frames[0] + (fmodf(frame, mod) * frameStep); + offsetframe = fmodf(frame, mod) * frameStep; + frame = spr2frames->frames[0] + offsetframe; } else { mod = md2->model->meshes[0].numFrames - md2->model->startFrame; if (!mod) mod = 1; - frame = fmodf(frame, mod) + md2->model->startFrame; + offsetframe = fmodf(frame, mod); + frame = offsetframe + md2->model->startFrame; } #ifdef USE_MODEL_NEXTFRAME @@ -1618,6 +1370,90 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) p.flip = atransform.flip; p.mirror = atransform.mirror; + //load textures for real now + if (!md2->notexturefile) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture + { + UINT8 intframe = offsetframe; + if (spr2frames) + { + if (spr2frames->extend) + { + float nextoffsetframe = nextFrame - frame + offsetframe; + float pol = (durs-tics)/durs; + if (pol > 1.0f) + pol = 1.0f; + if (pol < 0.0f) + pol = 0.0f; + float step = fabsf(frameStep) * pol; + intframe = (offsetframe + step >= offsetframe + fabsf(frameStep)) ? nextoffsetframe : offsetframe + step; //same logic in r_opengl + } + boolean super = P_ApplySuperFlagToSprite2(0, spr->mobj); + patch = md2_getSprite2ModelTexture(md2->model, spr2frames, intframe, super, false); + if (!md2->noblendfile) + blendpatch = md2_getSprite2ModelTexture(md2->model, spr2frames, intframe, super, true); + else + blendpatch = NULL; + } + else + { + patch = md2_getSpriteModelTexture(md2->model, intframe, false); + if (!md2->noblendfile) + blendpatch = md2_getSpriteModelTexture(md2->model, intframe, true); + else + blendpatch = NULL; + } + + INT32 skinnum = TC_DEFAULT; + + if ((spr->mobj->flags & (MF_ENEMY|MF_BOSS)) && (spr->mobj->flags2 & MF2_FRET) && !(spr->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" + { + if (spr->mobj->type == MT_CYBRAKDEMON || spr->mobj->colorized) + skinnum = TC_ALLWHITE; + else if (spr->mobj->type == MT_METALSONIC_BATTLE) + skinnum = TC_METALSONIC; + else + skinnum = TC_BOSS; + } + else if ((skincolornum_t)spr->mobj->color != SKINCOLOR_NONE) + { + if (spr->mobj->colorized) + skinnum = TC_RAINBOW; + else if (spr->mobj->player && spr->mobj->player->dashmode >= DASHMODE_THRESHOLD + && (spr->mobj->player->charflags & SF_DASHMODE) + && ((leveltime/2) & 1)) + { + if (spr->mobj->player->charflags & SF_MACHINE) + skinnum = TC_DASHMODE; + else + skinnum = TC_RAINBOW; + } + else if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) + skinnum = ((skin_t*)spr->mobj->skin)->skinnum; + else + skinnum = TC_DEFAULT; + } + + // Translation or skin number found + HWR_GetBlendedTexture(patch, blendpatch, skinnum, spr->colormap, (skincolornum_t)spr->mobj->color); + } + else // Sprite + { + // Check if sprite dimensions are different from previously used sprite. + // If so, uvs need to be readjusted. + // Comparing floats with the != operator here should be okay because they + // are just copies of glpatches' max_s and max_t values. + // Instead of the != operator, memcmp is used to avoid a compiler warning. + patch = spr->gpatch; + hwrPatch = (GLPatch_t*) patch->hardware; + if (hwrPatch) + { + if (memcmp(&(hwrPatch->max_s), &(md2->model->max_s), sizeof(md2->model->max_s)) != 0 || + memcmp(&(hwrPatch->max_t), &(md2->model->max_t), sizeof(md2->model->max_t)) != 0) + adjustTextureCoords(md2->model, spr->gpatch); + } + HWR_GetMappedPatch(spr->gpatch, spr->colormap); + } + if (HWR_UseShader()) HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_MODEL)); { diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h index 34b302ea0..5bb361b07 100644 --- a/src/hardware/hw_md2.h +++ b/src/hardware/hw_md2.h @@ -28,9 +28,7 @@ typedef struct 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; diff --git a/src/hardware/hw_md2load.c b/src/hardware/hw_md2load.c index 7a6ddb0d7..12991e728 100644 --- a/src/hardware/hw_md2load.c +++ b/src/hardware/hw_md2load.c @@ -231,7 +231,7 @@ typedef struct } md2frame_t; // Load the model -model_t *MD2_LoadModel(const char *buffer, int ztag, boolean useFloat) +model_t *MD2_LoadModel(char *buffer, int ztag, boolean useFloat) { model_t *retModel = NULL; md2header_t *header; diff --git a/src/hardware/hw_md2load.h b/src/hardware/hw_md2load.h index 62e440569..15be061db 100644 --- a/src/hardware/hw_md2load.h +++ b/src/hardware/hw_md2load.h @@ -14,6 +14,6 @@ #include "../doomtype.h" // Load the Model -model_t *MD2_LoadModel(const char *buffer, int ztag, boolean useFloat); +model_t *MD2_LoadModel(char *buffer, int ztag, boolean useFloat); #endif diff --git a/src/hardware/hw_md3load.c b/src/hardware/hw_md3load.c index a31e9222c..19b3b79e9 100644 --- a/src/hardware/hw_md3load.c +++ b/src/hardware/hw_md3load.c @@ -144,7 +144,7 @@ static void LatLngInit(void) static boolean latlnginit = false; -model_t *MD3_LoadModel(const char *buffer, int ztag, boolean useFloat) +model_t *MD3_LoadModel(char *buffer, int ztag, boolean useFloat) { const float WUNITS = 1.0f; model_t *retModel = NULL; diff --git a/src/hardware/hw_md3load.h b/src/hardware/hw_md3load.h index c07950d12..b15369ee0 100644 --- a/src/hardware/hw_md3load.h +++ b/src/hardware/hw_md3load.h @@ -14,6 +14,6 @@ #include "../doomtype.h" // Load the Model -model_t *MD3_LoadModel(const char *buffer, int ztag, boolean useFloat); +model_t *MD3_LoadModel(char *buffer, int ztag, boolean useFloat); #endif diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index 84997637d..0f2961e09 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -15,14 +15,14 @@ #include "../r_state.h" #include "../r_things.h" #include "../z_zone.h" +#include "hw_main.h" #include "hw_model.h" #include "hw_md2load.h" #include "hw_md3load.h" #include "hw_md2.h" #include "../u_list.h" #include -#include "../w_wad.h" - +#include "../v_video.h" static float PI = (3.1415926535897932384626433832795f); @@ -59,6 +59,23 @@ void VectorRotate(vector_t *rotVec, const vector_t *axisVec, float angle) rotVec->z = axisVec->z*(ux + vy + wz) + (rotVec->z*(axisVec->x*axisVec->x + axisVec->y*axisVec->y) - axisVec->z*(ux + vy))*ca + (-vx + uy)*sa; } +static void FreeTextureframeData(textureframe_t *texframe) +{ + for (int i = 0; i < texframe->numtextures; i++) + Patch_Free(texframe->patches[i]); + texframe->patches = NULL; + Z_Free(texframe->frames); + texframe->frames = NULL; + texframe->numtextures = 0; +} + +static void FreeTextureframe(textureframe_t *texframe, UINT8 numtexframes) +{ + for (int t = 0; t < numtexframes; t++) + FreeTextureframeData(&texframe[t]); + Z_Free(texframe); +} + void UnloadModel(model_t *model) { // Wouldn't it be great if C just had destructors? @@ -124,6 +141,38 @@ void UnloadModel(model_t *model) if (model->materials) Z_Free(model->materials); + if (model->frameNames) + Z_Free(model->frameNames); + + if (model->spr2frames) + { + for(UINT16 s = 0; s < free_spr2; s++) + { + if (model->spr2frames[s].textures.numtextures) + FreeTextureframeData(&model->spr2frames[s].textures); + if (model->spr2frames[s].blends.numtextures) + FreeTextureframeData(&model->spr2frames[s].blends); + } + Z_Free(model->spr2frames); + } + + if (model->superspr2frames) + { + for(UINT16 s = 0; s < free_spr2; s++) + { + if (model->superspr2frames[s].textures.numtextures) + FreeTextureframeData(&model->superspr2frames[s].textures); + if (model->superspr2frames[s].blends.numtextures) + FreeTextureframeData(&model->superspr2frames[s].blends); + } + Z_Free(model->superspr2frames); + } + + if (model->numtextures) + FreeTextureframe(model->textures, model->numtextures); + if (model->numblends) + FreeTextureframe(model->blends, model->numblends); + DeleteVBOs(model); Z_Free(model); } @@ -145,16 +194,7 @@ tag_t *GetTagByName(model_t *model, char *name, int frame) return NULL; } -typedef enum -{ - MODEL_TYPE_ZIP, - MODEL_TYPE_MD3, - MODEL_TYPE_MD3S, - MODEL_TYPE_MD2, - MODEL_TYPE_MD2S -} modeltype_t; - -static modeltype_t GetModelType(const char *name, boolean printfail) +modeltype_t GetModelType(const char *name, boolean printfail) { const char *extension = NULL; int i; @@ -165,7 +205,7 @@ static modeltype_t GetModelType(const char *name, boolean printfail) if (FIL_FileExists(name)) //wont work when this is called on lumps, so just move on to basic file extension checking { FILE *f = fopen(name, "rb"); - read = fread(&id, 1, sizeof id, f); + read = fread(&id, 1, sizeof(id), f); fclose(f); if (read >= sizeof(id)) @@ -186,7 +226,7 @@ static modeltype_t GetModelType(const char *name, boolean printfail) { if (printfail) CONS_Printf("Model %s is lacking a file extension, unable to determine type!\n", name); - return NULL; + return MODEL_TYPE_NONE; } else if (!strcmp(extension, ".md3")) { @@ -208,7 +248,7 @@ static modeltype_t GetModelType(const char *name, boolean printfail) { if (printfail) CONS_Printf("Unknown model format: %s\n", extension); - return NULL; + return MODEL_TYPE_NONE; } } @@ -219,16 +259,16 @@ static modeltype_t GetModelType(const char *name, boolean printfail) // model_t *LoadModel(const char *filename, int ztag, size_t spriteModelIndex) { - model_t *model; + model_t *model = NULL; wadfile_t *zip = NULL; - char *buffer; + char *buffer = NULL; modeltype_t type; int i; type = GetModelType(filename, true); - if (type == NULL) + if (type == MODEL_TYPE_NONE) return NULL; if (type == MODEL_TYPE_ZIP) @@ -243,10 +283,10 @@ model_t *LoadModel(const char *filename, int ztag, size_t spriteModelIndex) for (i = zip->numlumps - 1; i >= 0; i--) { type = GetModelType(zip->lumpinfo[i].fullname, false); - if (type != NULL) + if (type != MODEL_TYPE_NONE) break; } - if (type == NULL) + if (type == MODEL_TYPE_NONE) { CONS_Printf("MD3/MD2 not found in zip archive %s\n", filename); W_DeleteResourceFile(zip); @@ -283,8 +323,14 @@ model_t *LoadModel(const char *filename, int ztag, size_t spriteModelIndex) return NULL; } + if (!model) + return NULL; + Z_Free(buffer); + if (zip) + W_DeleteResourceFile(zip); + Optimize(model); GeneratePolygonNormals(model, ztag); LoadModelSprite2(model); @@ -361,8 +407,8 @@ void LoadModelSettings(model_t *model, size_t spriteModelIndex) model->interpolate[i] = false; model->zeroangle[i] = 0; count++; - namechars = strlen(framename);//framename can only be up to 16 chars so for very long sprite names this will just not work (current/default still will) - namechars-= 1 + floor(log10(count));//get digits of frame so they can be ignored + namechars = strlen(framename);//framename can only be up to 16 chars so for very long sprite names this will just not work (old way of loading still will) + namechars -= 1 + floor(log10(count));//get digits of frame so they can be ignored //theres a padded 0 for counts under 10, but this can be useful for determining if a '+' suffix is added and the count needs to be reset if (memcmp(framename, &lastframename, namechars)) count = 0; @@ -433,7 +479,7 @@ void LoadModelSprite2(model_t *model) char flags[5]; char framechars[4]; UINT8 frame = 0; - UINT8 spr2idx; + UINT16 spr2idx; boolean interpolate = false; boolean extend = false; //allow animation to go over default sprite length char zeroangle = 0; //-1 remove all, 0 follow sprites, 1 force all @@ -526,28 +572,337 @@ void LoadModelSprite2(model_t *model) model->superspr2frames = superspr2frames; } -boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT16 endlump, model_t *model, boolean blend, size_t spriteModelIndex) +#ifdef HAVE_PNG +static void PNG_error(png_structp PNG, png_const_charp pngtext) { - int i; + CONS_Debug(DBG_RENDER, "libpng error at %p: %s", PNG, pngtext); + //I_Error("libpng error at %p: %s", PNG, pngtext); +} + +static void PNG_warn(png_structp PNG, png_const_charp pngtext) +{ + CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext); +} + +static GLTextureFormat_t PNG_Load(const UINT8 *source, size_t source_size, int *w, int *h, GLPatch_t *grpatch) +{ + png_structp png_ptr; + png_infop png_info_ptr; + png_uint_32 width, height; + int bit_depth, color_type; +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + png_io_t png_io; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, + PNG_error, PNG_warn); + if (!png_ptr) + { + CONS_Debug(DBG_RENDER, "PNG_Load: Error on initialize libpng\n"); + return 0; + } + + png_info_ptr = png_create_info_struct(png_ptr); + if (!png_info_ptr) + { + CONS_Debug(DBG_RENDER, "PNG_Load: Error on allocate for libpng\n"); + png_destroy_read_struct(&png_ptr, NULL, NULL); + return 0; + } + +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_jmpbuf(png_ptr))) +#endif + { + //CONS_Debug(DBG_RENDER, "libpng load error on %s\n", filename); + png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); + Z_Free(grpatch->mipmap->data); + return 0; + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf); +#endif + + png_io.buffer = source; + png_io.size = source_size; + png_io.position = 0; + png_set_read_fn(png_ptr, &png_io, PNG_IOReader); + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_set_user_limits(png_ptr, 2048, 2048); +#endif + + png_read_info(png_ptr, png_info_ptr); + + png_get_IHDR(png_ptr, png_info_ptr, &width, &height, &bit_depth, &color_type, + NULL, NULL, NULL); + + if (bit_depth == 16) + png_set_strip_16(png_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + else if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png_ptr); + else if (color_type != PNG_COLOR_TYPE_RGB_ALPHA && color_type != PNG_COLOR_TYPE_GRAY_ALPHA) + { +#if PNG_LIBPNG_VER < 10207 + png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); +#else + png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); +#endif + } + + png_read_update_info(png_ptr, png_info_ptr); + + { + png_uint_32 i, pitch = png_get_rowbytes(png_ptr, png_info_ptr); + png_bytep PNG_image = Z_Malloc(pitch*height, PU_HWRMODELTEXTURE, &grpatch->mipmap->data); + png_bytepp row_pointers = png_malloc(png_ptr, height * sizeof (png_bytep)); + for (i = 0; i < height; i++) + row_pointers[i] = PNG_image + i*pitch; + png_read_image(png_ptr, row_pointers); + png_free(png_ptr, (png_voidp)row_pointers); + } + + png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); + + *w = (int)width; + *h = (int)height; + return GL_TEXFMT_RGBA; +} +#endif + +typedef struct +{ + UINT8 manufacturer; + UINT8 version; + UINT8 encoding; + UINT8 bitsPerPixel; + INT16 xmin; + INT16 ymin; + INT16 xmax; + INT16 ymax; + INT16 hDpi; + INT16 vDpi; + UINT8 colorMap[48]; + UINT8 reserved; + UINT8 numPlanes; + INT16 bytesPerLine; + INT16 paletteInfo; + INT16 hScreenSize; + INT16 vScreenSize; + UINT8 filler[54]; +} PcxHeader; + +static GLTextureFormat_t PCX_Load(const UINT8 *source, size_t source_size, int *w, int *h, + GLPatch_t *grpatch) +{ + PcxHeader header; +#define PALSIZE 768 + UINT8 palette[PALSIZE]; + const UINT8 *pal; + RGBA_t *image; + size_t pw, ph, size, getc, ptr = 0; + INT32 ch, rep; + + if (source_size < sizeof(PcxHeader) + PALSIZE) + return 0; + + memcpy(&header, source, sizeof(PcxHeader)); + + if (header.bitsPerPixel != 8) + return 0; + + pw = *w = header.xmax - header.xmin + 1; + ph = *h = header.ymax - header.ymin + 1; + image = Z_Malloc(pw*ph*4, PU_HWRMODELTEXTURE, &grpatch->mipmap->data); + + memcpy(&palette, source + source_size - PALSIZE, sizeof(UINT8) * PALSIZE); + + getc = sizeof(PcxHeader); + + size = pw * ph; + while (ptr < size) + { + ch = source[getc]; + getc++; //Hurdler: beurk + if (ch >= 192) + { + rep = ch - 192; + ch = source[getc]; + getc++; + } + else + { + rep = 1; + } + while (rep--) + { + pal = palette + ch*3; + image[ptr].s.red = *pal++; + image[ptr].s.green = *pal++; + image[ptr].s.blue = *pal++; + image[ptr].s.alpha = 0xFF; + ptr++; + } + } + return GL_TEXFMT_RGBA; +} + +/* +Assigns all of the textures (either blend or normal) from a model zip folder. +Requires at minimum an 'A' frame (as in THOKA for the thok object) in a sprite model or a DEFAULT for a sprite2 model. +Sprite2 models can also load in textures for Super frames, with an optional super default + + In sprite models, the A frame is required. Any extra textures after this (B, C, onwards, following sprite naming conventions) are filled in when possible + The model will look for the latest frame less than or equal to than the current frame number, so a first texture is necessary. + + In sprite2 models, a regular DEFAULT frame is required, with an optional super default frame, which will act as a fallback for any super frames. + Each spr2 animation optionally gets its own set of textures, which can be animated, similarly to sprite models, by including multiple at once. + These can also be completely omitted, which will result in falling back to the relevant default texture, which can be useful in preventing unnecessary texture bloat + +Returns true if any textures are loaded sucessfully. Does not error or return false if non-required textures fail to load +*/ +static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT16 endlump, model_t *model, boolean blend, size_t spriteModelIndex) +{ + int i = 0, width = 0, height = 0; char prefix[MAXSPRITENAME + 1]; + char folderpath[10]; + textureframe_t **texarray = blend ? &model->blends : &model->textures; + UINT8 *texarraynum = blend ? &model->numblends : &model->numtextures; UINT8 *buffer; size_t size; + UINT32 imgsize; + RGBA_t *image; + boolean png; + char *imgname = ZZ_Alloc(sizeof(char) * (9 + MAXSPRITENAME + 6)); //(Textures/[MAXSPRITENAME]A.png) + + if (blend) + strcpy(folderpath, "Blends/"); + else + strcpy(folderpath, "Textures/"); - - if (spriteModelIndex != NULL) + if (spriteModelIndex) /* regular sprite model loading, use sprite name + frame char ex: THOKA for first frame of the thok, THOK0 for 27th uses r_things.h Char2Frame for this, parity with sprite naming conventions */ { - textureframe_t *texarray; textureframe_t texarraybuffer[256]; + patch_t **patches; + patch_t *patch; + GLPatch_t *hwpatch; UINT8 texloaded = 0; + UINT16 firstlump; + + strcpy(prefix, sprnames[spriteModelIndex]); + //make sure that a sprite model always contains a [prefix]A frame; the first frame + sprintf(imgname, "%s%sA.png", folderpath, prefix); // Textures/THOKA.png for a non-blend thok texture + firstlump = INT16_MAX; + +#ifdef HAVE_PNG + firstlump = Resource_CheckNumForName(zip, imgname); + png = true; +#endif + if (firstlump == INT16_MAX) + { + FIL_ForceExtension(imgname, ".pcx"); + firstlump = Resource_CheckNumForName(zip, imgname); + png = false; + } + Z_Free(imgname); + if (firstlump == INT16_MAX) + { + if (*texarraynum) + { + FreeTextureframe(*texarray, *texarraynum); + *texarray = NULL; + *texarraynum = 0; + } + return false; + } + else + { + buffer = Resource_CacheLumpNum(zip, firstlump, PU_STATIC); + size = Resource_LumpLength(zip, firstlump); + + patch = Patch_Create(0, 0); + hwpatch = Patch_AllocateHardwarePatch(patch); + +#ifdef HAVE_PNG + if (png) + hwpatch->mipmap->format = PNG_Load(buffer, size, &width, &height, hwpatch); + else +#endif + hwpatch->mipmap->format = PCX_Load(buffer, size, &width, &height, hwpatch); + + Z_Free(buffer); + + if (hwpatch->mipmap->format != 0) + { + patch->width = (INT16)width; + patch->height = (INT16)height; + hwpatch->mipmap->width = (INT16)width; + hwpatch->mipmap->height = (INT16)height; + + // for palette rendering, color cube is applied in post-processing instead of here + if (!HWR_ShouldUsePaletteRendering()) + { + // Lactozilla: Apply colour cube + image = hwpatch->mipmap->data; + imgsize = width*height; + while (imgsize--) + { + V_CubeApply(&image->s.red, &image->s.green, &image->s.blue); + image++; + } + } + + textureframe_t texframe; + texframe.numtextures = 1; + + patches = ZZ_Alloc(sizeof(patch_t*)); //allocate patch (pointer) array of length 1 for each textureframe in the array + patches[0] = patch; + texframe.patches = patches; + UINT8 *frames = ZZ_Alloc(sizeof(UINT8)); + //each textureframe also includes a list of the actual frames that each texture corresponds to, incase theyre loaded out of order or skip frames. + //because we're only loading the required default texture here, this is 0, otherwise itll be the the number that corresponds to the character in the filename + frames[0] = 0; + texframe.frames = frames; + + texarraybuffer[texloaded] = texframe; + texloaded++; + } + else + { + Patch_Free(patch); + if (*texarraynum) + { + FreeTextureframe(*texarray, *texarraynum); + *texarray = NULL; + *texarraynum = 0; + } + return false; + } + } + for (i = startlump; i < endlump; i++) { + if (i == firstlump) + continue; + lumpinfo_t lumpinfo = zip->lumpinfo[i]; if (!strnicmp(prefix, lumpinfo.longname, strlen(prefix))) //create textureframe_ts that only contain a single texture, put them all in the textures/blends field of the model_t @@ -558,38 +913,62 @@ boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT16 endlu continue; buffer = Resource_CacheLumpNum(zip, i, PU_STATIC); - size = Resource_LumpLength(zip, i, PU_STATIC); + size = Resource_LumpLength(zip, i); - textureframe_t texframe; - texframe.numtextures = 1; + patch = Patch_Create(0, 0); + hwpatch = Patch_AllocateHardwarePatch(patch); +#ifdef HAVE_PNG + hwpatch->mipmap->format = PNG_Load(buffer, size, &width, &height, hwpatch); + if (hwpatch->mipmap->format == 0) +#endif + hwpatch->mipmap->format = PCX_Load(buffer, size, &width, &height, hwpatch); - GLPatch_t **patcharray = ZZ_Alloc(sizeof(GLPatch_t*)); - GLPatch_t *grpatch = ZZ_Alloc(sizeof(GLPatch_t)); - //make grpatch here - patcharray[0] = grpatch; - texframe.grpatches = patcharray; - UINT8 *frames = ZZ_Alloc(sizeof(UINT8)); - frames[0] = framenum; - texframe.frames = frames; + Z_Free(buffer); + if (hwpatch->mipmap->format == 0) + { + Patch_Free(patch); + continue; + } + else + { + patch->width = (INT16)width; + patch->height = (INT16)height; + hwpatch->mipmap->width = (INT16)width; + hwpatch->mipmap->height = (INT16)height; - texarraybuffer[texloaded] = texframe; - texloaded++; + // for palette rendering, color cube is applied in post-processing instead of here + if (!HWR_ShouldUsePaletteRendering()) + { + // Lactozilla: Apply colour cube + image = hwpatch->mipmap->data; + imgsize = width*height; + while (imgsize--) + { + V_CubeApply(&image->s.red, &image->s.green, &image->s.blue); + image++; + } + } + + textureframe_t texframe; + texframe.numtextures = 1; + + patches = ZZ_Alloc(sizeof(patch_t*)); + patches[0] = patch; + texframe.patches = patches; + UINT8 *frames = ZZ_Alloc(sizeof(UINT8)); + frames[0] = framenum; + texframe.frames = frames; + + texarraybuffer[texloaded] = texframe; + texloaded++; + } } } - - texarray = ZZ_Alloc(sizeof(textureframe_t) * texloaded); + if (*texarray && (*texarray)[0].numtextures) + FreeTextureframe(*texarray, *texarraynum); //free whole thing bc texloaded could technically be different + *texarray = ZZ_Alloc(sizeof(textureframe_t) * texloaded); memcpy(texarray, texarraybuffer, sizeof(textureframe_t) * texloaded); - - if (blend) - { - model->blends = texarray; - model->numblends = texloaded; - } - else - { - model->textures = texarray; - model->numtextures = texloaded; - } + *texarraynum = texloaded; } else if (model->spr2frames) /* @@ -599,105 +978,138 @@ boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT16 endlu */ { //first, load the default textures. the regular default must exist, but the super does not - textureframe_t *texarray = ZZ_Alloc(sizeof(textureframe_t)); - textureframe_t defaults; - GLPatch_t *default; - GLPatch_t *superdefault; - GLPatch_t **defaultpatches; + patch_t *patch; + GLPatch_t *hwpatch; + int numdefaults = 0; + patch_t **defaultpatches; UINT8 *defaultframes; - int numdefaults = 1; + UINT16 lumpnum; - UINT8 lumpnum; - - if (blend) - { - lumpnum = Resource_CheckNumForName(zip, "Blend/DEFAULT.png"); - buffer = Resource_CacheLumpNum(zip, lumpnum, PU_STATIC); - size = Resource_LumpLength(zip, lumpnum); - //load png to default - - if (!(lumpnum = Resource_CheckNumForName(zip, "Blend/Super/DEFAULT.png") == INT16_MAX)) - { - superdefault = ZZ_Alloc(sizeof(GLPatch_t)); - - buffer = Resource_CacheLumpNum(zip, lumpnum, PU_STATIC); - size = Resource_LumpLength(zip, lumpnum); - if (Picture_IsLumpPNG(buffer, size)) - { - - } - //load png to superdefault - free(buffer); - numdefaults = 2; - } - - defaultpatches = ZZ_Alloc(sizeof(GLPatch_t*) * numdefaults); - defaultframes = ZZ_Alloc(sizeof(UINT8) * numdefaults); - defaultpatches[0] = default; - defaultframes[0] = 0; - - if (numdefaults > 1) - { - defaultpatches[1] = superdefault; - defaultframes[1] = 1; - } - - texarray[0] = defaults; - model->blends = texarray; - model->numblends = 1; - } + defaultpatches = ZZ_Alloc(sizeof(patch_t*) * 2); + defaultframes = ZZ_Alloc(sizeof(UINT8) * 2); + if (*texarraynum) + FreeTextureframeData(texarray[0]); //only free data because the array will always be length 1 if it exists else - { - lumpnum = Resource_CheckNumForName(zip, "Textures/DEFAULT.png"); - buffer = Resource_CacheLumpNum(zip, lumpnum, PU_STATIC); - size = Resource_LumpLength(zip, lumpnum); - //load png to default + *texarray = ZZ_Alloc(sizeof(textureframe_t)); - if (!(lumpnum = Resource_CheckNumForName(zip, "Textures/Super/DEFAULT.png") == INT16_MAX)) + for (i = 0; i < 2; i++) + { + sprintf(imgname, "%s%sDEFAULT.png", folderpath, (i > 0 ? "Super/" : "")); // Blends/Super/DEFAULT.png for default super blend texture + lumpnum = INT16_MAX; + +#ifdef HAVE_PNG + lumpnum = Resource_CheckNumForName(zip, imgname); + png = true; +#endif + if (lumpnum == INT16_MAX) + { + FIL_ForceExtension(imgname, ".pcx"); + lumpnum = Resource_CheckNumForName(zip, imgname); + png = false; + } + Z_Free(imgname); + if (lumpnum == INT16_MAX) + { + if (i > 0) + break; //only return if first fails, otherwise ignore + Z_Free(defaultpatches); + Z_Free(defaultframes); + FreeTextureframe(*texarray, *texarraynum); + *texarray = NULL; + *texarraynum = 0; + return false; + } + else { - superdefault = ZZ_Alloc(sizeof(GLPatch_t)); - buffer = Resource_CacheLumpNum(zip, lumpnum, PU_STATIC); size = Resource_LumpLength(zip, lumpnum); - //load png to superdefault - numdefaults = 2; + + patch = Patch_Create(0, 0); + hwpatch = Patch_AllocateHardwarePatch(patch); +#ifdef HAVE_PNG + if (png) + hwpatch->mipmap->format = PNG_Load(buffer, size, &width, &height, hwpatch); + else +#endif + hwpatch->mipmap->format = PCX_Load(buffer, size, &width, &height, hwpatch); + + Z_Free(buffer); + + if (hwpatch->mipmap->format != 0) + { + numdefaults++; + patch->width = (INT16)width; + patch->height = (INT16)height; + hwpatch->mipmap->width = (INT16)width; + hwpatch->mipmap->height = (INT16)height; + + // for palette rendering, color cube is applied in post-processing instead of here + if (!HWR_ShouldUsePaletteRendering()) + { + // Lactozilla: Apply colour cube + image = hwpatch->mipmap->data; + imgsize = width*height; + while (imgsize--) + { + V_CubeApply(&image->s.red, &image->s.green, &image->s.blue); + image++; + } + } + + defaultpatches[i] = patch; + defaultframes[i] = i; + } + else + { + Patch_Free(patch); + if (i > 0) + break; //only return if first fails, otherwise ignore + + FreeTextureframe(*texarray, *texarraynum); + *texarray = NULL; + *texarraynum = 0; + Z_Free(defaultpatches); + Z_Free(defaultframes); + return false; + } } - - defaultpatches = ZZ_Alloc(sizeof(GLPatch_t*) * numdefaults); - defaultframes = ZZ_Alloc(sizeof(UINT8) * numdefaults); - defaultpatches[0] = default; - defaultframes[0] = 0; - - if (numdefaults > 1) - { - defaultpatches[1] = superdefault; - defaultframes[1] = 1; - } - - texarray[0] = defaults; - model->textures = texarray; - model->numtextures = 1; } + (*texarray)[0].numtextures = numdefaults; + (*texarray)[0].patches = defaultpatches; + (*texarray)[0].frames = defaultframes; + *texarraynum = 1; + //load the rest of the textures, also figure out which ones are super frames UINT16 superstart, superend; - superstart = Resource_CheckNumForFolderStartPK3(zip, "Textures/Super", startlump); - superend = Resource_CheckNumForFolderEndPK3(zip, "Textures/Super", startlump); - if (blend) - { - superstart = Resource_CheckNumForFolderStartPK3(zip, "Blend/Super", startlump); - superend = Resource_CheckNumForFolderEndPK3(zip, "Blend/Super", startlump); - } + char *superpath = ZZ_Alloc(sizeof(char) * 15); + sprintf(superpath, "%sSuper", folderpath); + superstart = Resource_CheckNumForFolderStartPK3(zip, superpath, startlump); + superend = Resource_CheckNumForFolderEndPK3(zip, superpath, startlump); + Z_Free(superpath); - for (int s = 0; s < free_spr2; s++) + for (UINT16 s = 0; s < free_spr2; s++) //create a textureframe_t for each spr2, which hold as many textures as provided. each goes into the corresponding modelspr2frames_t + //if we've reached this point, that means the model has at least a default texture, so any name or loading issues are just ignored { - GLPatch_t *grbuffer[256]; - GLPatch_t *supergrbuffer[256]; + patch_t *patchbuffer[256]; + patch_t *superpatchbuffer[256]; UINT8 framebuffer[256]; UINT8 superframebuffer[256]; - UINT8 numtextures = 0; - UINT8 numsupertextures = 0; + UINT8 numtexs = 0, numsupertexs = 0; + + if (blend) + { + FreeTextureframeData(&model->spr2frames[s].blends); + if (model->superspr2frames) + FreeTextureframeData(&model->superspr2frames[s].blends); + } + else + { + FreeTextureframeData(&model->spr2frames[s].textures); + if (model->superspr2frames) + FreeTextureframeData(&model->superspr2frames[s].textures); + } strcpy(prefix, spr2names[s]); for (i = startlump; i < endlump; i++) @@ -709,36 +1121,76 @@ boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT16 endlu if (!strnicmp(prefix, lumpinfo.longname, strlen(prefix))) { char frame[4]; - strcpy(frame, lumpinfo.longname + 4); + memset(frame, '\0', 4); + strcpy(frame, lumpinfo.longname + strlen(prefix)); int framenum = atoi(frame) - 1; if (framenum < 0 || framenum > 255) continue; buffer = Resource_CacheLumpNum(zip, i, PU_STATIC); - if (super) + size = Resource_LumpLength(zip, i); + + patch = Patch_Create(0, 0); + hwpatch = Patch_AllocateHardwarePatch(patch); +#ifdef HAVE_PNG + hwpatch->mipmap->format = PNG_Load(buffer, size, &width, &height, hwpatch); + if (hwpatch->mipmap->format == 0) +#endif + hwpatch->mipmap->format = PCX_Load(buffer, size, &width, &height, hwpatch); + + Z_Free(buffer); + if (hwpatch->mipmap->format == 0) { - //supergrpatches[numsupertextures] = - superframebuffer[numsupertextures] = framenum; - numsupertextures++; + Patch_Free(patch); + continue; } else { - //grpatches[numtextures] = - framebuffer[numtextures] = framenum; - numtextures++; + patch->width = (INT16)width; + patch->height = (INT16)height; + hwpatch->mipmap->width = (INT16)width; + hwpatch->mipmap->height = (INT16)height; + + // for palette rendering, color cube is applied in post-processing instead of here + if (!HWR_ShouldUsePaletteRendering()) + { + // Lactozilla: Apply colour cube + image = hwpatch->mipmap->data; + imgsize = width*height; + while (imgsize--) + { + V_CubeApply(&image->s.red, &image->s.green, &image->s.blue); + image++; + } + } + + if (super) + { + if (!model->superspr2frames) + continue; + superpatchbuffer[numsupertexs] = patch; + superframebuffer[numsupertexs] = framenum; + numsupertexs++; + } + else + { + patchbuffer[numtexs] = patch; + framebuffer[numtexs] = framenum; + numtexs++; + } } } } - if (numtextures) + if (numtexs) { - GLPatch_t **grpatches = ZZ_Alloc(sizeof(GLPatch_t*) * numtextures); - memcpy(grpatches, grbuffer, sizeof(GLPatch_t) * numtextures); + patch_t **patches = ZZ_Alloc(sizeof(patch_t*) * numtexs); + memcpy(patches, patchbuffer, sizeof(patch_t*) * numtexs); - UINT8 *frames = ZZ_Alloc(sizeof(UINT8) * numtextures); - memcpy(frames, framebuffer, sizeof(UINT8) * numtextures); + UINT8 *frames = ZZ_Alloc(sizeof(UINT8) * numtexs); + memcpy(frames, framebuffer, sizeof(UINT8) * numtexs); - textureframe_t texframe = {grpatches, frames, numtextures}; + textureframe_t texframe = {patches, frames, numtexs}; if (blend) model->spr2frames[s].blends = texframe; @@ -746,15 +1198,15 @@ boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT16 endlu model->spr2frames[s].textures = texframe; } - if (numsupertextures) + if (numsupertexs && model->superspr2frames) { - GLPatch_t **grpatches = ZZ_Alloc(sizeof(GLPatch_t*) * numsupertextures); - memcpy(grpatches, supergrbuffer, sizeof(GLPatch_t) * numsupertextures); + patch_t **patches = ZZ_Alloc(sizeof(patch_t*) * numsupertexs); + memcpy(patches, superpatchbuffer, sizeof(patch_t*) * numsupertexs); - UINT8 *frames = ZZ_Alloc(sizeof(UINT8) * numsupertextures); - memcpy(frames, superframebuffer, sizeof(UINT8) * numsupertextures); + UINT8 *frames = ZZ_Alloc(sizeof(UINT8) * numsupertexs); + memcpy(frames, superframebuffer, sizeof(UINT8) * numsupertexs); - textureframe_t texframe = {grpatches, frames, numsupertextures}; + textureframe_t texframe = {patches, frames, numsupertexs}; if (blend) model->superspr2frames[s].blends = texframe; @@ -763,6 +1215,115 @@ boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT16 endlu } } } + return true; +} + +static boolean AssignSingleModelTexture(const char *filename, model_t *model, boolean blend) +{ + UINT8 *buffer = NULL; + size_t size; + int width = 0, height = 0; + patch_t *patch; + GLPatch_t *hwpatch; + textureframe_t **texarray = blend ? &model->blends : &model->textures; + UINT8 *texarraynum = blend ? &model->numblends : &model->numtextures; + boolean png; + FILE *f = NULL; + char *imgname = ZZ_Alloc(sizeof(char) * strlen(filename + 11)); + strcpy(imgname, filename); + + if (blend) + FIL_ForceExtension(imgname, "_blend.png"); + else + FIL_ForceExtension(imgname, ".png"); + +#ifdef HAVE_PNG + f = fopen(imgname, "rb"); + png = true; +#endif + if (!f) + { + FIL_ForceExtension(imgname, ".pcx"); + f = fopen(imgname, "rb"); + png = false; + + if (!f) + { + Z_Free(imgname); + return false; + } + } + Z_Free(imgname); + + fseek(f, 0, SEEK_END); + size = ftell(f); + fseek(f, 0, SEEK_SET); + + buffer = ZZ_Alloc(sizeof(UINT8) * size); + + if (fread(buffer, sizeof(UINT8), size, f) != size) + { + fclose(f); + return false; + } + + patch = Patch_Create(0, 0); + hwpatch = Patch_AllocateHardwarePatch(patch); + +#ifdef HAVE_PNG + if (png) + hwpatch->mipmap->format = PNG_Load(buffer, size, &width, &height, hwpatch); + else +#endif + hwpatch->mipmap->format = PCX_Load(buffer, size, &width, &height, hwpatch); + + + Z_Free(buffer); + if (hwpatch->mipmap->format == 0) + { + Patch_Free(patch); + return false; + } + + patch->width = (INT16)width; + patch->height = (INT16)height; + hwpatch->mipmap->width = (INT16)width; + hwpatch->mipmap->height = (INT16)height; + + // for palette rendering, color cube is applied in post-processing instead of here + if (!HWR_ShouldUsePaletteRendering()) + { + UINT32 imgsize; + RGBA_t *image; + // Lactozilla: Apply colour cube + image = hwpatch->mipmap->data; + imgsize = width*height; + while (imgsize--) + { + V_CubeApply(&image->s.red, &image->s.green, &image->s.blue); + image++; + } + } + + if (*texarray && (*texarray)[0].numtextures) + FreeTextureframeData(texarray[0]); + else + *texarray = ZZ_Alloc(sizeof(textureframe_t*)); + + textureframe_t texframe; + texframe.numtextures = 1; + + patch_t **patcharray = ZZ_Alloc(sizeof(patch_t*)); + patcharray[0] = patch; + texframe.patches = patcharray; + UINT8 *frames = ZZ_Alloc(sizeof(UINT8)); + frames[0] = 0; + texframe.frames = frames; + + (*texarray)[0] = texframe; + *texarraynum = 1; + + return true; } modeltexload_t LoadModelTextures(const char *filename, model_t *model, wadfile_t *zip, size_t spriteModelIndex) @@ -773,25 +1334,33 @@ modeltexload_t LoadModelTextures(const char *filename, model_t *model, wadfile_t { if (Resource_LumpExists(zip, "Textures/DEFAULT.png"))//required for anything else, last-resort fallback texture for everything { - UINT16 startlump, endlump; + UINT16 startlump = 0, endlump = 0; startlump = Resource_CheckNumForFolderStartPK3(zip, "Textures", startlump); endlump = Resource_CheckNumForFolderEndPK3(zip, "Textures", startlump); - AssignZippedModelTextures(zip, startlump, endlump, model, false, spriteModelIndex); - filesloaded = TEXLOAD_TEXTURE; - if (Resource_LumpExists(zip, "Blend/DEFAULT.png")) //same thing + if (AssignZippedModelTextures(zip, startlump, endlump, model, false, spriteModelIndex)) { - startlump = Resource_CheckNumForFolderStartPK3(zip, "Blend", startlump); - endlump = Resource_CheckNumForFolderEndPK3(zip, "Blend", startlump); - AssignZippedModelTextures(zip, startlump, endlump, model, true, spriteModelIndex); - filesloaded = TEXLOAD_BLEND; + filesloaded = TEXLOAD_TEXTURE; + if (Resource_LumpExists(zip, "Blends/DEFAULT.png")) //same thing + { + startlump = Resource_CheckNumForFolderStartPK3(zip, "Blends", startlump); + endlump = Resource_CheckNumForFolderEndPK3(zip, "Blends", startlump); + if (AssignZippedModelTextures(zip, startlump, endlump, model, true, spriteModelIndex)) + filesloaded = TEXLOAD_BLEND; + } } } - return filesloaded; } else //normal md3/2, default back to normal texture loading { + if (AssignSingleModelTexture(filename, model, false)) + { + filesloaded = TEXLOAD_TEXTURE; + if (AssignSingleModelTexture(filename, model, true)) + filesloaded = TEXLOAD_BLEND; + } } + return filesloaded; } // diff --git a/src/hardware/hw_model.h b/src/hardware/hw_model.h index 7fdb2b6a5..d3f7765d5 100644 --- a/src/hardware/hw_model.h +++ b/src/hardware/hw_model.h @@ -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 { @@ -83,7 +85,17 @@ typedef struct tag_s #define MODEL_0ANGLE_FLAG 'o' #define MODEL_NO_0ANGLE_FLAG 'n' -typedef enum //results from the LoadModelTexture function +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, @@ -92,7 +104,7 @@ typedef enum //results from the LoadModelTexture function typedef struct { - void **grpatches; + patch_t **patches; UINT8 *frames; UINT8 numtextures; } textureframe_t; @@ -149,6 +161,7 @@ void HWR_ReloadModels(void); tag_t *GetTagByName(model_t *model, char *name, int frame); 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 LoadModelSettings(model_t *model, size_t spriteModelIndex); void LoadModelSprite2(model_t *model); @@ -157,6 +170,6 @@ 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); -model_t *LoadModelZip(const char *filename, int ztag); +modeltexload_t LoadModelTextures(const char *filename, model_t *model, wadfile_t *zip, size_t spriteModelIndex); #endif diff --git a/src/r_picformats.c b/src/r_picformats.c index d71657021..281029670 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -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)) diff --git a/src/r_picformats.h b/src/r_picformats.h index 098f927a5..8d7f63508 100644 --- a/src/r_picformats.h +++ b/src/r_picformats.h @@ -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 From 5d16a6e8e15b49dbf162ceeb8a4ebb1c029489f5 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:39:34 -0700 Subject: [PATCH 13/30] hoooly shit --- src/hardware/hw_md2.c | 60 +++++++++++++++++++---------------- src/hardware/hw_model.c | 69 ++++++++++++++++++----------------------- 2 files changed, 63 insertions(+), 66 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 4a00f2c02..36cb3e1c6 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -155,7 +155,6 @@ static void md2_loadTextures(const char *filename, md2_t *md2) md2->noblendfile = true; if (texload == TEXLOAD_NONE) md2->notexturefile = true; - if (texload >= TEXLOAD_TEXTURE) { patch = md2->model->textures[0].patches[0]; //default frame of spr2 or first frame of sprite model or generated patch if no texture is found @@ -168,7 +167,8 @@ static patch_t *md2_getSpriteModelTexture(model_t *model, UINT8 frame, boolean b patch_t *patch; textureframe_t *texframe; UINT8 numtexs; - UINT8 closestframe = 0, closestframeindex = 0; + int closestframe = -1; + UINT8 closestframeindex = 0; texframe = model->textures; numtexs = model->numtextures; @@ -185,12 +185,7 @@ static patch_t *md2_getSpriteModelTexture(model_t *model, UINT8 frame, boolean b closestframeindex = i; break; } - else if (!closestframe && texframe[i].frames[0] < frame) - { - closestframe = texframe[i].frames[0]; - closestframeindex = i; - } - else if (texframe[i].frames[0] > closestframe && texframe[i].frames[0] < frame) + else if ((int)texframe[i].frames[0] > closestframe && texframe[i].frames[0] < frame) { closestframe = texframe[i].frames[0]; closestframeindex = i; @@ -205,7 +200,8 @@ static patch_t *md2_getSprite2ModelTexture(model_t *model, modelspr2frames_t *sp { patch_t *patch; textureframe_t texframe; - UINT8 closestframe = 0, closestframeindex = 0; + int closestframe = -1; + UINT8 closestframeindex = 0; texframe = spr2frames->textures; if (blend) @@ -219,21 +215,14 @@ static patch_t *md2_getSprite2ModelTexture(model_t *model, modelspr2frames_t *sp closestframeindex = i; break; } - else if (!closestframe && texframe.frames[i] < frame) - { - closestframe = texframe.frames[i]; - closestframeindex = i; - } - else if (texframe.frames[i] > closestframe && texframe.frames[i] < frame) + else if ((int)texframe.frames[i] > closestframe && texframe.frames[i] < frame) { closestframe = texframe.frames[i]; closestframeindex = i; } } - if (closestframe) - { + if (closestframe > -1) patch = texframe.patches[closestframeindex]; - } else //default { UINT8 defaultframe; @@ -1080,6 +1069,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) // 2. preliminary texture loading if not already loaded // 3. draw model with correct position, rotation,... // 4. use frame information to pick correct texture + boolean justloaded = false; if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) // Use the player MD2 list if the mobj has a skin and is using the player sprites { @@ -1101,7 +1091,10 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) md2->model = md2_readModel(filename, md2->index); if (md2->model) + { md2_printModelInfo(md2->model); + justloaded = true; + } else { //CONS_Debug(DBG_RENDER, " FAILED\n"); @@ -1123,12 +1116,10 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) { if (!hwrPatch) { - CONS_Printf("loadtex1\n"); md2_loadTextures(filename, md2); } else if (!hwrPatch->mipmap->format || !hwrPatch->mipmap->downloaded) { - CONS_Printf("loadtex2\n"); md2_loadTextures(filename, md2); } } @@ -1160,12 +1151,16 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) md2->noblendfile = true; else if(!hwrBlendPatch->mipmap->format) md2->noblendfile = true; - - if (md2->notexturefile) - adjustTextureCoords(md2->model, spr->gpatch); - md2->model->vbo_max_s = md2->model->max_s; - md2->model->vbo_max_t = md2->model->max_t; - HWD.pfnCreateModelVBOs(md2->model); + + //do this now, since the textures are now loaded + if (justloaded) + { + if (md2->notexturefile) + adjustTextureCoords(md2->model, spr->gpatch); + md2->model->vbo_max_s = md2->model->max_s; + md2->model->vbo_max_t = md2->model->max_t; + HWD.pfnCreateModelVBOs(md2->model); + } if (spr->mobj->frame & FF_ANIMATE) { @@ -1387,7 +1382,18 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) float step = fabsf(frameStep) * pol; intframe = (offsetframe + step >= offsetframe + fabsf(frameStep)) ? nextoffsetframe : offsetframe + step; //same logic in r_opengl } - boolean super = P_ApplySuperFlagToSprite2(0, spr->mobj); + + boolean super = false; + if (md2->model->superspr2frames) + { + for (UINT16 s = 0; s < free_spr2; s++) + if (spr2frames == &md2->model->superspr2frames[s]) + { + super = true; + break; + } + } + patch = md2_getSprite2ModelTexture(md2->model, spr2frames, intframe, super, false); if (!md2->noblendfile) blendpatch = md2_getSprite2ModelTexture(md2->model, spr2frames, intframe, super, true); diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index 0f2961e09..3215249df 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -76,6 +76,18 @@ static void FreeTextureframe(textureframe_t *texframe, UINT8 numtexframes) Z_Free(texframe); } +static void FreeSpr2Frames(modelspr2frames_t *spr2frames) +{ + for(UINT16 s = 0; s < free_spr2; s++) + { + if (spr2frames[s].textures.numtextures) + FreeTextureframeData(&spr2frames[s].textures); + if (spr2frames[s].blends.numtextures) + FreeTextureframeData(&spr2frames[s].blends); + } + Z_Free(spr2frames); +} + void UnloadModel(model_t *model) { // Wouldn't it be great if C just had destructors? @@ -145,28 +157,10 @@ void UnloadModel(model_t *model) Z_Free(model->frameNames); if (model->spr2frames) - { - for(UINT16 s = 0; s < free_spr2; s++) - { - if (model->spr2frames[s].textures.numtextures) - FreeTextureframeData(&model->spr2frames[s].textures); - if (model->spr2frames[s].blends.numtextures) - FreeTextureframeData(&model->spr2frames[s].blends); - } - Z_Free(model->spr2frames); - } + FreeSpr2Frames(model->spr2frames); if (model->superspr2frames) - { - for(UINT16 s = 0; s < free_spr2; s++) - { - if (model->superspr2frames[s].textures.numtextures) - FreeTextureframeData(&model->superspr2frames[s].textures); - if (model->superspr2frames[s].blends.numtextures) - FreeTextureframeData(&model->superspr2frames[s].blends); - } - Z_Free(model->superspr2frames); - } + FreeSpr2Frames(model->superspr2frames); if (model->numtextures) FreeTextureframe(model->textures, model->numtextures); @@ -565,9 +559,9 @@ void LoadModelSprite2(model_t *model) } if (model->spr2frames) - Z_Free(model->spr2frames); + FreeSpr2Frames(model->spr2frames); if (model->superspr2frames) - Z_Free(model->superspr2frames); + FreeSpr2Frames(model->spr2frames); model->spr2frames = spr2frames; model->superspr2frames = superspr2frames; } @@ -810,6 +804,7 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 //make sure that a sprite model always contains a [prefix]A frame; the first frame sprintf(imgname, "%s%sA.png", folderpath, prefix); // Textures/THOKA.png for a non-blend thok texture + CONS_Printf("imgname: %s\n", imgname); firstlump = INT16_MAX; #ifdef HAVE_PNG @@ -967,7 +962,7 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 if (*texarray && (*texarray)[0].numtextures) FreeTextureframe(*texarray, *texarraynum); //free whole thing bc texloaded could technically be different *texarray = ZZ_Alloc(sizeof(textureframe_t) * texloaded); - memcpy(texarray, texarraybuffer, sizeof(textureframe_t) * texloaded); + memcpy(*texarray, texarraybuffer, sizeof(textureframe_t) * texloaded); *texarraynum = texloaded; } else if (model->spr2frames) @@ -1126,7 +1121,9 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 int framenum = atoi(frame) - 1; if (framenum < 0 || framenum > 255) continue; - + if ((super && model->superspr2frames && framenum >= model->superspr2frames[s].numframes) || + (!super && framenum >= model->spr2frames[s].numframes)) + continue; buffer = Resource_CacheLumpNum(zip, i, PU_STATIC); size = Resource_LumpLength(zip, i); @@ -1332,22 +1329,16 @@ modeltexload_t LoadModelTextures(const char *filename, model_t *model, wadfile_t if (zip) //zip, can support animated textures { - if (Resource_LumpExists(zip, "Textures/DEFAULT.png"))//required for anything else, last-resort fallback texture for everything + UINT16 startlump = 0, endlump = 0; + startlump = Resource_CheckNumForFolderStartPK3(zip, "Textures", startlump); + endlump = Resource_CheckNumForFolderEndPK3(zip, "Textures", startlump); + if (AssignZippedModelTextures(zip, startlump, endlump, model, false, spriteModelIndex)) { - UINT16 startlump = 0, endlump = 0; - startlump = Resource_CheckNumForFolderStartPK3(zip, "Textures", startlump); - endlump = Resource_CheckNumForFolderEndPK3(zip, "Textures", startlump); - if (AssignZippedModelTextures(zip, startlump, endlump, model, false, spriteModelIndex)) - { - filesloaded = TEXLOAD_TEXTURE; - if (Resource_LumpExists(zip, "Blends/DEFAULT.png")) //same thing - { - startlump = Resource_CheckNumForFolderStartPK3(zip, "Blends", startlump); - endlump = Resource_CheckNumForFolderEndPK3(zip, "Blends", startlump); - if (AssignZippedModelTextures(zip, startlump, endlump, model, true, spriteModelIndex)) - filesloaded = TEXLOAD_BLEND; - } - } + filesloaded = TEXLOAD_TEXTURE; + startlump = Resource_CheckNumForFolderStartPK3(zip, "Blends", startlump); + endlump = Resource_CheckNumForFolderEndPK3(zip, "Blends", startlump); + if (AssignZippedModelTextures(zip, startlump, endlump, model, true, spriteModelIndex)) + filesloaded = TEXLOAD_BLEND; } } else //normal md3/2, default back to normal texture loading From 5c56c4649fdf3bf225af57ce41050a8322c662ce Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:56:38 -0700 Subject: [PATCH 14/30] oops --- src/hardware/hw_model.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index 3215249df..e3fc41258 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -804,7 +804,6 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 //make sure that a sprite model always contains a [prefix]A frame; the first frame sprintf(imgname, "%s%sA.png", folderpath, prefix); // Textures/THOKA.png for a non-blend thok texture - CONS_Printf("imgname: %s\n", imgname); firstlump = INT16_MAX; #ifdef HAVE_PNG From 321fbcac31e49f17e88bdefb3924035279610197 Mon Sep 17 00:00:00 2001 From: kaldrum Date: Tue, 25 Jun 2024 22:27:53 -0700 Subject: [PATCH 15/30] istg --- src/hardware/hw_md2load.c | 1 - src/hardware/hw_md3load.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/hardware/hw_md2load.c b/src/hardware/hw_md2load.c index 12991e728..2a0f1bfd5 100644 --- a/src/hardware/hw_md2load.c +++ b/src/hardware/hw_md2load.c @@ -522,6 +522,5 @@ model_t *MD2_LoadModel(char *buffer, int ztag, boolean useFloat) } } - free(buffer); return retModel; } diff --git a/src/hardware/hw_md3load.c b/src/hardware/hw_md3load.c index 19b3b79e9..5f622255a 100644 --- a/src/hardware/hw_md3load.c +++ b/src/hardware/hw_md3load.c @@ -496,7 +496,5 @@ model_t *MD3_LoadModel(char *buffer, int ztag, boolean useFloat) }*/ - free(buffer); - return retModel; } From e4f7ffcd0d241c09a75f714837aac4e6138c5ece Mon Sep 17 00:00:00 2001 From: kaldrum Date: Wed, 26 Jun 2024 03:27:03 -0700 Subject: [PATCH 16/30] fixed invalid alloc and free (both with strings for some reason) --- src/hardware/hw_model.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index e3fc41258..00060c695 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -778,7 +778,7 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 UINT32 imgsize; RGBA_t *image; boolean png; - char *imgname = ZZ_Alloc(sizeof(char) * (9 + MAXSPRITENAME + 6)); //(Textures/[MAXSPRITENAME]A.png) + char *imgname = ZZ_Alloc(sizeof(char) * (9 + MAXSPRITENAME + 7)); //(Textures/[MAXSPRITENAME]A.png) if (blend) strcpy(folderpath, "Blends/"); @@ -981,7 +981,7 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 defaultpatches = ZZ_Alloc(sizeof(patch_t*) * 2); defaultframes = ZZ_Alloc(sizeof(UINT8) * 2); - if (*texarraynum) + if (*texarray && texarray[0]) FreeTextureframeData(texarray[0]); //only free data because the array will always be length 1 if it exists else *texarray = ZZ_Alloc(sizeof(textureframe_t)); @@ -1001,11 +1001,13 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 lumpnum = Resource_CheckNumForName(zip, imgname); png = false; } - Z_Free(imgname); + if (lumpnum == INT16_MAX) { if (i > 0) break; //only return if first fails, otherwise ignore + + Z_Free(imgname); Z_Free(defaultpatches); Z_Free(defaultframes); FreeTextureframe(*texarray, *texarraynum); @@ -1059,6 +1061,7 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 if (i > 0) break; //only return if first fails, otherwise ignore + Z_Free(imgname); FreeTextureframe(*texarray, *texarraynum); *texarray = NULL; *texarraynum = 0; @@ -1069,6 +1072,8 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 } } + Z_Free(imgname); + (*texarray)[0].numtextures = numdefaults; (*texarray)[0].patches = defaultpatches; (*texarray)[0].frames = defaultframes; @@ -1225,7 +1230,7 @@ static boolean AssignSingleModelTexture(const char *filename, model_t *model, bo UINT8 *texarraynum = blend ? &model->numblends : &model->numtextures; boolean png; FILE *f = NULL; - char *imgname = ZZ_Alloc(sizeof(char) * strlen(filename + 11)); + char *imgname = ZZ_Alloc(sizeof(char) * (strlen(filename) + 12)); strcpy(imgname, filename); if (blend) From f9d25a77dc8a9528a90684a0417bd3ea4f8ebd9f Mon Sep 17 00:00:00 2001 From: kaldrum Date: Thu, 27 Jun 2024 21:00:49 -0700 Subject: [PATCH 17/30] fixed memory alloc in individual model texture allocation, fixed issue with blend texture access --- src/hardware/hw_md2.c | 6 +++--- src/hardware/hw_model.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 04baf708e..aa0314a49 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -164,7 +164,7 @@ static void md2_loadTextures(const char *filename, md2_t *md2) } static patch_t *md2_getSpriteModelTexture(model_t *model, UINT8 frame, boolean blend) { - patch_t *patch; + patch_t *patch = NULL; textureframe_t *texframe; UINT8 numtexs; int closestframe = -1; @@ -198,7 +198,7 @@ static patch_t *md2_getSpriteModelTexture(model_t *model, UINT8 frame, boolean b static patch_t *md2_getSprite2ModelTexture(model_t *model, modelspr2frames_t *spr2frames, UINT8 frame, boolean super, boolean blend) { - patch_t *patch; + patch_t *patch = NULL; textureframe_t texframe; int closestframe = -1; UINT8 closestframeindex = 0; @@ -234,7 +234,7 @@ static patch_t *md2_getSprite2ModelTexture(model_t *model, modelspr2frames_t *sp else { defaultframe = (super && model->textures[0].numtextures > 1) ? 1 : 0; - patch = model->textures[0].patches[(UINT8)super]; + patch = model->textures[0].patches[defaultframe]; } } return patch; diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index 00060c695..6084331ad 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -1309,7 +1309,7 @@ static boolean AssignSingleModelTexture(const char *filename, model_t *model, bo if (*texarray && (*texarray)[0].numtextures) FreeTextureframeData(texarray[0]); else - *texarray = ZZ_Alloc(sizeof(textureframe_t*)); + *texarray = ZZ_Alloc(sizeof(textureframe_t)); textureframe_t texframe; texframe.numtextures = 1; From 3864f65e949a13abec054bd3564233be3b82e14b Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:03:30 -0700 Subject: [PATCH 18/30] fixed memory leak, support for 256 frames in longsprite models, fixed issue with framename checking that broke some old models --- src/hardware/hw_md2.c | 30 +++++++++---------------- src/hardware/hw_model.c | 50 +++++++++++++++++++++++++++++++++-------- 2 files changed, 51 insertions(+), 29 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index aa0314a49..9b2dd8b97 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -830,7 +830,7 @@ static boolean HWR_CanInterpolateSprite2(modelspr2frames_t *spr2frame) return spr2frame->interpolate; } -static modelspr2frames_t *HWR_GetModelSprite2Frames(md2_t *md2, UINT16 spr2) +static modelspr2frames_t *HWR_GetModelSprite2Frames(md2_t *md2, UINT16 spr2, boolean *superframes) { if (!md2 || !md2->model) return NULL; @@ -846,7 +846,11 @@ static modelspr2frames_t *HWR_GetModelSprite2Frames(md2_t *md2, UINT16 spr2) { modelspr2frames_t *frames = md2->model->superspr2frames; if (frames && md2->model->superspr2frames[spr2].numframes) + { + if (superframes) + *superframes = true; return &md2->model->superspr2frames[spr2]; + } } if (md2->model->spr2frames[spr2].numframes) @@ -863,7 +867,7 @@ static UINT16 HWR_GetModelSprite2Num(md2_t *md2, skin_t *skin, UINT16 spr2, play if (!md2 || !md2->model || !md2->model->spr2frames || !skin) return 0; - while (!HWR_GetModelSprite2Frames(md2, spr2) + while (!HWR_GetModelSprite2Frames(md2, spr2, NULL) && spr2 != SPR2_STND && ++i < 32) // recursion limiter { @@ -962,6 +966,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) float nextFrame = -1.0f; float frameStep = 1.0f; modelspr2frames_t *spr2frames = NULL; + boolean super = false; FTransform p; FSurfaceInfo Surf; @@ -1122,13 +1127,9 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) if (!md2->notexturefile) { if (!hwrPatch) - { md2_loadTextures(filename, md2); - } else if (!hwrPatch->mipmap->format || !hwrPatch->mipmap->downloaded) - { md2_loadTextures(filename, md2); - } } } @@ -1186,9 +1187,9 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) { spr2 = HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player); //need this for setting the mod correctly when spr2defaults stuff happens if (spr->mobj->type == MT_PLAYER) - spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, P_ApplySuperFlagToSprite2(P_GetStateSprite2(spr->mobj->state), spr->mobj), spr->mobj->player)); + spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, P_ApplySuperFlagToSprite2(P_GetStateSprite2(spr->mobj->state), spr->mobj), spr->mobj->player), &super); else - spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr2, spr->mobj->player)); + spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr2, spr->mobj->player), &super); } if (spr2frames) { @@ -1389,19 +1390,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) float step = fabsf(frameStep) * pol; intframe = (offsetframe + step >= offsetframe + fabsf(frameStep)) ? nextoffsetframe : offsetframe + step; //same logic in r_opengl } - - boolean super = false; - if (md2->model->superspr2frames) - { - for (UINT16 s = 0; s < free_spr2; s++) - if (spr2frames == &md2->model->superspr2frames[s]) - { - super = true; - break; - } - } - patch = md2_getSprite2ModelTexture(md2->model, spr2frames, intframe, super, false); + patch = md2_getSprite2ModelTexture(md2->model, spr2frames, intframe, super, false); //super is set when spr2frames are if (!md2->noblendfile) blendpatch = md2_getSprite2ModelTexture(md2->model, spr2frames, intframe, super, true); else diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index 6084331ad..e09a9dfdd 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -434,8 +434,7 @@ void LoadModelSettings(model_t *model, size_t spriteModelIndex) if (start == -1){ for (size_t k = 0; k < NUMSPRITES; k++)//numsprites? { - - if (!memcmp(sprnames[k], framename, namechars)) + if (!memcmp(sprnames[k], framename, namechars) && namechars >= 4) //make sure sprite names are at least 4 chars long { if (&md2_models[k] == &md2_models[spriteModelIndex]) { @@ -778,7 +777,7 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 UINT32 imgsize; RGBA_t *image; boolean png; - char *imgname = ZZ_Alloc(sizeof(char) * (9 + MAXSPRITENAME + 7)); //(Textures/[MAXSPRITENAME]A.png) + char *imgname = ZZ_Alloc(sizeof(char) * (9 + MAXSPRITENAME + 9)); //(Textures/[MAXSPRITENAME]256.png) if (blend) strcpy(folderpath, "Blends/"); @@ -788,7 +787,7 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 if (spriteModelIndex) /* regular sprite model loading, use sprite name + frame char - ex: THOKA for first frame of the thok, THOK0 for 27th + ex: THOKA for first frame of the thok, THOK0 for 27th, OR THOK1 for first, THOK27 for 27th. have to pick one though (if using longsprites with a lot of frames probably a good idea to use numbers) uses r_things.h Char2Frame for this, parity with sprite naming conventions */ { @@ -798,11 +797,12 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 GLPatch_t *hwpatch; UINT8 texloaded = 0; UINT16 firstlump; + boolean numeric = false; strcpy(prefix, sprnames[spriteModelIndex]); - //make sure that a sprite model always contains a [prefix]A frame; the first frame + //make sure that a sprite model always contains a [prefix]A or [prefix]1 frame; the first frame sprintf(imgname, "%s%sA.png", folderpath, prefix); // Textures/THOKA.png for a non-blend thok texture firstlump = INT16_MAX; @@ -816,7 +816,25 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 firstlump = Resource_CheckNumForName(zip, imgname); png = false; } + + if (firstlump == INT16_MAX) + { + numeric = true; + sprintf(imgname, "%s%s1.png", folderpath, prefix); // Textures/THOKA.png for a non-blend thok texture +#ifdef HAVE_PNG + firstlump = Resource_CheckNumForName(zip, imgname); + png = true; +#endif + if (firstlump == INT16_MAX) + { + FIL_ForceExtension(imgname, ".pcx"); + firstlump = Resource_CheckNumForName(zip, imgname); + png = false; + } + } + Z_Free(imgname); + if (firstlump == INT16_MAX) { if (*texarraynum) @@ -901,10 +919,23 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 if (!strnicmp(prefix, lumpinfo.longname, strlen(prefix))) //create textureframe_ts that only contain a single texture, put them all in the textures/blends field of the model_t { - char frame = lumpinfo.longname[strlen(lumpinfo.longname) - 1]; - UINT8 framenum = R_Char2Frame(frame); - if (framenum > 63) - continue; + int framenum; + if (!numeric) + { + char frame = lumpinfo.longname[strlen(lumpinfo.longname) - 1]; + framenum = R_Char2Frame(frame); + if (framenum > 63) + continue; + } + else + { + char frame[4]; + memset(frame, '\0', 4); + strcpy(frame, lumpinfo.longname + strlen(prefix)); + int framenum = atoi(frame) - 1; + if (framenum < 0 || framenum > 255) + continue; + } buffer = Resource_CacheLumpNum(zip, i, PU_STATIC); size = Resource_LumpLength(zip, i); @@ -1267,6 +1298,7 @@ static boolean AssignSingleModelTexture(const char *filename, model_t *model, bo fclose(f); return false; } + fclose(f); patch = Patch_Create(0, 0); hwpatch = Patch_AllocateHardwarePatch(patch); From 112432a1cacb2ea203656282fb50ff6e2be31605 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:11:15 -0700 Subject: [PATCH 19/30] :| --- src/hardware/hw_model.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index e09a9dfdd..59703949e 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -919,7 +919,7 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 if (!strnicmp(prefix, lumpinfo.longname, strlen(prefix))) //create textureframe_ts that only contain a single texture, put them all in the textures/blends field of the model_t { - int framenum; + int framenum = 0; if (!numeric) { char frame = lumpinfo.longname[strlen(lumpinfo.longname) - 1]; @@ -932,7 +932,7 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 char frame[4]; memset(frame, '\0', 4); strcpy(frame, lumpinfo.longname + strlen(prefix)); - int framenum = atoi(frame) - 1; + framenum = atoi(frame) - 1; if (framenum < 0 || framenum > 255) continue; } From 5cfd9f1b8f4dc488a38e8740722d43d62471b639 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Fri, 5 Jul 2024 12:48:32 -0700 Subject: [PATCH 20/30] fix blend and super texture loading --- src/hardware/hw_model.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index 59703949e..0e7c9c5ff 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -1115,7 +1115,7 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 char *superpath = ZZ_Alloc(sizeof(char) * 15); sprintf(superpath, "%sSuper", folderpath); superstart = Resource_CheckNumForFolderStartPK3(zip, superpath, startlump); - superend = Resource_CheckNumForFolderEndPK3(zip, superpath, startlump); + superend = Resource_CheckNumForFolderEndPK3(zip, superpath, superstart); Z_Free(superpath); for (UINT16 s = 0; s < free_spr2; s++) @@ -1156,7 +1156,7 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 int framenum = atoi(frame) - 1; if (framenum < 0 || framenum > 255) continue; - if ((super && model->superspr2frames && framenum >= model->superspr2frames[s].numframes) || + if ((super && !model->superspr2frames) || (super && framenum >= model->superspr2frames[s].numframes) || (!super && framenum >= model->spr2frames[s].numframes)) continue; buffer = Resource_CacheLumpNum(zip, i, PU_STATIC); @@ -1198,8 +1198,6 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 if (super) { - if (!model->superspr2frames) - continue; superpatchbuffer[numsupertexs] = patch; superframebuffer[numsupertexs] = framenum; numsupertexs++; @@ -1232,18 +1230,18 @@ static boolean AssignZippedModelTextures(wadfile_t *zip, UINT16 startlump, UINT1 if (numsupertexs && model->superspr2frames) { - patch_t **patches = ZZ_Alloc(sizeof(patch_t*) * numsupertexs); - memcpy(patches, superpatchbuffer, sizeof(patch_t*) * numsupertexs); + patch_t **superpatches = ZZ_Alloc(sizeof(patch_t*) * numsupertexs); + memcpy(superpatches, superpatchbuffer, sizeof(patch_t*) * numsupertexs); - UINT8 *frames = ZZ_Alloc(sizeof(UINT8) * numsupertexs); - memcpy(frames, superframebuffer, sizeof(UINT8) * numsupertexs); + UINT8 *superframes = ZZ_Alloc(sizeof(UINT8) * numsupertexs); + memcpy(superframes, superframebuffer, sizeof(UINT8) * numsupertexs); - textureframe_t texframe = {patches, frames, numsupertexs}; + textureframe_t supertexframe = {superpatches, superframes, numsupertexs}; if (blend) - model->superspr2frames[s].blends = texframe; + model->superspr2frames[s].blends = supertexframe; else - model->superspr2frames[s].textures = texframe; + model->superspr2frames[s].textures = supertexframe; } } } @@ -1366,12 +1364,12 @@ modeltexload_t LoadModelTextures(const char *filename, model_t *model, wadfile_t if (zip) //zip, can support animated textures { UINT16 startlump = 0, endlump = 0; - startlump = Resource_CheckNumForFolderStartPK3(zip, "Textures", startlump); + startlump = Resource_CheckNumForFolderStartPK3(zip, "Textures", 0); endlump = Resource_CheckNumForFolderEndPK3(zip, "Textures", startlump); if (AssignZippedModelTextures(zip, startlump, endlump, model, false, spriteModelIndex)) { filesloaded = TEXLOAD_TEXTURE; - startlump = Resource_CheckNumForFolderStartPK3(zip, "Blends", startlump); + startlump = Resource_CheckNumForFolderStartPK3(zip, "Blends", 0); endlump = Resource_CheckNumForFolderEndPK3(zip, "Blends", startlump); if (AssignZippedModelTextures(zip, startlump, endlump, model, true, spriteModelIndex)) filesloaded = TEXLOAD_BLEND; From a3ec917e08b29aa7f68b3259dae82175a845a2c1 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Fri, 5 Jul 2024 17:07:02 -0700 Subject: [PATCH 21/30] fix various interpolation issues, make interpolation work properly with speed-adjusted animations, set accurate tic values to tails' tailsoverlay states so they animate properly (while airwalking) --- src/hardware/hw_md2.c | 87 ++++++++++++++++++++++++++++++++++++++----- src/info.c | 20 +++++----- 2 files changed, 87 insertions(+), 20 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 9b2dd8b97..393ee816c 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -952,11 +952,82 @@ static void adjustTextureCoords(model_t *model, patch_t *patch) model->max_t = gpatch->max_t; } +static INT32 GetAnimDuration(mobj_t *mobj) //part of p_mobj's setplayermobjstate logic, used to make sure that anim durations are actually correct when the speed gets adjusted on players +{ + player_t *player = mobj->player; + INT32 tics= mobj->state->tics; + + if (!player && mobj->type == MT_TAILSOVERLAY) //so tails overlays interpolate properly + player = mobj->tracer->player; + if (player) + { + if (player->panim == PA_EDGE && (player->charflags & SF_FASTEDGE)) + tics = 2; + else if (!(disableSpeedAdjust || player->charflags & SF_NOSPEEDADJUST)) + { + fixed_t speed;// = FixedDiv(player->speed, FixedMul(mobj->scale, player->mo->movefactor)); + if (player->panim == PA_FALL) + { + speed = FixedDiv(abs(mobj->momz), mobj->scale); + if (speed < 10<panim == PA_ABILITY2 && player->charability2 == CA2_SPINDASH) + { + fixed_t step = (player->maxdash - player->mindash)/4; + speed = (player->dashspeed - player->mindash); + if (speed > 3*step) + tics = 1; + else if (speed > step) + tics = 2; + else + tics = 3; + } + else + { + speed = FixedDiv(player->speed, FixedMul(mobj->scale, player->mo->movefactor)); + if (player->panim == PA_ROLL || player->panim == PA_JUMP) + { + if (speed > 16<charability == CA_FLOAT || player->charability == CA_SLOWFALL) && player->secondjump == 1) || player->powers[pw_super]) // Only if on the ground or superflying. + { + if (player->panim == PA_WALK) + { + if (speed > 12< 6<panim == PA_RUN) || (player->panim == PA_DASH)) + { + if (speed > 52<mobj->state->tics; + float durs = GetAnimDuration(spr->mobj); float tics = (float)spr->mobj->tics; const boolean papersprite = (R_ThingIsPaperSprite(spr->mobj) && !R_ThingIsFloorSprite(spr->mobj)); const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(spr->mobj)); @@ -1221,11 +1292,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) #ifdef USE_MODEL_NEXTFRAME // Interpolate the model interpolation. (lol?) - if (spr2frames) - { - if (spr2frames->extend && (!(paused || P_AutoPause())) && !hu_stopped) - tics -= FixedToFloat(g_time.timefrac); //this feels extremely bad and hacky, if theres a better way to still get intermediates at 35 fps please lmk - } + if (spr2frames && spr2frames->extend && (!(paused || P_AutoPause())) && !hu_stopped) + tics -= FixedToFloat(g_time.timefrac); //this feels extremely bad and hacky, if theres a better way to still get intermediates at 35 fps please lmk else tics -= FixedToFloat(rendertimefrac); @@ -1282,10 +1350,10 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) } } } - if (spr2frames){ + if (spr2frames) + { if ((!HWR_CanInterpolateSprite2(spr2frames)|| !cv_glmodelinterpolation.value) && spr2frames->extend) { - UINT16 next_spr2 = P_GetStateSprite2(&states[spr->mobj->state->nextstate]); next_spr2 = P_ApplySuperFlagToSprite2(next_spr2, spr->mobj); if (spr->mobj->frame & FF_ANIMATE @@ -1308,7 +1376,6 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) frameStep *= -1.0f; //use negative framestep to indicate extend without interpolation (also keeps value) } } - } #undef INTERPOLERATION_LIMIT #endif diff --git a/src/info.c b/src/info.c index d66c24af8..73253722a 100644 --- a/src/info.c +++ b/src/info.c @@ -799,18 +799,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 From 24cd749bd95cfc5d1e63017804a2e32fe65b44bb Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Sat, 6 Jul 2024 16:01:00 -0700 Subject: [PATCH 22/30] fix tailsfly animation speed issues --- src/hardware/hw_md2.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 393ee816c..3849fd010 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -955,7 +955,7 @@ static void adjustTextureCoords(model_t *model, patch_t *patch) static INT32 GetAnimDuration(mobj_t *mobj) //part of p_mobj's setplayermobjstate logic, used to make sure that anim durations are actually correct when the speed gets adjusted on players { player_t *player = mobj->player; - INT32 tics= mobj->state->tics; + INT32 tics = mobj->state->tics; if (!player && mobj->type == MT_TAILSOVERLAY) //so tails overlays interpolate properly player = mobj->tracer->player; @@ -963,6 +963,15 @@ static INT32 GetAnimDuration(mobj_t *mobj) //part of p_mobj's setplayermobjstate { if (player->panim == PA_EDGE && (player->charflags & SF_FASTEDGE)) tics = 2; + else if (player->powers[pw_tailsfly] && (!(player->mo->eflags & MFE_UNDERWATER) || (mobj->type == MT_PLAYER))) //tailsoverlay does not get adjusted from these rules when underwater + { + if (player->fly1 > 0) + tics = 1; + else if (!(player->mo->eflags & MFE_UNDERWATER)) + tics = 2; + else + tics = 4; + } else if (!(disableSpeedAdjust || player->charflags & SF_NOSPEEDADJUST)) { fixed_t speed;// = FixedDiv(player->speed, FixedMul(mobj->scale, player->mo->movefactor)); @@ -1121,8 +1130,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) } // Apparently people don't like jump frames like that, so back it goes - //if (tics > durs) - //durs = tics; + if (tics > durs) + durs = tics; // Make linkdraw objects use their tracer's alpha value fixed_t newalpha = spr->mobj->alpha; From 2ba87f19cc0f4149578c18547e3670c2850d9695 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Mon, 8 Jul 2024 00:51:52 -0700 Subject: [PATCH 23/30] fix to changes in sprites being ignored due to state-based animation --- src/hardware/hw_md2.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 3849fd010..c41f9fdc2 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1267,7 +1267,45 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) { spr2 = HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player); //need this for setting the mod correctly when spr2defaults stuff happens if (spr->mobj->type == MT_PLAYER) - spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, P_ApplySuperFlagToSprite2(P_GetStateSprite2(spr->mobj->state), spr->mobj), spr->mobj->player), &super); + { + UINT16 statespr2 = P_ApplySuperFlagToSprite2(P_GetStateSprite2(spr->mobj->state), spr->mobj); + UINT8 i = 0; + if ((spr2 & SPR2F_MASK) != (statespr2 & SPR2F_MASK)) + { + while (statespr2 != SPR2_STND + && ++i < 32) //recursion limiter + { + if (statespr2 == (spr2 & SPR2F_MASK)) + { + statespr2 = P_ApplySuperFlagToSprite2(P_GetStateSprite2(spr->mobj->state), spr->mobj); //current sprite spr2 is somewhere down the state's spr2defaults chain, should be good to use instead because the actual sprite is probably missing + break; + } + switch(statespr2) + { + // Normal special cases. + case SPR2_JUMP: + statespr2 = ((spr->mobj->player + ? spr->mobj->player->charflags + : ((skin_t *)spr->mobj->skin)->flags) + & SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_ROLL; + break; + case SPR2_TIRE: + statespr2 = ((spr->mobj->player + ? spr->mobj->player->charability + : ((skin_t *)spr->mobj->skin)->ability) + == CA_SWIM) ? SPR2_SWIM : SPR2_FLY; + break; + // Use the handy list, that's what it's there for! + default: + statespr2 = spr2defaults[statespr2]; + break; + } + } + if (i >= 32 || statespr2 == SPR2_STND) + statespr2 = P_ApplySuperFlagToSprite2(spr2, spr->mobj); //spr2 wasn't found, probably intentionally set by an addon to something else (still get to use super frames though) + } + spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, statespr2, spr->mobj->player), &super); + } else spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr2, spr->mobj->player), &super); } From f1a393facc81909a0743fe9d33cfc1538222f947 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Mon, 8 Jul 2024 15:27:42 -0700 Subject: [PATCH 24/30] adjust interpolation duration based on speed, allow anim_duration to be used as a lua override to hardcoded values --- src/hardware/hw_md2.c | 3 +++ src/p_mobj.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index c41f9fdc2..0f53d50a1 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -957,6 +957,9 @@ static INT32 GetAnimDuration(mobj_t *mobj) //part of p_mobj's setplayermobjstate player_t *player = mobj->player; INT32 tics = mobj->state->tics; + if (!(mobj->frame & FF_ANIMATE) && mobj->anim_duration) //set manually by something through lua + return mobj->anim_duration; + if (!player && mobj->type == MT_TAILSOVERLAY) //so tails overlays interpolate properly player = mobj->tracer->player; if (player) diff --git a/src/p_mobj.c b/src/p_mobj.c index 1ec09ab85..92133c1dc 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -96,11 +96,15 @@ static void P_SetupStateAnimation(mobj_t *mobj, state_t *st) animlength = st->var1; if (!(st->frame & FF_ANIMATE)) + { + mobj->anim_duration = 0; return; + } if (animlength <= 0 || st->var2 == 0) { mobj->frame &= ~FF_ANIMATE; + mobj->anim_duration = 0; return; // Crash/stupidity prevention } From 2cd436a8a8d1378172097a0a97bedb4f937c0672 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Wed, 10 Jul 2024 21:14:11 -0700 Subject: [PATCH 25/30] fix crash when tails tails dont have a tails to be the tail of --- src/hardware/hw_md2.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 0f53d50a1..dc2f8c8ec 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -960,7 +960,7 @@ static INT32 GetAnimDuration(mobj_t *mobj) //part of p_mobj's setplayermobjstate if (!(mobj->frame & FF_ANIMATE) && mobj->anim_duration) //set manually by something through lua return mobj->anim_duration; - if (!player && mobj->type == MT_TAILSOVERLAY) //so tails overlays interpolate properly + if (!player && mobj->type == MT_TAILSOVERLAY && mobj->tracer) //so tails overlays interpolate properly player = mobj->tracer->player; if (player) { @@ -1197,7 +1197,6 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) return false; } } - if (md2->model->textures == NULL && !md2->notexturefile) md2_loadTextures(filename, md2); @@ -1593,7 +1592,6 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, frameStep, &p, md2->scale * xs, md2->scale * ys, flip, hflip, &Surf); } } - return true; } From f300bd5355766d0eacb0ea9d684d42035544fba1 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Wed, 17 Jul 2024 21:23:31 -0700 Subject: [PATCH 26/30] fixed crash when patching skins ingame, made nights sprites not use super frames when not intentionally set to do so, fixed ghost mobjs not being set to super frames when the main model is --- src/hardware/hw_md2.c | 7 ++++++- src/hardware/hw_model.c | 13 +++++++------ src/hardware/hw_model.h | 2 ++ src/r_skins.c | 2 +- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index dc2f8c8ec..e4f0730f3 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1309,7 +1309,12 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, statespr2, spr->mobj->player), &super); } else - spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr2, spr->mobj->player), &super); + { + if (spr->mobj->type == MT_GHOST && spr->mobj->target && spr->mobj->target->player) //should likely always be super when the player is + spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, P_ApplySuperFlagToSprite2(spr2, spr->mobj->target), spr->mobj->player), &super); + else + spr2frames = HWR_GetModelSprite2Frames(md2, HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr2, spr->mobj->player), &super); + } } if (spr2frames) { diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index 0e7c9c5ff..00cf7456a 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -76,9 +76,9 @@ static void FreeTextureframe(textureframe_t *texframe, UINT8 numtexframes) Z_Free(texframe); } -static void FreeSpr2Frames(modelspr2frames_t *spr2frames) +static void FreeSpr2Frames(modelspr2frames_t *spr2frames, playersprite_t num_spr2) { - for(UINT16 s = 0; s < free_spr2; s++) + for(UINT16 s = 0; s < num_spr2; s++) { if (spr2frames[s].textures.numtextures) FreeTextureframeData(&spr2frames[s].textures); @@ -157,10 +157,10 @@ void UnloadModel(model_t *model) Z_Free(model->frameNames); if (model->spr2frames) - FreeSpr2Frames(model->spr2frames); + FreeSpr2Frames(model->spr2frames, model->numspr2); if (model->superspr2frames) - FreeSpr2Frames(model->superspr2frames); + FreeSpr2Frames(model->superspr2frames, model->numspr2); if (model->numtextures) FreeTextureframe(model->textures, model->numtextures); @@ -558,9 +558,10 @@ void LoadModelSprite2(model_t *model) } if (model->spr2frames) - FreeSpr2Frames(model->spr2frames); + FreeSpr2Frames(model->spr2frames, model->numspr2); if (model->superspr2frames) - FreeSpr2Frames(model->spr2frames); + FreeSpr2Frames(model->superspr2frames, model->numspr2); + model->numspr2 = free_spr2; model->spr2frames = spr2frames; model->superspr2frames = superspr2frames; } diff --git a/src/hardware/hw_model.h b/src/hardware/hw_model.h index d3f7765d5..cfbe052ab 100644 --- a/src/hardware/hw_model.h +++ b/src/hardware/hw_model.h @@ -135,6 +135,8 @@ typedef struct model_s char *frameNames; boolean interpolate[256]; signed char zeroangle[256]; + + playersprite_t numspr2; modelspr2frames_t *spr2frames; modelspr2frames_t *superspr2frames; diff --git a/src/r_skins.c b/src/r_skins.c index a341ee80f..6b6eea2af 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -82,7 +82,7 @@ UINT16 P_ApplySuperFlagToSprite2(UINT16 spr2, mobj_t *mobj) { if (mobj->player->charflags & SF_NOSUPERSPRITES || (mobj->player->powers[pw_carry] == CR_NIGHTSMODE && (mobj->player->charflags & SF_NONIGHTSSUPER))) spr2 &= ~SPR2F_SUPER; - else if (mobj->player->powers[pw_super] || (mobj->player->powers[pw_carry] == CR_NIGHTSMODE && (mobj->player->charflags & SF_SUPER))) + else if (mobj->player->powers[pw_super] && !(mobj->player->powers[pw_carry] == CR_NIGHTSMODE)) spr2 |= SPR2F_SUPER; } From 69c5e7af99b06ee0f5815e89ddf156d6978aff10 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Thu, 18 Jul 2024 21:25:33 -0700 Subject: [PATCH 27/30] revert NiGHTS thing --- src/r_skins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_skins.c b/src/r_skins.c index 6b6eea2af..a341ee80f 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -82,7 +82,7 @@ UINT16 P_ApplySuperFlagToSprite2(UINT16 spr2, mobj_t *mobj) { if (mobj->player->charflags & SF_NOSUPERSPRITES || (mobj->player->powers[pw_carry] == CR_NIGHTSMODE && (mobj->player->charflags & SF_NONIGHTSSUPER))) spr2 &= ~SPR2F_SUPER; - else if (mobj->player->powers[pw_super] && !(mobj->player->powers[pw_carry] == CR_NIGHTSMODE)) + else if (mobj->player->powers[pw_super] || (mobj->player->powers[pw_carry] == CR_NIGHTSMODE && (mobj->player->charflags & SF_SUPER))) spr2 |= SPR2F_SUPER; } From 81585955b1fba181eefb8226e4e4dccf7839bd36 Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Fri, 19 Jul 2024 12:23:22 -0700 Subject: [PATCH 28/30] fix issues with extended animations having textures set incorrectly --- src/hardware/hw_md2.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index e4f0730f3..2abb3da46 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1120,6 +1120,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) UINT16 spr2 = 0; spriteframe_t *sprframe; INT32 mod; + boolean extend = false; signed char zeroangle; interpmobjstate_t interp; @@ -1328,6 +1329,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) mod = defaultdef->numframes; else if (defaultdef->numframes < sprdef->numframes) mod = defaultdef->numframes; + else + extend = true; } if (!mod) @@ -1346,7 +1349,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) #ifdef USE_MODEL_NEXTFRAME // Interpolate the model interpolation. (lol?) - if (spr2frames && spr2frames->extend && (!(paused || P_AutoPause())) && !hu_stopped) + if (spr2frames && extend && (!(paused || P_AutoPause())) && !hu_stopped) tics -= FixedToFloat(g_time.timefrac); //this feels extremely bad and hacky, if theres a better way to still get intermediates at 35 fps please lmk else tics -= FixedToFloat(rendertimefrac); @@ -1406,7 +1409,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) } if (spr2frames) { - if ((!HWR_CanInterpolateSprite2(spr2frames)|| !cv_glmodelinterpolation.value) && spr2frames->extend) + if ((!HWR_CanInterpolateSprite2(spr2frames)|| !cv_glmodelinterpolation.value) && extend) { UINT16 next_spr2 = P_GetStateSprite2(&states[spr->mobj->state->nextstate]); next_spr2 = P_ApplySuperFlagToSprite2(next_spr2, spr->mobj); @@ -1500,7 +1503,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) UINT8 intframe = offsetframe; if (spr2frames) { - if (spr2frames->extend) + if (extend) { float nextoffsetframe = nextFrame - frame + offsetframe; float pol = (durs-tics)/durs; From 18e26f5deda2591c9e660923fe7d5a97672abc0b Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Fri, 19 Jul 2024 16:38:46 -0700 Subject: [PATCH 29/30] fix spr2defaults issue --- src/hardware/hw_md2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 2abb3da46..cd5ffef56 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1268,7 +1268,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) frame = (spr->mobj->frame & FF_FRAMEMASK); if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY && md2->model->spr2frames) { - spr2 = HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player); //need this for setting the mod correctly when spr2defaults stuff happens + spr2 = spr->mobj->sprite2; //need this for setting the mod correctly when spr2defaults stuff happens if (spr->mobj->type == MT_PLAYER) { UINT16 statespr2 = P_ApplySuperFlagToSprite2(P_GetStateSprite2(spr->mobj->state), spr->mobj); From 32c05fc0513f630894bc4097414bb40388829daa Mon Sep 17 00:00:00 2001 From: kaldrum1 <116390251+kaldrum1@users.noreply.github.com> Date: Thu, 1 Aug 2024 21:32:52 -0700 Subject: [PATCH 30/30] fix multi-model loading issue --- src/hardware/hw_model.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index 00cf7456a..26ba8591d 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -327,8 +327,9 @@ model_t *LoadModel(const char *filename, int ztag, size_t spriteModelIndex) Optimize(model); GeneratePolygonNormals(model, ztag); - LoadModelSprite2(model); - if (!model->spr2frames) + if (!spriteModelIndex) + LoadModelSprite2(model); + else LoadModelSettings(model, spriteModelIndex); // Default material properties @@ -408,7 +409,7 @@ void LoadModelSettings(model_t *model, size_t spriteModelIndex) count = 0; else if (count != atoi(framename + namechars + ((log10(count) < 2)? 0 : 1)))//if the counts dont match, set to 0 (should only happen if the frames are named really weirdly) count = 0; - namechars = strlen(framename) - 1 - (log10(count) < 2 ? 2 : floor(log10(count))); + namechars = strlen(framename) - (log10(count) < 2 ? 2 : floor(log10(count))); for (int j = 0; j < namechars; j++) { if (*(framename + j) == '+') //should add frame flags regardless of name prefix