shithub: qk1

ref: 3d9a179d3de101cf405df256918a7769d02698ee
dir: /model_bsp30.c/

View raw version
#include "quakedef.h"

int BSP_CalcSurfaceExtents(model_t *mod, msurface_t *s);

int
BSP30_LoadEntities(model_t *mod, byte *in, int sz)
{
	char *p, *s, *e, path[32];
	Wad *w;
	int maxw;

	mod->numwads = 0;
	if(sz == 0){
		mod->entities = nil;
		return 0;
	}

	memcpy(mod->entities = Hunk_Alloc(sz), in, sz);
	if((s = strstr((char*)mod->entities, "\"wad\"")) == nil ||
	   (s = strchr(s+5, '"')) == nil ||
	   (e = strchr(s+1, '"')) == nil)
		return 0;

	maxw = 4;
	mod->wads = Hunk_Alloc(maxw * sizeof(*mod->wads));
	for(s = s+1, p = s; s <= e; s++){
		if(p != s && (*s == ';' || s == e)){
			snprintf(path, sizeof(path), "%.*s", (int)(s-p), p);
			if((w = W_OpenWad(path)) != nil){
				mod->wads = Arr_AllocExtra(mod->wads, &maxw, mod->numwads-maxw);
				mod->wads[mod->numwads++] = w;
			}else{
				Con_Printf("BSP_LoadEntities: %s\n", lerr());
				continue;
			}
			p = s+1;
		}else if(*s == '\\')
			p = s+1;
	}
	return 0;
}

int
BSP30_LoadLighting(model_t *mod, byte *in, int sz)
{
	if(sz == 0){
		mod->lightdata = nil;
		return 0;
	}

	memcpy(mod->lightdata = Hunk_Alloc(sz), in, sz);
	return 0;
}

int
BSP30_LoadFaces(model_t *mod, byte *in, int sz)
{
	msurface_t *out;
	int i, surfnum;
	static const int elsz = 2+2+4+2+2+MAXLIGHTMAPS+4;

	if(sz % elsz){
		werrstr("BSP_LoadFaces: funny lump size");
		return -1;
	}
	mod->numsurfaces = sz / elsz;
	mod->surfaces = out = Hunk_Alloc(mod->numsurfaces * sizeof(*out));

	for(surfnum = 0; surfnum < mod->numsurfaces; surfnum++, out++){
		out->plane = mod->planes + le16u(in);
		out->flags = le16u(in) ? SURF_PLANEBACK : 0;
		out->firstedge = le32u(in);
		out->numedges = le16u(in);
		out->texinfo = mod->texinfo + le16u(in);

		if(BSP_CalcSurfaceExtents(mod, out) != 0)
			return -1;

		// lighting info
		memmove(out->styles, in, MAXLIGHTMAPS);
		in += MAXLIGHTMAPS;
		i = le32(in);
		if(i >= 0){
			if(i % 3)
				Con_Printf("misaligned light samples: %d\n", i);
			else{
				out->samples = mod->lightdata + i;
			}
		}

		// set the drawing flags flag
		if(strncmp(out->texinfo->texture->name, "sky", 3) == 0)
			out->flags |= SURF_DRAWSKY | SURF_DRAWTILED;
		else if(out->texinfo->texture->name[0] == '!'){	// turbulent
			out->flags |= SURF_DRAWTURB | SURF_DRAWTILED | SURF_TRANS;
			for(i = 0; i < 2; i++){
				out->extents[i] = 16384;
				out->texturemins[i] = -8192;
			}
		}else if(out->texinfo->texture->name[0] == '{')
			out->flags |= SURF_TRANS | SURF_FENCE;
	}
	return 0;
}

