sezero / quakespasm

QuakeSpasm -- A modern, cross-platform Quake game engine based on FitzQuake.
https://sourceforge.net/projects/quakespasm/
GNU General Public License v2.0
244 stars 97 forks source link

"Angled" sprites from FTEQW #73

Closed erysdren closed 1 year ago

erysdren commented 1 year ago

I found out that FTEQW supports "angled" sprites, i.e. ones that change frame based on player viewing angle. The code is rather simple.

I ported it to QuakeSpasm in a few minutes.

To author an angled sprite, one must construct a regular sprite with a traditional "Group Frame" (with 8 frames in the group), and mark the type integer as "2" rather than "1".

This can be done using my sprconv tool:

https://github.com/erysdren/sprconv

sezero commented 1 year ago

Any maps that uses this kind of sprites ?

erysdren commented 1 year ago

Not that I know of, but I've authored a few example sprites to show how they work. I thought it might be useful to modders, especially since the footprint in the codebase is so small.

Since an "angled" frame group has the same format as a regular "group" frame, it is represented as 1 frame in QuakeC. so you can animate a sprite walking, for example, and the engine (with these changes) will automatically switch to the correct frame based on the player's viewing perspective to the sprite.

sezero commented 1 year ago

@ericwa: What do you think about this one? I'm not sure myself..

4LT commented 1 year ago

Shouldn't Mod_LoadSpriteModel need to be updated to ensure there are 8 frames in the framegroup?

ericwa commented 1 year ago

I'm fine with this as it looks handy for porting e.g. doom-style sprites, small code, and already supported in FTE.

Documenting that it's 8 frames per group would be good + checking in the loading code, to avoid crashes.

Maybe a demo .spr file would be useful to attach here for testing.

sezero commented 1 year ago

I'm fine with this as it looks handy for porting e.g. doom-style sprites, small code, and already supported in FTE.

OK then. A few notes:

See the following patch (on top of yours) that does most of the above -- the framenum validation hopefully being correct (please check!).

diff --git a/Quake/r_sprite.c b/Quake/r_sprite.c
index 9893a64..19c8425 100644
--- a/Quake/r_sprite.c
+++ b/Quake/r_sprite.c
@@ -51,15 +51,17 @@ mspriteframe_t *R_GetSpriteFrame (entity_t *currentent)
    }
    else if (psprite->frames[frame].type == SPR_ANGLED)
    {
-       // erysdren - angled sprites
+       // erysdren - angled sprites backported from FTEQW
        vec3_t axis[3];
        AngleVectors(currententity->angles, axis[0], axis[1], axis[2]);
+       {
        float f = DotProduct(vpn, axis[0]);
        float r = DotProduct(vright, axis[0]);
        int dir = (atan2(r, f)+1.125*M_PI)*(4/M_PI);

        pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
        pspriteframe = pspritegroup->frames[dir&7];
+       }
    }
    else
    {
diff --git a/Quake/gl_model.c b/Quake/gl_model.c
index 6fc3c18..1e97626 100644
--- a/Quake/gl_model.c
+++ b/Quake/gl_model.c
@@ -2956,7 +2956,7 @@ static void *Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int fram
 Mod_LoadSpriteGroup
 =================
 */
-static void *Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe, int framenum)
+static void *Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe, int framenum, spriteframetype_t type)
 {
    dspritegroup_t      *pingroup;
    mspritegroup_t      *pspritegroup;
@@ -2968,6 +2968,8 @@ static void *Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe, int fram
    pingroup = (dspritegroup_t *)pin;

    numframes = LittleLong (pingroup->numframes);
+   if (type == SPR_ANGLED && numframes != 8)
+       Sys_Error ("Mod_LoadSpriteGroup: Bad # of frames: %d", numframes);

    pspritegroup = (mspritegroup_t *) Hunk_AllocName (sizeof (mspritegroup_t) +
                (numframes - 1) * sizeof (pspritegroup->frames[0]), loadname);
@@ -3071,7 +3073,7 @@ static void Mod_LoadSpriteModel (qmodel_t *mod, void *buffer)
        else
        {
            pframetype = (dspriteframetype_t *)
-                   Mod_LoadSpriteGroup (pframetype + 1, &psprite->frames[i].frameptr, i);
+                   Mod_LoadSpriteGroup (pframetype + 1, &psprite->frames[i].frameptr, i, frametype);
        }
    }

Documenting that it's 8 frames per group would be good

Where to put that info ?

Maybe a demo .spr file would be useful to attach here for testing.

Yes, I think

sezero commented 1 year ago

Looks like the author lost interest. I tend to reject-close this if I won't get any response in about 3 days.

sezero commented 1 year ago

Looks like the author lost interest. I tend to reject-close this if I won't get any response in about 3 days.

@ericwa: Any objections?

erysdren commented 1 year ago

Sorry, haven't had time to work on it lately. I'll see if i can get to it today.

erysdren commented 1 year ago

i added your changes, sorry for the delay.

sezero commented 1 year ago

i added your changes, sorry for the delay.

Thanks. Can you give us a sample sprite, possibly a map along with it, as @ericwa requested?

erysdren commented 1 year ago

Here's a map with a sample sprite (it overwrites s_light.spr)

https://erysdren.me/files/angled_sprite_example.zip

sezero commented 1 year ago

Here's a map with a sample sprite (it overwrites s_light.spr)

https://erysdren.me/files/angled_sprite_example.zip

OK, thanks!

Will be merging the patch tomorrow.

sezero commented 1 year ago

This patch is in now. Thank you.