Ambient occlusion on Quake lightmaps

Discuss programming topics for any language, any source base. If it is programming related but doesn't fit in one of the below categories, it goes here.
Post Reply
JasonX
Posts: 422
Joined: Tue Apr 21, 2009 2:08 pm

Ambient occlusion on Quake lightmaps

Post by JasonX »

I was thinking about this and noticed that, maybe, Quake map compilers should run an Ambient occlusion pass, just like Q3Map2 does (-dirty). Has it been done yet?
Teiman
Posts: 311
Joined: Sun Jun 03, 2007 9:39 am

Post by Teiman »

Anything that combat the "tile based" look of most maps will be good in my untrained eyes.
metlslime
Posts: 316
Joined: Tue Feb 05, 2008 11:03 pm

Post by metlslime »

I got this working a few years ago, but it's kind of hacked into bjp's light tool and not really in a releasable state. Plus it really needs optimization.

But yeah, it's a good idea, it makes outdoor areas look nicer.
JasonX
Posts: 422
Joined: Tue Apr 21, 2009 2:08 pm

Post by JasonX »

Here's the "dirty" feature from Q3Map2, their ambient occlusion implementation.

Line 1442: https://zerowing.idsoftware.com/svn/rad ... ht_ydnar.c
LordHavoc
Posts: 322
Joined: Fri Nov 05, 2004 3:12 am
Location: western Oregon, USA
Contact:

Post by LordHavoc »

The (experimental and unusable - it doesn't save! and it's only meant for q3bsp at the moment) mod_generatelightmaps code in DP does ambient occlusion in a somewhat interesting and fast way...

It builds an svbsp tree for each light, so it know precisely where shadows are in a geometric sense, but then instead of sampling that directly, it jitters the world position of each lightmap sample with a series of fixed offsets (randomly generated at start, but fixed during a run), this gives the characteristic ambient occlusion and antialiasing at the same time.
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Post by revelator »

hmm i wonder if that was what the codebit i found in bakers quake2 was for ?

as far as i could read from it it also parses the bsp tree and saves it as a cached version (bit like the old .ms files but with .bsp extension).

Code: Select all


