optimized AngleVectors calls (pass NULL for vectors that should not be generated)
[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 = {"r_mipsprites", "1", true};
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)
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         if (!pspriteframe->texture)
92         {
93                 pspriteframe->texture = R_LoadTexture (name, width, height, (byte *)(pinframe + 1), TEXF_ALPHA | (bytesperpixel > 1 ? TEXF_RGBA : 0) | (r_mipsprites.value ? TEXF_MIPMAP : 0) | TEXF_PRECACHE);
94                 // make fog version (just alpha)
95                 pixbuf = pixel = qmalloc(width*height*4);
96                 inpixel = (byte *)(pinframe + 1);
97                 if (bytesperpixel == 1)
98                 {
99                         for (i = 0;i < width*height;i++)
100                         {
101                                 *pixel++ = 255;
102                                 *pixel++ = 255;
103                                 *pixel++ = 255;
104                                 if (*inpixel++ != 255)
105                                         *pixel++ = 255;
106                                 else
107                                         *pixel++ = 0;
108                         }
109                 }
110                 else
111                 {
112                         inpixel+=3;
113                         for (i = 0;i < width*height;i++)
114                         {
115                                 *pixel++ = 255;
116                                 *pixel++ = 255;
117                                 *pixel++ = 255;
118                                 *pixel++ = *inpixel;
119                                 inpixel+=4;
120                         }
121                 }
122                 sprintf (name, "%s_%ifog", loadmodel->name, framenum);
123                 pspriteframe->fogtexture = R_LoadTexture (name, width, height, pixbuf, TEXF_ALPHA | TEXF_RGBA | (r_mipsprites.value ? TEXF_MIPMAP : 0) | TEXF_PRECACHE);
124                 qfree(pixbuf);
125         }
126
127         return (void *)((byte *)pinframe + sizeof (dspriteframe_t) + size);
128 }
129
130
131 /*
132 =================
133 Mod_LoadSpriteGroup
134 =================
135 */
136 void *Mod_LoadSpriteGroup (void * pin, mspriteframe_t *frame, int numframes, int framenum, int bytesperpixel)
137 {
138         int i;
139         void *ptemp;
140
141         ptemp = (void *)(sizeof(dspriteinterval_t) * numframes + sizeof(dspritegroup_t) + (int) pin);
142
143         for (i = 0;i < numframes;i++)
144                 ptemp = Mod_LoadSpriteFrame (ptemp, frame++, framenum * 100 + i, bytesperpixel);
145
146         return ptemp;
147 }
148
149
150 /*
151 =================
152 Mod_LoadSpriteModel
153 =================
154 */
155 void Mod_LoadSpriteModel (model_t *mod, void *buffer)
156 {
157         int                                     i, j, version, numframes, realframes, size, bytesperpixel, start, end, total, maxwidth, maxheight;
158         dsprite_t                       *pin;
159         msprite_t                       *psprite;
160         dspriteframetype_t      *pframetype;
161         dspriteframe_t          *pframe;
162         animscene_t                     *animscenes;
163         mspriteframe_t          *frames;
164         dspriteframe_t          **framedata;
165
166         start = Hunk_LowMark ();
167
168         mod->flags = EF_FULLBRIGHT;
169         // LordHavoc: hack to allow sprites to be non-fullbright
170         for (i = 0;i < MAX_QPATH && mod->name[i];i++)
171         {
172                 if (mod->name[i] == '!')
173                 {
174                         mod->flags &= ~EF_FULLBRIGHT;
175                         break;
176                 }
177         }
178
179         // build a list of frames while parsing
180         framedata = qmalloc(65536*sizeof(dspriteframe_t));
181
182         pin = (dsprite_t *)buffer;
183
184         version = LittleLong (pin->version);
185         if (version == 2)
186         {
187                 version = 32;
188                 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);
189         }
190         // LordHavoc: 32bit textures
191         if (version != SPRITE_VERSION && version != SPRITE32_VERSION)
192                 Host_Error ("%s has wrong version number (%i should be %i or %i)", mod->name, version, SPRITE_VERSION, SPRITE32_VERSION);
193         bytesperpixel = 1;
194         if (version == SPRITE32_VERSION)
195                 bytesperpixel = 4;
196
197         numframes = LittleLong (pin->numframes);
198
199         psprite = Hunk_AllocName (sizeof(msprite_t), va("%s info", loadname));
200
201 //      mod->cache.data = psprite;
202
203         psprite->type = LittleLong (pin->type);
204         maxwidth = LittleLong (pin->width);
205         maxheight = LittleLong (pin->height);
206 //      psprite->beamlength = LittleFloat (pin->beamlength);
207         mod->synctype = LittleLong (pin->synctype);
208 //      psprite->numframes = numframes;
209
210         mod->mins[0] = mod->mins[1] = -maxwidth/2;
211         mod->maxs[0] = mod->maxs[1] = maxwidth/2;
212         mod->mins[2] = -maxheight/2;
213         mod->maxs[2] = maxheight/2;
214         
215 //
216 // load the frames
217 //
218         if (numframes < 1)
219                 Host_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes);
220
221         mod->numframes = numframes;
222
223         pframetype = (dspriteframetype_t *)(pin + 1);
224
225         animscenes = Hunk_AllocName(sizeof(animscene_t) * mod->numframes, va("%s sceneinfo", loadname));
226
227         realframes = 0;
228
229         for (i = 0;i < numframes;i++)
230         {
231                 spriteframetype_t       frametype;
232
233                 frametype = LittleLong (pframetype->type);
234
235                 sprintf(animscenes[i].name, "frame%i", i);
236                 animscenes[i].firstframe = realframes;
237                 animscenes[i].loop = true;
238                 if (frametype == SPR_SINGLE)
239                 {
240                         animscenes[i].framecount = 1;
241                         animscenes[i].framerate = 10;
242                         pframe = (dspriteframe_t *) (pframetype + 1);
243                         framedata[realframes] = pframe;
244                         size = LittleLong(pframe->width) * LittleLong(pframe->height) * bytesperpixel;
245                         pframetype = (dspriteframetype_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
246                         realframes++;
247                 }
248                 else
249                 {
250                         j = LittleLong(((dspritegroup_t *) (sizeof(dspriteframetype_t) + (int) pframetype))->numframes);
251                         animscenes[i].framecount = j;
252                         // FIXME: support variable framerate?
253                         animscenes[i].framerate = 1.0f / LittleFloat(((dspriteinterval_t *) (sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype))->interval);
254                         pframe = (dspriteframe_t *) (sizeof(dspriteinterval_t) * j + sizeof(dspritegroup_t) + sizeof(dspriteframetype_t) + (int) pframetype);
255                         while (j--)
256                         {
257                                 framedata[realframes] = pframe;
258                                 size = LittleLong(pframe->width) * LittleLong(pframe->height) * bytesperpixel;
259                                 pframe = (dspriteframe_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
260                                 realframes++;
261                         }
262                         pframetype = (dspriteframetype_t *) pframe;
263                 }
264         }
265
266         mod->ofs_scenes = (int) animscenes - (int) psprite;
267
268         frames = Hunk_AllocName(sizeof(mspriteframe_t) * realframes, va("%s frames", loadname));
269
270         realframes = 0;
271         for (i = 0;i < numframes;i++)
272         {
273                 for (j = 0;j < animscenes[i].framecount;j++)
274                 {
275                         Mod_LoadSpriteFrame (framedata[realframes], frames + realframes, i, bytesperpixel);
276                         realframes++;
277                 }
278         }
279
280         psprite->ofs_frames = (int) frames - (int) psprite;
281
282         qfree(framedata);
283
284         mod->type = mod_sprite;
285
286 // move the complete, relocatable sprite model to the cache
287         end = Hunk_LowMark ();
288         mod->cachesize = total = end - start;
289         
290         Cache_Alloc (&mod->cache, total, loadname);
291         if (!mod->cache.data)
292                 return;
293         memcpy (mod->cache.data, psprite, total);
294
295         Hunk_FreeToLowMark (start);
296 }