added CVAR_SAVE and CVAR_NOTIFY flags to cvar_t structure (at the beginning), updated...
[divverent/darkplaces.git] / model_sprite.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // models.c -- model loading and caching
21
22 // models are the only shared resource between a client and server running
23 // on the same machine.
24
25 #include "quakedef.h"
26
27 cvar_t r_mipsprites = {CVAR_SAVE, "r_mipsprites", "1"};
28
29 /*
30 ===============
31 Mod_SpriteInit
32 ===============
33 */
34 void Mod_SpriteInit (void)
35 {
36         Cvar_RegisterVariable(&r_mipsprites);
37 }
38
39 void Mod_Sprite_StripExtension(char *in, char *out)
40 {
41         char *end;
42         end = in + strlen(in);
43         if ((end - in) >= 6)
44                 if (strcmp(end - 6, ".spr32") == 0)
45                         end -= 6;
46         if ((end - in) >= 4)
47                 if (strcmp(end - 4, ".spr") == 0)
48                         end -= 4;
49         while (in < end)
50                 *out++ = *in++;
51         *out++ = 0;
52 }
53
54 /*
55 =================
56 Mod_LoadSpriteFrame
57 =================
58 */
59 void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t *frame, int framenum, int bytesperpixel, byte *palette)
60 {
61         dspriteframe_t          *pinframe;
62         mspriteframe_t          *pspriteframe;
63         int                                     i, width, height, size, origin[2];
64         char                            name[256], tempname[256];
65         byte                            *pixbuf, *pixel, *inpixel;
66
67         pinframe = (dspriteframe_t *)pin;
68
69         width = LittleLong (pinframe->width);
70         height = LittleLong (pinframe->height);
71         size = width * height * bytesperpixel;
72
73         pspriteframe = frame;
74
75         memset (pspriteframe, 0, sizeof (mspriteframe_t));
76
77 //      pspriteframe->width = width;
78 //      pspriteframe->height = height;
79         origin[0] = LittleLong (pinframe->origin[0]);
80         origin[1] = LittleLong (pinframe->origin[1]);
81
82         pspriteframe->up = origin[1];
83         pspriteframe->down = origin[1] - height;
84         pspriteframe->left = origin[0];
85         pspriteframe->right = width + origin[0];
86
87         Mod_Sprite_StripExtension(loadmodel->name, tempname);
88         sprintf (name, "%s_%i", tempname, framenum);
89         pspriteframe->texture = loadtextureimagewithmask(name, 0, 0, false, r_mipsprites.value, true);
90         pspriteframe->fogtexture = image_masktex;
91
92         pixbuf = qmalloc(width*height*4);
93
94         inpixel = (byte *)(pinframe + 1);
95         pixel = pixbuf;
96         if (bytesperpixel == 1)
97         {
98                 for (i = 0;i < width * height;i++)
99                 {
100                         *pixel++ = palette[inpixel[i]*4+0];
101                         *pixel++ = palette[inpixel[i]*4+1];
102                         *pixel++ = palette[inpixel[i]*4+2];
103                         *pixel++ = palette[inpixel[i]*4+3];
104                 }
105         }
106         else
107                 memcpy(pixel, inpixel, width*height*4);
108
109         if (!pspriteframe->texture)
110         {
111                 pspriteframe->texture = R_LoadTexture (name, width, height, pixbuf, TEXF_ALPHA | TEXF_RGBA | (r_mipsprites.value ? TEXF_MIPMAP : 0) | TEXF_PRECACHE);
112                 // make fog version (just alpha)
113                 pixel = pixbuf;
114                 for (i = 0;i < width*height;i++)
115                 {
116                         *pixel++ = 255;
117                         *pixel++ = 255;
118                         *pixel++ = 255;
119                         pixel++;
120                 }
121                 sprintf (name, "%s_%ifog", loadmodel->name, framenum);
122                 pspriteframe->fogtexture = R_LoadTexture (name, width, height, pixbuf, TEXF_ALPHA | TEXF_RGBA | (r_mipsprites.value ? TEXF_MIPMAP : 0) | TEXF_PRECACHE);
123         }
124
125         qfree(pixbuf);
126
127         return (void *)((byte *)pinframe + sizeof (dspriteframe_t) + size);
128 }
129
130
131 /*
132 =================
133 Mod_LoadSpriteGroup
134 =================
135 */
136 /*
137 void *Mod_LoadSpriteGroup (void * pin, mspriteframe_t *frame, int numframes, int framenum, int bytesperpixel)
138 {
139         int i;
140         void *ptemp;
141
142         ptemp = (void *)(sizeof(dspriteinterval_t) * numframes + sizeof(dspritegroup_t) + (int) pin);
143
144         for (i = 0;i < numframes;i++)
145                 ptemp = Mod_LoadSpriteFrame (ptemp, frame++, framenum * 100 + i, bytesperpixel);
146
147         return ptemp;
148 }
149 */
150
151 // this actually handles both quake sprite and darkplaces sprite32
152 void Mod_LoadQuakeSprite (model_t *mod, void *buffer)
153 {
154         int                                     i, j, version, numframes, realframes, size, bytesperpixel, start, end, total, maxwidth, maxheight;
155         dsprite_t                       *pin;
156         msprite_t                       *psprite;
157         dspriteframetype_t      *pframetype;
158         dspriteframe_t          *pframe;
159         animscene_t                     *animscenes;
160         mspriteframe_t          *frames;
161         dspriteframe_t          **framedata;
162
163         start = Hunk_LowMark ();
164
165         mod->flags = EF_FULLBRIGHT;
166         // LordHavoc: hack to allow sprites to be non-fullbright
167         for (i = 0;i < MAX_QPATH && mod->name[i];i++)
168         {
169                 if (mod->name[i] == '!')
170                 {
171                         mod->flags &= ~EF_FULLBRIGHT;
172                         break;
173                 }
174         }
175
176         // build a list of frames while parsing
177         framedata = qmalloc(65536*sizeof(dspriteframe_t));
178
179         pin = (dsprite_t *)buffer;
180
181         version = LittleLong (pin->version);
182         // LordHavoc: 32bit textures
183         bytesperpixel = 1;
184         if (version == SPRITE32_VERSION)
185                 bytesperpixel = 4;
186
187         numframes = LittleLong (pin->numframes);
188
189         psprite = Hunk_AllocName (sizeof(msprite_t), va("%s info", loadname));
190
191 //      mod->cache.data = psprite;
192
193         psprite->type = LittleLong (pin->type);
194         maxwidth = LittleLong (pin->width);
195         maxheight = LittleLong (pin->height);
196 //      psprite->beamlength = LittleFloat (pin->beamlength);
197         mod->synctype = LittleLong (pin->synctype);
198 //      psprite->numframes = numframes;
199
200         mod->mins[0] = mod->mins[1] = -maxwidth/2;
201         mod->maxs[0] = mod->maxs[1] = maxwidth/2;
202         mod->mins[2] = -maxheight/2;
203         mod->maxs[2] = maxheight/2;
204
205 //
206 // load the frames
207 //
208         if (numframes < 1)
209                 Host_Error ("Mod_LoadQuakeSprite: Invalid # of frames: %d\n", numframes);
210
211         mod->numframes = numframes;
212
213         pframetype = (dspriteframetype_t *)(pin + 1);
214
215         animscenes = Hunk_AllocName(sizeof(animscene_t) * mod->numframes, va("%s sceneinfo", loadname));
216
217         realframes = 0;
218
219         for (i = 0;i < numframes;i++)
220         {
221                 spriteframetype_t       frametype;
222
223                 frametype = LittleLong (pframetype->type);
224
225                 sprintf(animscenes[i].name, "frame%i", i);
226                 animscenes[i].firstframe = realframes;
227                 animscenes[i].loop = true;
228                 if (frametype == SPR_SINGLE)
229                 {
230                         animscenes[i].framecount = 1;
231                         animscenes[i].framerate = 10;
232                         pframe = (dspriteframe_t *) (pframetype + 1);
233                         framedata[realframes] = pframe;
234                         size = LittleLong(pframe->width) * LittleLong(pframe->height) * bytesperpixel;
235                         pframetype = (dspriteframetype_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
236                         realframes++;
237                 }
238                 else
239                 {
240                         j = LittleLong(((dspritegroup_t *) (sizeof(dspriteframetype_t) + (int) pframetype))->numframes);
241                         animscenes[i].framecount = j;
242                         // FIXME: support variable framerate?
243                         animscenes[i].framerate = 1.0f / LittleFloat(((dspriteinterval_t *) (sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype))->interval);
244                         pframe = (dspriteframe_t *) (sizeof(dspriteinterval_t) * j + sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype);
245                         while (j--)
246                         {
247                                 framedata[realframes] = pframe;
248                                 size = LittleLong(pframe->width) * LittleLong(pframe->height) * bytesperpixel;
249                                 pframe = (dspriteframe_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
250                                 realframes++;
251                         }
252                         pframetype = (dspriteframetype_t *) pframe;
253                 }
254         }
255
256         mod->ofs_scenes = (int) animscenes - (int) psprite;
257
258         frames = Hunk_AllocName(sizeof(mspriteframe_t) * realframes, va("%s frames", loadname));
259
260         realframes = 0;
261         for (i = 0;i < numframes;i++)
262         {
263                 for (j = 0;j < animscenes[i].framecount;j++)
264                 {
265                         Mod_LoadSpriteFrame (framedata[realframes], frames + realframes, i, bytesperpixel, (byte *)&d_8to24table);
266                         realframes++;
267                 }
268         }
269
270         psprite->ofs_frames = (int) frames - (int) psprite;
271
272         qfree(framedata);
273
274         mod->type = mod_sprite;
275
276 // move the complete, relocatable sprite model to the cache
277         end = Hunk_LowMark ();
278         mod->cachesize = total = end - start;
279
280         Cache_Alloc (&mod->cache, total, loadname);
281         if (!mod->cache.data)
282                 return;
283         memcpy (mod->cache.data, psprite, total);
284
285         Hunk_FreeToLowMark (start);
286 }
287
288 void Mod_LoadHLSprite (model_t *mod, void *buffer)
289 {
290         int                                     i, j, numframes, realframes, size, start, end, total, maxwidth, maxheight, rendermode;
291         byte                            palette[256][4], *in;
292         dspritehl_t                     *pin;
293         msprite_t                       *psprite;
294         dspriteframetype_t      *pframetype;
295         dspriteframe_t          *pframe;
296         animscene_t                     *animscenes;
297         mspriteframe_t          *frames;
298         dspriteframe_t          **framedata;
299
300         start = Hunk_LowMark ();
301
302         mod->flags = EF_FULLBRIGHT;
303
304         // build a list of frames while parsing
305         framedata = qmalloc(65536*sizeof(dspriteframe_t));
306
307         pin = (dspritehl_t *)buffer;
308
309         numframes = LittleLong (pin->numframes);
310
311         psprite = Hunk_AllocName (sizeof(msprite_t), va("%s info", loadname));
312
313         psprite->type = LittleLong (pin->type);
314         maxwidth = LittleLong (pin->width);
315         maxheight = LittleLong (pin->height);
316         mod->synctype = LittleLong (pin->synctype);
317         rendermode = pin->rendermode;
318
319         mod->mins[0] = mod->mins[1] = -maxwidth/2;
320         mod->maxs[0] = mod->maxs[1] = maxwidth/2;
321         mod->mins[2] = -maxheight/2;
322         mod->maxs[2] = maxheight/2;
323
324 //
325 // load the frames
326 //
327         if (numframes < 1)
328                 Host_Error ("Mod_LoadHLSprite: Invalid # of frames: %d\n", numframes);
329
330         mod->numframes = numframes;
331
332         in = (byte *)(pin + 1);
333         i = in[0] + in[1] * 256;
334         if (i != 256)
335                 Host_Error ("Mod_LoadHLSprite: unexpected number of palette colors %i (should be 256)", i);
336         in += 2;
337         switch(rendermode)
338         {
339         case SPRHL_NORMAL:
340                 for (i = 0;i < 256;i++)
341                 {
342                         palette[i][0] = *in++;
343                         palette[i][1] = *in++;
344                         palette[i][2] = *in++;
345                         palette[i][3] = 255;
346                 }
347                 palette[255][0] = palette[255][1] = palette[255][2] = palette[255][3] = 0;
348                 break;
349         case SPRHL_ADDITIVE:
350                 for (i = 0;i < 256;i++)
351                 {
352                         palette[i][0] = *in++;
353                         palette[i][1] = *in++;
354                         palette[i][2] = *in++;
355                         palette[i][3] = 255;
356                 }
357 //              palette[255][0] = palette[255][1] = palette[255][2] = palette[255][3] = 0;
358                 mod->flags |= EF_ADDITIVE;
359                 break;
360         case SPRHL_INDEXALPHA:
361                 for (i = 0;i < 256;i++)
362                 {
363                         palette[i][0] = 255;
364                         palette[i][1] = 255;
365                         palette[i][2] = 255;
366                         palette[i][3] = i;
367                         in += 3;
368                 }
369                 break;
370         case SPRHL_ALPHATEST:
371                 for (i = 0;i < 256;i++)
372                 {
373                         palette[i][0] = *in++;
374                         palette[i][1] = *in++;
375                         palette[i][2] = *in++;
376                         palette[i][3] = 255;
377                 }
378                 palette[0][0] = palette[0][1] = palette[0][2] = palette[0][3] = 0;
379                 break;
380         default:
381                 Host_Error("Mod_LoadHLSprite: unknown texFormat (%i, should be 0, 1, 2, or 3)\n", i);
382                 return;
383         }
384
385         pframetype = (dspriteframetype_t *)in;
386
387         animscenes = Hunk_AllocName(sizeof(animscene_t) * mod->numframes, va("%s sceneinfo", loadname));
388
389         realframes = 0;
390
391         for (i = 0;i < numframes;i++)
392         {
393                 spriteframetype_t       frametype;
394
395                 frametype = LittleLong (pframetype->type);
396
397                 sprintf(animscenes[i].name, "frame%i", i);
398                 animscenes[i].firstframe = realframes;
399                 animscenes[i].loop = true;
400                 if (frametype == SPR_SINGLE)
401                 {
402                         animscenes[i].framecount = 1;
403                         animscenes[i].framerate = 10;
404                         pframe = (dspriteframe_t *) (pframetype + 1);
405                         framedata[realframes] = pframe;
406                         size = LittleLong(pframe->width) * LittleLong(pframe->height);
407                         pframetype = (dspriteframetype_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
408                         realframes++;
409                 }
410                 else
411                 {
412                         j = LittleLong(((dspritegroup_t *) (sizeof(dspriteframetype_t) + (int) pframetype))->numframes);
413                         animscenes[i].framecount = j;
414                         // FIXME: support variable framerate?
415                         animscenes[i].framerate = 1.0f / LittleFloat(((dspriteinterval_t *) (sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype))->interval);
416                         pframe = (dspriteframe_t *) (sizeof(dspriteinterval_t) * j + sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype);
417                         while (j--)
418                         {
419                                 framedata[realframes] = pframe;
420                                 size = LittleLong(pframe->width) * LittleLong(pframe->height);
421                                 pframe = (dspriteframe_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
422                                 realframes++;
423                         }
424                         pframetype = (dspriteframetype_t *) pframe;
425                 }
426         }
427
428         mod->ofs_scenes = (int) animscenes - (int) psprite;
429
430         frames = Hunk_AllocName(sizeof(mspriteframe_t) * realframes, va("%s frames", loadname));
431
432         realframes = 0;
433         for (i = 0;i < numframes;i++)
434         {
435                 for (j = 0;j < animscenes[i].framecount;j++)
436                 {
437                         Mod_LoadSpriteFrame (framedata[realframes], frames + realframes, i, 1, &palette[0][0]);
438                         realframes++;
439                 }
440         }
441
442         psprite->ofs_frames = (int) frames - (int) psprite;
443
444         qfree(framedata);
445
446         mod->type = mod_sprite;
447
448 // move the complete, relocatable sprite model to the cache
449         end = Hunk_LowMark ();
450         mod->cachesize = total = end - start;
451
452         Cache_Alloc (&mod->cache, total, loadname);
453         if (!mod->cache.data)
454                 return;
455         memcpy (mod->cache.data, psprite, total);
456
457         Hunk_FreeToLowMark (start);
458 }
459
460
461 /*
462 =================
463 Mod_LoadSpriteModel
464 =================
465 */
466 void Mod_LoadSpriteModel (model_t *mod, void *buffer)
467 {
468         int version;
469         version = ((dsprite_t *)buffer)->version;
470         switch(version)
471         {
472         case SPRITEHL_VERSION:
473                 Mod_LoadHLSprite (mod, buffer);
474                 break;
475         case SPRITE_VERSION:
476         case SPRITE32_VERSION:
477                 Mod_LoadQuakeSprite(mod, buffer);
478                 break;
479         default:
480                 Host_Error ("Mod_LoadSpriteModel: %s has wrong version number (%i should be 1 (quake) or 32 (sprite32) or 2 (halflife)", mod->name, version);
481                 break;
482         }
483 }