mirror of
https://github.com/id-Software/Quake-2-Tools.git
synced 2026-03-19 16:39:44 +01:00
The Quake 2 tools as originally released under the GPL license.
This commit is contained in:
1316
bsp/qrad3/lightmap.c
Normal file
1316
bsp/qrad3/lightmap.c
Normal file
File diff suppressed because it is too large
Load Diff
77
bsp/qrad3/makefile
Normal file
77
bsp/qrad3/makefile
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
CFLAGS = -c
|
||||
LDFLAGS =
|
||||
ODIR = baddir
|
||||
|
||||
EXEBASE = qrad3
|
||||
EXE = $(ODIR)/qrad3
|
||||
all: $(EXE)
|
||||
|
||||
_next:
|
||||
make "CFLAGS = -c -g -I../../common" "ODIR = next"
|
||||
|
||||
_irix:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
|
||||
_irixdebug:
|
||||
make "CFLAGS = -c -g -I../../common -Xcpluscomm" "LDFLAGS = " "ODIR = irix"
|
||||
|
||||
_irixinst:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
_irixclean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
_osf:
|
||||
make "CFLAGS = -c -O4 -I../../common -threads" "LDFLAGS = -threads" "ODIR = osf"
|
||||
|
||||
clean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
install:
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
|
||||
FILES = $(ODIR)/bspfile.o $(ODIR)/cmdlib.o $(ODIR)/lbmlib.o $(ODIR)/mathlib.o $(ODIR)/scriplib.o $(ODIR)/polylib.o $(ODIR)/qrad3.o $(ODIR)/threads.o $(ODIR)/trace.o $(ODIR)/lightmap.o $(ODIR)/patches.o
|
||||
|
||||
$(EXE) : $(FILES)
|
||||
cc -o $(EXE) $(LDFLAGS) $(FILES) -lm
|
||||
|
||||
$(ODIR)/qrad3.o : qrad3.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/patches.o : patches.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/trace.o : trace.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/vismat.o : vismat.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/lightmap.o : lightmap.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cmdlib.o : ../../common/cmdlib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/lbmlib.o : ../../common/lbmlib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/mathlib.o : ../../common/mathlib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/polylib.o : ../../common/polylib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/scriplib.o : ../../common/scriplib.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/threads.o : ../../common/threads.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/bspfile.o : ../../common/bspfile.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
515
bsp/qrad3/patches.c
Normal file
515
bsp/qrad3/patches.c
Normal file
@@ -0,0 +1,515 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qrad.h"
|
||||
|
||||
vec3_t texture_reflectivity[MAX_MAP_TEXINFO];
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
TEXTURE LIGHT VALUES
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
======================
|
||||
CalcTextureReflectivity
|
||||
======================
|
||||
*/
|
||||
void CalcTextureReflectivity (void)
|
||||
{
|
||||
int i;
|
||||
int j, k, texels;
|
||||
int color[3];
|
||||
int texel;
|
||||
byte *palette;
|
||||
char path[1024];
|
||||
float r, scale;
|
||||
miptex_t *mt;
|
||||
|
||||
sprintf (path, "%spics/colormap.pcx", gamedir);
|
||||
|
||||
// get the game palette
|
||||
Load256Image (path, NULL, &palette, NULL, NULL);
|
||||
|
||||
// allways set index 0 even if no textures
|
||||
texture_reflectivity[0][0] = 0.5;
|
||||
texture_reflectivity[0][1] = 0.5;
|
||||
texture_reflectivity[0][2] = 0.5;
|
||||
|
||||
for (i=0 ; i<numtexinfo ; i++)
|
||||
{
|
||||
// see if an earlier texinfo allready got the value
|
||||
for (j=0 ; j<i ; j++)
|
||||
{
|
||||
if (!strcmp (texinfo[i].texture, texinfo[j].texture))
|
||||
{
|
||||
VectorCopy (texture_reflectivity[j], texture_reflectivity[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j != i)
|
||||
continue;
|
||||
|
||||
// load the wal file
|
||||
sprintf (path, "%stextures/%s.wal", gamedir, texinfo[i].texture);
|
||||
if (TryLoadFile (path, (void **)&mt) == -1)
|
||||
{
|
||||
printf ("Couldn't load %s\n", path);
|
||||
texture_reflectivity[i][0] = 0.5;
|
||||
texture_reflectivity[i][1] = 0.5;
|
||||
texture_reflectivity[i][2] = 0.5;
|
||||
continue;
|
||||
}
|
||||
texels = LittleLong(mt->width)*LittleLong(mt->height);
|
||||
color[0] = color[1] = color[2] = 0;
|
||||
|
||||
for (j=0 ; j<texels ; j++)
|
||||
{
|
||||
texel = ((byte *)mt)[LittleLong(mt->offsets[0]) + j];
|
||||
for (k=0 ; k<3 ; k++)
|
||||
color[k] += palette[texel*3+k];
|
||||
}
|
||||
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
r = color[j]/texels/255.0;
|
||||
texture_reflectivity[i][j] = r;
|
||||
}
|
||||
// scale the reflectivity up, because the textures are
|
||||
// so dim
|
||||
scale = ColorNormalize (texture_reflectivity[i],
|
||||
texture_reflectivity[i]);
|
||||
if (scale < 0.5)
|
||||
{
|
||||
scale *= 2;
|
||||
VectorScale (texture_reflectivity[i], scale, texture_reflectivity[i]);
|
||||
}
|
||||
#if 0
|
||||
texture_reflectivity[i][0] = 0.5;
|
||||
texture_reflectivity[i][1] = 0.5;
|
||||
texture_reflectivity[i][2] = 0.5;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
MAKE FACES
|
||||
|
||||
=======================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=============
|
||||
WindingFromFace
|
||||
=============
|
||||
*/
|
||||
winding_t *WindingFromFace (dface_t *f)
|
||||
{
|
||||
int i;
|
||||
int se;
|
||||
dvertex_t *dv;
|
||||
int v;
|
||||
winding_t *w;
|
||||
|
||||
w = AllocWinding (f->numedges);
|
||||
w->numpoints = f->numedges;
|
||||
|
||||
for (i=0 ; i<f->numedges ; i++)
|
||||
{
|
||||
se = dsurfedges[f->firstedge + i];
|
||||
if (se < 0)
|
||||
v = dedges[-se].v[1];
|
||||
else
|
||||
v = dedges[se].v[0];
|
||||
|
||||
dv = &dvertexes[v];
|
||||
VectorCopy (dv->point, w->p[i]);
|
||||
}
|
||||
|
||||
RemoveColinearPoints (w);
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
BaseLightForFace
|
||||
=============
|
||||
*/
|
||||
void BaseLightForFace (dface_t *f, vec3_t color)
|
||||
{
|
||||
texinfo_t *tx;
|
||||
|
||||
//
|
||||
// check for light emited by texture
|
||||
//
|
||||
tx = &texinfo[f->texinfo];
|
||||
if (!(tx->flags & SURF_LIGHT) || tx->value == 0)
|
||||
{
|
||||
VectorClear (color);
|
||||
return;
|
||||
}
|
||||
|
||||
VectorScale (texture_reflectivity[f->texinfo], tx->value, color);
|
||||
}
|
||||
|
||||
qboolean IsSky (dface_t *f)
|
||||
{
|
||||
texinfo_t *tx;
|
||||
|
||||
tx = &texinfo[f->texinfo];
|
||||
if (tx->flags & SURF_SKY)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
MakePatchForFace
|
||||
=============
|
||||
*/
|
||||
float totalarea;
|
||||
void MakePatchForFace (int fn, winding_t *w)
|
||||
{
|
||||
dface_t *f;
|
||||
float area;
|
||||
patch_t *patch;
|
||||
dplane_t *pl;
|
||||
int i;
|
||||
vec3_t color;
|
||||
dleaf_t *leaf;
|
||||
|
||||
f = &dfaces[fn];
|
||||
|
||||
area = WindingArea (w);
|
||||
totalarea += area;
|
||||
|
||||
patch = &patches[num_patches];
|
||||
if (num_patches == MAX_PATCHES)
|
||||
Error ("num_patches == MAX_PATCHES");
|
||||
patch->next = face_patches[fn];
|
||||
face_patches[fn] = patch;
|
||||
|
||||
patch->winding = w;
|
||||
|
||||
if (f->side)
|
||||
patch->plane = &backplanes[f->planenum];
|
||||
else
|
||||
patch->plane = &dplanes[f->planenum];
|
||||
if (face_offset[fn][0] || face_offset[fn][1] || face_offset[fn][2] )
|
||||
{ // origin offset faces must create new planes
|
||||
if (numplanes + fakeplanes >= MAX_MAP_PLANES)
|
||||
Error ("numplanes + fakeplanes >= MAX_MAP_PLANES");
|
||||
pl = &dplanes[numplanes + fakeplanes];
|
||||
fakeplanes++;
|
||||
|
||||
*pl = *(patch->plane);
|
||||
pl->dist += DotProduct (face_offset[fn], pl->normal);
|
||||
patch->plane = pl;
|
||||
}
|
||||
|
||||
WindingCenter (w, patch->origin);
|
||||
VectorAdd (patch->origin, patch->plane->normal, patch->origin);
|
||||
leaf = PointInLeaf(patch->origin);
|
||||
patch->cluster = leaf->cluster;
|
||||
if (patch->cluster == -1)
|
||||
qprintf ("patch->cluster == -1\n");
|
||||
|
||||
patch->area = area;
|
||||
if (patch->area <= 1)
|
||||
patch->area = 1;
|
||||
patch->sky = IsSky (f);
|
||||
|
||||
VectorCopy (texture_reflectivity[f->texinfo], patch->reflectivity);
|
||||
|
||||
// non-bmodel patches can emit light
|
||||
if (fn < dmodels[0].numfaces)
|
||||
{
|
||||
BaseLightForFace (f, patch->baselight);
|
||||
|
||||
ColorNormalize (patch->reflectivity, color);
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
patch->baselight[i] *= color[i];
|
||||
|
||||
VectorCopy (patch->baselight, patch->totallight);
|
||||
}
|
||||
num_patches++;
|
||||
}
|
||||
|
||||
|
||||
entity_t *EntityForModel (int modnum)
|
||||
{
|
||||
int i;
|
||||
char *s;
|
||||
char name[16];
|
||||
|
||||
sprintf (name, "*%i", modnum);
|
||||
// search the entities for one using modnum
|
||||
for (i=0 ; i<num_entities ; i++)
|
||||
{
|
||||
s = ValueForKey (&entities[i], "model");
|
||||
if (!strcmp (s, name))
|
||||
return &entities[i];
|
||||
}
|
||||
|
||||
return &entities[0];
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
MakePatches
|
||||
=============
|
||||
*/
|
||||
void MakePatches (void)
|
||||
{
|
||||
int i, j, k;
|
||||
dface_t *f;
|
||||
int fn;
|
||||
winding_t *w;
|
||||
dmodel_t *mod;
|
||||
vec3_t origin;
|
||||
entity_t *ent;
|
||||
|
||||
qprintf ("%i faces\n", numfaces);
|
||||
|
||||
for (i=0 ; i<nummodels ; i++)
|
||||
{
|
||||
mod = &dmodels[i];
|
||||
ent = EntityForModel (i);
|
||||
// bmodels with origin brushes need to be offset into their
|
||||
// in-use position
|
||||
GetVectorForKey (ent, "origin", origin);
|
||||
//VectorCopy (vec3_origin, origin);
|
||||
|
||||
for (j=0 ; j<mod->numfaces ; j++)
|
||||
{
|
||||
fn = mod->firstface + j;
|
||||
face_entity[fn] = ent;
|
||||
VectorCopy (origin, face_offset[fn]);
|
||||
f = &dfaces[fn];
|
||||
w = WindingFromFace (f);
|
||||
for (k=0 ; k<w->numpoints ; k++)
|
||||
{
|
||||
VectorAdd (w->p[k], origin, w->p[k]);
|
||||
}
|
||||
MakePatchForFace (fn, w);
|
||||
}
|
||||
}
|
||||
|
||||
qprintf ("%i sqaure feet\n", (int)(totalarea/64));
|
||||
}
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
SUBDIVIDE
|
||||
|
||||
=======================================================================
|
||||
*/
|
||||
|
||||
void FinishSplit (patch_t *patch, patch_t *newp)
|
||||
{
|
||||
dleaf_t *leaf;
|
||||
|
||||
VectorCopy (patch->baselight, newp->baselight);
|
||||
VectorCopy (patch->totallight, newp->totallight);
|
||||
VectorCopy (patch->reflectivity, newp->reflectivity);
|
||||
newp->plane = patch->plane;
|
||||
newp->sky = patch->sky;
|
||||
|
||||
patch->area = WindingArea (patch->winding);
|
||||
newp->area = WindingArea (newp->winding);
|
||||
|
||||
if (patch->area <= 1)
|
||||
patch->area = 1;
|
||||
if (newp->area <= 1)
|
||||
newp->area = 1;
|
||||
|
||||
WindingCenter (patch->winding, patch->origin);
|
||||
VectorAdd (patch->origin, patch->plane->normal, patch->origin);
|
||||
leaf = PointInLeaf(patch->origin);
|
||||
patch->cluster = leaf->cluster;
|
||||
if (patch->cluster == -1)
|
||||
qprintf ("patch->cluster == -1\n");
|
||||
|
||||
WindingCenter (newp->winding, newp->origin);
|
||||
VectorAdd (newp->origin, newp->plane->normal, newp->origin);
|
||||
leaf = PointInLeaf(newp->origin);
|
||||
newp->cluster = leaf->cluster;
|
||||
if (newp->cluster == -1)
|
||||
qprintf ("patch->cluster == -1\n");
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SubdividePatch
|
||||
|
||||
Chops the patch only if its local bounds exceed the max size
|
||||
=============
|
||||
*/
|
||||
void SubdividePatch (patch_t *patch)
|
||||
{
|
||||
winding_t *w, *o1, *o2;
|
||||
vec3_t mins, maxs, total;
|
||||
vec3_t split;
|
||||
vec_t dist;
|
||||
int i, j;
|
||||
vec_t v;
|
||||
patch_t *newp;
|
||||
|
||||
w = patch->winding;
|
||||
mins[0] = mins[1] = mins[2] = 99999;
|
||||
maxs[0] = maxs[1] = maxs[2] = -99999;
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
v = w->p[i][j];
|
||||
if (v < mins[j])
|
||||
mins[j] = v;
|
||||
if (v > maxs[j])
|
||||
maxs[j] = v;
|
||||
}
|
||||
}
|
||||
VectorSubtract (maxs, mins, total);
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (total[i] > (subdiv+1) )
|
||||
break;
|
||||
if (i == 3)
|
||||
{
|
||||
// no splitting needed
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// split the winding
|
||||
//
|
||||
VectorCopy (vec3_origin, split);
|
||||
split[i] = 1;
|
||||
dist = (mins[i] + maxs[i])*0.5;
|
||||
ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2);
|
||||
|
||||
//
|
||||
// create a new patch
|
||||
//
|
||||
if (num_patches == MAX_PATCHES)
|
||||
Error ("MAX_PATCHES");
|
||||
newp = &patches[num_patches];
|
||||
num_patches++;
|
||||
|
||||
newp->next = patch->next;
|
||||
patch->next = newp;
|
||||
|
||||
patch->winding = o1;
|
||||
newp->winding = o2;
|
||||
|
||||
FinishSplit (patch, newp);
|
||||
|
||||
SubdividePatch (patch);
|
||||
SubdividePatch (newp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
DicePatch
|
||||
|
||||
Chops the patch by a global grid
|
||||
=============
|
||||
*/
|
||||
void DicePatch (patch_t *patch)
|
||||
{
|
||||
winding_t *w, *o1, *o2;
|
||||
vec3_t mins, maxs;
|
||||
vec3_t split;
|
||||
vec_t dist;
|
||||
int i;
|
||||
patch_t *newp;
|
||||
|
||||
w = patch->winding;
|
||||
WindingBounds (w, mins, maxs);
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (floor((mins[i]+1)/subdiv) < floor((maxs[i]-1)/subdiv))
|
||||
break;
|
||||
if (i == 3)
|
||||
{
|
||||
// no splitting needed
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// split the winding
|
||||
//
|
||||
VectorCopy (vec3_origin, split);
|
||||
split[i] = 1;
|
||||
dist = subdiv*(1+floor((mins[i]+1)/subdiv));
|
||||
ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2);
|
||||
|
||||
//
|
||||
// create a new patch
|
||||
//
|
||||
if (num_patches == MAX_PATCHES)
|
||||
Error ("MAX_PATCHES");
|
||||
newp = &patches[num_patches];
|
||||
num_patches++;
|
||||
|
||||
newp->next = patch->next;
|
||||
patch->next = newp;
|
||||
|
||||
patch->winding = o1;
|
||||
newp->winding = o2;
|
||||
|
||||
FinishSplit (patch, newp);
|
||||
|
||||
DicePatch (patch);
|
||||
DicePatch (newp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
SubdividePatches
|
||||
=============
|
||||
*/
|
||||
void SubdividePatches (void)
|
||||
{
|
||||
int i, num;
|
||||
|
||||
if (subdiv < 1)
|
||||
return;
|
||||
|
||||
num = num_patches; // because the list will grow
|
||||
for (i=0 ; i<num ; i++)
|
||||
{
|
||||
// SubdividePatch (&patches[i]);
|
||||
DicePatch (&patches[i]);
|
||||
}
|
||||
qprintf ("%i patches after subdivision\n", num_patches);
|
||||
}
|
||||
|
||||
//=====================================================================
|
||||
158
bsp/qrad3/qrad.h
Normal file
158
bsp/qrad3/qrad.h
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "bspfile.h"
|
||||
#include "polylib.h"
|
||||
#include "threads.h"
|
||||
#include "lbmlib.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
emit_surface,
|
||||
emit_point,
|
||||
emit_spotlight
|
||||
} emittype_t;
|
||||
|
||||
|
||||
|
||||
typedef struct directlight_s
|
||||
{
|
||||
struct directlight_s *next;
|
||||
emittype_t type;
|
||||
|
||||
float intensity;
|
||||
int style;
|
||||
vec3_t origin;
|
||||
vec3_t color;
|
||||
vec3_t normal; // for surfaces and spotlights
|
||||
float stopdot; // for spotlights
|
||||
} directlight_t;
|
||||
|
||||
|
||||
// the sum of all tranfer->transfer values for a given patch
|
||||
// should equal exactly 0x10000, showing that all radiance
|
||||
// reaches other patches
|
||||
typedef struct
|
||||
{
|
||||
unsigned short patch;
|
||||
unsigned short transfer;
|
||||
} transfer_t;
|
||||
|
||||
|
||||
#define MAX_PATCHES 65000 // larger will cause 32 bit overflows
|
||||
|
||||
typedef struct patch_s
|
||||
{
|
||||
winding_t *winding;
|
||||
struct patch_s *next; // next in face
|
||||
int numtransfers;
|
||||
transfer_t *transfers;
|
||||
|
||||
int cluster; // for pvs checking
|
||||
vec3_t origin;
|
||||
dplane_t *plane;
|
||||
|
||||
qboolean sky;
|
||||
|
||||
vec3_t totallight; // accumulated by radiosity
|
||||
// does NOT include light
|
||||
// accounted for by direct lighting
|
||||
float area;
|
||||
|
||||
// illuminance * reflectivity = radiosity
|
||||
vec3_t reflectivity;
|
||||
vec3_t baselight; // emissivity only
|
||||
|
||||
// each style 0 lightmap sample in the patch will be
|
||||
// added up to get the average illuminance of the entire patch
|
||||
vec3_t samplelight;
|
||||
int samples; // for averaging direct light
|
||||
} patch_t;
|
||||
|
||||
extern patch_t *face_patches[MAX_MAP_FACES];
|
||||
extern entity_t *face_entity[MAX_MAP_FACES];
|
||||
extern vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels
|
||||
extern patch_t patches[MAX_PATCHES];
|
||||
extern unsigned num_patches;
|
||||
|
||||
extern int leafparents[MAX_MAP_LEAFS];
|
||||
extern int nodeparents[MAX_MAP_NODES];
|
||||
|
||||
extern float lightscale;
|
||||
|
||||
|
||||
void MakeShadowSplits (void);
|
||||
|
||||
//==============================================
|
||||
|
||||
|
||||
void BuildVisMatrix (void);
|
||||
qboolean CheckVisBit (unsigned p1, unsigned p2);
|
||||
|
||||
//==============================================
|
||||
|
||||
extern float ambient, maxlight;
|
||||
|
||||
void LinkPlaneFaces (void);
|
||||
|
||||
extern qboolean extrasamples;
|
||||
extern int numbounce;
|
||||
|
||||
extern directlight_t *directlights[MAX_MAP_LEAFS];
|
||||
|
||||
extern byte nodehit[MAX_MAP_NODES];
|
||||
|
||||
void BuildLightmaps (void);
|
||||
|
||||
void BuildFacelights (int facenum);
|
||||
|
||||
void FinalLightFace (int facenum);
|
||||
|
||||
qboolean PvsForOrigin (vec3_t org, byte *pvs);
|
||||
|
||||
int TestLine_r (int node, vec3_t start, vec3_t stop);
|
||||
|
||||
void CreateDirectLights (void);
|
||||
|
||||
dleaf_t *PointInLeaf (vec3_t point);
|
||||
|
||||
|
||||
extern dplane_t backplanes[MAX_MAP_PLANES];
|
||||
extern int fakeplanes; // created planes for origin offset
|
||||
|
||||
extern float subdiv;
|
||||
|
||||
extern float direct_scale;
|
||||
extern float entity_scale;
|
||||
|
||||
int PointInLeafnum (vec3_t point);
|
||||
void MakeTnodes (dmodel_t *bm);
|
||||
void MakePatches (void);
|
||||
void SubdividePatches (void);
|
||||
void PairEdges (void);
|
||||
void CalcTextureReflectivity (void);
|
||||
717
bsp/qrad3/qrad3.c
Normal file
717
bsp/qrad3/qrad3.c
Normal file
@@ -0,0 +1,717 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qrad.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
NOTES
|
||||
-----
|
||||
|
||||
every surface must be divided into at least two patches each axis
|
||||
|
||||
*/
|
||||
|
||||
patch_t *face_patches[MAX_MAP_FACES];
|
||||
entity_t *face_entity[MAX_MAP_FACES];
|
||||
patch_t patches[MAX_PATCHES];
|
||||
unsigned num_patches;
|
||||
|
||||
vec3_t radiosity[MAX_PATCHES]; // light leaving a patch
|
||||
vec3_t illumination[MAX_PATCHES]; // light arriving at a patch
|
||||
|
||||
vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels
|
||||
dplane_t backplanes[MAX_MAP_PLANES];
|
||||
|
||||
char inbase[32], outbase[32];
|
||||
|
||||
int fakeplanes; // created planes for origin offset
|
||||
|
||||
int numbounce = 8;
|
||||
qboolean extrasamples;
|
||||
|
||||
float subdiv = 64;
|
||||
qboolean dumppatches;
|
||||
|
||||
void BuildLightmaps (void);
|
||||
int TestLine (vec3_t start, vec3_t stop);
|
||||
|
||||
int junk;
|
||||
|
||||
float ambient = 0;
|
||||
float maxlight = 196;
|
||||
|
||||
float lightscale = 1.0;
|
||||
|
||||
qboolean glview;
|
||||
|
||||
qboolean nopvs;
|
||||
|
||||
char source[1024];
|
||||
|
||||
float direct_scale = 0.4;
|
||||
float entity_scale = 1.0;
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
MISC
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
MakeBackplanes
|
||||
=============
|
||||
*/
|
||||
void MakeBackplanes (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<numplanes ; i++)
|
||||
{
|
||||
backplanes[i].dist = -dplanes[i].dist;
|
||||
VectorSubtract (vec3_origin, dplanes[i].normal, backplanes[i].normal);
|
||||
}
|
||||
}
|
||||
|
||||
int leafparents[MAX_MAP_LEAFS];
|
||||
int nodeparents[MAX_MAP_NODES];
|
||||
|
||||
/*
|
||||
=============
|
||||
MakeParents
|
||||
=============
|
||||
*/
|
||||
void MakeParents (int nodenum, int parent)
|
||||
{
|
||||
int i, j;
|
||||
dnode_t *node;
|
||||
|
||||
nodeparents[nodenum] = parent;
|
||||
node = &dnodes[nodenum];
|
||||
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
j = node->children[i];
|
||||
if (j < 0)
|
||||
leafparents[-j - 1] = nodenum;
|
||||
else
|
||||
MakeParents (j, nodenum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
TRANSFER SCALES
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
int PointInLeafnum (vec3_t point)
|
||||
{
|
||||
int nodenum;
|
||||
vec_t dist;
|
||||
dnode_t *node;
|
||||
dplane_t *plane;
|
||||
|
||||
nodenum = 0;
|
||||
while (nodenum >= 0)
|
||||
{
|
||||
node = &dnodes[nodenum];
|
||||
plane = &dplanes[node->planenum];
|
||||
dist = DotProduct (point, plane->normal) - plane->dist;
|
||||
if (dist > 0)
|
||||
nodenum = node->children[0];
|
||||
else
|
||||
nodenum = node->children[1];
|
||||
}
|
||||
|
||||
return -nodenum - 1;
|
||||
}
|
||||
|
||||
|
||||
dleaf_t *PointInLeaf (vec3_t point)
|
||||
{
|
||||
int num;
|
||||
|
||||
num = PointInLeafnum (point);
|
||||
return &dleafs[num];
|
||||
}
|
||||
|
||||
|
||||
qboolean PvsForOrigin (vec3_t org, byte *pvs)
|
||||
{
|
||||
dleaf_t *leaf;
|
||||
|
||||
if (!visdatasize)
|
||||
{
|
||||
memset (pvs, 255, (numleafs+7)/8 );
|
||||
return true;
|
||||
}
|
||||
|
||||
leaf = PointInLeaf (org);
|
||||
if (leaf->cluster == -1)
|
||||
return false; // in solid leaf
|
||||
|
||||
DecompressVis (dvisdata + dvis->bitofs[leaf->cluster][DVIS_PVS], pvs);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
MakeTransfers
|
||||
|
||||
=============
|
||||
*/
|
||||
int total_transfer;
|
||||
|
||||
void MakeTransfers (int i)
|
||||
{
|
||||
int j;
|
||||
vec3_t delta;
|
||||
vec_t dist, scale;
|
||||
float trans;
|
||||
int itrans;
|
||||
patch_t *patch, *patch2;
|
||||
float total;
|
||||
dplane_t plane;
|
||||
vec3_t origin;
|
||||
float transfers[MAX_PATCHES], *all_transfers;
|
||||
int s;
|
||||
int itotal;
|
||||
byte pvs[(MAX_MAP_LEAFS+7)/8];
|
||||
int cluster;
|
||||
|
||||
patch = patches + i;
|
||||
total = 0;
|
||||
|
||||
VectorCopy (patch->origin, origin);
|
||||
plane = *patch->plane;
|
||||
|
||||
if (!PvsForOrigin (patch->origin, pvs))
|
||||
return;
|
||||
|
||||
// find out which patch2s will collect light
|
||||
// from patch
|
||||
|
||||
all_transfers = transfers;
|
||||
patch->numtransfers = 0;
|
||||
for (j=0, patch2 = patches ; j<num_patches ; j++, patch2++)
|
||||
{
|
||||
transfers[j] = 0;
|
||||
|
||||
if (j == i)
|
||||
continue;
|
||||
|
||||
// check pvs bit
|
||||
if (!nopvs)
|
||||
{
|
||||
cluster = patch2->cluster;
|
||||
if (cluster == -1)
|
||||
continue;
|
||||
if ( ! ( pvs[cluster>>3] & (1<<(cluster&7)) ) )
|
||||
continue; // not in pvs
|
||||
}
|
||||
|
||||
// calculate vector
|
||||
VectorSubtract (patch2->origin, origin, delta);
|
||||
dist = VectorNormalize (delta, delta);
|
||||
if (!dist)
|
||||
continue; // should never happen
|
||||
|
||||
// reletive angles
|
||||
scale = DotProduct (delta, plane.normal);
|
||||
scale *= -DotProduct (delta, patch2->plane->normal);
|
||||
if (scale <= 0)
|
||||
continue;
|
||||
|
||||
// check exact tramsfer
|
||||
if (TestLine_r (0, patch->origin, patch2->origin) )
|
||||
continue;
|
||||
|
||||
trans = scale * patch2->area / (dist*dist);
|
||||
|
||||
if (trans < 0)
|
||||
trans = 0; // rounding errors...
|
||||
|
||||
transfers[j] = trans;
|
||||
if (trans > 0)
|
||||
{
|
||||
total += trans;
|
||||
patch->numtransfers++;
|
||||
}
|
||||
}
|
||||
|
||||
// copy the transfers out and normalize
|
||||
// total should be somewhere near PI if everything went right
|
||||
// because partial occlusion isn't accounted for, and nearby
|
||||
// patches have underestimated form factors, it will usually
|
||||
// be higher than PI
|
||||
if (patch->numtransfers)
|
||||
{
|
||||
transfer_t *t;
|
||||
|
||||
if (patch->numtransfers < 0 || patch->numtransfers > MAX_PATCHES)
|
||||
Error ("Weird numtransfers");
|
||||
s = patch->numtransfers * sizeof(transfer_t);
|
||||
patch->transfers = malloc (s);
|
||||
if (!patch->transfers)
|
||||
Error ("Memory allocation failure");
|
||||
|
||||
//
|
||||
// normalize all transfers so all of the light
|
||||
// is transfered to the surroundings
|
||||
//
|
||||
t = patch->transfers;
|
||||
itotal = 0;
|
||||
for (j=0 ; j<num_patches ; j++)
|
||||
{
|
||||
if (transfers[j] <= 0)
|
||||
continue;
|
||||
itrans = transfers[j]*0x10000 / total;
|
||||
itotal += itrans;
|
||||
t->transfer = itrans;
|
||||
t->patch = j;
|
||||
t++;
|
||||
}
|
||||
}
|
||||
|
||||
// don't bother locking around this. not that important.
|
||||
total_transfer += patch->numtransfers;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
FreeTransfers
|
||||
=============
|
||||
*/
|
||||
void FreeTransfers (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<num_patches ; i++)
|
||||
{
|
||||
free (patches[i].transfers);
|
||||
patches[i].transfers = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
|
||||
/*
|
||||
=============
|
||||
WriteWorld
|
||||
=============
|
||||
*/
|
||||
void WriteWorld (char *name)
|
||||
{
|
||||
int i, j;
|
||||
FILE *out;
|
||||
patch_t *patch;
|
||||
winding_t *w;
|
||||
|
||||
out = fopen (name, "w");
|
||||
if (!out)
|
||||
Error ("Couldn't open %s", name);
|
||||
|
||||
for (j=0, patch=patches ; j<num_patches ; j++, patch++)
|
||||
{
|
||||
w = patch->winding;
|
||||
fprintf (out, "%i\n", w->numpoints);
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
fprintf (out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
|
||||
w->p[i][0],
|
||||
w->p[i][1],
|
||||
w->p[i][2],
|
||||
patch->totallight[0],
|
||||
patch->totallight[1],
|
||||
patch->totallight[2]);
|
||||
}
|
||||
fprintf (out, "\n");
|
||||
}
|
||||
|
||||
fclose (out);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
WriteGlView
|
||||
=============
|
||||
*/
|
||||
void WriteGlView (void)
|
||||
{
|
||||
char name[1024];
|
||||
FILE *f;
|
||||
int i, j;
|
||||
patch_t *p;
|
||||
winding_t *w;
|
||||
|
||||
strcpy (name, source);
|
||||
StripExtension (name);
|
||||
strcat (name, ".glr");
|
||||
|
||||
f = fopen (name, "w");
|
||||
if (!f)
|
||||
Error ("Couldn't open %s", f);
|
||||
|
||||
for (j=0 ; j<num_patches ; j++)
|
||||
{
|
||||
p = &patches[j];
|
||||
w = p->winding;
|
||||
fprintf (f, "%i\n", w->numpoints);
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
fprintf (f, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
|
||||
w->p[i][0],
|
||||
w->p[i][1],
|
||||
w->p[i][2],
|
||||
p->totallight[0]/128,
|
||||
p->totallight[1]/128,
|
||||
p->totallight[2]/128);
|
||||
}
|
||||
fprintf (f, "\n");
|
||||
}
|
||||
|
||||
fclose (f);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================
|
||||
|
||||
/*
|
||||
=============
|
||||
CollectLight
|
||||
=============
|
||||
*/
|
||||
float CollectLight (void)
|
||||
{
|
||||
int i, j;
|
||||
patch_t *patch;
|
||||
vec_t total;
|
||||
|
||||
total = 0;
|
||||
|
||||
for (i=0, patch=patches ; i<num_patches ; i++, patch++)
|
||||
{
|
||||
// skys never collect light, it is just dropped
|
||||
if (patch->sky)
|
||||
{
|
||||
VectorClear (radiosity[i]);
|
||||
VectorClear (illumination[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
patch->totallight[j] += illumination[i][j] / patch->area;
|
||||
radiosity[i][j] = illumination[i][j] * patch->reflectivity[j];
|
||||
}
|
||||
|
||||
total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2];
|
||||
VectorClear (illumination[i]);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
ShootLight
|
||||
|
||||
Send light out to other patches
|
||||
Run multi-threaded
|
||||
=============
|
||||
*/
|
||||
void ShootLight (int patchnum)
|
||||
{
|
||||
int k, l;
|
||||
transfer_t *trans;
|
||||
int num;
|
||||
patch_t *patch;
|
||||
vec3_t send;
|
||||
|
||||
// this is the amount of light we are distributing
|
||||
// prescale it so that multiplying by the 16 bit
|
||||
// transfer values gives a proper output value
|
||||
for (k=0 ; k<3 ; k++)
|
||||
send[k] = radiosity[patchnum][k] / 0x10000;
|
||||
patch = &patches[patchnum];
|
||||
|
||||
trans = patch->transfers;
|
||||
num = patch->numtransfers;
|
||||
|
||||
for (k=0 ; k<num ; k++, trans++)
|
||||
{
|
||||
for (l=0 ; l<3 ; l++)
|
||||
illumination[trans->patch][l] += send[l]*trans->transfer;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
BounceLight
|
||||
=============
|
||||
*/
|
||||
void BounceLight (void)
|
||||
{
|
||||
int i, j;
|
||||
float added;
|
||||
char name[64];
|
||||
patch_t *p;
|
||||
|
||||
for (i=0 ; i<num_patches ; i++)
|
||||
{
|
||||
p = &patches[i];
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
// p->totallight[j] = p->samplelight[j];
|
||||
radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0 ; i<numbounce ; i++)
|
||||
{
|
||||
RunThreadsOnIndividual (num_patches, false, ShootLight);
|
||||
added = CollectLight ();
|
||||
|
||||
qprintf ("bounce:%i added:%f\n", i, added);
|
||||
if ( dumppatches && (i==0 || i == numbounce-1) )
|
||||
{
|
||||
sprintf (name, "bounce%i.txt", i);
|
||||
WriteWorld (name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============================================================
|
||||
|
||||
void CheckPatches (void)
|
||||
{
|
||||
int i;
|
||||
patch_t *patch;
|
||||
|
||||
for (i=0 ; i<num_patches ; i++)
|
||||
{
|
||||
patch = &patches[i];
|
||||
if (patch->totallight[0] < 0 || patch->totallight[1] < 0 || patch->totallight[2] < 0)
|
||||
Error ("negative patch totallight\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
RadWorld
|
||||
=============
|
||||
*/
|
||||
void RadWorld (void)
|
||||
{
|
||||
if (numnodes == 0 || numfaces == 0)
|
||||
Error ("Empty map");
|
||||
MakeBackplanes ();
|
||||
MakeParents (0, -1);
|
||||
MakeTnodes (&dmodels[0]);
|
||||
|
||||
// turn each face into a single patch
|
||||
MakePatches ();
|
||||
|
||||
// subdivide patches to a maximum dimension
|
||||
SubdividePatches ();
|
||||
|
||||
// create directlights out of patches and lights
|
||||
CreateDirectLights ();
|
||||
|
||||
// build initial facelights
|
||||
RunThreadsOnIndividual (numfaces, true, BuildFacelights);
|
||||
|
||||
if (numbounce > 0)
|
||||
{
|
||||
// build transfer lists
|
||||
RunThreadsOnIndividual (num_patches, true, MakeTransfers);
|
||||
qprintf ("transfer lists: %5.1f megs\n"
|
||||
, (float)total_transfer * sizeof(transfer_t) / (1024*1024));
|
||||
|
||||
// spread light around
|
||||
BounceLight ();
|
||||
|
||||
FreeTransfers ();
|
||||
|
||||
CheckPatches ();
|
||||
}
|
||||
|
||||
if (glview)
|
||||
WriteGlView ();
|
||||
|
||||
// blend bounced light into direct light and save
|
||||
PairEdges ();
|
||||
LinkPlaneFaces ();
|
||||
|
||||
lightdatasize = 0;
|
||||
RunThreadsOnIndividual (numfaces, true, FinalLightFace);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
========
|
||||
main
|
||||
|
||||
light modelfile
|
||||
========
|
||||
*/
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
double start, end;
|
||||
char name[1024];
|
||||
|
||||
printf ("----- Radiosity ----\n");
|
||||
|
||||
verbose = false;
|
||||
|
||||
for (i=1 ; i<argc ; i++)
|
||||
{
|
||||
if (!strcmp(argv[i],"-dump"))
|
||||
dumppatches = true;
|
||||
else if (!strcmp(argv[i],"-bounce"))
|
||||
{
|
||||
numbounce = atoi (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-v"))
|
||||
{
|
||||
verbose = true;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-extra"))
|
||||
{
|
||||
extrasamples = true;
|
||||
printf ("extrasamples = true\n");
|
||||
}
|
||||
else if (!strcmp(argv[i],"-threads"))
|
||||
{
|
||||
numthreads = atoi (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-chop"))
|
||||
{
|
||||
subdiv = atoi (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-scale"))
|
||||
{
|
||||
lightscale = atof (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-direct"))
|
||||
{
|
||||
direct_scale *= atof(argv[i+1]);
|
||||
printf ("direct light scaling at %f\n", direct_scale);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-entity"))
|
||||
{
|
||||
entity_scale *= atof(argv[i+1]);
|
||||
printf ("entity light scaling at %f\n", entity_scale);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-glview"))
|
||||
{
|
||||
glview = true;
|
||||
printf ("glview = true\n");
|
||||
}
|
||||
else if (!strcmp(argv[i],"-nopvs"))
|
||||
{
|
||||
nopvs = true;
|
||||
printf ("nopvs = true\n");
|
||||
}
|
||||
else if (!strcmp(argv[i],"-ambient"))
|
||||
{
|
||||
ambient = atof (argv[i+1]) * 128;
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-maxlight"))
|
||||
{
|
||||
maxlight = atof (argv[i+1]) * 128;
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp (argv[i],"-tmpin"))
|
||||
strcpy (inbase, "/tmp");
|
||||
else if (!strcmp (argv[i],"-tmpout"))
|
||||
strcpy (outbase, "/tmp");
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
ThreadSetDefault ();
|
||||
|
||||
if (maxlight > 255)
|
||||
maxlight = 255;
|
||||
|
||||
if (i != argc - 1)
|
||||
Error ("usage: qrad [-v] [-chop num] [-scale num] [-ambient num] [-maxlight num] [-threads num] bspfile");
|
||||
|
||||
start = I_FloatTime ();
|
||||
|
||||
SetQdirFromPath (argv[i]);
|
||||
strcpy (source, ExpandArg(argv[i]));
|
||||
StripExtension (source);
|
||||
DefaultExtension (source, ".bsp");
|
||||
|
||||
// ReadLightFile ();
|
||||
|
||||
sprintf (name, "%s%s", inbase, source);
|
||||
printf ("reading %s\n", name);
|
||||
LoadBSPFile (name);
|
||||
ParseEntities ();
|
||||
CalcTextureReflectivity ();
|
||||
|
||||
if (!visdatasize)
|
||||
{
|
||||
printf ("No vis information, direct lighting only.\n");
|
||||
numbounce = 0;
|
||||
ambient = 0.1;
|
||||
}
|
||||
|
||||
RadWorld ();
|
||||
|
||||
sprintf (name, "%s%s", outbase, source);
|
||||
printf ("writing %s\n", name);
|
||||
WriteBSPFile (name);
|
||||
|
||||
end = I_FloatTime ();
|
||||
printf ("%5.0f seconds elapsed\n", end-start);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
295
bsp/qrad3/trace.c
Normal file
295
bsp/qrad3/trace.c
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "mathlib.h"
|
||||
#include "bspfile.h"
|
||||
|
||||
#define ON_EPSILON 0.1
|
||||
|
||||
typedef struct tnode_s
|
||||
{
|
||||
int type;
|
||||
vec3_t normal;
|
||||
float dist;
|
||||
int children[2];
|
||||
int pad;
|
||||
} tnode_t;
|
||||
|
||||
tnode_t *tnodes, *tnode_p;
|
||||
|
||||
/*
|
||||
==============
|
||||
MakeTnode
|
||||
|
||||
Converts the disk node structure into the efficient tracing structure
|
||||
==============
|
||||
*/
|
||||
void MakeTnode (int nodenum)
|
||||
{
|
||||
tnode_t *t;
|
||||
dplane_t *plane;
|
||||
int i;
|
||||
dnode_t *node;
|
||||
|
||||
t = tnode_p++;
|
||||
|
||||
node = dnodes + nodenum;
|
||||
plane = dplanes + node->planenum;
|
||||
|
||||
t->type = plane->type;
|
||||
VectorCopy (plane->normal, t->normal);
|
||||
t->dist = plane->dist;
|
||||
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
if (node->children[i] < 0)
|
||||
t->children[i] = (dleafs[-node->children[i] - 1].contents & CONTENTS_SOLID) | (1<<31);
|
||||
else
|
||||
{
|
||||
t->children[i] = tnode_p - tnodes;
|
||||
MakeTnode (node->children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
MakeTnodes
|
||||
|
||||
Loads the node structure out of a .bsp file to be used for light occlusion
|
||||
=============
|
||||
*/
|
||||
void MakeTnodes (dmodel_t *bm)
|
||||
{
|
||||
// 32 byte align the structs
|
||||
tnodes = malloc( (numnodes+1) * sizeof(tnode_t));
|
||||
tnodes = (tnode_t *)(((int)tnodes + 31)&~31);
|
||||
tnode_p = tnodes;
|
||||
|
||||
MakeTnode (0);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================
|
||||
|
||||
|
||||
int TestLine_r (int node, vec3_t start, vec3_t stop)
|
||||
{
|
||||
tnode_t *tnode;
|
||||
float front, back;
|
||||
vec3_t mid;
|
||||
float frac;
|
||||
int side;
|
||||
int r;
|
||||
|
||||
if (node & (1<<31))
|
||||
return node & ~(1<<31); // leaf node
|
||||
|
||||
tnode = &tnodes[node];
|
||||
switch (tnode->type)
|
||||
{
|
||||
case PLANE_X:
|
||||
front = start[0] - tnode->dist;
|
||||
back = stop[0] - tnode->dist;
|
||||
break;
|
||||
case PLANE_Y:
|
||||
front = start[1] - tnode->dist;
|
||||
back = stop[1] - tnode->dist;
|
||||
break;
|
||||
case PLANE_Z:
|
||||
front = start[2] - tnode->dist;
|
||||
back = stop[2] - tnode->dist;
|
||||
break;
|
||||
default:
|
||||
front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist;
|
||||
back = (stop[0]*tnode->normal[0] + stop[1]*tnode->normal[1] + stop[2]*tnode->normal[2]) - tnode->dist;
|
||||
break;
|
||||
}
|
||||
|
||||
if (front >= -ON_EPSILON && back >= -ON_EPSILON)
|
||||
return TestLine_r (tnode->children[0], start, stop);
|
||||
|
||||
if (front < ON_EPSILON && back < ON_EPSILON)
|
||||
return TestLine_r (tnode->children[1], start, stop);
|
||||
|
||||
side = front < 0;
|
||||
|
||||
frac = front / (front-back);
|
||||
|
||||
mid[0] = start[0] + (stop[0] - start[0])*frac;
|
||||
mid[1] = start[1] + (stop[1] - start[1])*frac;
|
||||
mid[2] = start[2] + (stop[2] - start[2])*frac;
|
||||
|
||||
r = TestLine_r (tnode->children[side], start, mid);
|
||||
if (r)
|
||||
return r;
|
||||
return TestLine_r (tnode->children[!side], mid, stop);
|
||||
}
|
||||
|
||||
int TestLine (vec3_t start, vec3_t stop)
|
||||
{
|
||||
return TestLine_r (0, start, stop);
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
LINE TRACING
|
||||
|
||||
The major lighting operation is a point to point visibility test, performed
|
||||
by recursive subdivision of the line by the BSP tree.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec3_t backpt;
|
||||
int side;
|
||||
int node;
|
||||
} tracestack_t;
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
TestLine
|
||||
==============
|
||||
*/
|
||||
qboolean _TestLine (vec3_t start, vec3_t stop)
|
||||
{
|
||||
int node;
|
||||
float front, back;
|
||||
tracestack_t *tstack_p;
|
||||
int side;
|
||||
float frontx,fronty, frontz, backx, backy, backz;
|
||||
tracestack_t tracestack[64];
|
||||
tnode_t *tnode;
|
||||
|
||||
frontx = start[0];
|
||||
fronty = start[1];
|
||||
frontz = start[2];
|
||||
backx = stop[0];
|
||||
backy = stop[1];
|
||||
backz = stop[2];
|
||||
|
||||
tstack_p = tracestack;
|
||||
node = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (node == CONTENTS_SOLID)
|
||||
{
|
||||
#if 0
|
||||
float d1, d2, d3;
|
||||
|
||||
d1 = backx - frontx;
|
||||
d2 = backy - fronty;
|
||||
d3 = backz - frontz;
|
||||
|
||||
if (d1*d1 + d2*d2 + d3*d3 > 1)
|
||||
#endif
|
||||
return false; // DONE!
|
||||
}
|
||||
|
||||
while (node < 0)
|
||||
{
|
||||
// pop up the stack for a back side
|
||||
tstack_p--;
|
||||
if (tstack_p < tracestack)
|
||||
return true;
|
||||
node = tstack_p->node;
|
||||
|
||||
// set the hit point for this plane
|
||||
|
||||
frontx = backx;
|
||||
fronty = backy;
|
||||
frontz = backz;
|
||||
|
||||
// go down the back side
|
||||
|
||||
backx = tstack_p->backpt[0];
|
||||
backy = tstack_p->backpt[1];
|
||||
backz = tstack_p->backpt[2];
|
||||
|
||||
node = tnodes[tstack_p->node].children[!tstack_p->side];
|
||||
}
|
||||
|
||||
tnode = &tnodes[node];
|
||||
|
||||
switch (tnode->type)
|
||||
{
|
||||
case PLANE_X:
|
||||
front = frontx - tnode->dist;
|
||||
back = backx - tnode->dist;
|
||||
break;
|
||||
case PLANE_Y:
|
||||
front = fronty - tnode->dist;
|
||||
back = backy - tnode->dist;
|
||||
break;
|
||||
case PLANE_Z:
|
||||
front = frontz - tnode->dist;
|
||||
back = backz - tnode->dist;
|
||||
break;
|
||||
default:
|
||||
front = (frontx*tnode->normal[0] + fronty*tnode->normal[1] + frontz*tnode->normal[2]) - tnode->dist;
|
||||
back = (backx*tnode->normal[0] + backy*tnode->normal[1] + backz*tnode->normal[2]) - tnode->dist;
|
||||
break;
|
||||
}
|
||||
|
||||
if (front > -ON_EPSILON && back > -ON_EPSILON)
|
||||
// if (front > 0 && back > 0)
|
||||
{
|
||||
node = tnode->children[0];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (front < ON_EPSILON && back < ON_EPSILON)
|
||||
// if (front <= 0 && back <= 0)
|
||||
{
|
||||
node = tnode->children[1];
|
||||
continue;
|
||||
}
|
||||
|
||||
side = front < 0;
|
||||
|
||||
front = front / (front-back);
|
||||
|
||||
tstack_p->node = node;
|
||||
tstack_p->side = side;
|
||||
tstack_p->backpt[0] = backx;
|
||||
tstack_p->backpt[1] = backy;
|
||||
tstack_p->backpt[2] = backz;
|
||||
|
||||
tstack_p++;
|
||||
|
||||
backx = frontx + front*(backx-frontx);
|
||||
backy = fronty + front*(backy-fronty);
|
||||
backz = frontz + front*(backz-frontz);
|
||||
|
||||
node = tnode->children[side];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user