Ambient occlusion on Quake lightmaps
Ambient occlusion on Quake lightmaps
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?
Here's the "dirty" feature from Q3Map2, their ambient occlusion implementation.
Line 1442: https://zerowing.idsoftware.com/svn/rad ... ht_ydnar.c
Line 1442: https://zerowing.idsoftware.com/svn/rad ... ht_ydnar.c
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.
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.
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).
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;
}
}
ups wrong code section
was this one
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.
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 = ¤tmodel->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 = ¤tmodel->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 = ¤tmodel->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 = ¤tmodel->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
}
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.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.
However no relevance to the discussion at hand.