void Mod_LoadAliasModel(model_t * mod, void *buffer)
{
	int				i, j;
	dmdl_t			*pinmodel, *pheader;
	dstvert_t		*pinst, *poutst;
	dtriangle_t		*pintri, *pouttri, *tris;
	daliasframe_t	*pinframe, *poutframe;
	int				*pincmd, *poutcmd;
	int				version;
	
	vec3_t			tempr, tempv;
	int				k,l;
	char			nam[MAX_OSPATH];
	char			*buff;

	daliasframe_t	*frame;
	dtrivertx_t		*verts;
	byte			*norms = NULL, *tangents, *binormals;
	float			s, t;
	float			iw, ih;
	fstvert_t		*st;
	byte			smooth;
	int				ax, cx;
	vec3_t			binormals_[MAX_VERTS];
	vec3_t			tangents_[MAX_VERTS];
	char			cachename[MAX_OSPATH];
	FILE			*f;
	unsigned		checksum, cs_binormals, cs_tangents;
	qboolean		success = false, cache = false, err = true;;
	
	mod->memorySize = 0;

	pinmodel = (dmdl_t *) buffer;

	version = LittleLong(pinmodel->version);
	if (version != ALIAS_VERSION)
		VID_Error(ERR_DROP, "%s has wrong version number (%i should be %i)", mod->name, version, ALIAS_VERSION);
	
	pheader = Hunk_Alloc(LittleLong(pinmodel->ofs_end));
	
	mod->memorySize += LittleLong(pinmodel->ofs_end);
	
	aliasSize += mod->memorySize;

	// byte swap the header fields and sanity check
	for (i = 0; i < sizeof(dmdl_t) * 0.25; i++)
		((int *) pheader)[i] = LittleLong(((int *) buffer)[i]);

	if (pheader->skinheight > MAX_LBM_HEIGHT)
		VID_Error(ERR_DROP, "model %s has a skin taller than %d",
				  mod->name, MAX_LBM_HEIGHT);

	if (pheader->num_xyz <= 0)
		VID_Error(ERR_DROP, "model %s has no vertices", mod->name);

	if (pheader->num_xyz > MAX_VERTS)
		VID_Error(ERR_DROP, "model %s has too many vertices", mod->name);

	if (pheader->num_st <= 0)
		VID_Error(ERR_DROP, "model %s has no st vertices", mod->name);

	if (pheader->num_tris <= 0)
		VID_Error(ERR_DROP, "model %s has no triangles", mod->name);

	if (pheader->num_frames <= 0)
		VID_Error(ERR_DROP, "model %s has no frames", mod->name);

//
// load base s and t vertices (not used in gl version)
//
	pinst = (dstvert_t *) ((byte *) pinmodel + pheader->ofs_st);
	poutst = (dstvert_t *) ((byte *) pheader + pheader->ofs_st);

	for (i = 0; i < pheader->num_st; i++) {
		poutst[i].s = LittleShort(pinst[i].s);
		poutst[i].t = LittleShort(pinst[i].t);
	}

//
// load triangle lists
//
	pintri = (dtriangle_t *) ((byte *) pinmodel + pheader->ofs_tris);
	pouttri = (dtriangle_t *) ((byte *) pheader + pheader->ofs_tris);

	for (i = 0, tris = pouttri; i < pheader->num_tris; i++, tris++) {
		for (j = 0; j < 3; j++) {
			tris->index_xyz[j] = LittleShort(pintri[i].index_xyz[j]);
			tris->index_st[j] = LittleShort(pintri[i].index_st[j]);
		}
	}

	// find neighbours
	mod->neighbors = malloc(pheader->num_tris * sizeof(neighbors_t));
	Mod_BuildTriangleNeighbors(mod->neighbors, pouttri, pheader->num_tris);
	mod->memorySize += pheader->num_tris * sizeof(neighbors_t);
//
// load the frames
//
	for (i = 0; i < pheader->num_frames; i++) {
		pinframe = (daliasframe_t *) ((byte *) pinmodel + pheader->ofs_frames + i * pheader->framesize);
		poutframe =	(daliasframe_t *) ((byte *) pheader + pheader->ofs_frames + i * pheader->framesize);

		Q_memcpy(poutframe->name, pinframe->name, sizeof(poutframe->name));

		for (j = 0; j < 3; j++) {
			poutframe->scale[j] = LittleFloat(pinframe->scale[j]);
			poutframe->translate[j] = LittleFloat(pinframe->translate[j]);
		}

		// verts are all 8 bit, so no swapping needed
		Q_memcpy(poutframe->verts, pinframe->verts, pheader->num_xyz * sizeof(dtrivertx_t));
	}
	mod->type = mod_alias;

	// 
	// load the glcmds
	// 
	pincmd = (int *) ((byte *) pinmodel + pheader->ofs_glcmds);
	poutcmd = (int *) ((byte *) pheader + pheader->ofs_glcmds);

	for (i = 0; i < pheader->num_glcmds; i++) {
		poutcmd[i] = LittleLong(pincmd[i]);
	}

	// register all skins
	Q_memcpy((char *) pheader + pheader->ofs_skins, (char *) pinmodel + pheader->ofs_skins, pheader->num_skins * MAX_SKINNAME);
	
	for (i = 0; i < pheader->num_skins; i++) {
		char *pname;
		char gl[48];
	    
		pname = (char *) pheader + pheader->ofs_skins + i * MAX_SKINNAME;
		mod->skins[i] = GL_FindImage(pname, it_skin);
		
		// GlowMaps loading
		Q_strcpy(gl, pname);
		gl[strlen(gl) - 4] = 0;
		Q_strcat(gl, "_gl.tga");
		mod->glowtexture[i] = GL_FindImage(gl, it_skin);

		if(!mod->glowtexture[i]){
		Q_strcpy(gl, pname);
		gl[strlen(gl) - 4] = 0;
		Q_strcat(gl, "_gl.png");
		mod->glowtexture[i] = GL_FindImage(gl, it_skin);
		}

		// Loading Normal maps
		Q_strcpy(gl, pname);
		gl[strlen(gl) - 4] = 0;
		Q_strcat(gl, "_nm.dds");
		mod->skins_normal[i] = GL_FindImage(gl, it_wall);
		
		if (!mod->skins_normal[i]){
        Q_strcpy(gl, pname);
        gl[strlen(gl) - 4] = 0;
        Q_strcat(gl, "_nm.tga");
        mod->skins_normal[i] = GL_FindImage(gl, it_wall);
		}
		
		Q_strcpy(gl, pname);
		gl[strlen(gl) - 4] = 0;
		Q_strcat(gl, "_env.tga");
		mod->skin_env[i] = GL_FindImage(gl, it_skin);		
	}
	mod->flags = 0;

	// set default render fx values
	mod->ambient = r_ambientLevel->value;
	mod->diffuse = r_diffuseLevel->value;
	mod->specular = r_specularScale->value;
	mod->glowCfg[0] = 0.3;
	mod->glowCfg[1] = 1.0;
	mod->glowCfg[2] = 5.666;
	mod->noselfshadow = false;
	mod->envmap = false;

	i = strlen(mod->name);
	memcpy(nam, mod->name, i);
	nam[i-3]='r';
	nam[i-2]='f';
	nam[i-1]='x';
	nam[i]=0;

	// load the .rfx
	i = FS_LoadFile (nam, (void **)&buff);

	if (buff)
	{
		char bak=buff[i];
		buff[i] = 0;
		Mod_LoadAliasModelFx(mod, buff);
		buff[i] = bak;
		FS_FreeFile (buff);
	}
	
	// Calculate texcoords for triangles (for compute tangents and binormals)
	tris = (dtriangle_t *) ((byte *)pheader + pheader->ofs_tris);
	mod->st = st = (fstvert_t*)Hunk_Alloc (pheader->num_st * sizeof(fstvert_t));
	mod->memorySize += pheader->num_st * sizeof(fstvert_t);
	iw = 1.0 / pheader->skinwidth;
	ih = 1.0 / pheader->skinheight;

	for (i=0; i<pheader->num_st ; i++)
	{
		s = poutst[i].s;
		t = poutst[i].t;
		st[i].s = (s - 0.5) * iw;
		st[i].t = (t - 0.5) * ih;
	}

	// create the cache directory
	Q_sprintf (cachename, sizeof(cachename), "%s/cache/%s", FS_Gamedir(), mod->name);
	FS_CreatePath(cachename);
	f = fopen (cachename, "rb");

	if (f)
	{	
		// read from cache
		ax = fread(&smooth, 1, sizeof(smooth), f);

		if(ax==sizeof(smooth))
		{
			unsigned	ang;
			if(fread(&ang, 1, sizeof(unsigned), f)!=sizeof(unsigned)) goto badd;
			if (ang != (unsigned)(cos(DEG2RAD(45))*0x7fffffff))
			{
badd:			fclose(f);
				goto bad;
			}
			cache = true;
				
			cx = pheader->num_xyz * pheader->num_frames * sizeof(byte);
			mod->binormals = binormals =(byte*)Hunk_Alloc (cx);
			mod->tangents = tangents = (byte*)Hunk_Alloc (cx);
			mod->memorySize += cx;
			mod->memorySize += cx;
			if(fread(&cs_binormals, 1, sizeof(int), f)!=sizeof(int)) goto badd;
			ax = fread(mod->binormals, 1, cx, f);
			if(ax==cx)
			{
				if(fread(&cs_tangents, 1, sizeof(int), f)!=sizeof(int))	goto badd;
				ax = fread(mod->tangents, 1, cx, f);
				success = (ax==cx); 
				if(success) {
					goto ok;
				}
			}					
		}
		fclose(f);
	}
	
bad:
	Com_Printf("^1%s: invalid cache\n", mod->name);
	success = false;
ok: 
	if(success)
	{
		checksum = LittleLong (Com_BlockChecksum (mod->binormals, cx));

		if(checksum == cs_binormals)
		{
			checksum = LittleLong (Com_BlockChecksum (mod->tangents, cx));
			if(checksum == cs_tangents){
					goto okey;
			}
		}
		Com_Printf("^1%s: invalid checksum!\n", mod->name);
		success = false;
	}

	if(success)
	{
okey:	
		Com_DPrintf("%s: loaded from cache\n", mod->name);

		HACK_RecalcVertsLightNormalIdx(pheader);

		goto exit;
	}

	if (cache)
	{
		Com_DPrintf("error loading /%s from cache...\n", mod->name);
	}
	Com_Printf("^3%s: calculating extra data\n", mod->name);

	/* ==============
	cache not found - recalc it
	=============== */
	HACK_RecalcVertsLightNormalIdx(pheader);

	cx = pheader->num_xyz * pheader->num_frames * sizeof(byte);
		
	// Calculate tangents for vertices (bump mapping)		
	mod->binormals = binormals = (byte*)Hunk_Alloc (cx);
	mod->tangents = tangents = (byte*)Hunk_Alloc (cx);
	mod->memorySize += cx;
	mod->memorySize += cx;

	//for all frames
	for (i=0; i<pheader->num_frames; i++)
	{
		//set temp to zero
		memset(tangents_, 0, pheader->num_xyz*sizeof(vec3_t));
		memset(binormals_, 0, pheader->num_xyz*sizeof(vec3_t));

		frame = (daliasframe_t *)((byte *)pheader + pheader->ofs_frames + i * pheader->framesize);
		verts = frame->verts;

		//for all tris
		for (j=0; j<pheader->num_tris; j++)
		{
			vec3_t	vv0,vv1,vv2;
			vec3_t tangent, binormal;

			vv0[0] = (float)verts[tris[j].index_xyz[0]].v[0];
			vv0[1] = (float)verts[tris[j].index_xyz[0]].v[1];
			vv0[2] = (float)verts[tris[j].index_xyz[0]].v[2];
			vv1[0] = (float)verts[tris[j].index_xyz[1]].v[0];
			vv1[1] = (float)verts[tris[j].index_xyz[1]].v[1];
			vv1[2] = (float)verts[tris[j].index_xyz[1]].v[2];
			vv2[0] = (float)verts[tris[j].index_xyz[2]].v[0];
			vv2[1] = (float)verts[tris[j].index_xyz[2]].v[1];
			vv2[2] = (float)verts[tris[j].index_xyz[2]].v[2];

			VecsForTris(vv0, vv1, vv2,
						&st[tris[j].index_st[0]].s,
						&st[tris[j].index_st[1]].s,
						&st[tris[j].index_st[2]].s,
						tangent, binormal);			//for all vertices in the tri

			for (k=0; k<3; k++)
			{
				l = tris[j].index_xyz[k];
				VectorAdd(tangents_[l], tangent, tangents_[l]);
				VectorAdd(binormals_[l], binormal, binormals_[l]);
			}
		}

		/// Berserker:
		//  íåêîòîðûõ ìîäåëÿõ èçðåäêà ïîïàäàþòñÿ íåñêîëüêî òî÷åê, èìåþùèå îäèíàêîâûå êîîðäèíàòû.
		// Äëÿ òàêèõ ñëó÷àåâ îáúåäèíÿåì èõ âåêòîðà (åñëè óãîë ìåæäó íîðìàëÿìè íåâåëèê (äî 15 ãðàäóñîâ)).
		for (j=0; j<pheader->num_xyz; j++)
		{
			for (k=j+1; k<pheader->num_xyz; k++)
			{
				if(verts[j].v[0] == verts[k].v[0] && verts[j].v[1] == verts[k].v[1] && verts[j].v[2] == verts[k].v[2])
				{
					float *jnormal = r_avertexnormals[verts[j].lightnormalindex];
					float *knormal = r_avertexnormals[verts[k].lightnormalindex];

					if(DotProduct(jnormal, knormal) >= cos(DEG2RAD(45)))		/// smooth_cosine = cos(N), ïðè âåëè÷èíå óãëà ìåæäó íîðìàëÿìè ìåíåå ÷åì N ãðàäóñîâ, ñ÷èòàåì, ÷òî ýòî îäíà òî÷êà
					{
						VectorAdd(tangents_[j], tangents_[k], tangents_[j]);
						VectorCopy(tangents_[j], tangents_[k]);
						VectorAdd(binormals_[j], binormals_[k], binormals_[j]);
						VectorCopy(binormals_[j], binormals_[k]);
					}
				}
			}

			// normalize averages
			VectorNormalize(tangents_[j]);
			VectorNormalize(binormals_[j]);

			tangents[i * pheader->num_xyz + j] = CalcNormal2Index(tangents_[j]);
			binormals[i * pheader->num_xyz + j] = CalcNormal2Index(binormals_[j]);
		}
	}
	
	// write cache to disk
	Q_sprintf (cachename, sizeof(cachename), "%s/cache/%s", FS_Gamedir(), mod->name);
	FS_CreatePath(cachename);
	f = fopen (cachename, "wb");

	if(f)
	{
		unsigned	sc;
		fwrite(&smooth, 1, sizeof(smooth), f);
		sc = (unsigned)(cos(DEG2RAD(45))*0x7fffffff);
		fwrite(&sc, 1, sizeof(unsigned), f);
		
		checksum = LittleLong (Com_BlockChecksum (binormals, cx));
		fwrite(&checksum, 1, sizeof(int), f);
		fwrite(binormals, 1, cx, f);

		checksum = LittleLong (Com_BlockChecksum (tangents, cx));
		fwrite(&checksum, 1, sizeof(int), f);
		fwrite(tangents, 1, cx, f);

		fclose(f);
	}
exit:	
	// Load the Md2 Indices
	Mod_LoadMd2Indices (mod, pheader);

	ClearBounds(mod->mins, mod->maxs);
	VectorClear(mod->center);
	frame = (daliasframe_t *)((byte *)pheader + pheader->ofs_frames);/// + i * pheader->framesize);		Áåðåì òîëüêî íóëåâîé êàäð!
	verts = frame->verts;

	for (k=0; k<pheader->num_xyz; k++)
	{
		for (l=0; l<3; l++)
		{
			if (mod->mins[l] > verts[k].v[l])	mod->mins[l] = verts[k].v[l];
			if (mod->maxs[l] < verts[k].v[l])	mod->maxs[l] = verts[k].v[l];
		}
	}

	for (l=0; l<3; l++)
	{
		mod->mins[l] = mod->mins[l] * frame->scale[l] + frame->translate[l];
		mod->maxs[l] = mod->maxs[l] * frame->scale[l] + frame->translate[l];
		mod->center[l] = (mod->mins[l] + mod->maxs[l]) * 0.5;
	}
	tempr[0] = mod->maxs[0] - mod->mins[0];
	tempr[1] = mod->maxs[1] - mod->mins[1];
	tempr[2] = 0;
	tempv[0] = 0;
	tempv[1] = 0;
	tempv[2] = mod->maxs[2] - mod->mins[2];
	mod->radius = max(VectorLength(tempr), VectorLength(tempv));

	for(i=0; i<3; i++)
	{
		mod->center[i] = (mod->maxs[i] + mod->mins[i]) * 0.5;
	}
}
LordHavoc
Posts: 322
Joined: Fri Nov 05, 2004 3:12 am
Location: western Oregon, USA
Contact:

