06 Jan 2019

This commit is contained in:
g-cont 2019-01-06 00:00:00 +03:00 committed by Alibek Omarov
parent 073fa79bd4
commit f838d648a7
7 changed files with 335 additions and 71 deletions

View File

@ -134,6 +134,8 @@ BRUSH MODELS
#define TEX_EXTRA_LIGHTMAP BIT( 3 ) // bsp31 legacy - using 8 texels per luxel instead of 16 texels per luxel
#define TEX_SCROLL BIT( 6 ) // Doom special FX
#define IsLiquidContents( cnt ) ( cnt == CONTENTS_WATER || cnt == CONTENTS_SLIME || cnt == CONTENTS_LAVA )
// ambient sound types
enum
{

View File

@ -109,6 +109,15 @@ typedef struct
int reserved[32]; // just for future expansions or mod-makers
} mfaceinfo_t;
typedef struct
{
mplane_t *edges;
int numedges;
vec3_t origin;
vec_t radius; // for culling tests
int contents; // sky or solid
} mfacebevel_t;
typedef struct
{
float vecs[2][4]; // [s/t] unit vectors in world space.
@ -208,7 +217,7 @@ typedef struct mextrasurf_s
// begin userdata
struct msurface_s *lightmapchain; // lightmapped polys
struct mextrasurf_s *detailchain; // for detail textures drawing
struct mextrasurf_s *mirrorchain; // for gl_texsort drawing
mfacebevel_t *bevel; // for exact face traceline
struct mextrasurf_s *lumachain; // draw fullbrights
struct cl_entity_s *parent; // upcast to owner entity

View File

@ -112,6 +112,9 @@ void GL_ApplyTextureParams( gl_texture_t *tex )
{
vec4_t border = { 0.0f, 0.0f, 0.0f, 1.0f };
if( !glw_state.initialized )
return;
Assert( tex != NULL );
// set texture filter
@ -1085,6 +1088,10 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic )
qboolean normalMap;
const byte *bufend;
// dedicated server
if( !glw_state.initialized )
return true;
Assert( pic != NULL );
Assert( tex != NULL );
@ -1210,6 +1217,7 @@ do specified actions on pixels
*/
static void GL_ProcessImage( gl_texture_t *tex, rgbdata_t *pic )
{
float emboss_scale = 0.0f;
uint img_flags = 0;
// force upload texture as RGB or RGBA (detail textures requires this)
@ -1255,8 +1263,12 @@ static void GL_ProcessImage( gl_texture_t *tex, rgbdata_t *pic )
if( pic->type == PF_INDEXED_24 || pic->type == PF_INDEXED_32 )
img_flags |= IMAGE_FORCE_RGBA;
// dedicated server doesn't register this variable
if( gl_emboss_scale != NULL )
emboss_scale = gl_emboss_scale->value;
// processing image before uploading (force to rgba, make luma etc)
if( pic->buffer ) Image_Process( &pic, 0, 0, img_flags, gl_emboss_scale->value );
if( pic->buffer ) Image_Process( &pic, 0, 0, img_flags, emboss_scale );
if( FBitSet( tex->flags, TF_LUMINANCE ))
ClearBits( pic->flags, IMAGE_HAS_COLOR );
@ -1270,7 +1282,7 @@ GL_CheckTexName
*/
qboolean GL_CheckTexName( const char *name )
{
if( !COM_CheckString( name ) || !glw_state.initialized )
if( !COM_CheckString( name ))
return false;
// because multi-layered textures can exceed name string
@ -1385,7 +1397,8 @@ static void GL_DeleteTexture( gl_texture_t *tex )
if( tex->original )
FS_FreeImage( tex->original );
pglDeleteTextures( 1, &tex->texnum );
if( glw_state.initialized )
pglDeleteTextures( 1, &tex->texnum );
memset( tex, 0, sizeof( *tex ));
}
@ -1643,6 +1656,7 @@ int GL_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags
}
GL_ProcessImage( tex, pic );
if( !GL_UploadTexture( tex, pic ))
{
memset( tex, 0, sizeof( gl_texture_t ));
@ -1784,8 +1798,7 @@ GL_FreeTexture
void GL_FreeTexture( GLenum texnum )
{
// number 0 it's already freed
if( texnum <= 0 || !glw_state.initialized )
return;
if( texnum <= 0 ) return;
GL_DeleteTexture( &gl_textures[texnum] );
}

View File

@ -151,11 +151,16 @@ void Image_Init( void )
image.loadformats = load_game;
image.saveformats = save_game;
break;
default: // all other instances not using imagelib
image.cmd_flags = 0;
case HOST_DEDICATED:
image.cmd_flags = 0;
image.loadformats = load_game;
image.saveformats = save_null;
break;
default: // all other instances not using imagelib
image.cmd_flags = 0;
image.loadformats = load_null;
image.saveformats = save_null;
break;
}
image.tempbuffer = NULL;

View File

@ -885,6 +885,59 @@ int Mod_SampleSizeForFace( msurface_t *surf )
return LM_SAMPLE_SIZE;
}
/*
==================
Mod_GetFaceContents
determine face contents by name
==================
*/
static int Mod_GetFaceContents( const char *name )
{
if( !Q_strnicmp( name, "SKY", 3 ))
return CONTENTS_SKY;
if( name[0] == '!' || name[0] == '*' )
{
if( !Q_strnicmp( name + 1, "lava", 4 ))
return CONTENTS_LAVA;
else if( !Q_strnicmp( name + 1, "slime", 5 ))
return CONTENTS_SLIME;
return CONTENTS_WATER; // otherwise it's water
}
if( !Q_strnicmp( name, "water", 5 ))
return CONTENTS_WATER;
return CONTENTS_SOLID;
}
/*
==================
Mod_GetFaceContents
determine face contents by name
==================
*/
static mvertex_t *Mod_GetVertexByNumber( model_t *mod, int surfedge )
{
int lindex;
medge_t *edge;
lindex = mod->surfedges[surfedge];
if( lindex > 0 )
{
edge = &mod->edges[lindex];
return &mod->vertexes[edge->v[0]];
}
else
{
edge = &mod->edges[-lindex];
return &mod->vertexes[edge->v[1]];
}
}
/*
==================
Mod_MakeNormalAxial
@ -1067,6 +1120,66 @@ static void Mod_CalcSurfaceBounds( msurface_t *surf )
VectorAverage( surf->info->mins, surf->info->maxs, surf->info->origin );
}
/*
=================
Mod_CreateFaceBevels
=================
*/
static void Mod_CreateFaceBevels( msurface_t *surf )
{
vec3_t delta, edgevec;
byte *facebevel;
vec3_t faceNormal;
mvertex_t *v0, *v1;
int contents;
int i, size;
vec_t radius;
mfacebevel_t *fb;
if( surf->texinfo && surf->texinfo->texture )
contents = Mod_GetFaceContents( surf->texinfo->texture->name );
else contents = CONTENTS_SOLID;
size = sizeof( mfacebevel_t ) + surf->numedges * sizeof( mplane_t );
facebevel = (byte *)Mem_Calloc( loadmodel->mempool, size );
fb = (mfacebevel_t *)facebevel;
facebevel += sizeof( mfacebevel_t );
fb->edges = (mplane_t *)facebevel;
fb->numedges = surf->numedges;
fb->contents = contents;
surf->info->bevel = fb;
if( FBitSet( surf->flags, SURF_PLANEBACK ))
VectorNegate( surf->plane->normal, faceNormal );
else VectorCopy( surf->plane->normal, faceNormal );
// compute face origin and plane edges
for( i = 0; i < surf->numedges; i++ )
{
mplane_t *dest = &fb->edges[i];
v0 = Mod_GetVertexByNumber( loadmodel, surf->firstedge + i );
v1 = Mod_GetVertexByNumber( loadmodel, surf->firstedge + (i + 1) % surf->numedges );
VectorSubtract( v1->position, v0->position, edgevec );
CrossProduct( faceNormal, edgevec, dest->normal );
VectorNormalize( dest->normal );
dest->dist = DotProduct( dest->normal, v0->position );
dest->type = PlaneTypeForNormal( dest->normal );
VectorAdd( fb->origin, v0->position, fb->origin );
}
VectorScale( fb->origin, 1.0f / surf->numedges, fb->origin );
// compute face radius
for( i = 0; i < surf->numedges; i++ )
{
v0 = Mod_GetVertexByNumber( loadmodel, surf->firstedge + i );
VectorSubtract( v0->position, fb->origin, delta );
radius = DotProduct( delta, delta );
fb->radius = Q_max( radius, fb->radius );
}
}
/*
=================
Mod_SetParent
@ -1818,6 +1931,8 @@ static void Mod_LoadTextures( dbspmodel_t *bmod )
for( i = 0; i < loadmodel->numtextures; i++ )
{
int txFlags = 0;
if( in->dataofs[i] == -1 )
{
// create default texture (some mods requires this)
@ -1845,6 +1960,9 @@ static void Mod_LoadTextures( dbspmodel_t *bmod )
tx->width = mt->width;
tx->height = mt->height;
if( FBitSet( host.features, ENGINE_LOAD_DELUXEDATA ) && mt->name[0] == '{' )
SetBits( txFlags, TF_KEEP_SOURCE ); // Paranoia2 texture alpha-tracing
if( mt->offsets[0] > 0 )
{
int size = (int)sizeof( mip_t ) + ((mt->width * mt->height * 85)>>6);
@ -1892,7 +2010,7 @@ static void Mod_LoadTextures( dbspmodel_t *bmod )
if( FS_FileExists( texpath, false ))
{
tx->gl_texturenum = GL_LoadTexture( texpath, NULL, 0, TF_ALLOW_EMBOSS );
tx->gl_texturenum = GL_LoadTexture( texpath, NULL, 0, TF_ALLOW_EMBOSS|txFlags );
bmod->wadlist.wadusage[j]++; // this wad are really used
break;
}
@ -1908,14 +2026,13 @@ static void Mod_LoadTextures( dbspmodel_t *bmod )
if( custom_palette ) size += sizeof( short ) + 768;
Q_snprintf( texname, sizeof( texname ), "#%s:%s.mip", loadstat.name, mt->name );
tx->gl_texturenum = GL_LoadTexture( texname, (byte *)mt, size, TF_ALLOW_EMBOSS );
tx->gl_texturenum = GL_LoadTexture( texname, (byte *)mt, size, TF_ALLOW_EMBOSS|txFlags );
}
// if texture is completely missed
if( !tx->gl_texturenum )
{
if( host.type != HOST_DEDICATED )
Con_DPrintf( S_ERROR "unable to find %s.mip\n", mt->name );
Con_DPrintf( S_ERROR "unable to find %s.mip\n", mt->name );
tx->gl_texturenum = tr.defaultTexture;
}
@ -2210,6 +2327,7 @@ static void Mod_LoadSurfaces( dbspmodel_t *bmod )
Mod_CalcSurfaceBounds( out );
Mod_CalcSurfaceExtents( out );
Mod_CreateFaceBevels( out );
// grab the second sample to detect colored lighting
if( test_lightsize > 0 && lightofs != -1 )

View File

@ -16,84 +16,153 @@ GNU General Public License for more details.
#include "common.h"
#include "mathlib.h"
#include "pm_local.h"
#include "gl_local.h"
#define FRAC_EPSILON (1.0f / 32.0f)
typedef struct
{
float fraction;
int contents;
float fraction;
int contents;
msurface_t *surface;
} linetrace_t;
/*
==============
fix_coord
converts the reletive tex coords to absolute
==============
*/
static uint fix_coord( vec_t in, uint width )
{
if( in > 0 ) return (uint)in % width;
return width - ((uint)fabs( in ) % width);
}
/*
=============
SampleMiptex
fence texture testing
=============
*/
int PM_SampleMiptex( const msurface_t *surf, const vec3_t point )
{
mextrasurf_t *info = surf->info;
mfacebevel_t *fb = info->bevel;
int contents;
vec_t ds, dt;
byte *data;
int x, y;
mtexinfo_t *tx;
texture_t *mt;
rgbdata_t *src;
// fill the default contents
if( fb ) contents = fb->contents;
else contents = CONTENTS_SOLID;
if( !surf->texinfo || !surf->texinfo->texture )
return contents;
tx = surf->texinfo;
mt = tx->texture;
if( mt->name[0] != '{' )
return contents;
src = R_GetTexture( mt->gl_texturenum )->original;
if( !src ) return contents; // original doesn't kept
ds = DotProduct( point, tx->vecs[0] ) + tx->vecs[0][3];
dt = DotProduct( point, tx->vecs[1] ) + tx->vecs[1][3];
// convert ST to real pixels position
x = fix_coord( ds, mt->width - 1 );
y = fix_coord( dt, mt->height - 1 );
ASSERT( x >= 0 && y >= 0 );
data = src->buffer;
if( data[(mt->width * y) + x] == 255 )
return CONTENTS_EMPTY;
return CONTENTS_SOLID;
}
/*
==================
PM_RecursiveSurfCheck
==================
*/
msurface_t *PM_RecursiveSurfCheck( model_t *model, mnode_t *node, vec3_t p1, vec3_t p2 )
msurface_t *PM_RecursiveSurfCheck( model_t *mod, mnode_t *node, vec3_t p1, vec3_t p2 )
{
float t1, t2, frac;
int side, ds, dt;
mplane_t *plane;
int i, side;
msurface_t *surf;
vec3_t mid;
int i;
loc0:
if( node->contents < 0 )
return NULL;
plane = node->plane;
t1 = PlaneDiff( p1, node->plane );
t2 = PlaneDiff( p2, node->plane );
if( plane->type < 3 )
if( t1 >= -FRAC_EPSILON && t2 >= -FRAC_EPSILON )
{
t1 = p1[plane->type] - plane->dist;
t2 = p2[plane->type] - plane->dist;
}
else
{
t1 = DotProduct( plane->normal, p1 ) - plane->dist;
t2 = DotProduct( plane->normal, p2 ) - plane->dist;
node = node->children[0];
goto loc0;
}
if( t1 >= 0.0f && t2 >= 0.0f )
return PM_RecursiveSurfCheck( model, node->children[0], p1, p2 );
if( t1 < 0.0f && t2 < 0.0f )
return PM_RecursiveSurfCheck( model, node->children[1], p1, p2 );
if( t1 < FRAC_EPSILON && t2 < FRAC_EPSILON )
{
node = node->children[1];
goto loc0;
}
side = (t1 < 0.0f);
frac = t1 / ( t1 - t2 );
if( frac < 0.0f ) frac = 0.0f;
if( frac > 1.0f ) frac = 1.0f;
frac = bound( 0.0f, frac, 1.0f );
VectorLerp( p1, frac, p2, mid );
side = (t1 < 0.0f);
// now this is weird.
surf = PM_RecursiveSurfCheck( model, node->children[side], p1, mid );
if( surf != NULL || ( t1 >= 0.0f && t2 >= 0.0f ) || ( t1 < 0.0f && t2 < 0.0f ))
{
if(( surf = PM_RecursiveSurfCheck( mod, node->children[side], p1, mid )) != NULL )
return surf;
}
surf = model->surfaces + node->firstsurface;
for( i = 0; i < node->numsurfaces; i++, surf++ )
// walk through real faces
for( i = 0; i < node->numsurfaces; i++ )
{
ds = (int)((float)DotProduct( mid, surf->texinfo->vecs[0] ) + surf->texinfo->vecs[0][3] );
dt = (int)((float)DotProduct( mid, surf->texinfo->vecs[1] ) + surf->texinfo->vecs[1][3] );
msurface_t *surf = &mod->surfaces[node->firstsurface + i];
mextrasurf_t *info = surf->info;
mfacebevel_t *fb = info->bevel;
int j, contents;
vec3_t delta;
if( ds >= surf->texturemins[0] && dt >= surf->texturemins[1] )
if( !fb ) continue; // ???
VectorSubtract( mid, fb->origin, delta );
if( DotProduct( delta, delta ) >= fb->radius )
continue; // no intersection
for( j = 0; j < fb->numedges; j++ )
{
int s = ds - surf->texturemins[0];
int t = dt - surf->texturemins[1];
if( s <= surf->extents[0] && t <= surf->extents[1] )
return surf;
if( PlaneDiff( mid, &fb->edges[j] ) > FRAC_EPSILON )
break; // outside the bounds
}
if( j != fb->numedges )
continue; // we are outside the bounds of the facet
// hit the surface
contents = PM_SampleMiptex( surf, mid );
if( contents != CONTENTS_EMPTY )
return surf;
return NULL; // through the fence
}
return PM_RecursiveSurfCheck( model, node->children[side^1], mid, p2 );
return PM_RecursiveSurfCheck( mod, node->children[side^1], mid, p2 );
}
/*
@ -160,32 +229,34 @@ PM_TestLine_r
optimized trace for light gathering
==================
*/
int PM_TestLine_r( mnode_t *node, vec_t p1f, vec_t p2f, const vec3_t start, const vec3_t stop, linetrace_t *trace )
int PM_TestLine_r( model_t *mod, mnode_t *node, vec_t p1f, vec_t p2f, const vec3_t start, const vec3_t stop, linetrace_t *trace )
{
float front, back;
float frac, midf;
int r, side;
int i, r, side;
vec3_t mid;
loc0:
if( node->contents < 0 )
trace->contents = node->contents;
if( node->contents == CONTENTS_SOLID )
return CONTENTS_SOLID;
if( node->contents == CONTENTS_SKY )
return CONTENTS_SKY;
if( node->contents < 0 )
{
// water, slime or lava interpret as empty
if( node->contents == CONTENTS_SOLID )
return CONTENTS_SOLID;
if( node->contents == CONTENTS_SKY )
return CONTENTS_SKY;
trace->fraction = 1.0f;
return CONTENTS_EMPTY;
}
front = PlaneDiff( start, node->plane );
back = PlaneDiff( stop, node->plane );
if( front >= -ON_EPSILON && back >= -ON_EPSILON )
if( front >= -FRAC_EPSILON && back >= -FRAC_EPSILON )
{
node = node->children[0];
goto loc0;
}
if( front < ON_EPSILON && back < ON_EPSILON )
if( front < FRAC_EPSILON && back < FRAC_EPSILON )
{
node = node->children[1];
goto loc0;
@ -198,15 +269,54 @@ loc0:
VectorLerp( start, frac, stop, mid );
midf = p1f + ( p2f - p1f ) * frac;
r = PM_TestLine_r( node->children[side], p1f, midf, start, mid, trace );
r = PM_TestLine_r( mod, node->children[side], p1f, midf, start, mid, trace );
if( r != CONTENTS_EMPTY )
{
trace->fraction = midf;
if( trace->surface == NULL )
trace->fraction = midf;
trace->contents = r;
return r;
}
return PM_TestLine_r( node->children[!side], midf, p2f, mid, stop, trace );
// walk through real faces
for( i = 0; i < node->numsurfaces; i++ )
{
msurface_t *surf = &mod->surfaces[node->firstsurface + i];
mextrasurf_t *info = surf->info;
mfacebevel_t *fb = info->bevel;
int j, contents;
vec3_t delta;
if( !fb ) continue;
VectorSubtract( mid, fb->origin, delta );
if( DotProduct( delta, delta ) >= fb->radius )
continue; // no intersection
for( j = 0; j < fb->numedges; j++ )
{
if( PlaneDiff( mid, &fb->edges[j] ) > FRAC_EPSILON )
break; // outside the bounds
}
if( j != fb->numedges )
continue; // we are outside the bounds of the facet
// hit the surface
contents = PM_SampleMiptex( surf, mid );
// fill the trace and out
trace->contents = contents;
trace->fraction = midf;
if( contents != CONTENTS_EMPTY )
trace->surface = surf;
return contents;
}
return PM_TestLine_r( mod, node->children[!side], midf, p2f, mid, stop, trace );
}
int PM_TestLineExt( playermove_t *pmove, physent_t *ents, int numents, const vec3_t start, const vec3_t end, int flags )
@ -221,18 +331,19 @@ int PM_TestLineExt( playermove_t *pmove, physent_t *ents, int numents, const vec
trace.contents = CONTENTS_EMPTY;
trace.fraction = 1.0f;
trace.surface = NULL;
for( i = 0; i < numents; i++ )
{
pe = &ents[i];
if( i != 0 && ( flags & PM_WORLD_ONLY ))
if( i != 0 && FBitSet( flags, PM_WORLD_ONLY ))
break;
if( !pe->model || pe->model->type != mod_brush || pe->solid != SOLID_BSP )
continue;
if( pe->rendermode != kRenderNormal )
if( FBitSet( flags, PM_GLASS_IGNORE ) && pe->rendermode != kRenderNormal )
continue;
hull = &pe->model->hulls[0];
@ -257,8 +368,9 @@ int PM_TestLineExt( playermove_t *pmove, physent_t *ents, int numents, const vec
trace_bbox.contents = CONTENTS_EMPTY;
trace_bbox.fraction = 1.0f;
trace_bbox.surface = NULL;
PM_TestLine_r( &pe->model->nodes[hull->firstclipnode], 0.0f, 1.0f, start_l, end_l, &trace_bbox );
PM_TestLine_r( pe->model, &pe->model->nodes[hull->firstclipnode], 0.0f, 1.0f, start_l, end_l, &trace_bbox );
if( trace_bbox.contents != CONTENTS_EMPTY || trace_bbox.fraction < trace.fraction )
{

View File

@ -339,6 +339,11 @@ void SV_AddLaddersToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3
SV_AddLaddersToPmove( node->children[1], pmove_mins, pmove_maxs );
}
int SV_TestLine( const vec3_t start, const vec3_t end, int flags )
{
return PM_TestLineExt( svgame.pmove, svgame.pmove->physents, svgame.pmove->numphysent, start, end, flags );
}
static int pfnTestPlayerPosition( float *pos, pmtrace_t *ptrace )
{
return PM_TestPlayerPosition( svgame.pmove, pos, ptrace, NULL );