]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_sprite.c
fix for two Con_Printf calls that are passed a string as the format string
[xonotic/darkplaces.git] / model_sprite.c
index 430b18fb42aaff809088cd158e78d638224d390f..d2509037263453cea54c4f494f39a154c1e60554 100644 (file)
@@ -24,6 +24,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
+cvar_t r_mipsprites = {CVAR_SAVE, "r_mipsprites", "1"};
+
 /*
 ===============
 Mod_SpriteInit
@@ -31,6 +33,22 @@ Mod_SpriteInit
 */
 void Mod_SpriteInit (void)
 {
+       Cvar_RegisterVariable(&r_mipsprites);
+}
+
+void Mod_Sprite_StripExtension(char *in, char *out)
+{
+       char *end;
+       end = in + strlen(in);
+       if ((end - in) >= 6)
+               if (strcmp(end - 6, ".spr32") == 0)
+                       end -= 6;
+       if ((end - in) >= 4)
+               if (strcmp(end - 4, ".spr") == 0)
+                       end -= 4;
+       while (in < end)
+               *out++ = *in++;
+       *out++ = 0;
 }
 
 /*
@@ -38,12 +56,12 @@ void Mod_SpriteInit (void)
 Mod_LoadSpriteFrame
 =================
 */
-void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int framenum, int bytesperpixel)
+void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t *frame, int framenum, int bytesperpixel, byte *palette)
 {
        dspriteframe_t          *pinframe;
        mspriteframe_t          *pspriteframe;
        int                                     i, width, height, size, origin[2];
-       char                            name[64];
+       char                            name[256], tempname[256];
        byte                            *pixbuf, *pixel, *inpixel;
 
        pinframe = (dspriteframe_t *)pin;
@@ -52,14 +70,12 @@ void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int framenum,
        height = LittleLong (pinframe->height);
        size = width * height * bytesperpixel;
 
-       pspriteframe = Hunk_AllocName (sizeof (mspriteframe_t),loadname);
+       pspriteframe = frame;
 
        memset (pspriteframe, 0, sizeof (mspriteframe_t));
 
-       *ppframe = pspriteframe;
-
-       pspriteframe->width = width;
-       pspriteframe->height = height;
+//     pspriteframe->width = width;
+//     pspriteframe->height = height;
        origin[0] = LittleLong (pinframe->origin[0]);
        origin[1] = LittleLong (pinframe->origin[1]);
 
@@ -68,39 +84,45 @@ void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int framenum,
        pspriteframe->left = origin[0];
        pspriteframe->right = width + origin[0];
 
-       sprintf (name, "%s_%i", loadmodel->name, framenum);
-       pspriteframe->gl_texturenum = GL_LoadTexture (name, width, height, (byte *)(pinframe + 1), true, true, bytesperpixel);
-       // make fog version (just alpha)
-       pixbuf = pixel = malloc(width*height*4);
+       Mod_Sprite_StripExtension(loadmodel->name, tempname);
+       sprintf (name, "%s_%i", tempname, framenum);
+       pspriteframe->texture = loadtextureimagewithmask(name, 0, 0, false, r_mipsprites.value, true);
+       pspriteframe->fogtexture = image_masktex;
+
+       pixbuf = qmalloc(width*height*4);
+
        inpixel = (byte *)(pinframe + 1);
+       pixel = pixbuf;
        if (bytesperpixel == 1)
        {
-               for (i = 0;i < width*height;i++)
+               for (i = 0;i < width * height;i++)
                {
-                       *pixel++ = 255;
-                       *pixel++ = 255;
-                       *pixel++ = 255;
-                       if (*inpixel++ != 255)
-                               *pixel++ = 255;
-                       else
-                               *pixel++ = 0;
+                       *pixel++ = palette[inpixel[i]*4+0];
+                       *pixel++ = palette[inpixel[i]*4+1];
+                       *pixel++ = palette[inpixel[i]*4+2];
+                       *pixel++ = palette[inpixel[i]*4+3];
                }
        }
        else
+               memcpy(pixel, inpixel, width*height*4);
+
+       if (!pspriteframe->texture)
        {
-               inpixel+=3;
+               pspriteframe->texture = R_LoadTexture (name, width, height, pixbuf, TEXF_ALPHA | TEXF_RGBA | (r_mipsprites.value ? TEXF_MIPMAP : 0) | TEXF_PRECACHE);
+               // make fog version (just alpha)
+               pixel = pixbuf;
                for (i = 0;i < width*height;i++)
                {
                        *pixel++ = 255;
                        *pixel++ = 255;
                        *pixel++ = 255;
-                       *pixel++ = *inpixel;
-                       inpixel+=4;
+                       pixel++;
                }
+               sprintf (name, "%s_%ifog", loadmodel->name, framenum);
+               pspriteframe->fogtexture = R_LoadTexture (name, width, height, pixbuf, TEXF_ALPHA | TEXF_RGBA | (r_mipsprites.value ? TEXF_MIPMAP : 0) | TEXF_PRECACHE);
        }
-       sprintf (name, "%s_%ifog", loadmodel->name, framenum);
-       pspriteframe->gl_fogtexturenum = GL_LoadTexture (name, width, height, pixbuf, true, true, 4);
-       free(pixbuf);
+
+       qfree(pixbuf);
 
        return (void *)((byte *)pinframe + sizeof (dspriteframe_t) + size);
 }
