Ambient occlusion on Quake lightmaps
Posted: Fri Mar 26, 2010 6:33 pm
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?
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;
}
}
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
}
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.