rewrote RecursiveHullCheck, no longer gets stuck on angle changes, and is generally...
[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, float *modelradius)
60 {
61         dspriteframe_t          *pinframe;
62         mspriteframe_t          *pspriteframe;
63         float                           dist;
64         int                                     i, width, height, size, origin[2];
65         char                            name[256], tempname[256];
66         byte                            *pixbuf, *pixel, *inpixel;
67
68         pinframe = (dspriteframe_t *)pin;
69
70         origin[0] = LittleLong (pinframe->origin[0]);
71         origin[1] = LittleLong (pinframe->origin[1]);
72         width = LittleLong (pinframe->width);
73         height = LittleLong (pinframe->height);
74         size = width * height * bytesperpixel;
75
76         pspriteframe = frame;
77
78         memset (pspriteframe, 0, sizeof (mspriteframe_t));
79
80         pspriteframe->left = origin[0];
81         pspriteframe->right = origin[0] + width;
82         pspriteframe->up = origin[1];
83         pspriteframe->down = origin[1] - height;
84
85         dist = pspriteframe->left*pspriteframe->left+pspriteframe->up*pspriteframe->up;
86         if (*modelradius < dist)
87                 *modelradius = dist;
88         dist = pspriteframe->right*pspriteframe->right+pspriteframe->down*pspriteframe->down;
89         if (*modelradius < dist)
90                 *modelradius = dist;
91
92         Mod_Sprite_StripExtension(loadmodel->name, tempname);
93         sprintf (name, "%s_%i", tempname, framenum);
94         pspriteframe->texture = loadtextureimagewithmask(name, 0, 0, false, r_mipsprites.value, true);
95         pspriteframe->fogtexture = image_masktex;
96
97         pixbuf = qmalloc(width*height*4);
98
99         inpixel = (byte *)(pinframe + 1);
100         pixel = pixbuf;
101         if (bytesperpixel == 1)
102         {
103                 for (i = 0;i < width * height;i++)
104                 {
105                         *pixel++ = palette[inpixel[i]*4+0];
106                         *pixel++ = palette[inpixel[i]*4+1];
107                         *pixel++ = palette[inpixel[i]*4+2];
108                         *pixel++ = palette[inpixel[i]*4+3];
109                 }
110         }
111         else
112                 memcpy(pixel, inpixel, width*height*4);
113
114         if (!pspriteframe->texture)
115         {
116                 pspriteframe->texture = R_LoadTexture (name, width, height, pixbuf, TEXF_ALPHA | TEXF_RGBA | (r_mipsprites.value ? TEXF_MIPMAP : 0) | TEXF_PRECACHE);
117                 // make fog version (just alpha)
118                 pixel = pixbuf;
119                 for (i = 0;i < width*height;i++)
120                 {
121                         *pixel++ = 255;
122                         *pixel++ = 255;
123                         *pixel++ = 255;
124                         pixel++;
125                 }
126                 sprintf (name, "%s_%ifog", loadmodel->name, framenum);
127                 pspriteframe->fogtexture = R_LoadTexture (name, width, height, pixbuf, TEXF_ALPHA | TEXF_RGBA | (r_mipsprites.value ? TEXF_MIPMAP : 0) | TEXF_PRECACHE);
128         }
129
130         qfree(pixbuf);
131
132         return (void *)((byte *)pinframe + sizeof (dspriteframe_t) + size);
133 }
134
135
136 /*
137 =================
138 Mod_LoadSpriteGroup
139 =================
140 */
141 /*
142 void *Mod_LoadSpriteGroup (void * pin, mspriteframe_t *frame, int numframes, int framenum, int bytesperpixel)
143 {
144         int i;
145         void *ptemp;
146
147         ptemp = (void *)(sizeof(dspriteinterval_t) * numframes + sizeof(dspritegroup_t) + (int) pin);
148
149         for (i = 0;i < numframes;i++)
150                 ptemp = Mod_LoadSpriteFrame (ptemp, frame++, framenum * 100 + i, bytesperpixel);
151
152         return ptemp;
153 }
154 */
155
156 // this actually handles both quake sprite and darkplaces sprite32
157 void Mod_LoadQuakeSprite (model_t *mod, void *buffer)
158 {
159         int                                     i, j, version, numframes, realframes, size, bytesperpixel, start, end, total;
160         dsprite_t                       *pin;
161         msprite_t                       *psprite;
162         dspriteframetype_t      *pframetype;
163         dspriteframe_t          *pframe;
164         animscene_t                     *animscenes;
165         mspriteframe_t          *frames;
166         dspriteframe_t          **framedata;
167         float                           modelradius;
168
169         modelradius = 0;
170
171         start = Hunk_LowMark ();
172
173         mod->flags = EF_FULLBRIGHT;
174         // LordHavoc: hack to allow sprites to be non-fullbright
175         for (i = 0;i < MAX_QPATH && mod->name[i];i++)
176         {
177                 if (mod->name[i] == '!')
178                 {
179                         mod->flags &= ~EF_FULLBRIGHT;
180                         break;
181                 }
182         }
183
184         // build a list of frames while parsing
185         framedata = qmalloc(65536*sizeof(dspriteframe_t));
186
187         pin = (dsprite_t *)buffer;
188
189         version = LittleLong (pin->version);
190         // LordHavoc: 32bit textures
191         bytesperpixel = 1;
192         if (version == SPRITE32_VERSION)
193                 bytesperpixel = 4;
194
195         numframes = LittleLong (pin->numframes);
196
197         psprite = Hunk_AllocName (sizeof(msprite_t), va("%s info", loadname));
198
199 //      mod->cache.data = psprite;
200
201         psprite->type = LittleLong (pin->type);
202 //      maxwidth = LittleLong (pin->width);
203 //      maxheight = LittleLong (pin->height);
204 //      psprite->beamlength = LittleFloat (pin->beamlength);
205         mod->synctype = LittleLong (pin->synctype);
206 //      psprite->numframes = numframes;
207
208 //      mod->mins[0] = mod->mins[1] = -maxwidth/2;
209 //      mod->maxs[0] = mod->maxs[1] = maxwidth/2;
210 //      mod->mins[2] = -maxheight/2;
211 //      mod->maxs[2] = maxheight/2;
212
213 //
214 // load the frames
215 //
216         if (numframes < 1)
217                 Host_Error ("Mod_LoadQuakeSprite: Invalid # of frames: %d\n", numframes);
218
219         mod->numframes = numframes;
220
221         pframetype = (dspriteframetype_t *)(pin + 1);
222
223         animscenes = Hunk_AllocName(sizeof(animscene_t) * mod->numframes, va("%s sceneinfo", loadname));
224
225         realframes = 0;
226
227         for (i = 0;i < numframes;i++)
228         {
229                 spriteframetype_t       frametype;
230
231                 frametype = LittleLong (pframetype->type);
232
233                 sprintf(animscenes[i].name, "frame%i", i);
234                 animscenes[i].firstframe = realframes;
235                 animscenes[i].loop = true;
236                 if (frametype == SPR_SINGLE)
237                 {
238                         animscenes[i].framecount = 1;
239                         animscenes[i].framerate = 10;
240                         pframe = (dspriteframe_t *) (pframetype + 1);
241                         framedata[realframes] = pframe;
242                         size = LittleLong(pframe->width) * LittleLong(pframe->height) * bytesperpixel;
243                         pframetype = (dspriteframetype_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
244                         realframes++;
245                 }
246                 else
247                 {
248                         j = LittleLong(((dspritegroup_t *) (sizeof(dspriteframetype_t) + (int) pframetype))->numframes);
249                         animscenes[i].framecount = j;
250                         // FIXME: support variable framerate?
251                         animscenes[i].framerate = 1.0f / LittleFloat(((dspriteinterval_t *) (sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype))->interval);
252                         pframe = (dspriteframe_t *) (sizeof(dspriteinterval_t) * j + sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype);
253                         while (j--)
254                         {
255                                 framedata[realframes] = pframe;
256                                 size = LittleLong(pframe->width) * LittleLong(pframe->height) * bytesperpixel;
257                                 pframe = (dspriteframe_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
258                                 realframes++;
259                         }
260                         pframetype = (dspriteframetype_t *) pframe;
261                 }
262         }
263
264         mod->ofs_scenes = (int) animscenes - (int) psprite;
265
266         frames = Hunk_AllocName(sizeof(mspriteframe_t) * realframes, va("%s frames", loadname));
267
268         realframes = 0;
269         for (i = 0;i < numframes;i++)
270         {
271                 for (j = 0;j < animscenes[i].framecount;j++)
272                 {
273                         Mod_LoadSpriteFrame (framedata[realframes], frames + realframes, i, bytesperpixel, (byte *)&d_8to24table, &modelradius);
274                         realframes++;
275                 }
276         }
277
278         psprite->ofs_frames = (int) frames - (int) psprite;
279
280         qfree(framedata);
281
282         mod->type = mod_sprite;
283
284         modelradius = sqrt(modelradius);
285         for (i = 0;i < 3;i++)
286         {
287                 mod->normalmins[i] = mod->yawmins[i] = mod->rotatedmins[i] = -modelradius;
288                 mod->normalmaxs[i] = mod->yawmaxs[i] = mod->rotatedmaxs[i] = modelradius;
289         }
290 //      mod->modelradius = modelradius;
291
292 // move the complete, relocatable sprite model to the cache
293         end = Hunk_LowMark ();
294         mod->cachesize = total = end - start;
295
296         Cache_Alloc (&mod->cache, total, loadname);
297         if (!mod->cache.data)
298                 return;
299         memcpy (mod->cache.data, psprite, total);
300
301         Hunk_FreeToLowMark (start);
302 }
303
304 void Mod_LoadHLSprite (model_t *mod, void *buffer)
305 {
306         int                                     i, j, numframes, realframes, size, start, end, total, rendermode;
307         byte                            palette[256][4], *in;
308         dspritehl_t                     *pin;
309         msprite_t                       *psprite;
310         dspriteframetype_t      *pframetype;
311         dspriteframe_t          *pframe;
312         animscene_t                     *animscenes;
313         mspriteframe_t          *frames;
314         dspriteframe_t          **framedata;
315         float                           modelradius;
316
317         modelradius = 0;
318
319         start = Hunk_LowMark ();
320
321         mod->flags = EF_FULLBRIGHT;
322
323         // build a list of frames while parsing
324         framedata = qmalloc(65536*sizeof(dspriteframe_t));
325
326         pin = (dspritehl_t *)buffer;
327
328         numframes = LittleLong (pin->numframes);
329
330         psprite = Hunk_AllocName (sizeof(msprite_t), va("%s info", loadname));
331
332         psprite->type = LittleLong (pin->type);
333 //      maxwidth = LittleLong (pin->width);
334 //      maxheight = LittleLong (pin->height);
335         mod->synctype = LittleLong (pin->synctype);
336         rendermode = pin->rendermode;
337
338 //      mod->mins[0] = mod->mins[1] = -maxwidth/2;
339 //      mod->maxs[0] = mod->maxs[1] = maxwidth/2;
340 //      mod->mins[2] = -maxheight/2;
341 //      mod->maxs[2] = maxheight/2;
342
343 //
344 // load the frames
345 //
346         if (numframes < 1)
347                 Host_Error ("Mod_LoadHLSprite: Invalid # of frames: %d\n", numframes);
348
349         mod->numframes = numframes;
350
351         in = (byte *)(pin + 1);
352         i = in[0] + in[1] * 256;
353         if (i != 256)
354                 Host_Error ("Mod_LoadHLSprite: unexpected number of palette colors %i (should be 256)", i);
355         in += 2;
356         switch(rendermode)
357         {
358         case SPRHL_NORMAL:
359                 for (i = 0;i < 256;i++)
360                 {
361                         palette[i][0] = *in++;
362                         palette[i][1] = *in++;
363                         palette[i][2] = *in++;
364                         palette[i][3] = 255;
365                 }
366                 palette[255][0] = palette[255][1] = palette[255][2] = palette[255][3] = 0;
367                 break;
368         case SPRHL_ADDITIVE:
369                 for (i = 0;i < 256;i++)
370                 {
371                         palette[i][0] = *in++;
372                         palette[i][1] = *in++;
373                         palette[i][2] = *in++;
374                         palette[i][3] = 255;
375                 }
376 //              palette[255][0] = palette[255][1] = palette[255][2] = palette[255][3] = 0;
377                 mod->flags |= EF_ADDITIVE;
378                 break;
379         case SPRHL_INDEXALPHA:
380                 for (i = 0;i < 256;i++)
381                 {
382                         palette[i][0] = 255;
383                         palette[i][1] = 255;
384                         palette[i][2] = 255;
385                         palette[i][3] = i;
386                         in += 3;
387                 }
388                 break;
389         case SPRHL_ALPHATEST:
390                 for (i = 0;i < 256;i++)
391                 {
392                         palette[i][0] = *in++;
393                         palette[i][1] = *in++;
394                         palette[i][2] = *in++;
395                         palette[i][3] = 255;
396                 }
397                 palette[0][0] = palette[0][1] = palette[0][2] = palette[0][3] = 0;
398                 break;
399         default:
400                 Host_Error("Mod_LoadHLSprite: unknown texFormat (%i, should be 0, 1, 2, or 3)\n", i);
401                 return;
402         }
403
404         pframetype = (dspriteframetype_t *)in;
405
406         animscenes = Hunk_AllocName(sizeof(animscene_t) * mod->numframes, va("%s sceneinfo", loadname));
407
408         realframes = 0;
409
410         for (i = 0;i < numframes;i++)
411         {
412                 spriteframetype_t       frametype;
413
414                 frametype = LittleLong (pframetype->type);
415
416                 sprintf(animscenes[i].name, "frame%i", i);
417                 animscenes[i].firstframe = realframes;
418                 animscenes[i].loop = true;
419                 if (frametype == SPR_SINGLE)
420                 {
421                         animscenes[i].framecount = 1;
422                         animscenes[i].framerate = 10;
423                         pframe = (dspriteframe_t *) (pframetype + 1);
424                         framedata[realframes] = pframe;
425                         size = LittleLong(pframe->width) * LittleLong(pframe->height);
426                         pframetype = (dspriteframetype_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
427                         realframes++;
428                 }
429                 else
430                 {
431                         j = LittleLong(((dspritegroup_t *) (sizeof(dspriteframetype_t) + (int) pframetype))->numframes);
432                         animscenes[i].framecount = j;
433                         // FIXME: support variable framerate?
434                         animscenes[i].framerate = 1.0f / LittleFloat(((dspriteinterval_t *) (sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype))->interval);
435                         pframe = (dspriteframe_t *) (sizeof(dspriteinterval_t) * j + sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype);
436                         while (j--)
437                         {
438                                 framedata[realframes] = pframe;
439                                 size = LittleLong(pframe->width) * LittleLong(pframe->height);
440                                 pframe = (dspriteframe_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
441                                 realframes++;
442                         }
443                         pframetype = (dspriteframetype_t *) pframe;
444                 }
445         }
446
447         mod->ofs_scenes = (int) animscenes - (int) psprite;
448
449         frames = Hunk_AllocName(sizeof(mspriteframe_t) * realframes, va("%s frames", loadname));
450
451         realframes = 0;
452         for (i = 0;i < numframes;i++)
453         {
454                 for (j = 0;j < animscenes[i].framecount;j++)
455                 {
456                         Mod_LoadSpriteFrame (framedata[realframes], frames + realframes, i, 1, &palette[0][0], &modelradius);
457                         realframes++;
458                 }
459         }
460
461         psprite->ofs_frames = (int) frames - (int) psprite;
462
463         qfree(framedata);
464
465         mod->type = mod_sprite;
466
467         modelradius = sqrt(modelradius);
468         for (i = 0;i < 3;i++)
469         {
470                 mod->normalmins[i] = mod->yawmins[i] = mod->rotatedmins[i] = -modelradius;
471                 mod->normalmaxs[i] = mod->yawmaxs[i] = mod->rotatedmaxs[i] = modelradius;
472         }
473
474 // move the complete, relocatable sprite model to the cache
475         end = Hunk_LowMark ();
476         mod->cachesize = total = end - start;
477
478         Cache_Alloc (&mod->cache, total, loadname);
479         if (!mod->cache.data)
480                 return;
481         memcpy (mod->cache.data, psprite, total);
482
483         Hunk_FreeToLowMark (start);
484 }
485
486 void Mod_Sprite_SERAddEntity(void)
487 {
488         R_ClipSprite();
489 }
490
491
492 /*
493 =================
494 Mod_LoadSpriteModel
495 =================
496 */
497 void Mod_LoadSpriteModel (model_t *mod, void *buffer)
498 {
499         int version;
500         version = ((dsprite_t *)buffer)->version;
501         switch(version)
502         {
503         case SPRITEHL_VERSION:
504                 Mod_LoadHLSprite (mod, buffer);
505                 break;
506         case SPRITE_VERSION:
507         case SPRITE32_VERSION:
508                 Mod_LoadQuakeSprite(mod, buffer);
509                 break;
510         default:
511                 Host_Error ("Mod_LoadSpriteModel: %s has wrong version number (%i should be 1 (quake) or 32 (sprite32) or 2 (halflife)", mod->name, version);
512                 break;
513         }
514         mod->SERAddEntity = Mod_Sprite_SERAddEntity;
515         mod->DrawEarly = R_DrawSpriteModel;
516         mod->DrawLate = NULL;
517         mod->DrawShadow = NULL;
518 }