@@ -111,69 +133,34 @@ void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int framenum,
 Mod_LoadSpriteGroup
 =================
 */
-void * Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe, int framenum, int bytesperpixel)
+/*
+void *Mod_LoadSpriteGroup (void * pin, mspriteframe_t *frame, int numframes, int framenum, int bytesperpixel)
 {
-       dspritegroup_t          *pingroup;
-       mspritegroup_t          *pspritegroup;
-       int                                     i, numframes;
-       dspriteinterval_t       *pin_intervals;
-       float                           *poutintervals;
-       void                            *ptemp;
-
-       pingroup = (dspritegroup_t *)pin;
-
-       numframes = LittleLong (pingroup->numframes);
-
-       pspritegroup = Hunk_AllocName (sizeof (mspritegroup_t) +
-                               (numframes - 1) * sizeof (pspritegroup->frames[0]), loadname);
+       int i;
+       void *ptemp;
 
-       pspritegroup->numframes = numframes;
+       ptemp = (void *)(sizeof(dspriteinterval_t) * numframes + sizeof(dspritegroup_t) + (int) pin);
 
-       *ppframe = (mspriteframe_t *)pspritegroup;
-
-       pin_intervals = (dspriteinterval_t *)(pingroup + 1);
-
-       poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname);
-
-       pspritegroup->intervals = poutintervals;
-
-       for (i=0 ; i<numframes ; i++)
-       {
-               *poutintervals = LittleFloat (pin_intervals->interval);
-               if (*poutintervals <= 0.0)
-                       Host_Error ("Mod_LoadSpriteGroup: interval<=0");
-
-               poutintervals++;
-               pin_intervals++;
-       }
-
-       ptemp = (void *)pin_intervals;
-
-       for (i=0 ; i<numframes ; i++)
-       {
-               ptemp = Mod_LoadSpriteFrame (ptemp, &pspritegroup->frames[i], framenum * 100 + i, bytesperpixel);
-       }
+       for (i = 0;i < numframes;i++)
+               ptemp = Mod_LoadSpriteFrame (ptemp, frame++, framenum * 100 + i, bytesperpixel);
 
        return ptemp;
 }
-
-
-/*
-=================
-Mod_LoadSpriteModel
-=================
 */
-void Mod_LoadSpriteModel (model_t *mod, void *buffer)
+
+// this actually handles both quake sprite and darkplaces sprite32
+void Mod_LoadQuakeSprite (model_t *mod, void *buffer)
 {
-       int                                     i;
-       int                                     version;
+       int                                     i, j, version, numframes, realframes, size, bytesperpixel, start, end, total, maxwidth, maxheight;
        dsprite_t                       *pin;
        msprite_t                       *psprite;
-       int                                     numframes;
-       int                                     size;
        dspriteframetype_t      *pframetype;
-       // LordHavoc: 32bit textures
-       int             bytesperpixel;
+       dspriteframe_t          *pframe;
+       animscene_t                     *animscenes;
+       mspriteframe_t          *frames;
+       dspriteframe_t          **framedata;
+
+       start = Hunk_LowMark ();
 
        mod->flags = EF_FULLBRIGHT;
        // LordHavoc: hack to allow sprites to be non-fullbright
@@ -186,72 +173,311 @@ void Mod_LoadSpriteModel (model_t *mod, void *buffer)
                }
        }
 
