2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // models.c -- model loading and caching
22 // models are the only shared resource between a client and server running
23 // on the same machine.
27 cvar_t r_mipsprites = {"r_mipsprites", "1", true};
34 void Mod_SpriteInit (void)
36 Cvar_RegisterVariable(&r_mipsprites);
39 void Mod_Sprite_StripExtension(char *in, char *out)
42 end = in + strlen(in);
44 if (strcmp(end - 6, ".spr32") == 0)
47 if (strcmp(end - 4, ".spr") == 0)
59 void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t *frame, int framenum, int bytesperpixel)
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;
67 pinframe = (dspriteframe_t *)pin;
69 width = LittleLong (pinframe->width);
70 height = LittleLong (pinframe->height);
71 size = width * height * bytesperpixel;
75 memset (pspriteframe, 0, sizeof (mspriteframe_t));
77 // pspriteframe->width = width;
78 // pspriteframe->height = height;
79 origin[0] = LittleLong (pinframe->origin[0]);
80 origin[1] = LittleLong (pinframe->origin[1]);
82 pspriteframe->up = origin[1];
83 pspriteframe->down = origin[1] - height;
84 pspriteframe->left = origin[0];
85 pspriteframe->right = width + origin[0];
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)
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)
99 for (i = 0;i < width*height;i++)
104 if (*inpixel++ != 255)
113 for (i = 0;i < width*height;i++)
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);
127 return (void *)((byte *)pinframe + sizeof (dspriteframe_t) + size);
136 void *Mod_LoadSpriteGroup (void * pin, mspriteframe_t *frame, int numframes, int framenum, int bytesperpixel)
141 ptemp = (void *)(sizeof(dspriteinterval_t) * numframes + sizeof(dspritegroup_t) + (int) pin);
143 for (i = 0;i < numframes;i++)
144 ptemp = Mod_LoadSpriteFrame (ptemp, frame++, framenum * 100 + i, bytesperpixel);
155 void Mod_LoadSpriteModel (model_t *mod, void *buffer)
157 int i, j, version, numframes, realframes, size, bytesperpixel, start, end, total, maxwidth, maxheight;
160 dspriteframetype_t *pframetype;
161 dspriteframe_t *pframe;
162 animscene_t *animscenes;
163 mspriteframe_t *frames;
164 dspriteframe_t **framedata;
166 start = Hunk_LowMark ();
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++)
172 if (mod->name[i] == '!')
174 mod->flags &= ~EF_FULLBRIGHT;
179 // build a list of frames while parsing
180 framedata = qmalloc(65536*sizeof(dspriteframe_t));
182 pin = (dsprite_t *)buffer;
184 version = LittleLong (pin->version);
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);
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);
194 if (version == SPRITE32_VERSION)
197 numframes = LittleLong (pin->numframes);
199 psprite = Hunk_AllocName (sizeof(msprite_t), va("%s info", loadname));
201 // mod->cache.data = psprite;
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;
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;
219 Host_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes);
221 mod->numframes = numframes;
223 pframetype = (dspriteframetype_t *)(pin + 1);
225 animscenes = Hunk_AllocName(sizeof(animscene_t) * mod->numframes, va("%s sceneinfo", loadname));
229 for (i = 0;i < numframes;i++)
231 spriteframetype_t frametype;
233 frametype = LittleLong (pframetype->type);
235 sprintf(animscenes[i].name, "frame%i", i);
236 animscenes[i].firstframe = realframes;
237 animscenes[i].loop = true;
238 if (frametype == SPR_SINGLE)
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);
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);
257 framedata[realframes] = pframe;
258 size = LittleLong(pframe->width) * LittleLong(pframe->height) * bytesperpixel;
259 pframe = (dspriteframe_t *) (size + sizeof(dspriteframe_t) + (int) pframe);
262 pframetype = (dspriteframetype_t *) pframe;
266 mod->ofs_scenes = (int) animscenes - (int) psprite;
268 frames = Hunk_AllocName(sizeof(mspriteframe_t) * realframes, va("%s frames", loadname));
271 for (i = 0;i < numframes;i++)
273 for (j = 0;j < animscenes[i].framecount;j++)
275 Mod_LoadSpriteFrame (framedata[realframes], frames + realframes, i, bytesperpixel);
280 psprite->ofs_frames = (int) frames - (int) psprite;
284 mod->type = mod_sprite;
286 // move the complete, relocatable sprite model to the cache
287 end = Hunk_LowMark ();
288 mod->cachesize = total = end - start;
290 Cache_Alloc (&mod->cache, total, loadname);
291 if (!mod->cache.data)
293 memcpy (mod->cache.data, psprite, total);
295 Hunk_FreeToLowMark (start);