int
BSP30_LoadTextures(model_t *mod, byte *in, int sz)
{
	int off, i, j, pixels, num, max, altmax, w, h, palsz;
	byte *p, *in0, *x;
	texture_t *tx, *tx2;
	texture_t *anims[10];
	texture_t *altanims[10];
	static const int elsz = 16+2*4+4*4;

	if(sz < 1){
		mod->textures = nil;
		return 0;
	}
	if(sz < 4 || (sz % 4) != 0){
		werrstr("funny lump size");
		goto err;
	}

	in0 = in;
	mod->numtextures = le32(in);
	if(mod->numtextures*4 > sz-4){
		werrstr("overflow? %d > %d", mod->numtextures*4, sz-4);
		goto err;
	}
	mod->textures = Hunk_Alloc(mod->numtextures * sizeof(*mod->textures));

	for(i = 0; i < mod->numtextures; i++){
		off = le32(in);
		if(off == -1)
			continue;
		if(off < 0 || off > sz-elsz){
			werrstr("bad offset %d (sz %d)", off, sz);
			goto err;
		}
		p = in0+off+16;
		w = le32(p);
		h = le32(p);
		pixels = w*h*85/64;
		tx = Hunk_Alloc(sizeof(*tx) + pixels*sizeof(pixel_t));
		strncpy(tx->name, (char*)in0+off, sizeof(tx->name)-1);
		tx->name[sizeof(tx->name)-1] = 0;
		for(j = 0; j < MIPLEVELS; j++)
			tx->offsets[j] = le32(p) - (16+2*4+4*4);
		mod->textures[i] = tx;
		tx->width = w;
		tx->height = h;
		if(tx->offsets[0] >= 0){
			// the pixels immediately follow the structures
			x = p + pixels;
			if((palsz = le16(x)) > 0){
				pal3torgbx(p, tx->pixels, pixels, x, palsz);
				if(tx->name[0] == '{'){
					/* last color is transparent */
					for(j = 0; j < pixels; j++){
						if(p[j] == palsz-1)
							tx->pixels[j] = 0;
					}
				}
				if(strchr(tx->name, '~') != nil){
					/* last 32 colors are fullbright */
					for(j = 0; j < pixels; j++){
						if(p[j] >= 256-32)
							tx->pixels[j] &= 0xffffff;
					}
				}
			}
		}else{
			// alternative: outside, in a wad
			for(j = 0; j < mod->numwads; j++){
				if(W_ReadMipTex(mod->wads[j], tx->name, tx) >= 0)
					break;
			}
			if(j >= mod->numwads)
				Con_Printf("missing texture: %s\n", tx->name);
		}
		if(strncmp(tx->name, "sky", 3) == 0)
			R_InitSky(nil); /* FIXME(sigrid): skybox */
	}

	// sequence the animations
	for(i = 0; i < mod->numtextures; i++){
		tx = mod->textures[i];
		if(!tx || tx->name[0] != '+')
			continue;
		if(tx->anim_next)
			continue;	// already sequenced

		// find the number of frames in the animation
		memset(anims, 0, sizeof(anims));
		memset(altanims, 0, sizeof(altanims));

		max = tx->name[1];
		if(max >= 'a' && max <= 'z')
			max -= 'a' - 'A';
		if(max >= '0' && max <= '9'){
			max -= '0';
			altmax = 0;
			anims[max++] = tx;
		}else if(max >= 'A' && max <= 'J'){
			altmax = max - 'A';
			max = 0;
			altanims[altmax++] = tx;
		}else{
badanim:
			werrstr("bad animating texture: %s", tx->name);
			goto err;
		}

		for(j = i+1; j < mod->numtextures; j++){
			tx2 = mod->textures[j];
			if(!tx2 || tx2->name[0] != '+')
				continue;
			if(strcmp(tx2->name+2, tx->name+2) != 0)
				continue;

			num = tx2->name[1];
			if(num >= 'a' && num <= 'z')
				num -= 'a' - 'A';
			if(num >= '0' && num <= '9'){
				num -= '0';
				anims[num] = tx2;
				if(num+1 > max)
					max = num + 1;
			}else if(num >= 'A' && num <= 'J'){
				num = num - 'A';
				altanims[num] = tx2;
				if(num+1 > altmax)
					altmax = num+1;
			}else{
				goto badanim;
			}
		}

#define	ANIM_CYCLE	2
		// link them all together
		for(j = 0; j < max; j++){
			tx2 = anims[j];
			if(!tx2){
badframe:
				werrstr("missing frame %d of %s", j, tx->name);
				goto err;
			}
			tx2->anim_total = max * ANIM_CYCLE;
			tx2->anim_min = j * ANIM_CYCLE;
			tx2->anim_max = (j+1) * ANIM_CYCLE;
			tx2->anim_next = anims[(j+1) % max];
			if(altmax)
				tx2->alternate_anims = altanims[0];
		}
		for(j = 0; j < altmax; j++){
			tx2 = altanims[j];
			if(!tx2)
				goto badframe;
			tx2->anim_total = altmax * ANIM_CYCLE;
			tx2->anim_min = j * ANIM_CYCLE;
			tx2->anim_max = (j+1) * ANIM_CYCLE;
			tx2->anim_next = altanims[(j+1) % altmax];
			if(max)
				tx2->alternate_anims = anims[0];
		}
	}

	return 0;
err:
	werrstr("BSP_LoadTextures: %s", lerr());
	return -1;
}