+       // build a list of frames while parsing
+       framedata = qmalloc(65536*sizeof(dspriteframe_t));
+
        pin = (dsprite_t *)buffer;
 
        version = LittleLong (pin->version);
-       if (version == 2)
-       {
-               version = 32;
-               Con_Printf("warning: %s is a version 2 sprite (RGBA), supported for now, please hex edit to version 32 incase HalfLife sprites might be supported at some point.\n", mod->name);
-       }
        // LordHavoc: 32bit textures
-       if (version != SPRITE_VERSION && version != SPRITE32_VERSION)
-               Host_Error ("%s has wrong version number "
-                                "(%i should be %i or %i)", mod->name, version, SPRITE_VERSION, SPRITE32_VERSION);
        bytesperpixel = 1;
        if (version == SPRITE32_VERSION)
                bytesperpixel = 4;
 
        numframes = LittleLong (pin->numframes);
 
-       size = sizeof (msprite_t) +     (numframes - 1) * sizeof (psprite->frames);
+       psprite = Hunk_AllocName (sizeof(msprite_t), va("%s info", loadname));
 
-       psprite = Hunk_AllocName (size, loadname);
-
-       mod->cache.data = psprite;
+//     mod->cache.data = psprite;
 
        psprite->type = LittleLong (pin->type);
-       psprite->maxwidth = LittleLong (pin->width);
-       psprite->maxheight = LittleLong (pin->height);
-       psprite->beamlength = LittleFloat (pin->beamlength);
+       maxwidth = LittleLong (pin->width);
+       maxheight = LittleLong (pin->height);
+//     psprite->beamlength = LittleFloat (pin->beamlength);
        mod->synctype = LittleLong (pin->synctype);
-       psprite->numframes = numframes;
+//     psprite->numframes = numframes;
+
+       mod->mins[0] = mod->mins[1] = -maxwidth/2;
+       mod->maxs[0] = mod->maxs[1] = maxwidth/2;
+       mod->mins[2] = -maxheight/2;
+       mod->maxs[2] = maxheight/2;
 
-       mod->mins[0] = mod->mins[1] = -psprite->maxwidth/2;
-       mod->maxs[0] = mod->maxs[1] = psprite->maxwidth/2;
-       mod->mins[2] = -psprite->maxheight/2;
-       mod->maxs[2] = psprite->maxheight/2;
-       
 //
 // load the frames
 //
        if (numframes < 1)
-               Host_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes);
+               Host_Error ("Mod_LoadQuakeSprite: Invalid # of frames: %d\n", numframes);
 
        mod->numframes = numframes;
 
        pframetype = (dspriteframetype_t *)(pin + 1);
 