Post by LordHavoc »

I do not see any relation between model loading and lightmap ambient occlusion.
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Post by revelator »

ups wrong code section :oops:

was this one

Code: Select all

void Mod_LoadFaces(lump_t * l)
{
#define MAGIC_CACHE 1237
	dface_t		*in;
	msurface_t	*out;
	int			i, count, surfnum;
	int			planenum, side;
	int			ti;
	byte		*cache = NULL;
	char		cachename[MAX_QPATH];
	int			ci, cj, flp;
	float		*vi, *vj;
	msurface_t	*si, *sj;
	vec3_t		ni, nj, ttt, tttt, ttttt, vector;
	FILE		*f = NULL;
	unsigned	sc = (unsigned)(cos(DEG2RAD(45))*0x7fffffff);
	int			j;
	int			offs = 0;
	unsigned	chk = LittleLong (Com_BlockChecksum (mod_base, mod_filelen));
	qboolean	caching__ = false; 
	unsigned	checksum;
	qboolean	caching_calc = false;
	
	in = (void *) (mod_base + l->fileofs);

	if (l->filelen % sizeof(*in)) {
		VID_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
	}
	count = l->filelen / sizeof(*in);
	out = Hunk_Alloc(count * sizeof(*out));
	
	loadmodel->surfaces = out;
	loadmodel->numsurfaces = count;	
	loadmodel->memorySize += count * sizeof(*out);

	currentmodel = loadmodel;

	GL_BeginBuildingLightmaps(loadmodel);

	for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++) {
		out->firstedge = LittleLong(in->firstedge);
		out->numedges = LittleShort(in->numedges);		
		out->flags = 0;
		out->polys = NULL;

		planenum = LittleShort(in->planenum);
		side = LittleShort(in->side);

		if (side) {
			out->flags |= SURF_PLANEBACK;			
		}
		out->plane = loadmodel->planes + planenum;

		ti = LittleShort (in->texinfo);

		if (ti < 0 || ti >= loadmodel->numtexinfo) {
			Sys_Error ("MOD_LoadBmodel: bad texinfo number");
		}
		out->texinfo = loadmodel->texinfo + ti;

		CalcSurfaceExtents (out);
				
		// lighting info
		for (i=0 ; i<MAXLIGHTMAPS ; i++) {
			out->styles[i] = in->styles[i];
		}
		i = LittleLong(in->lightofs);

		if (i == -1) {
			out->samples = NULL;
		} else {
			out->samples = loadmodel->lightdata + i;
		}

		// set the drawing flags
		if (out->texinfo->flags & SURF_WARP) {
			out->flags |= SURF_DRAWTURB;
			for (i=0 ; i<2 ; i++) {
				out->extents[i] = 16384;
				out->texturemins[i] = -8192;
			}
			GL_SubdivideSurface (out);	// cut up polygon for warps
		}

		// create lightmaps and polygons
		if (!(out->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP))) {
			GL_CreateSurfaceLightmap (out);
		}

		if (!(out->texinfo->flags & SURF_WARP)) {
			GL_BuildPolygonFromSurface(out);		
			GL_AddFlareSurface(out);			
		}

		// pick up some pvs info.
		// someone needs to be shot here btw go figure.
		CalcSurfaceBounds(out);
	}

	// Calc Tangent space
	// create the cache directory
	Q_sprintf (cachename, sizeof(cachename), "%s/cache/%s", FS_Gamedir(), loadmodel->name);

	FS_CreatePath(cachename);

	f = fopen (cachename, "rb");

	if (f) {

		// read from cache
		unsigned	ang;
		unsigned	check;
		unsigned	check_from_cache;

		flp = FS_filelength2(f) - sizeof(float) - sizeof(unsigned) - sizeof(float);
		
		if (flp < 0) goto bad;
		if(fread(&ang, 1, sizeof(unsigned), f) != sizeof(unsigned)) goto bad;
		if (ang != (unsigned)( cos(DEG2RAD(45)) * 0x7fffffff)) goto bad;
		if(fread(&check_from_cache, 1, sizeof(unsigned), f) != sizeof(unsigned)) goto bad;
		if (check_from_cache != chk) goto bad;
		cache = (byte*)malloc(flp);
		fread(&check, 1, sizeof(unsigned), f);
		check += MAGIC_CACHE;
		fread(cache, 1, flp, f);
		checksum = LittleLong (Com_BlockChecksum (cache, flp));

		if (checksum == check) {

			flp = 0;

			for (i=0 ; i<count ; i++) {

				si = &currentmodel->surfaces[i];

				if (!(si->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_NODRAW))) {
					for (ci=0, vi = si->polys->verts[0]; ci<si->numedges; ci++, vi+=VERTEXSIZE)	{
						vi[7] = r_avertexnormals[cache[flp]][0];
						vi[8] = r_avertexnormals[cache[flp]][1];
						vi[9] = r_avertexnormals[cache[flp++]][2];
						vi[10] = r_avertexnormals[cache[flp]][0];
						vi[11] = r_avertexnormals[cache[flp]][1];
						vi[12] = r_avertexnormals[cache[flp++]][2];
						vi[13] = r_avertexnormals[cache[flp]][0];
						vi[14] = r_avertexnormals[cache[flp]][1];
						vi[15] = r_avertexnormals[cache[flp++]][2];
					}
				}
			}
			free (cache);
			fclose (f);
		} else {
			free (cache);
bad:		
			fclose (f);
			Com_Printf("^3 Invalid cache\n");
			goto crea;
		}
	} else {
crea:	
		if (!caching__) {
			Com_Printf("^3Calculating extra data\n");
		} else {
			caching_calc = true;
		}
		f = fopen (cachename, "wb");

		flp = 0;

		for (i=0 ; i<count ; i++) {

			si = &currentmodel->surfaces[i];

			if (!(si->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_NODRAW))) {

				vi = si->polys->verts[0];

				for (ci=0; ci<si->numedges; ci++, vi+=VERTEXSIZE) {
					vi[7] = vi[8] = vi[9] = vi[10] = vi[11] = vi[12] = vi[13] = vi[14] = vi[15] = 0;
				}

				if (si->flags & SURF_PLANEBACK)	{
					VectorNegate(si->plane->normal, ni);
				} else {
					VectorCopy(si->plane->normal, ni);
				}

				for (j=0 ; j<count ; j++) {

					sj = &currentmodel->surfaces[j];

					if (!(sj->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_NODRAW))) {
						if (sj->flags & SURF_PLANEBACK) {
							VectorNegate(sj->plane->normal, nj);
						} else {
							VectorCopy(sj->plane->normal, nj);
						}

						if(DotProduct(ni, nj) >= cos(DEG2RAD(45)) ) {

							vi = si->polys->verts[0];

							for (ci=0; ci<si->numedges; ci++, vi+=VERTEXSIZE) {

								vj = sj->polys->verts[0];

								for (cj=0; cj<sj->numedges; cj++, vj+=VERTEXSIZE) {
									if (VectorCompare(vi, vj)) {
										vi[7] += nj[0];
										vi[8] += nj[1];
										vi[9] += nj[2];
									}
								}
							}
						}
					}
				}
				vi = si->polys->verts[0];

				for (ci=0; ci<si->numedges; ci++, vi+=VERTEXSIZE) {

					VectorSet(ttt, vi[7], vi[8], vi[9]);
					VectorNormalize(ttt);

					if(DotProduct(ttt, ni)<cos(DEG2RAD(45))) {
						vi[7] = ttt[0] = ni[0];
						vi[8] = ttt[1] = ni[1];
						vi[9] = ttt[2] = ni[2];
					} else {
						vi[7] = ttt[0];
						vi[8] = ttt[1];
						vi[9] = ttt[2];
					}
					CrossProduct(ttt, si->texinfo->vecs[0], tttt);
					CrossProduct(ttt, tttt, ttttt);
					VectorNormalize(ttttt);

					if (DotProduct(ttttt, si->texinfo->vecs[0]) < 0) {
						vi[10] = -ttttt[0];
						vi[11] = -ttttt[1];
						vi[12] = -ttttt[2];
					} else {
						vi[10] = ttttt[0];
						vi[11] = ttttt[1];
						vi[12] = ttttt[2];
					}
					CrossProduct(ttt, si->texinfo->vecs[1], tttt);
					CrossProduct(ttt, tttt, ttttt);
					VectorNormalize(ttttt);

					if (DotProduct(ttttt, si->texinfo->vecs[1]) < 0) {
						vi[13] = -ttttt[0];
						vi[14] = -ttttt[1];
						vi[15] = -ttttt[2];
					} else {
						vi[13] = ttttt[0];
						vi[14] = ttttt[1];
						vi[15] = ttttt[2];
					}
					flp += 3;
				}
			}
		}

		// write to cache
		cache = (byte *)malloc(flp);

		for (i=0 ; i<count ; i++) {

			si = &currentmodel->surfaces[i];

			if (!(si->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_NODRAW))) {
				for (ci=0, vi = si->polys->verts[0]; ci<si->numedges; ci++, vi+=VERTEXSIZE)	{
					vector[0] = vi[7];
					vector[1] = vi[8];
					vector[2] = vi[9];
					cache[offs++] = CalcNormal2Index(vector);
					vector[0] = vi[10];
					vector[1] = vi[11];
					vector[2] = vi[12];
					cache[offs++] = CalcNormal2Index(vector);
					vector[0] = vi[13];
					vector[1] = vi[14];
					vector[2] = vi[15];
					cache[offs++] = CalcNormal2Index(vector);
				}
			}
		}
		checksum = LittleLong (Com_BlockChecksum (cache, flp));
		
		fwrite(&sc, 1, sizeof(unsigned), f);
		fwrite(&chk, 1, sizeof(unsigned), f);
		checksum -= MAGIC_CACHE;
		fwrite(&checksum, 1, sizeof(unsigned), f);
		fwrite (cache, 1, flp, f);
		free(cache);
		fclose (f);
	}
	GL_EndBuildingLightmaps();
#undef MAGIC_CACHE
}
it does seem to be lightmap related allthough i cant tell if any of it is for ambient acclusion.

to me it looks like its storing the vertex values my guess is its used for normalmaps and such.
LordHavoc
Posts: 322
Joined: Fri Nov 05, 2004 3:12 am
Location: western Oregon, USA
Contact:

Post by LordHavoc »

reckless wrote:it does seem to be lightmap related allthough i cant tell if any of it is for ambient acclusion.

to me it looks like its storing the vertex values my guess is its used for normalmaps and such.
Also not related at all to ambient occlusion, but at least on the topic of lightmaps.

However no relevance to the discussion at hand.
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Post by revelator »

aye had a look at the code and theres a bit more to it.

just noticed you had the feature in dp and i remembered seing something similar in this but as turns out not exactly related.
Post Reply