mirror of
https://github.com/UberGames/GtkRadiant.git
synced 2024-11-29 23:22:23 +00:00
603 lines
13 KiB
C
603 lines
13 KiB
C
/*
|
|
Copyright (C) 1999-2007 id Software, Inc. and contributors.
|
|
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
|
|
|
This file is part of GtkRadiant.
|
|
|
|
GtkRadiant 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.
|
|
|
|
GtkRadiant 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 GtkRadiant; 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_Quake2
|
|
======================
|
|
*/
|
|
void CalcTextureReflectivity_Quake2( 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 ) {
|
|
Sys_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
|
|
}
|
|
}
|
|
|
|
/*
|
|
======================
|
|
CalcTextureReflectivity_Heretic2
|
|
======================
|
|
*/
|
|
void CalcTextureReflectivity_Heretic2( void ){
|
|
int i;
|
|
int j, texels;
|
|
int color[3];
|
|
int texel;
|
|
char path[1024];
|
|
float r;
|
|
miptex_m8_t *mt;
|
|
miptex_m32_t *mt32;
|
|
byte *pos;
|
|
|
|
|
|
// 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.m32", gamedir, texinfo[i].texture );
|
|
if ( TryLoadFile( path, (void **)&mt32 ) == -1 ) {
|
|
sprintf( path, "%stextures/%s.m8", gamedir, texinfo[i].texture );
|
|
if ( TryLoadFile( path, (void **)&mt ) == -1 ) {
|
|
Sys_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[0] ) * LittleLong( mt->height[0] );
|
|
color[0] = color[1] = color[2] = 0;
|
|
|
|
for ( j = 0 ; j < texels ; j++ )
|
|
{
|
|
texel = ( (byte *)mt )[LittleLong( mt->offsets[0] ) + j];
|
|
color[0] += mt->palette[texel].r;
|
|
color[1] += mt->palette[texel].g;
|
|
color[2] += mt->palette[texel].b;
|
|
}
|
|
|
|
free( mt );
|
|
}
|
|
else
|
|
{
|
|
texels = LittleLong( mt32->width[0] ) * LittleLong( mt32->height[0] );
|
|
color[0] = color[1] = color[2] = 0;
|
|
|
|
for ( j = 0 ; j < texels ; j++ )
|
|
{
|
|
pos = (byte *)mt32 + mt32->offsets[0] + ( j << 2 );
|
|
color[0] += *pos++; // r
|
|
color[1] += *pos++; // g
|
|
color[2] += *pos++; // b
|
|
}
|
|
|
|
free( mt32 );
|
|
}
|
|
|
|
|
|
for ( j = 0 ; j < 3 ; j++ )
|
|
{
|
|
r = color[j] / ( (float) texels * 255.0 );
|
|
texture_reflectivity[i][j] = r;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=======================================================================
|
|
|
|
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 = Rad_PointInLeaf( patch->origin );
|
|
patch->cluster = leaf->cluster;
|
|
if ( patch->cluster == -1 ) {
|
|
Sys_FPrintf( SYS_VRB, "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;
|
|
|
|
Sys_FPrintf( SYS_VRB, "%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 );
|
|
}
|
|
}
|
|
|
|
Sys_FPrintf( SYS_VRB, "%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 = Rad_PointInLeaf( patch->origin );
|
|
patch->cluster = leaf->cluster;
|
|
if ( patch->cluster == -1 ) {
|
|
Sys_FPrintf( SYS_VRB, "patch->cluster == -1\n" );
|
|
}
|
|
|
|
WindingCenter( newp->winding, newp->origin );
|
|
VectorAdd( newp->origin, newp->plane->normal, newp->origin );
|
|
leaf = Rad_PointInLeaf( newp->origin );
|
|
newp->cluster = leaf->cluster;
|
|
if ( newp->cluster == -1 ) {
|
|
Sys_FPrintf( SYS_VRB, "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] );
|
|
}
|
|
Sys_FPrintf( SYS_VRB, "%i patches after subdivision\n", num_patches );
|
|
}
|
|
|
|
//=====================================================================
|