-       for (i=0 ; i<numframes ; i++)
+       animscenes = Hunk_AllocName(sizeof(animscene_t) * mod->numframes, va("%s sceneinfo", loadname));
+
+       realframes = 0;
+
+       for (i = 0;i < numframes;i++)
+       {
+               spriteframetype_t       frametype;
+
+               frametype = LittleLong (pframetype->type);
+
+               sprintf(animscenes[i].name, "frame%i", i);
+               animscenes[i].firstframe = realframes;
+               animscenes[i].loop = true;
+               if (frametype == SPR_SINGLE)
+               {
+                       animscenes[i].framecount = 1;
+                       animscenes[i].framerate = 10;
+                       pframe = (dspriteframe_t *) (pframetype + 1);
+                       framedata[realframes] = pframe;
+                       size = LittleLong(pframe->width) * LittleLong(pframe->height) * bytesperpixel;
+                       pframetype = (dspriteframetype_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
+                       realframes++;
+               }
+               else
+               {
+                       j = LittleLong(((dspritegroup_t *) (sizeof(dspriteframetype_t) + (int) pframetype))->numframes);
+                       animscenes[i].framecount = j;
+                       // FIXME: support variable framerate?
+                       animscenes[i].framerate = 1.0f / LittleFloat(((dspriteinterval_t *) (sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype))->interval);
+                       pframe = (dspriteframe_t *) (sizeof(dspriteinterval_t) * j + sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype);
+                       while (j--)
+                       {
+                               framedata[realframes] = pframe;
+                               size = LittleLong(pframe->width) * LittleLong(pframe->height) * bytesperpixel;
+                               pframe = (dspriteframe_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
+                               realframes++;
+                       }
+                       pframetype = (dspriteframetype_t *) pframe;
+               }
+       }
+
+       mod->ofs_scenes = (int) animscenes - (int) psprite;
+
+       frames = Hunk_AllocName(sizeof(mspriteframe_t) * realframes, va("%s frames", loadname));
+
+       realframes = 0;
+       for (i = 0;i < numframes;i++)
+       {
+               for (j = 0;j < animscenes[i].framecount;j++)
+               {
+                       Mod_LoadSpriteFrame (framedata[realframes], frames + realframes, i, bytesperpixel, (byte *)&d_8to24table);
+                       realframes++;
+               }
+       }
+
+       psprite->ofs_frames = (int) frames - (int) psprite;
+
+       qfree(framedata);
+
+       mod->type = mod_sprite;
+
+// move the complete, relocatable sprite model to the cache
+       end = Hunk_LowMark ();
+       mod->cachesize = total = end - start;
+
+       Cache_Alloc (&mod->cache, total, loadname);
+       if (!mod->cache.data)
+               return;
+       memcpy (mod->cache.data, psprite, total);
+
+       Hunk_FreeToLowMark (start);
+}
+
+void Mod_LoadHLSprite (model_t *mod, void *buffer)
+{
+       int                                     i, j, numframes, realframes, size, start, end, total, maxwidth, maxheight, rendermode;
+       byte                            palette[256][4], *in;
+       dspritehl_t                     *pin;
+       msprite_t                       *psprite;
+       dspriteframetype_t      *pframetype;
+       dspriteframe_t          *pframe;
+       animscene_t                     *animscenes;
+       mspriteframe_t          *frames;
+       dspriteframe_t          **framedata;
+
+       start = Hunk_LowMark ();
+
+       mod->flags = EF_FULLBRIGHT;
+
+       // build a list of frames while parsing
+       framedata = qmalloc(65536*sizeof(dspriteframe_t));
+
+       pin = (dspritehl_t *)buffer;
+
+       numframes = LittleLong (pin->numframes);
+
+       psprite = Hunk_AllocName (sizeof(msprite_t), va("%s info", loadname));
+
+       psprite->type = LittleLong (pin->type);
+       maxwidth = LittleLong (pin->width);
+       maxheight = LittleLong (pin->height);
+       mod->synctype = LittleLong (pin->synctype);
+       rendermode = pin->rendermode;
+
+       mod->mins[0] = mod->mins[1] = -maxwidth/2;
+       mod->maxs[0] = mod->maxs[1] = maxwidth/2;
+       mod->mins[2] = -maxheight/2;
+       mod->maxs[2] = maxheight/2;
+
+//
+// load the frames
+//
+       if (numframes < 1)
+               Host_Error ("Mod_LoadHLSprite: Invalid # of frames: %d\n", numframes);
+
+       mod->numframes = numframes;
+
+       in = (byte *)(pin + 1);
+       i = in[0] + in[1] * 256;
+       if (i != 256)
+               Host_Error ("Mod_LoadHLSprite: unexpected number of palette colors %i (should be 256)", i);
+       in += 2;
+       switch(rendermode)
+       {
+       case SPRHL_NORMAL:
+               for (i = 0;i < 256;i++)
+               {
+                       palette[i][0] = *in++;
+                       palette[i][1] = *in++;
+                       palette[i][2] = *in++;
+                       palette[i][3] = 255;
+               }
+               palette[255][0] = palette[255][1] = palette[255][2] = palette[255][3] = 0;
+               break;
+       case SPRHL_ADDITIVE:
+               for (i = 0;i < 256;i++)
+               {
+                       palette[i][0] = *in++;
+                       palette[i][1] = *in++;
+                       palette[i][2] = *in++;
+                       palette[i][3] = 255;
+               }
+//             palette[255][0] = palette[255][1] = palette[255][2] = palette[255][3] = 0;
+               mod->flags |= EF_ADDITIVE;
+               break;
+       case SPRHL_INDEXALPHA:
+               for (i = 0;i < 256;i++)
+               {
+                       palette[i][0] = 255;
+                       palette[i][1] = 255;
+                       palette[i][2] = 255;
+                       palette[i][3] = i;
+                       in += 3;
+               }
+               break;
+       case SPRHL_ALPHATEST:
+               for (i = 0;i < 256;i++)
+               {
+                       palette[i][0] = *in++;
+                       palette[i][1] = *in++;
+                       palette[i][2] = *in++;
+                       palette[i][3] = 255;
+               }
+               palette[0][0] = palette[0][1] = palette[0][2] = palette[0][3] = 0;
+               break;
+       default:
+               Host_Error("Mod_LoadHLSprite: unknown texFormat (%i, should be 0, 1, 2, or 3)\n", i);
+               return;
+       }
+
+       pframetype = (dspriteframetype_t *)in;
+
+       animscenes = Hunk_AllocName(sizeof(animscene_t) * mod->numframes, va("%s sceneinfo", loadname));
+
+       realframes = 0;
+
+       for (i = 0;i < numframes;i++)
        {
                spriteframetype_t       frametype;
 
                frametype = LittleLong (pframetype->type);
-               psprite->frames[i].type = frametype;
 
+               sprintf(animscenes[i].name, "frame%i", i);
+               animscenes[i].firstframe = realframes;
+               animscenes[i].loop = true;
                if (frametype == SPR_SINGLE)
                {
-                       pframetype = (dspriteframetype_t *)
-                                       Mod_LoadSpriteFrame (pframetype + 1,
-                                                                                &psprite->frames[i].frameptr, i, bytesperpixel);
+                       animscenes[i].framecount = 1;
+                       animscenes[i].framerate = 10;
+                       pframe = (dspriteframe_t *) (pframetype + 1);
+                       framedata[realframes] = pframe;
+                       size = LittleLong(pframe->width) * LittleLong(pframe->height);
+                       pframetype = (dspriteframetype_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
+                       realframes++;
                }
                else
                {
-                       pframetype = (dspriteframetype_t *)
-                                       Mod_LoadSpriteGroup (pframetype + 1,
-                                                                                &psprite->frames[i].frameptr, i, bytesperpixel);
+                       j = LittleLong(((dspritegroup_t *) (sizeof(dspriteframetype_t) + (int) pframetype))->numframes);
+                       animscenes[i].framecount = j;
+                       // FIXME: support variable framerate?
+                       animscenes[i].framerate = 1.0f / LittleFloat(((dspriteinterval_t *) (sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype))->interval);
+                       pframe = (dspriteframe_t *) (sizeof(dspriteinterval_t) * j + sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype);
+                       while (j--)
+                       {
+                               framedata[realframes] = pframe;
+                               size = LittleLong(pframe->width) * LittleLong(pframe->height);
+                               pframe = (dspriteframe_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
+                               realframes++;
+                       }
+                       pframetype = (dspriteframetype_t *) pframe;
                }
        }
 
+       mod->ofs_scenes = (int) animscenes - (int) psprite;
+
+       frames = Hunk_AllocName(sizeof(mspriteframe_t) * realframes, va("%s frames", loadname));
+
+       realframes = 0;
+       for (i = 0;i < numframes;i++)
+       {
+               for (j = 0;j < animscenes[i].framecount;j++)
+               {
+                       Mod_LoadSpriteFrame (framedata[realframes], frames + realframes, i, 1, &palette[0][0]);
+                       realframes++;
+               }
+       }
+
+       psprite->ofs_frames = (int) frames - (int) psprite;
+
+       qfree(framedata);
+
        mod->type = mod_sprite;
+
+// move the complete, relocatable sprite model to the cache
+       end = Hunk_LowMark ();
+       mod->cachesize = total = end - start;
+
+       Cache_Alloc (&mod->cache, total, loadname);
+       if (!mod->cache.data)
+               return;
+       memcpy (mod->cache.data, psprite, total);
+
+       Hunk_FreeToLowMark (start);
+}
+
+
+/*
+=================
+Mod_LoadSpriteModel
+=================
+*/
+void Mod_LoadSpriteModel (model_t *mod, void *buffer)
+{
+       int version;
+       version = ((dsprite_t *)buffer)->version;
+       switch(version)
+       {
+       case SPRITEHL_VERSION:
+               Mod_LoadHLSprite (mod, buffer);
+               break;
+       case SPRITE_VERSION:
+       case SPRITE32_VERSION:
+               Mod_LoadQuakeSprite(mod, buffer);
+               break;
+       default:
+               Host_Error ("Mod_LoadSpriteModel: %s has wrong version number (%i should be 1 (quake) or 32 (sprite32) or 2 (halflife)", mod->name, version);
+               break;
+       }
 }