}
}
-
-
/*
FixWinding() - ydnar
removes degenerate edges from a winding
------------------------------------------------------------------------------- */
-
/*
ProcessAdvertisements()
copies advertisement info into the BSP structures
char level[ 2 ], shader[ 1024 ];
const char *value;
-
/* sets integer blockSize from worldspawn "_blocksize" key if it exists */
value = ValueForKey( &entities[ 0 ], "_blocksize" );
if( value[ 0 ] == '\0' )
Sys_FPrintf( SYS_NOXML, "******* leaked *******\n" );
Sys_FPrintf( SYS_NOXML, "**********************\n" );
polyline = LeakFile( tree );
- leaknode = xmlNewNode( NULL, "message" );
- xmlNodeSetContent( leaknode, "MAP LEAKED\n" );
+ leaknode = xmlNewNode( NULL, (xmlChar*)"message" );
+ xmlNodeSetContent( leaknode, (xmlChar*)"MAP LEAKED\n" );
xmlAddChild( leaknode, polyline );
level[0] = (int) '0' + SYS_ERR;
level[1] = 0;
- xmlSetProp( leaknode, "level", (char*) &level );
+ xmlSetProp( leaknode, (xmlChar*)"level", (xmlChar*) &level );
xml_SendNode( leaknode );
if( leaktest )
{
VectorSet( normal, 0, 0, -1 );
/* create the flare surface (note shader defaults automatically) */
- DrawSurfaceForFlare( mapEntityNum, origin, normal, color, (char*) flareShader, lightStyle );
+ DrawSurfaceForFlare( mapEntityNum, origin, normal, color, flareShader, lightStyle );
}
}
}
/* write fogs */
EmitFogs();
+
+ /* vortex: emit meta stats */
+ EmitMetaStats();
}
{
char out[ 1024 ];
+ char save_cmdline[1024], save_version[1024];
+ const char *p;
/* note it */
Sys_Printf( "--- OnlyEnts ---\n" );
sprintf( out, "%s.bsp", source );
LoadBSPFile( out );
+
+ ParseEntities();
+ p = ValueForKey(&entities[0], "_q3map2_cmdline");
+ strncpy(save_cmdline, p, sizeof(save_cmdline));
+ save_cmdline[sizeof(save_cmdline)-1] = 0;
+ p = ValueForKey(&entities[0], "_q3map2_version");
+ strncpy(save_version, p, sizeof(save_version));
+ save_version[sizeof(save_version)-1] = 0;
+
numEntities = 0;
LoadShaderInfo();
- LoadMapFile( name, qfalse );
+ LoadMapFile( name, qfalse, qfalse );
SetModelNumbers();
SetLightStyles();
+
+ if(*save_cmdline)
+ SetKeyValue(&entities[0], "_q3map2_cmdline", save_cmdline);
+ if(*save_version)
+ SetKeyValue(&entities[0], "_q3map2_version", save_version);
numBSPEntities = numEntities;
UnparseEntities();
numMapDrawSurfs = 0;
tempSource[ 0 ] = '\0';
+ globalCelShader[0] = 0;
/* set standard game flags */
maxSurfaceVerts = game->maxSurfaceVerts;
i++;
Sys_Printf( "Lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
}
+ else if( !strcmp( argv[ i ], "-minsamplesize" ) )
+ {
+ minSampleSize = atoi( argv[ i + 1 ] );
+ if( minSampleSize < 1 )
+ minSampleSize = 1;
+ i++;
+ Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
+ }
else if( !strcmp( argv[ i ], "-custinfoparms") )
{
Sys_Printf( "Custom info parms enabled\n" );
Sys_Printf( "Flatshading enabled\n" );
flat = qtrue;
}
+ else if( !strcmp( argv[ i ], "-celshader" ) )
+ {
+ ++i;
+ if(argv[i][0])
+ sprintf( globalCelShader, "textures/%s", argv[ i ] );
+ else
+ *globalCelShader = 0;
+ Sys_Printf( "Global cel shader set to \"%s\"\n", globalCelShader );
+ }
else if( !strcmp( argv[ i ], "-meta" ) )
{
Sys_Printf( "Creating meta surfaces from brush faces\n" );
Sys_Printf( "Debug portal surfaces enabled\n" );
debugPortals = qtrue;
}
+ else if( !strcmp( argv[ i ], "-altsplit" ) )
+ {
+ Sys_Printf( "Alternate BSP splitting (by 27) enabled\n" );
+ bspAlternateSplitWeights = qtrue;
+ }
+ else if( !strcmp( argv[ i ], "-deep" ) )
+ {
+ Sys_Printf( "Deep BSP tree generation enabled\n" );
+ deepBSP = qtrue;
+ }
+ else if( !strcmp( argv[ i ], "-maxarea" ) )
+ {
+ Sys_Printf( "Max Area face surface generation enabled\n" );
+ maxAreaFaceSurface = qtrue;
+ }
else if( !strcmp( argv[ i ], "-bsp" ) )
Sys_Printf( "-bsp argument unnecessary\n" );
else
+ {
Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] );
+ }
}
/* fixme: print more useful usage here */
/* load original file from temp spot in case it was renamed by the editor on the way in */
if( strlen( tempSource ) > 0 )
- LoadMapFile( tempSource, qfalse );
+ LoadMapFile( tempSource, qfalse, qfalse );
else
- LoadMapFile( name, qfalse );
+ LoadMapFile( name, qfalse, qfalse );
+
+ /* div0: inject command line parameters */
+ InjectCommandLine(argv, 1, argc - 1);
/* ydnar: decal setup */
ProcessDecals();
ProcessAdvertisements();
/* finish and write bsp */
- EndBSPFile();
+ EndBSPFile(qtrue);
/* remove temp map source file if appropriate */
if( strlen( tempSource ) > 0)
if(bspDrawVerts == 0)
{
- numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS / 37;
+ numBSPDrawVertsBuffer = 1024;
bspDrawVerts = safe_malloc_info(sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer, "IncDrawVerts");
numBSPDrawVertsBuffer *= 3; // multiply by 1.5
numBSPDrawVertsBuffer /= 2;
- if(numBSPDrawVertsBuffer > MAX_MAP_DRAW_VERTS)
- numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS;
-
bspDrawVerts = realloc(bspDrawVerts, sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer);
if(!bspDrawVerts)
return length / size;
}
+int CopyLump_Allocate( bspHeader_t *header, int lump, void **dest, int size, int *allocationVariable )
+{
+ /* get lump length and offset */
+ *allocationVariable = header->lumps[ lump ].length / size;
+ *dest = realloc(*dest, size * *allocationVariable);
+ return CopyLump(header, lump, *dest, size);
+}
/*
numBSPEntities = numEntities;
}
+/*
+ * must be called before UnparseEntities
+ */
+void InjectCommandLine(char **argv, int beginArgs, int endArgs)
+{
+ const char *previousCommandLine;
+ char newCommandLine[1024];
+ const char *inpos;
+ char *outpos = newCommandLine;
+ char *sentinel = newCommandLine + sizeof(newCommandLine) - 1;
+ int i;
+
+ previousCommandLine = ValueForKey(&entities[0], "_q3map2_cmdline");
+ if(previousCommandLine && *previousCommandLine)
+ {
+ inpos = previousCommandLine;
+ while(outpos != sentinel && *inpos)
+ *outpos++ = *inpos++;
+ if(outpos != sentinel)
+ *outpos++ = ';';
+ if(outpos != sentinel)
+ *outpos++ = ' ';
+ }
+ for(i = beginArgs; i < endArgs; ++i)
+ {
+ if(outpos != sentinel && i != beginArgs)
+ *outpos++ = ' ';
+ inpos = argv[i];
+ while(outpos != sentinel && *inpos)
+ if(*inpos != '\\' && *inpos != '"' && *inpos != ';' && (unsigned char) *inpos >= ' ')
+ *outpos++ = *inpos++;
+ }
+
+ *outpos = 0;
+ SetKeyValue(&entities[0], "_q3map2_cmdline", newCommandLine);
+ SetKeyValue(&entities[0], "_q3map2_version", Q3MAP_VERSION);
+}
/*
UnparseEntities()
/* setup */
+ AUTOEXPAND_BY_REALLOC(bspEntData, 0, allocatedBSPEntData, 1024);
buf = bspEntData;
end = buf;
*end = 0;
+
/* run through entity list */
for( i = 0; i < numBSPEntities && i < numEntities; i++ )
{
+ {
+ int sz = end - buf;
+ AUTOEXPAND_BY_REALLOC(bspEntData, sz + 65536, allocatedBSPEntData, 1024);
+ buf = bspEntData;
+ end = buf + sz;
+ }
+
/* get epair */
ep = entities[ i ].epairs;
if( ep == NULL )
end += 2;
/* check for overflow */
- if( end > buf + MAX_MAP_ENTSTRING )
+ if( end > buf + allocatedBSPEntData )
Error( "Entity text too long" );
}
ep->value = copystring( value );
}
+/*
+KeyExists()
+returns true if entity has this key
+*/
+
+qboolean KeyExists( const entity_t *ent, const char *key )
+{
+ epair_t *ep;
+
+ /* walk epair list */
+ for( ep = ent->epairs; ep != NULL; ep = ep->next )
+ {
+ if( !EPAIR_STRCMP( ep->key, key ) )
+ return qtrue;
+ }
+ /* no match */
+ return qfalse;
+}
/*
ValueForKey()
{
const char *value;
-
/* get cast shadows */
if( castShadows != NULL )
{
if( value[ 0 ] != '\0' )
*recvShadows = atoi( value );
}
+
+ /* vortex: game-specific default eneity keys */
+ value = ValueForKey( ent, "classname" );
+ if (!Q_stricmp( game->magic, "dq" ) || !Q_stricmp( game->magic, "prophecy" ) )
+ {
+ /* vortex: deluxe quake default shadow flags */
+ if (!Q_stricmp( value, "func_wall" ) )
+ {
+ if( recvShadows != NULL )
+ *recvShadows = 1;
+ if( castShadows != NULL )
+ *castShadows = 1;
+ }
+ }
}
/* copy */
in = GetLump( (bspHeader_t*) header, LUMP_BRUSHSIDES );
- out = bspBrushSides;
for( i = 0; i < numBSPBrushSides; i++ )
{
+ AUTOEXPAND_BY_REALLOC(bspBrushSides, i, allocatedBSPBrushSides, 1024);
+ out = &bspBrushSides[i];
out->planeNum = in->planeNum;
out->shaderNum = in->shaderNum;
out->surfaceNum = -1;
in++;
- out++;
}
}
Error( "%s is version %d, not %d", filename, header->version, game->bspVersion );
/* load/convert lumps */
- numBSPShaders = CopyLump( (bspHeader_t*) header, LUMP_SHADERS, bspShaders, sizeof( bspShader_t ) );
+ numBSPShaders = CopyLump_Allocate( (bspHeader_t*) header, LUMP_SHADERS, (void **) &bspShaders, sizeof( bspShader_t ), &allocatedBSPShaders );
- numBSPModels = CopyLump( (bspHeader_t*) header, LUMP_MODELS, bspModels, sizeof( bspModel_t ) );
+ numBSPModels = CopyLump_Allocate( (bspHeader_t*) header, LUMP_MODELS, (void **) &bspModels, sizeof( bspModel_t ), &allocatedBSPModels );
- numBSPPlanes = CopyLump( (bspHeader_t*) header, LUMP_PLANES, bspPlanes, sizeof( bspPlane_t ) );
+ numBSPPlanes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_PLANES, (void **) &bspPlanes, sizeof( bspPlane_t ), &allocatedBSPPlanes );
- numBSPLeafs = CopyLump( (bspHeader_t*) header, LUMP_LEAFS, bspLeafs, sizeof( bspLeaf_t ) );
+ numBSPLeafs = CopyLump( (bspHeader_t*) header, LUMP_LEAFS, bspLeafs, sizeof( bspLeaf_t ) ); // TODO fix overflow
- numBSPNodes = CopyLump( (bspHeader_t*) header, LUMP_NODES, bspNodes, sizeof( bspNode_t ) );
+ numBSPNodes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_NODES, (void **) &bspNodes, sizeof( bspNode_t ), &allocatedBSPNodes );
- numBSPLeafSurfaces = CopyLump( (bspHeader_t*) header, LUMP_LEAFSURFACES, bspLeafSurfaces, sizeof( bspLeafSurfaces[ 0 ] ) );
+ numBSPLeafSurfaces = CopyLump_Allocate( (bspHeader_t*) header, LUMP_LEAFSURFACES, (void **) &bspLeafSurfaces, sizeof( bspLeafSurfaces[ 0 ] ), &allocatedBSPLeafSurfaces );
- numBSPLeafBrushes = CopyLump( (bspHeader_t*) header, LUMP_LEAFBRUSHES, bspLeafBrushes, sizeof( bspLeafBrushes[ 0 ] ) );
+ numBSPLeafBrushes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_LEAFBRUSHES, (void **) &bspLeafBrushes, sizeof( bspLeafBrushes[ 0 ] ), &allocatedBSPLeafBrushes );
- numBSPBrushes = CopyLump( (bspHeader_t*) header, LUMP_BRUSHES, bspBrushes, sizeof( bspBrush_t ) );
+ numBSPBrushes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_BRUSHES, (void **) &bspBrushes, sizeof( bspBrush_t ), &allocatedBSPLeafBrushes );
CopyBrushSidesLump( header );
CopyDrawSurfacesLump( header );
- numBSPFogs = CopyLump( (bspHeader_t*) header, LUMP_FOGS, bspFogs, sizeof( bspFog_t ) );
+ numBSPFogs = CopyLump( (bspHeader_t*) header, LUMP_FOGS, bspFogs, sizeof( bspFog_t ) ); // TODO fix overflow
numBSPDrawIndexes = CopyLump( (bspHeader_t*) header, LUMP_DRAWINDEXES, bspDrawIndexes, sizeof( bspDrawIndexes[ 0 ] ) );
- numBSPVisBytes = CopyLump( (bspHeader_t*) header, LUMP_VISIBILITY, bspVisBytes, 1 );
+ numBSPVisBytes = CopyLump( (bspHeader_t*) header, LUMP_VISIBILITY, bspVisBytes, 1 ); // TODO fix overflow
- numBSPLightBytes = GetLumpElements( (bspHeader_t*) header, LUMP_LIGHTMAPS, 1 );
+ numBSPLightBytes = GetLumpElements( (bspHeader_t*) header, LUMP_LIGHTMAPS, 1 ); // TODO change to CopyLump_Allocate
bspLightBytes = safe_malloc( numBSPLightBytes );
CopyLump( (bspHeader_t*) header, LUMP_LIGHTMAPS, bspLightBytes, 1 );
- bspEntDataSize = CopyLump( (bspHeader_t*) header, LUMP_ENTITIES, bspEntData, 1);
+ bspEntDataSize = CopyLump_Allocate( (bspHeader_t*) header, LUMP_ENTITIES, (void **) &bspEntData, 1, &allocatedBSPEntData);
CopyLightGridLumps( header );
Error( "%s is version %d, not %d", filename, header->version, game->bspVersion );
/* load/convert lumps */
- numBSPShaders = CopyLump( (bspHeader_t*) header, LUMP_SHADERS, bspShaders, sizeof( bspShader_t ) );
+ numBSPShaders = CopyLump_Allocate( (bspHeader_t*) header, LUMP_SHADERS, (void **) &bspShaders, sizeof( bspShader_t ), &allocatedBSPShaders );
- numBSPModels = CopyLump( (bspHeader_t*) header, LUMP_MODELS, bspModels, sizeof( bspModel_t ) );
+ numBSPModels = CopyLump_Allocate( (bspHeader_t*) header, LUMP_MODELS, (void **) &bspModels, sizeof( bspModel_t ), &allocatedBSPModels );
- numBSPPlanes = CopyLump( (bspHeader_t*) header, LUMP_PLANES, bspPlanes, sizeof( bspPlane_t ) );
+ numBSPPlanes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_PLANES, (void **) &bspPlanes, sizeof( bspPlane_t ), &allocatedBSPPlanes );
numBSPLeafs = CopyLump( (bspHeader_t*) header, LUMP_LEAFS, bspLeafs, sizeof( bspLeaf_t ) );
- numBSPNodes = CopyLump( (bspHeader_t*) header, LUMP_NODES, bspNodes, sizeof( bspNode_t ) );
+ numBSPNodes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_NODES, (void **) &bspNodes, sizeof( bspNode_t ), &allocatedBSPNodes );
- numBSPLeafSurfaces = CopyLump( (bspHeader_t*) header, LUMP_LEAFSURFACES, bspLeafSurfaces, sizeof( bspLeafSurfaces[ 0 ] ) );
+ numBSPLeafSurfaces = CopyLump_Allocate( (bspHeader_t*) header, LUMP_LEAFSURFACES, (void **) &bspLeafSurfaces, sizeof( bspLeafSurfaces[ 0 ] ), &allocatedBSPLeafSurfaces );
- numBSPLeafBrushes = CopyLump( (bspHeader_t*) header, LUMP_LEAFBRUSHES, bspLeafBrushes, sizeof( bspLeafBrushes[ 0 ] ) );
+ numBSPLeafBrushes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_LEAFBRUSHES, (void **) &bspLeafBrushes, sizeof( bspLeafBrushes[ 0 ] ), &allocatedBSPLeafBrushes );
- numBSPBrushes = CopyLump( (bspHeader_t*) header, LUMP_BRUSHES, bspBrushes, sizeof( bspBrush_t ) );
+ numBSPBrushes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_BRUSHES, (void **) &bspBrushes, sizeof( bspBrush_t ), &allocatedBSPLeafBrushes );
- numBSPBrushSides = CopyLump( (bspHeader_t*) header, LUMP_BRUSHSIDES, bspBrushSides, sizeof( bspBrushSide_t ) );
+ numBSPBrushSides = CopyLump_Allocate( (bspHeader_t*) header, LUMP_BRUSHSIDES, (void **) &bspBrushSides, sizeof( bspBrushSide_t ), &allocatedBSPBrushSides );
numBSPDrawVerts = GetLumpElements( (bspHeader_t*) header, LUMP_DRAWVERTS, sizeof( bspDrawVerts[ 0 ] ) );
SetDrawVerts( numBSPDrawVerts );
bspLightBytes = safe_malloc( numBSPLightBytes );
CopyLump( (bspHeader_t*) header, LUMP_LIGHTMAPS, bspLightBytes, 1 );
- bspEntDataSize = CopyLump( (bspHeader_t*) header, LUMP_ENTITIES, bspEntData, 1);
+ bspEntDataSize = CopyLump_Allocate( (bspHeader_t*) header, LUMP_ENTITIES, (void **) &bspEntData, 1, &allocatedBSPEntData);
CopyLightGridLumps( header );
converts a bsp drawsurface to an ase chunk
*/
+int numLightmapsASE = 0;
static void ConvertSurface( FILE *f, bspModel_t *model, int modelNum, bspDrawSurface_t *ds, int surfaceNum, vec3_t origin )
{
int i, v, face, a, b, c;
fprintf( f, "\t*PROP_MOTIONBLUR\t0\r\n" );
fprintf( f, "\t*PROP_CASTSHADOW\t1\r\n" );
fprintf( f, "\t*PROP_RECVSHADOW\t1\r\n" );
- fprintf( f, "\t*MATERIAL_REF\t%d\r\n", ds->shaderNum );
+ if(lightmapsAsTexcoord)
+ {
+ if(ds->lightmapNum[0] >= 0 && ds->lightmapNum[0] + deluxemap < numLightmapsASE)
+ fprintf( f, "\t*MATERIAL_REF\t%d\r\n", ds->lightmapNum[0] + deluxemap );
+ else
+ Sys_Printf( "WARNING: lightmap %d out of range, not exporting\n", ds->lightmapNum[0] + deluxemap );
+ }
+ else
+ fprintf( f, "\t*MATERIAL_REF\t%d\r\n", ds->shaderNum );
fprintf( f, "}\r\n" );
}
fprintf( f, "\t\t\t*MAP_SUBNO\t1\r\n" );
fprintf( f, "\t\t\t*MAP_AMOUNT\t1.0\r\n" );
fprintf( f, "\t\t\t*MAP_TYPE\tScreen\r\n" );
- fprintf( f, "\t\t\t*BITMAP\t\"..\\%s\"\r\n", filename );
+ if(shadersAsBitmap)
+ fprintf( f, "\t\t\t*BITMAP\t\"%s\"\r\n", shader->shader );
+ else
+ fprintf( f, "\t\t\t*BITMAP\t\"..\\%s\"\r\n", filename );
fprintf( f, "\t\t\t*BITMAP_FILTER\tPyramidal\r\n" );
fprintf( f, "\t\t}\r\n" );
fprintf( f, "\t}\r\n" );
}
+static void ConvertLightmap( FILE *f, const char *base, int lightmapNum )
+{
+ /* print shader info */
+ fprintf( f, "\t*MATERIAL\t%d\t{\r\n", lightmapNum );
+ fprintf( f, "\t\t*MATERIAL_NAME\t\"lm_%04d\"\r\n", lightmapNum );
+ fprintf( f, "\t\t*MATERIAL_CLASS\t\"Standard\"\r\n" );
+ fprintf( f, "\t\t*MATERIAL_DIFFUSE\t1\t1\t1\r\n");
+ fprintf( f, "\t\t*MATERIAL_SHADING Phong\r\n" );
+
+ /* print map info */
+ if(lightmapNum >= 0)
+ {
+ fprintf( f, "\t\t*MAP_DIFFUSE\t{\r\n" );
+ fprintf( f, "\t\t\t*MAP_NAME\t\"lm_%04d\"\r\n", lightmapNum );
+ fprintf( f, "\t\t\t*MAP_CLASS\t\"Bitmap\"\r\n");
+ fprintf( f, "\t\t\t*MAP_SUBNO\t1\r\n" );
+ fprintf( f, "\t\t\t*MAP_AMOUNT\t1.0\r\n" );
+ fprintf( f, "\t\t\t*MAP_TYPE\tScreen\r\n" );
+ fprintf( f, "\t\t\t*BITMAP\t\"%s\\lm_%04d.tga\"\r\n", base, lightmapNum );
+ fprintf( f, "\t\t\t*BITMAP_FILTER\tPyramidal\r\n" );
+ fprintf( f, "\t\t}\r\n" );
+ }
+
+ fprintf( f, "\t}\r\n" );
+}
entity_t *e;
vec3_t origin;
const char *key;
- char name[ 1024 ], base[ 1024 ];
+ char name[ 1024 ], base[ 1024 ], dirname[ 1024 ];
/* note it */
Sys_Printf( "--- Convert BSP to ASE ---\n" );
/* create the ase filename from the bsp name */
+ strcpy( dirname, bspName );
+ StripExtension( dirname );
strcpy( name, bspName );
StripExtension( name );
strcat( name, ".ase" );
Sys_Printf( "writing %s\n", name );
ExtractFileBase( bspName, base );
- strcat( base, ".bsp" );
/* open it */
f = fopen( name, "wb" );
fprintf( f, "*3DSMAX_ASCIIEXPORT\t200\r\n" );
fprintf( f, "*COMMENT\t\"Generated by Q3Map2 (ydnar) -convert -format ase\"\r\n" );
fprintf( f, "*SCENE\t{\r\n" );
- fprintf( f, "\t*SCENE_FILENAME\t\"%s\"\r\n", base );
+ fprintf( f, "\t*SCENE_FILENAME\t\"%s.bsp\"\r\n", base );
fprintf( f, "\t*SCENE_FIRSTFRAME\t0\r\n" );
fprintf( f, "\t*SCENE_LASTFRAME\t100\r\n" );
fprintf( f, "\t*SCENE_FRAMESPEED\t30\r\n" );
/* print materials */
fprintf( f, "*MATERIAL_LIST\t{\r\n" );
- fprintf( f, "\t*MATERIAL_COUNT\t%d\r\n", numBSPShaders );
- for( i = 0; i < numBSPShaders; i++ )
+ if(lightmapsAsTexcoord)
{
- shader = &bspShaders[ i ];
- ConvertShader( f, shader, i );
+ int lightmapCount;
+ for( lightmapCount = 0; lightmapCount < numBSPLightmaps; lightmapCount++ )
+ ;
+ for( ; ; lightmapCount++ )
+ {
+ char buf[1024];
+ FILE *tmp;
+ snprintf(buf, sizeof(buf), "%s/lm_%04d.tga", dirname, lightmapCount);
+ buf[sizeof(buf) - 1] = 0;
+ tmp = fopen(buf, "rb");
+ if(!tmp)
+ break;
+ fclose(tmp);
+ }
+ fprintf( f, "\t*MATERIAL_COUNT\t%d\r\n", lightmapCount );
+ for( i = 0; i < lightmapCount; i++ )
+ ConvertLightmap( f, base, i );
+ numLightmapsASE = lightmapCount;
+ }
+ else
+ {
+ fprintf( f, "\t*MATERIAL_COUNT\t%d\r\n", numBSPShaders );
+ for( i = 0; i < numBSPShaders; i++ )
+ {
+ shader = &bspShaders[ i ];
+ ConvertShader( f, shader, i );
+ }
}
fprintf( f, "}\r\n" );
#define SNAP_FLOAT_TO_INT 4
#define SNAP_INT_TO_FLOAT (1.0 / SNAP_FLOAT_TO_INT)
-static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin )
+typedef vec_t vec2_t[2];
+
+static vec_t Det3x3(vec_t a00, vec_t a01, vec_t a02,
+ vec_t a10, vec_t a11, vec_t a12,
+ vec_t a20, vec_t a21, vec_t a22)
+{
+ return
+ a00 * (a11 * a22 - a12 * a21)
+ - a01 * (a10 * a22 - a12 * a20)
+ + a02 * (a10 * a21 - a11 * a20);
+}
+
+void GetBestSurfaceTriangleMatchForBrushside(side_t *buildSide, bspDrawVert_t *bestVert[3])
+{
+ bspDrawSurface_t *s;
+ int i;
+ int t;
+ vec_t best = 0;
+ vec_t thisarea;
+ vec3_t normdiff;
+ vec3_t v1v0, v2v0, norm;
+ bspDrawVert_t *vert[3];
+ winding_t *polygon;
+ plane_t *buildPlane = &mapplanes[buildSide->planenum];
+ int matches = 0;
+
+ // first, start out with NULLs
+ bestVert[0] = bestVert[1] = bestVert[2] = NULL;
+
+ // brute force through all surfaces
+ for(s = bspDrawSurfaces; s != bspDrawSurfaces + numBSPDrawSurfaces; ++s)
+ {
+ if(s->surfaceType != MST_PLANAR && s->surfaceType != MST_TRIANGLE_SOUP)
+ continue;
+ if(strcmp(buildSide->shaderInfo->shader, bspShaders[s->shaderNum].shader))
+ continue;
+ for(t = 0; t + 3 <= s->numIndexes; t += 3)
+ {
+ vert[0] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 0]];
+ vert[1] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 1]];
+ vert[2] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 2]];
+ if(s->surfaceType == MST_PLANAR && VectorCompare(vert[0]->normal, vert[1]->normal) && VectorCompare(vert[1]->normal, vert[2]->normal))
+ {
+ VectorSubtract(vert[0]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
+ VectorSubtract(vert[1]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
+ VectorSubtract(vert[2]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
+ }
+ else
+ {
+ // this is more prone to roundoff errors, but with embedded
+ // models, there is no better way
+ VectorSubtract(vert[1]->xyz, vert[0]->xyz, v1v0);
+ VectorSubtract(vert[2]->xyz, vert[0]->xyz, v2v0);
+ CrossProduct(v2v0, v1v0, norm);
+ VectorNormalize(norm, norm);
+ VectorSubtract(norm, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
+ }
+ if(abs(DotProduct(vert[0]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
+ if(abs(DotProduct(vert[1]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
+ if(abs(DotProduct(vert[2]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
+ // Okay. Correct surface type, correct shader, correct plane. Let's start with the business...
+ polygon = CopyWinding(buildSide->winding);
+ for(i = 0; i < 3; ++i)
+ {
+ // 0: 1, 2
+ // 1: 2, 0
+ // 2; 0, 1
+ vec3_t *v1 = &vert[(i+1)%3]->xyz;
+ vec3_t *v2 = &vert[(i+2)%3]->xyz;
+ vec3_t triNormal;
+ vec_t triDist;
+ vec3_t sideDirection;
+ // we now need to generate triNormal and triDist so that they represent the plane spanned by normal and (v2 - v1).
+ VectorSubtract(*v2, *v1, sideDirection);
+ CrossProduct(sideDirection, buildPlane->normal, triNormal);
+ triDist = DotProduct(*v1, triNormal);
+ ChopWindingInPlace(&polygon, triNormal, triDist, distanceEpsilon);
+ if(!polygon)
+ goto exwinding;
+ }
+ thisarea = WindingArea(polygon);
+ if(thisarea > 0)
+ ++matches;
+ if(thisarea > best)
+ {
+ best = thisarea;
+ bestVert[0] = vert[0];
+ bestVert[1] = vert[1];
+ bestVert[2] = vert[2];
+ }
+ FreeWinding(polygon);
+exwinding:
+ ;
+ }
+ }
+ //if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
+ // fprintf(stderr, "brushside with %s: %d matches (%f area)\n", buildSide->shaderInfo->shader, matches, best);
+}
+
+#define FRAC(x) ((x) - floor(x))
+static void ConvertOriginBrush( FILE *f, int num, vec3_t origin, qboolean brushPrimitives )
+{
+ int originSize = 256;
+
+ char pattern[6][7][3] = {
+ { "+++", "+-+", "-++", "- ", " + ", " - ", "- " },
+ { "+++", "-++", "++-", "- ", " +", "+ ", " +" },
+ { "+++", "++-", "+-+", " - ", " +", " - ", " +" },
+ { "---", "+--", "-+-", "- ", " + ", " - ", "+ " },
+ { "---", "--+", "+--", "- ", " +", "- ", " +" },
+ { "---", "-+-", "--+", " - ", " +", " + ", " +" }
+ };
+ int i;
+#define S(a,b,c) (pattern[a][b][c] == '+' ? +1 : pattern[a][b][c] == '-' ? -1 : 0)
+
+ /* start brush */
+ fprintf( f, "\t// brush %d\n", num );
+ fprintf( f, "\t{\n" );
+ if(brushPrimitives)
+ {
+ fprintf( f, "\tbrushDef\n" );
+ fprintf( f, "\t{\n" );
+ }
+ /* print brush side */
+ /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
+
+ for(i = 0; i < 6; ++i)
+ {
+ if(brushPrimitives)
+ {
+ fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
+ origin[0] + 8 * S(i,0,0), origin[1] + 8 * S(i,0,1), origin[2] + 8 * S(i,0,2),
+ origin[0] + 8 * S(i,1,0), origin[1] + 8 * S(i,1,1), origin[2] + 8 * S(i,1,2),
+ origin[0] + 8 * S(i,2,0), origin[1] + 8 * S(i,2,1), origin[2] + 8 * S(i,2,2),
+ 1.0f/16.0f, 0.0f, FRAC((S(i,5,0) * origin[0] + S(i,5,1) * origin[1] + S(i,5,2) * origin[2]) / 16.0 + 0.5),
+ 0.0f, 1.0f/16.0f, FRAC((S(i,6,0) * origin[0] + S(i,6,1) * origin[1] + S(i,6,2) * origin[2]) / 16.0 + 0.5),
+ "common/origin",
+ 0
+ );
+ }
+ else
+ {
+ fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s %.8f %.8f %.8f %.8f %.8f %d 0 0\n",
+ origin[0] + 8 * S(i,0,0), origin[1] + 8 * S(i,0,1), origin[2] + 8 * S(i,0,2),
+ origin[0] + 8 * S(i,1,0), origin[1] + 8 * S(i,1,1), origin[2] + 8 * S(i,1,2),
+ origin[0] + 8 * S(i,2,0), origin[1] + 8 * S(i,2,1), origin[2] + 8 * S(i,2,2),
+ "common/origin",
+ FRAC((S(i,3,0) * origin[0] + S(i,3,1) * origin[1] + S(i,3,2) * origin[2]) / 16.0 + 0.5) * originSize,
+ FRAC((S(i,4,0) * origin[0] + S(i,4,1) * origin[1] + S(i,4,2) * origin[2]) / 16.0 + 0.5) * originSize,
+ 0.0f, 16.0 / originSize, 16.0 / originSize,
+ 0
+ );
+ }
+ }
+#undef S
+
+ /* end brush */
+ if(brushPrimitives)
+ fprintf( f, "\t}\n" );
+ fprintf( f, "\t}\n\n" );
+}
+
+static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin, qboolean brushPrimitives )
{
int i, j;
bspBrushSide_t *side;
bspShader_t *shader;
char *texture;
bspPlane_t *plane;
+ plane_t *buildPlane;
vec3_t pts[ 3 ];
+ bspDrawVert_t *vert[3];
+ int valid;
/* start brush */
fprintf( f, "\t// brush %d\n", num );
fprintf( f, "\t{\n" );
+ if(brushPrimitives)
+ {
+ fprintf( f, "\tbrushDef\n" );
+ fprintf( f, "\t{\n" );
+ }
/* clear out build brush */
for( i = 0; i < buildBrush->numsides; i++ )
if( side->shaderNum < 0 || side->shaderNum >= numBSPShaders )
continue;
shader = &bspShaders[ side->shaderNum ];
- if( !Q_stricmp( shader->shader, "default" ) || !Q_stricmp( shader->shader, "noshader" ) )
- continue;
+ //if( !Q_stricmp( shader->shader, "default" ) || !Q_stricmp( shader->shader, "noshader" ) )
+ // continue;
/* get plane */
plane = &bspPlanes[ side->planeNum ];
/* make brush windings */
if( !CreateBrushWindings( buildBrush ) )
+ {
+ Sys_Printf( "CreateBrushWindings failed\n" );
return;
+ }
/* iterate through build brush sides */
for( i = 0; i < buildBrush->numsides; i++ )
/* get build side */
buildSide = &buildBrush->sides[ i ];
+ /* get plane */
+ buildPlane = &mapplanes[ buildSide->planenum ];
+
/* dummy check */
if( buildSide->shaderInfo == NULL || buildSide->winding == NULL )
continue;
-
+
+ // st-texcoords -> texMat block
+ // start out with dummy
+ VectorSet(buildSide->texMat[0], 1/32.0, 0, 0);
+ VectorSet(buildSide->texMat[1], 0, 1/32.0, 0);
+
+ // find surface for this side (by brute force)
+ // surface format:
+ // - meshverts point in pairs of three into verts
+ // - (triangles)
+ // - find the triangle that has most in common with our side
+ GetBestSurfaceTriangleMatchForBrushside(buildSide, vert);
+ valid = 0;
+
/* get texture name */
if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) )
texture = buildSide->shaderInfo->shader + 9;
//% pts[ j ][ 1 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 1 ] * SNAP_FLOAT_TO_INT + 0.5f );
//% pts[ j ][ 2 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 2 ] * SNAP_FLOAT_TO_INT + 0.5f );
}
-
- /* print brush side */
- /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
- fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s 0 0 0 0.5 0.5 0 0 0\n",
- pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
- pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
- pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
- texture );
+
+ if(vert[0] && vert[1] && vert[2])
+ {
+ if(brushPrimitives)
+ {
+ int i;
+ vec3_t texX, texY;
+ vec2_t xyI, xyJ, xyK;
+ vec2_t stI, stJ, stK;
+ vec_t D, D0, D1, D2;
+
+ ComputeAxisBase(buildPlane->normal, texX, texY);
+
+ xyI[0] = DotProduct(vert[0]->xyz, texX);
+ xyI[1] = DotProduct(vert[0]->xyz, texY);
+ xyJ[0] = DotProduct(vert[1]->xyz, texX);
+ xyJ[1] = DotProduct(vert[1]->xyz, texY);
+ xyK[0] = DotProduct(vert[2]->xyz, texX);
+ xyK[1] = DotProduct(vert[2]->xyz, texY);
+ stI[0] = vert[0]->st[0]; stI[1] = vert[0]->st[1];
+ stJ[0] = vert[1]->st[0]; stJ[1] = vert[1]->st[1];
+ stK[0] = vert[2]->st[0]; stK[1] = vert[2]->st[1];
+
+ // - solve linear equations:
+ // - (x, y) := xyz . (texX, texY)
+ // - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2]
+ // (for three vertices)
+ D = Det3x3(
+ xyI[0], xyI[1], 1,
+ xyJ[0], xyJ[1], 1,
+ xyK[0], xyK[1], 1
+ );
+ if(D != 0)
+ {
+ for(i = 0; i < 2; ++i)
+ {
+ D0 = Det3x3(
+ stI[i], xyI[1], 1,
+ stJ[i], xyJ[1], 1,
+ stK[i], xyK[1], 1
+ );
+ D1 = Det3x3(
+ xyI[0], stI[i], 1,
+ xyJ[0], stJ[i], 1,
+ xyK[0], stK[i], 1
+ );
+ D2 = Det3x3(
+ xyI[0], xyI[1], stI[i],
+ xyJ[0], xyJ[1], stJ[i],
+ xyK[0], xyK[1], stK[i]
+ );
+ VectorSet(buildSide->texMat[i], D0 / D, D1 / D, D2 / D);
+ }
+ valid = 1;
+ }
+ else
+ fprintf(stderr, "degenerate triangle found when solving texMat equations for\n(%f %f %f) (%f %f %f) (%f %f %f)\n( %f %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n",
+ buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2],
+ vert[0]->normal[0], vert[0]->normal[1], vert[0]->normal[2],
+ texX[0], texX[1], texX[2], texY[0], texY[1], texY[2],
+ vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xyI[0], xyI[1],
+ vert[1]->xyz[0], vert[1]->xyz[1], vert[1]->xyz[2], xyJ[0], xyJ[1],
+ vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xyK[0], xyK[1]
+ );
+
+ /* print brush side */
+ /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
+ fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
+ pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
+ pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
+ pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
+ buildSide->texMat[0][0], buildSide->texMat[0][1], FRAC(buildSide->texMat[0][2]),
+ buildSide->texMat[1][0], buildSide->texMat[1][1], FRAC(buildSide->texMat[1][2]),
+ texture,
+ // DEBUG: valid ? 0 : C_DETAIL
+ 0
+ );
+ }
+ else
+ {
+ // invert QuakeTextureVecs
+ int i;
+ vec3_t vecs[2];
+ int sv, tv;
+ vec2_t stI, stJ, stK;
+ vec3_t sts[2];
+ vec2_t shift, scale;
+ vec_t rotate;
+ vec_t D, D0, D1, D2;
+
+ TextureAxisFromPlane(buildPlane, vecs[0], vecs[1]);
+ if (vecs[0][0])
+ sv = 0;
+ else if (vecs[0][1])
+ sv = 1;
+ else
+ sv = 2;
+ if (vecs[1][0])
+ tv = 0;
+ else if (vecs[1][1])
+ tv = 1;
+ else
+ tv = 2;
+
+ stI[0] = vert[0]->st[0] * buildSide->shaderInfo->shaderWidth; stI[1] = vert[0]->st[1] * buildSide->shaderInfo->shaderHeight;
+ stJ[0] = vert[1]->st[0] * buildSide->shaderInfo->shaderWidth; stJ[1] = vert[1]->st[1] * buildSide->shaderInfo->shaderHeight;
+ stK[0] = vert[2]->st[0] * buildSide->shaderInfo->shaderWidth; stK[1] = vert[2]->st[1] * buildSide->shaderInfo->shaderHeight;
+
+ D = Det3x3(
+ vert[0]->xyz[sv], vert[0]->xyz[tv], 1,
+ vert[1]->xyz[sv], vert[1]->xyz[tv], 1,
+ vert[2]->xyz[sv], vert[2]->xyz[tv], 1
+ );
+ if(D != 0)
+ {
+ for(i = 0; i < 2; ++i)
+ {
+ D0 = Det3x3(
+ stI[i], vert[0]->xyz[tv], 1,
+ stJ[i], vert[1]->xyz[tv], 1,
+ stK[i], vert[2]->xyz[tv], 1
+ );
+ D1 = Det3x3(
+ vert[0]->xyz[sv], stI[i], 1,
+ vert[1]->xyz[sv], stJ[i], 1,
+ vert[2]->xyz[sv], stK[i], 1
+ );
+ D2 = Det3x3(
+ vert[0]->xyz[sv], vert[0]->xyz[tv], stI[i],
+ vert[1]->xyz[sv], vert[1]->xyz[tv], stJ[i],
+ vert[2]->xyz[sv], vert[2]->xyz[tv], stK[i]
+ );
+ VectorSet(sts[i], D0 / D, D1 / D, D2 / D);
+ }
+ valid = 1;
+ }
+ else
+ fprintf(stderr, "degenerate triangle found when solving texDef equations\n"); // FIXME add stuff here
+
+ // now we must solve:
+ // // now we must invert:
+ // ang = rotate / 180 * Q_PI;
+ // sinv = sin(ang);
+ // cosv = cos(ang);
+ // ns = cosv * vecs[0][sv];
+ // nt = sinv * vecs[0][sv];
+ // vecsrotscaled[0][sv] = ns / scale[0];
+ // vecsrotscaled[0][tv] = nt / scale[0];
+ // ns = -sinv * vecs[1][tv];
+ // nt = cosv * vecs[1][tv];
+ // vecsrotscaled[1][sv] = ns / scale[1];
+ // vecsrotscaled[1][tv] = nt / scale[1];
+ scale[0] = 1.0/sqrt(sts[0][0] * sts[0][0] + sts[0][1] * sts[0][1]);
+ scale[1] = 1.0/sqrt(sts[1][0] * sts[1][0] + sts[1][1] * sts[1][1]);
+ rotate = atan2(sts[0][1] * vecs[0][sv] - sts[1][0] * vecs[1][tv], sts[0][0] * vecs[0][sv] + sts[1][1] * vecs[1][tv]) * (180.0f / Q_PI);
+ shift[0] = buildSide->shaderInfo->shaderWidth * FRAC(sts[0][2] / buildSide->shaderInfo->shaderWidth);
+ shift[1] = buildSide->shaderInfo->shaderHeight * FRAC(sts[1][2] / buildSide->shaderInfo->shaderHeight);
+
+ /* print brush side */
+ /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
+ fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s %.8f %.8f %.8f %.8f %.8f %d 0 0\n",
+ pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
+ pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
+ pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
+ texture,
+ shift[0], shift[1], rotate, scale[0], scale[1],
+ // DEBUG: valid ? 0 : C_DETAIL
+ 0
+ );
+ }
+ }
+ else
+ {
+ vec3_t vecs[ 2 ];
+ if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
+ if(strcmp(buildSide->shaderInfo->shader, "noshader"))
+ if(strcmp(buildSide->shaderInfo->shader, "default"))
+ {
+ fprintf(stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader);
+ texture = "common/WTF";
+ }
+
+ MakeNormalVectors( buildPlane->normal, vecs[ 0 ], vecs[ 1 ] );
+ VectorMA( vec3_origin, buildPlane->dist, buildPlane->normal, pts[ 0 ] );
+ VectorMA( pts[ 0 ], 256.0f, vecs[ 0 ], pts[ 1 ] );
+ VectorMA( pts[ 0 ], 256.0f, vecs[ 1 ], pts[ 2 ] );
+ if(brushPrimitives)
+ {
+ fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
+ pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
+ pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
+ pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
+ 1.0f/16.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f/16.0f, 0.0f,
+ texture,
+ // DEBUG: valid ? 0 : C_DETAIL
+ 0
+ );
+ }
+ else
+ {
+ fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s %.8f %.8f %.8f %.8f %.8f %d 0 0\n",
+ pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
+ pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
+ pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
+ texture,
+ 0.0f, 0.0f, 0.0f, 0.25f, 0.25f,
+ // DEBUG: valid ? 0 : C_DETAIL
+ 0
+ );
+ }
+ }
}
/* end brush */
+ if(brushPrimitives)
+ {
+ fprintf( f, "\t}\n" );
+ }
fprintf( f, "\t}\n\n" );
}
+#undef FRAC
#if 0
/* iterate through the brush sides (ignore the first 6 bevel planes) */
exports a bsp model to a map file
*/
-static void ConvertModel( FILE *f, bspModel_t *model, int modelNum, vec3_t origin )
+static void ConvertModel( FILE *f, bspModel_t *model, int modelNum, vec3_t origin, qboolean brushPrimitives )
{
int i, num;
bspBrush_t *brush;
/* convert bsp planes to map planes */
nummapplanes = numBSPPlanes;
+ AUTOEXPAND_BY_REALLOC(mapplanes, nummapplanes, allocatedmapplanes, 1024);
for( i = 0; i < numBSPPlanes; i++ )
{
VectorCopy( bspPlanes[ i ].normal, mapplanes[ i ].normal );
mapplanes[ i ].dist = bspPlanes[ i ].dist;
mapplanes[ i ].type = PlaneTypeForNormal( mapplanes[ i ].normal );
- mapplanes[ i ].hash_chain = NULL;
+ mapplanes[ i ].hash_chain = 0;
}
/* allocate a build brush */
buildBrush = AllocBrush( 512 );
buildBrush->entityNum = 0;
buildBrush->original = buildBrush;
+
+ if(origin[0] != 0 || origin[1] != 0 || origin[2] != 0)
+ ConvertOriginBrush(f, -1, origin, brushPrimitives);
/* go through each brush in the model */
for( i = 0; i < model->numBSPBrushes; i++ )
{
num = i + model->firstBSPBrush;
brush = &bspBrushes[ num ];
- ConvertBrush( f, num, brush, origin );
+ ConvertBrush( f, num, brush, origin, brushPrimitives );
}
/* free the build brush */
exports entity key/value pairs to a map file
*/
-static void ConvertEPairs( FILE *f, entity_t *e )
+static void ConvertEPairs( FILE *f, entity_t *e, qboolean skip_origin )
{
epair_t *ep;
if( !Q_stricmp( ep->key, "model" ) && ep->value[ 0 ] == '*' )
continue;
+ /* ignore origin keys if skip_origin is set */
+ if( skip_origin && !Q_stricmp( ep->key, "origin" ) )
+ continue;
+
/* emit the epair */
fprintf( f, "\t\"%s\" \"%s\"\n", ep->key, ep->value );
}
exports an quake map file from the bsp
*/
-int ConvertBSPToMap( char *bspName )
+int ConvertBSPToMap_Ext( char *bspName, qboolean brushPrimitives )
{
int i, modelNum;
FILE *f;
fprintf( f, "// entity %d\n", i );
fprintf( f, "{\n" );
- /* export keys */
- ConvertEPairs( f, e );
- fprintf( f, "\n" );
-
/* get model num */
if( i == 0 )
modelNum = 0;
modelNum = -1;
}
+ /* export keys */
+ ConvertEPairs( f, e, modelNum >= 0 );
+ fprintf( f, "\n" );
+
/* only handle bsp models */
if( modelNum >= 0 )
{
GetVectorForKey( e, "origin", origin );
/* convert model */
- ConvertModel( f, model, modelNum, origin );
+ ConvertModel( f, model, modelNum, origin, brushPrimitives );
}
/* end entity */
/* return to sender */
return 0;
}
+
+int ConvertBSPToMap( char *bspName )
+{
+ return ConvertBSPToMap_Ext(bspName, qfalse);
+}
+
+int ConvertBSPToMap_BP( char *bspName )
+{
+ return ConvertBSPToMap_Ext(bspName, qtrue);
+}
--- /dev/null
+/* -------------------------------------------------------------------------------
+
+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
+
+----------------------------------------------------------------------------------
+
+This code has been altered significantly from its original form, to support
+several games based on the Quake III Arena engine, in the form of "Q3Map2."
+
+------------------------------------------------------------------------------- */
+
+
+
+/* marker */
+#define CONVERT_ASE_C
+
+
+
+/* dependencies */
+#include "q3map2.h"
+
+
+
+/*
+ConvertSurface()
+converts a bsp drawsurface to an obj chunk
+*/
+
+int firstLightmap = 0;
+int lastLightmap = -1;
+static void ConvertLightmapToMTL( FILE *f, const char *base, int lightmapNum );
+
+int objVertexCount = 0;
+int objLastShaderNum = -1;
+static void ConvertSurfaceToOBJ( FILE *f, bspModel_t *model, int modelNum, bspDrawSurface_t *ds, int surfaceNum, vec3_t origin )
+{
+ int i, v, face, a, b, c;
+ bspDrawVert_t *dv;
+
+ /* ignore patches for now */
+ if( ds->surfaceType != MST_PLANAR && ds->surfaceType != MST_TRIANGLE_SOUP )
+ return;
+
+ fprintf(f, "g mat%dmodel%dsurf%d\r\n", ds->shaderNum, modelNum, surfaceNum);
+ switch( ds->surfaceType )
+ {
+ case MST_PLANAR:
+ fprintf( f, "# SURFACETYPE MST_PLANAR\r\n" );
+ break;
+ case MST_TRIANGLE_SOUP:
+ fprintf( f, "# SURFACETYPE MST_TRIANGLE_SOUP\r\n" );
+ break;
+ }
+
+ /* export shader */
+ if(lightmapsAsTexcoord)
+ {
+ if(objLastShaderNum != ds->lightmapNum[0])
+ {
+ fprintf(f, "usemtl lm_%04d\r\n", ds->lightmapNum[0] + deluxemap);
+ objLastShaderNum = ds->lightmapNum[0] + deluxemap;
+ }
+ if(ds->lightmapNum[0] + deluxemap < firstLightmap)
+ {
+ Sys_Printf( "WARNING: lightmap %d out of range (exporting anyway)\n", ds->lightmapNum[0] + deluxemap );
+ firstLightmap = ds->lightmapNum[0] + deluxemap;
+ }
+ if(ds->lightmapNum[0] > lastLightmap)
+ {
+ Sys_Printf( "WARNING: lightmap %d out of range (exporting anyway)\n", ds->lightmapNum[0] + deluxemap );
+ lastLightmap = ds->lightmapNum[0] + deluxemap;
+ }
+ }
+ else
+ {
+ if(objLastShaderNum != ds->shaderNum)
+ {
+ fprintf(f, "usemtl %s\r\n", bspShaders[ds->shaderNum].shader);
+ objLastShaderNum = ds->shaderNum;
+ }
+ }
+
+ /* export vertex */
+ for( i = 0; i < ds->numVerts; i++ )
+ {
+ v = i + ds->firstVert;
+ dv = &bspDrawVerts[ v ];
+ fprintf(f, "# vertex %d\r\n", i + objVertexCount + 1);
+ fprintf(f, "v %f %f %f\r\n", dv->xyz[ 0 ], dv->xyz[ 1 ], dv->xyz[ 2 ]);
+ fprintf(f, "vn %f %f %f\r\n", dv->normal[ 0 ], dv->normal[ 1 ], dv->normal[ 2 ]);
+ if(lightmapsAsTexcoord)
+ fprintf(f, "vt %f %f\r\n", dv->lightmap[0][0], 1.0 - dv->lightmap[0][1]);
+ else
+ fprintf(f, "vt %f %f\r\n", dv->st[ 0 ], 1.0 - dv->st[ 1 ]);
+ }
+
+ /* export faces */
+ for( i = 0; i < ds->numIndexes; i += 3 )
+ {
+ face = (i / 3);
+ a = bspDrawIndexes[ i + ds->firstIndex ];
+ c = bspDrawIndexes[ i + ds->firstIndex + 1 ];
+ b = bspDrawIndexes[ i + ds->firstIndex + 2 ];
+ fprintf(f, "f %d/%d/%d %d/%d/%d %d/%d/%d\r\n",
+ a + objVertexCount + 1, a + objVertexCount + 1, a + objVertexCount + 1,
+ b + objVertexCount + 1, b + objVertexCount + 1, b + objVertexCount + 1,
+ c + objVertexCount + 1, c + objVertexCount + 1, c + objVertexCount + 1
+ );
+ }
+
+ objVertexCount += ds->numVerts;
+}
+
+
+
+/*
+ConvertModel()
+exports a bsp model to an ase chunk
+*/
+
+static void ConvertModelToOBJ( FILE *f, bspModel_t *model, int modelNum, vec3_t origin )
+{
+ int i, s;
+ bspDrawSurface_t *ds;
+
+
+ /* go through each drawsurf in the model */
+ for( i = 0; i < model->numBSPSurfaces; i++ )
+ {
+ s = i + model->firstBSPSurface;
+ ds = &bspDrawSurfaces[ s ];
+ ConvertSurfaceToOBJ( f, model, modelNum, ds, s, origin );
+ }
+}
+
+
+
+/*
+ConvertShader()
+exports a bsp shader to an ase chunk
+*/
+
+static void ConvertShaderToMTL( FILE *f, bspShader_t *shader, int shaderNum )
+{
+ shaderInfo_t *si;
+ char *c, filename[ 1024 ];
+
+
+ /* get shader */
+ si = ShaderInfoForShader( shader->shader );
+ if( si == NULL )
+ {
+ Sys_Printf( "WARNING: NULL shader in BSP\n" );
+ return;
+ }
+
+ /* set bitmap filename */
+ if( si->shaderImage->filename[ 0 ] != '*' )
+ strcpy( filename, si->shaderImage->filename );
+ else
+ sprintf( filename, "%s.tga", si->shader );
+
+ /* blender hates this, so let's not do it
+ for( c = filename; *c != '\0'; c++ )
+ if( *c == '/' )
+ *c = '\\';
+ */
+
+ /* print shader info */
+ fprintf( f, "newmtl %s\r\n", shader->shader );
+ fprintf( f, "Kd %f %f %f\r\n", si->color[ 0 ], si->color[ 1 ], si->color[ 2 ] );
+ if(shadersAsBitmap)
+ fprintf( f, "map_Kd %s\r\n", shader->shader );
+ else
+ /* blender hates this, so let's not do it
+ fprintf( f, "map_Kd ..\\%s\r\n", filename );
+ */
+ fprintf( f, "map_Kd ../%s\r\n", filename );
+}
+
+static void ConvertLightmapToMTL( FILE *f, const char *base, int lightmapNum )
+{
+ /* print shader info */
+ fprintf( f, "newmtl lm_%04d\r\n", lightmapNum );
+ if(lightmapNum >= 0)
+ /* blender hates this, so let's not do it
+ fprintf( f, "map_Kd %s\\lm_%04d.tga\r\n", base, lightmapNum );
+ */
+ fprintf( f, "map_Kd %s/lm_%04d.tga\r\n", base, lightmapNum );
+}
+
+
+
+/*
+ConvertBSPToASE()
+exports an 3d studio ase file from the bsp
+*/
+
+int ConvertBSPToOBJ( char *bspName )
+{
+ int i, modelNum;
+ FILE *f, *fmtl;
+ bspShader_t *shader;
+ bspModel_t *model;
+ entity_t *e;
+ vec3_t origin;
+ const char *key;
+ char name[ 1024 ], base[ 1024 ], mtlname[ 1024 ], dirname[ 1024 ];
+
+
+ /* note it */
+ Sys_Printf( "--- Convert BSP to OBJ ---\n" );
+
+ /* create the ase filename from the bsp name */
+ strcpy( dirname, bspName );
+ StripExtension( dirname );
+ strcpy( name, bspName );
+ StripExtension( name );
+ strcat( name, ".obj" );
+ Sys_Printf( "writing %s\n", name );
+ strcpy( mtlname, bspName );
+ StripExtension( mtlname );
+ strcat( mtlname, ".mtl" );
+ Sys_Printf( "writing %s\n", mtlname );
+
+ ExtractFileBase( bspName, base );
+
+ /* open it */
+ f = fopen( name, "wb" );
+ if( f == NULL )
+ Error( "Open failed on %s\n", name );
+ fmtl = fopen( mtlname, "wb" );
+ if( fmtl == NULL )
+ Error( "Open failed on %s\n", mtlname );
+
+ /* print header */
+ fprintf( f, "o %s\r\n", base );
+ fprintf( f, "# Generated by Q3Map2 (ydnar) -convert -format obj\r\n" );
+ fprintf( f, "mtllib %s.mtl\r\n", base );
+
+ fprintf( fmtl, "# Generated by Q3Map2 (ydnar) -convert -format obj\r\n" );
+ if(lightmapsAsTexcoord)
+ {
+ int lightmapCount;
+ for( lightmapCount = 0; lightmapCount < numBSPLightmaps; lightmapCount++ )
+ ;
+ for( ; ; lightmapCount++ )
+ {
+ char buf[1024];
+ FILE *tmp;
+ snprintf(buf, sizeof(buf), "%s/lm_%04d.tga", dirname, lightmapCount);
+ buf[sizeof(buf) - 1] = 0;
+ tmp = fopen(buf, "rb");
+ if(!tmp)
+ break;
+ fclose(tmp);
+ }
+ lastLightmap = lightmapCount - 1;
+ }
+ else
+ {
+ for( i = 0; i < numBSPShaders; i++ )
+ {
+ shader = &bspShaders[ i ];
+ ConvertShaderToMTL( fmtl, shader, i );
+ }
+ }
+
+ /* walk entity list */
+ for( i = 0; i < numEntities; i++ )
+ {
+ /* get entity and model */
+ e = &entities[ i ];
+ if( i == 0 )
+ modelNum = 0;
+ else
+ {
+ key = ValueForKey( e, "model" );
+ if( key[ 0 ] != '*' )
+ continue;
+ modelNum = atoi( key + 1 );
+ }
+ model = &bspModels[ modelNum ];
+
+ /* get entity origin */
+ key = ValueForKey( e, "origin" );
+ if( key[ 0 ] == '\0' )
+ VectorClear( origin );
+ else
+ GetVectorForKey( e, "origin", origin );
+
+ /* convert model */
+ ConvertModelToOBJ( f, model, modelNum, origin );
+ }
+
+ if(lightmapsAsTexcoord)
+ {
+ for( i = firstLightmap; i <= lastLightmap; i++ )
+ ConvertLightmapToMTL( fmtl, base, i );
+ }
+
+ /* close the file and return */
+ fclose( f );
+ fclose( fmtl );
+
+ /* return to sender */
+ return 0;
+}
+
+
+
ds2->shaderInfo = dp->si;
ds2->fogNum = ds->fogNum; /* why was this -1? */
ds2->lightmapScale = ds->lightmapScale;
+ ds2->shadeAngleDegrees = ds->shadeAngleDegrees;
ds2->numVerts = w->numpoints;
ds2->verts = safe_malloc( ds2->numVerts * sizeof( *ds2->verts ) );
memset( ds2->verts, 0, ds2->numVerts * sizeof( *ds2->verts ) );
vec3_t normal;
float dist;
int planenum;
-
+ float sizeBias;
+
+ //int frontC,backC,splitsC,facingC;
+
/* ydnar: set some defaults */
*splitPlaneNum = -1; /* leaf */
bestValue = -99999;
bestSplit = list;
- for( split = list; split; split = split->next )
- split->checked = qfalse;
+
+ // div0: this check causes detail/structural mixes
+ //for( split = list; split; split = split->next )
+ // split->checked = qfalse;
for( split = list; split; split = split->next )
{
- if ( split->checked )
- continue;
-
+ //if ( split->checked )
+ // continue;
+
plane = &mapplanes[ split->planenum ];
splits = 0;
facing = 0;
for ( check = list ; check ; check = check->next ) {
if ( check->planenum == split->planenum ) {
facing++;
- check->checked = qtrue; // won't need to test this plane again
+ //check->checked = qtrue; // won't need to test this plane again
continue;
}
side = WindingOnPlaneSide( check->w, plane->normal, plane->dist );
back++;
}
}
- value = 5*facing - 5*splits; // - abs(front-back);
- if ( plane->type < 3 ) {
- value+=5; // axial is better
+
+ if(bspAlternateSplitWeights)
+ {
+ // from 27
+
+ //Bigger is better
+ sizeBias=WindingArea(split->w);
+
+ //Base score = 20000 perfectly balanced
+ value = 20000-(abs(front-back));
+ value -= plane->counter;// If we've already used this plane sometime in the past try not to use it again
+ value -= facing ; // if we're going to have alot of other surfs use this plane, we want to get it in quickly.
+ value -= splits*5; //more splits = bad
+ value += sizeBias*10; //We want a huge score bias based on plane size
+ }
+ else
+ {
+ value = 5*facing - 5*splits; // - abs(front-back);
+ if ( plane->type < 3 ) {
+ value+=5; // axial is better
+ }
}
+
value += split->priority; // prioritize hints higher
if ( value > bestValue ) {
bestValue = value;
bestSplit = split;
+ //frontC=front;
+ //backC=back;
+ //splitsC=splits;
+ //facingC=facing;
}
}
if( bestValue == -99999 )
return;
+ //Sys_FPrintf (SYS_VRB, "F: %d B:%d S:%d FA:%ds\n",frontC,backC,splitsC,facingC );
+
/* set best split data */
*splitPlaneNum = bestSplit->planenum;
*compileFlags = bestSplit->compileFlags;
+
+#if 0
+ if(bestSplit->compileFlags & C_DETAIL)
+ for( split = list; split; split = split->next )
+ if(!(split->compileFlags & C_DETAIL))
+ Sys_FPrintf(SYS_ERR, "DON'T DO SUCH SPLITS (1)\n");
+ if((node->compileFlags & C_DETAIL) && !(bestSplit->compileFlags & C_DETAIL))
+ Sys_FPrintf(SYS_ERR, "DON'T DO SUCH SPLITS (2)\n");
+#endif
+
+ if (*splitPlaneNum>-1) mapplanes[ *splitPlaneNum ].counter++;
}
winding_t *frontWinding, *backWinding;
int i;
int splitPlaneNum, compileFlags;
+ qboolean isstruct = qfalse;
/* count faces left */
if ( splitPlaneNum == -1 )
{
node->planenum = PLANENUM_LEAF;
+ node->has_structural_children = qfalse;
c_faceLeafs++;
return;
}
/* partition the list */
node->planenum = splitPlaneNum;
node->compileFlags = compileFlags;
+ node->has_structural_children = !(compileFlags & C_DETAIL) && !node->opaque;
plane = &mapplanes[ splitPlaneNum ];
childLists[0] = NULL;
childLists[1] = NULL;
+
for( split = list; split; split = next )
{
/* set next */
FreeBspFace( split );
continue;
}
+
+ if(!(split->compileFlags & C_DETAIL))
+ isstruct = 1;
/* determine which side the face falls on */
side = WindingOnPlaneSide( split->w, plane->normal, plane->dist );
}
}
+#if 0
+ if((node->compileFlags & C_DETAIL) && isstruct)
+ Sys_FPrintf(SYS_ERR, "I am detail, my child is structural, this is a wtf1\n", node->has_structural_children);
+#endif
+
for ( i = 0 ; i < 2 ; i++ ) {
BuildFaceTree_r ( node->children[i], childLists[i]);
+ node->has_structural_children |= node->children[i]->has_structural_children;
}
+
+#if 0
+ if((node->compileFlags & C_DETAIL) && !(node->children[0]->compileFlags & C_DETAIL) && node->children[0]->planenum != PLANENUM_LEAF)
+ Sys_FPrintf(SYS_ERR, "I am detail, my child is structural\n", node->has_structural_children);
+ if((node->compileFlags & C_DETAIL) && isstruct)
+ Sys_FPrintf(SYS_ERR, "I am detail, my child is structural, this is a wtf2\n", node->has_structural_children);
+#endif
}
}
Sys_FPrintf( SYS_VRB, "%9d faces\n", count );
+ for( i = 0; i < nummapplanes; i++)
+ {
+ mapplanes[ i ].counter=0;
+ }
+
tree->headnode = AllocNode();
VectorCopy( tree->mins, tree->headnode->mins );
VectorCopy( tree->maxs, tree->headnode->maxs );
flist = NULL;
for( b = list; b != NULL; b = b->next )
{
- if( b->detail )
+ if( !deepBSP && b->detail )
continue;
for( i = 0; i < b->numsides; i++ )
f->w = CopyWinding( w );
f->planenum = s->planenum & ~1;
f->compileFlags = s->compileFlags; /* ydnar */
+ if(b->detail)
+ f->compileFlags |= C_DETAIL;
/* ydnar: set priority */
f->priority = 0;
f->priority += ANTIPORTAL_PRIORITY;
if( f->compileFlags & C_AREAPORTAL )
f->priority += AREAPORTAL_PRIORITY;
+ if( f->compileFlags & C_DETAIL )
+ f->priority += DETAIL_PRIORITY;
/* get next face */
f->next = flist;
flist = NULL;
for( b = list; b != NULL; b = b->next )
{
- if( b->detail )
+ if( !deepBSP && b->detail )
continue;
for( i = 0; i < b->numsides; i++ )
f->w = CopyWinding( w );
f->planenum = s->planenum & ~1;
f->compileFlags = s->compileFlags; /* ydnar */
+ if(b->detail)
+ f->compileFlags |= C_DETAIL;
/* ydnar: set priority */
f->priority = 0;
f->priority += ANTIPORTAL_PRIORITY;
if( f->compileFlags & C_AREAPORTAL )
f->priority += AREAPORTAL_PRIORITY;
+ if( f->compileFlags & C_DETAIL )
+ f->priority += DETAIL_PRIORITY;
/* get next face */
f->next = flist;
--- /dev/null
+/* -------------------------------------------------------------------------------
+
+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
+
+----------------------------------------------------------------------------------
+
+This code has been altered significantly from its original form, to support
+several games based on the Quake III Arena engine, in the form of "Q3Map2."
+
+------------------------------------------------------------------------------- */
+
+
+
+/* marker */
+#ifndef GAME__NULL_H
+#define GAME__NULL_H
+
+
+
+/* -------------------------------------------------------------------------------
+
+content and surface flags
+are in game_quake3.h
+
+------------------------------------------------------------------------------- */
+
+
+
+/* -------------------------------------------------------------------------------
+
+game_t struct
+
+------------------------------------------------------------------------------- */
+
+{
+ NULL, /* -game x */
+ NULL, /* default base game data dir */
+ NULL, /* unix home sub-dir */
+ NULL, /* magic path word */
+ NULL, /* shader directory */
+ 0, /* max lightmapped surface verts */
+ 0, /* max surface verts */
+ 0, /* max surface indexes */
+ qfalse, /* flares */
+ NULL, /* default flare shader */
+ qfalse, /* wolf lighting model? */
+ 0, /* lightmap width/height */
+ 0, /* lightmap gamma */
+ 0, /* lightmap exposure */
+ 0, /* lightmap compensate */
+ 0, /* lightgrid scale */
+ 0, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qfalse, /* disable shader lightstyles hack */
+ qfalse, /* keep light entities on bsp */
+ 0, /* default patchMeta subdivisions tolerance */
+ qfalse, /* patch casting enabled */
+ qfalse, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 0, /* minimap size */
+ 0, /* minimap sharpener */
+ 0, /* minimap border */
+ qfalse, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ NULL, /* minimap name format */
+ NULL, /* bsp file prefix */
+ 0, /* bsp file version */
+ qfalse, /* cod-style lump len/ofs order */
+ NULL, /* bsp load function */
+ NULL, /* bsp write function */
+
+ {
+ { NULL, 0, 0, 0, 0, 0, 0 }
+ }
+}
+
+
+
+/* end marker */
+#endif
+
--- /dev/null
+/* -------------------------------------------------------------------------------
+
+Copyright (C) 1999-2006 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
+
+----------------------------------------------------------------------------------
+
+This code has been altered significantly from its original form, to support
+several games based on the Quake III Arena engine, in the form of "Q3Map2."
+
+------------------------------------------------------------------------------- */
+
+
+
+/* marker */
+#ifndef GAME_DARKPLACES_H
+#define GAME_DARKPLACES_H
+
+/* content and surface flags get form quake3 */
+
+/* -------------------------------------------------------------------------------
+
+game_t struct
+
+------------------------------------------------------------------------------- */
+
+{
+ "darkplaces", /* -game x */
+ "id1", /* default base game data dir */
+ ".darkplaces ", /* unix home sub-dir */
+ "darkplaces", /* magic path word */
+ "scripts", /* shader directory */
+ 999, /* max lightmapped surface verts */
+ 999, /* max surface verts */
+ 6000, /* max surface indexes */
+ qfalse, /* flares */
+ "flareshader", /* default flare shader */
+ qfalse, /* wolf lighting model? */
+ 128, /* lightmap width/height */
+ 1.0f, /* lightmap gamma */
+ 200.0f, /* lightmap exposure */
+ 1.0f, /* lightmap compensate */
+ 0.3f, /* lightgrid scale */
+ 0.6f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qtrue, /* disable shader lightstyles hack */
+ qtrue, /* keep light entities on bsp */
+ 4, /* default patchMeta subdivisions tolerance */
+ qfalse, /* patch casting enabled */
+ qfalse, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "%s.tga", /* minimap name format */
+ "IBSP", /* bsp file prefix */
+ 46, /* bsp file version */
+ qfalse, /* cod-style lump len/ofs order */
+ LoadIBSPFile, /* bsp load function */
+ WriteIBSPFile, /* bsp write function */
+
+ {
+ /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */
+
+ /* default */
+ { "default", Q_CONT_SOLID, -1, 0, -1, C_SOLID, -1 },
+
+
+ /* ydnar */
+ { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 },
+ { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 },
+ { "skip", 0, 0, 0, 0, C_SKIP, 0 },
+
+
+ /* compiler */
+ { "origin", Q_CONT_ORIGIN, Q_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID },
+ { "areaportal", Q_CONT_AREAPORTAL, Q_CONT_SOLID, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID },
+ { "trans", Q_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 },
+ { "detail", Q_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 },
+ { "structural", Q_CONT_STRUCTURAL, 0, 0, 0, C_STRUCTURAL, 0 },
+ { "hint", 0, 0, Q_SURF_HINT, 0, C_HINT, 0 },
+ { "nodraw", 0, 0, Q_SURF_NODRAW, 0, C_NODRAW, 0 },
+
+ { "alphashadow", 0, 0, Q_SURF_ALPHASHADOW, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 },
+ { "lightfilter", 0, 0, Q_SURF_LIGHTFILTER, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 },
+ { "nolightmap", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 },
+ { "pointlight", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 },
+
+
+ /* game */
+ { "nonsolid", 0, Q_CONT_SOLID, Q_SURF_NONSOLID, 0, 0, C_SOLID },
+
+ { "trigger", Q_CONT_TRIGGER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+
+ { "water", Q_CONT_WATER, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID },
+ { "slime", Q_CONT_SLIME, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID },
+ { "lava", Q_CONT_LAVA, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID },
+
+ { "playerclip", Q_CONT_PLAYERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID },
+ { "monsterclip", Q_CONT_MONSTERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID },
+ { "nodrop", Q_CONT_NODROP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+
+ { "clusterportal", Q_CONT_CLUSTERPORTAL, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+ { "donotenter", Q_CONT_DONOTENTER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+ { "botclip", Q_CONT_BOTCLIP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+
+ { "fog", Q_CONT_FOG, Q_CONT_SOLID, 0, 0, C_FOG, C_SOLID },
+ { "sky", 0, 0, Q_SURF_SKY, 0, C_SKY, 0 },
+
+ { "slick", 0, 0, Q_SURF_SLICK, 0, 0, 0 },
+
+ { "noimpact", 0, 0, Q_SURF_NOIMPACT, 0, 0, 0 },
+ { "nomarks", 0, 0, Q_SURF_NOMARKS, 0, C_NOMARKS, 0 },
+ { "ladder", 0, 0, Q_SURF_LADDER, 0, 0, 0 },
+ { "nodamage", 0, 0, Q_SURF_NODAMAGE, 0, 0, 0 },
+ { "metalsteps", 0, 0, Q_SURF_METALSTEPS, 0, 0, 0 },
+ { "flesh", 0, 0, Q_SURF_FLESH, 0, 0, 0 },
+ { "nosteps", 0, 0, Q_SURF_NOSTEPS, 0, 0, 0 },
+ { "nodlight", 0, 0, Q_SURF_NODLIGHT, 0, 0, 0 },
+ { "dust", 0, 0, Q_SURF_DUST, 0, 0, 0 },
+
+
+ /* null */
+ { NULL, 0, 0, 0, 0, 0, 0 }
+ }
+}
+
+
+
+/* end marker */
+#endif
+
--- /dev/null
+/* -------------------------------------------------------------------------------
+
+Copyright (C) 1999-2006 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
+
+----------------------------------------------------------------------------------
+
+This code has been altered significantly from its original form, to support
+several games based on the Quake III Arena engine, in the form of "Q3Map2."
+
+------------------------------------------------------------------------------- */
+
+
+
+/* marker */
+#ifndef GAME_DQ_H
+#define GAME_DQ_H
+
+/* content and surface flags get form quake3 */
+
+/* -------------------------------------------------------------------------------
+
+game_t struct
+
+------------------------------------------------------------------------------- */
+
+{
+ "dq", /* -game x */
+ "basedq", /* default base game data dir */
+ ".dq", /* unix home sub-dir */
+ "dq", /* magic path word */
+ "scripts", /* shader directory */
+ 64, /* max lightmapped surface verts */
+ 999, /* max surface verts */
+ 6000, /* max surface indexes */
+ qfalse, /* flares */
+ "flareshader", /* default flare shader */
+ qfalse, /* wolf lighting model? */
+ 128, /* lightmap width/height */
+ 1.2f, /* lightmap gamma */
+ 200.0f, /* lightmap exposure */
+ 1.0f, /* lightmap compensate */
+ 0.3f, /* lightgrid scale */
+ 0.6f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qtrue, /* disable shader lightstyles hack */
+ qtrue, /* keep light entities on bsp */
+ 4, /* default patchMeta subdivisions tolerance */
+ qtrue, /* patch casting enabled */
+ qtrue, /* compile deluxemaps */
+ 1, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "%s.tga", /* minimap name format */
+ "IBSP", /* bsp file prefix */
+ 46, /* bsp file version */
+ qfalse, /* cod-style lump len/ofs order */
+ LoadIBSPFile, /* bsp load function */
+ WriteIBSPFile, /* bsp write function */
+
+ {
+ /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */
+
+ /* default */
+ { "default", Q_CONT_SOLID, -1, 0, -1, C_SOLID, -1 },
+
+
+ /* ydnar */
+ { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 },
+ { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 },
+ { "skip", 0, 0, 0, 0, C_SKIP, 0 },
+
+
+ /* compiler */
+ { "origin", Q_CONT_ORIGIN, Q_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID },
+ { "areaportal", Q_CONT_AREAPORTAL, Q_CONT_SOLID, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID },
+ { "trans", Q_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 },
+ { "detail", Q_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 },
+ { "structural", Q_CONT_STRUCTURAL, 0, 0, 0, C_STRUCTURAL, 0 },
+ { "hint", 0, 0, Q_SURF_HINT, 0, C_HINT, 0 },
+ { "nodraw", 0, 0, Q_SURF_NODRAW, 0, C_NODRAW, 0 },
+
+ { "alphashadow", 0, 0, Q_SURF_ALPHASHADOW, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 },
+ { "lightfilter", 0, 0, Q_SURF_LIGHTFILTER, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 },
+ { "nolightmap", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 },
+ { "pointlight", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 },
+
+
+ /* game */
+ { "nonsolid", 0, Q_CONT_SOLID, Q_SURF_NONSOLID, 0, 0, C_SOLID },
+
+ { "trigger", Q_CONT_TRIGGER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+
+ { "water", Q_CONT_WATER, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID },
+ { "slime", Q_CONT_SLIME, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID },
+ { "lava", Q_CONT_LAVA, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID },
+
+ { "playerclip", Q_CONT_PLAYERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID },
+ { "monsterclip", Q_CONT_MONSTERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID },
+ { "nodrop", Q_CONT_NODROP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+
+ { "clusterportal", Q_CONT_CLUSTERPORTAL, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+ { "donotenter", Q_CONT_DONOTENTER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+ { "botclip", Q_CONT_BOTCLIP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+
+ { "fog", Q_CONT_FOG, Q_CONT_SOLID, 0, 0, C_FOG, C_SOLID },
+ { "sky", 0, 0, Q_SURF_SKY, 0, C_SKY, 0 },
+
+ { "slick", 0, 0, Q_SURF_SLICK, 0, 0, 0 },
+
+ { "noimpact", 0, 0, Q_SURF_NOIMPACT, 0, 0, 0 },
+ { "nomarks", 0, 0, Q_SURF_NOMARKS, 0, C_NOMARKS, 0 },
+ { "ladder", 0, 0, Q_SURF_LADDER, 0, 0, 0 },
+ { "nodamage", 0, 0, Q_SURF_NODAMAGE, 0, 0, 0 },
+ { "metalsteps", 0, 0, Q_SURF_METALSTEPS, 0, 0, 0 },
+ { "flesh", 0, 0, Q_SURF_FLESH, 0, 0, 0 },
+ { "nosteps", 0, 0, Q_SURF_NOSTEPS, 0, 0, 0 },
+ { "nodlight", 0, 0, Q_SURF_NODLIGHT, 0, 0, 0 },
+ { "dust", 0, 0, Q_SURF_DUST, 0, 0, 0 },
+
+
+ /* null */
+ { NULL, 0, 0, 0, 0, 0, 0 }
+ }
+}
+
+
+
+/* end marker */
+#endif
+
qfalse, /* wolf lighting model? */
128, /* lightmap width/height */
1.0f, /* lightmap gamma */
+ 1.0f, /* lightmap exposure */
1.0f, /* lightmap compensate */
+ 1.0f, /* lightgrid scale */
+ 1.0f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qfalse, /* disable shader lightstyles hack */
+ qfalse, /* keep light entities on bsp */
+ 8, /* default patchMeta subdivisions tolerance */
+ qfalse, /* patch casting enabled */
+ qfalse, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "%s.tga", /* minimap name format */
"IBSP", /* bsp file prefix */
46, /* bsp file version */
qfalse, /* cod-style lump len/ofs order */
qfalse, /* wolf lighting model? */
128, /* lightmap width/height */
2.2f, /* lightmap gamma */
+ 1.0f, /* lightmap exposure */
1.0f, /* lightmap compensate */
+ 1.0f, /* lightgrid scale */
+ 1.0f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qfalse, /* disable shader lightstyles hack */
+ qfalse, /* keep light entities on bsp */
+ 8, /* default patchMeta subdivisions tolerance */
+ qfalse, /* patch casting enabled */
+ qfalse, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "%s.tga", /* minimap name format */
"IBSP", /* bsp file prefix */
47, /* bsp file version */
qfalse, /* cod-style lump len/ofs order */
qfalse, /* wolf lighting model? */
128, /* lightmap width/height */
1.0f, /* lightmap gamma */
+ 1.0f, /* lightmap exposure */
1.0f, /* lightmap compensate */
+ 1.0f, /* lightgrid scale */
+ 1.0f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qfalse, /* disable shader lightstyles hack */
+ qfalse, /* keep light entities on bsp */
+ 8, /* default patchMeta subdivisions tolerance */
+ qfalse, /* patch casting enabled */
+ qfalse, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "%s.tga", /* minimap name format */
"RBSP", /* bsp file prefix */
1, /* bsp file version */
qfalse, /* cod-style lump len/ofs order */
qfalse, /* wolf lighting model? */
128, /* lightmap width/height */
1.0f, /* lightmap gamma */
+ 1.0f, /* lightmap exposure */
1.0f, /* lightmap compensate */
+ 1.0f, /* lightgrid scale */
+ 1.0f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qfalse, /* disable shader lightstyles hack */
+ qfalse, /* keep light entities on bsp */
+ 8, /* default patchMeta subdivisions tolerance */
+ qfalse, /* patch casting enabled */
+ qfalse, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "%s.tga", /* minimap name format */
"RBSP", /* bsp file prefix */
1, /* bsp file version */
qfalse, /* cod-style lump len/ofs order */
qfalse, /* wolf lighting model? */
128, /* lightmap width/height */
1.0f, /* lightmap gamma */
+ 1.0f, /* lightmap exposure */
1.0f, /* lightmap compensate */
+ 1.0f, /* lightgrid scale */
+ 1.0f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qtrue, /* disable shader lightstyles hack */
+ qtrue, /* keep light entities on bsp */
+ 8, /* default patchMeta subdivisions tolerance */
+ qfalse, /* patch casting enabled */
+ qfalse, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 1.0f/66.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "../gfx/%s_mini.tga", /* minimap name format */
"IBSP", /* bsp file prefix */
46, /* bsp file version */
qfalse, /* cod-style lump len/ofs order */
{ "nodlight", 0, 0, Q_SURF_NODLIGHT, 0, 0, 0 },
{ "dust", 0, 0, Q_SURF_DUST, 0, 0, 0 },
+
/* null */
{ NULL, 0, 0, 0, 0, 0, 0 }
}
--- /dev/null
+/* -------------------------------------------------------------------------------
+
+Copyright (C) 1999-2006 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
+
+----------------------------------------------------------------------------------
+
+This code has been altered significantly from its original form, to support
+several games based on the Quake III Arena engine, in the form of "Q3Map2."
+
+------------------------------------------------------------------------------- */
+
+
+
+/* marker */
+#ifndef GAME_PROPHECY_H
+#define GAME_PROPHECY_H
+
+/* content and surface flags get form quake3 */
+
+/* -------------------------------------------------------------------------------
+
+game_t struct
+
+------------------------------------------------------------------------------- */
+
+{
+ "prophecy", /* -game x */
+ "base", /* default base game data dir */
+ ".prophecy", /* unix home sub-dir */
+ "prophecy", /* magic path word */
+ "scripts", /* shader directory */
+ 64, /* max lightmapped surface verts */
+ 999, /* max surface verts */
+ 6000, /* max surface indexes */
+ qfalse, /* flares */
+ "flareshader", /* default flare shader */
+ qfalse, /* wolf lighting model? */
+ 128, /* lightmap width/height */
+ 1.0f, /* lightmap gamma */
+ 200.0f, /* lightmap exposure */
+ 1.0f, /* lightmap compensate */
+ 0.4f, /* lightgrid scale */
+ 0.6f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qtrue, /* disable shader lightstyles hack */
+ qtrue, /* keep light entities on bsp */
+ 4, /* default patchMeta subdivisions tolerance */
+ qtrue, /* patch casting enabled */
+ qtrue, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "%s.tga", /* minimap name format */
+ "IBSP", /* bsp file prefix */
+ 46, /* bsp file version */
+ qfalse, /* cod-style lump len/ofs order */
+ LoadIBSPFile, /* bsp load function */
+ WriteIBSPFile, /* bsp write function */
+
+ {
+ /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */
+
+ /* default */
+ { "default", Q_CONT_SOLID, -1, 0, -1, C_SOLID, -1 },
+
+
+ /* ydnar */
+ { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 },
+ { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 },
+ { "skip", 0, 0, 0, 0, C_SKIP, 0 },
+
+
+ /* compiler */
+ { "origin", Q_CONT_ORIGIN, Q_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID },
+ { "areaportal", Q_CONT_AREAPORTAL, Q_CONT_SOLID, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID },
+ { "trans", Q_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 },
+ { "detail", Q_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 },
+ { "structural", Q_CONT_STRUCTURAL, 0, 0, 0, C_STRUCTURAL, 0 },
+ { "hint", 0, 0, Q_SURF_HINT, 0, C_HINT, 0 },
+ { "nodraw", 0, 0, Q_SURF_NODRAW, 0, C_NODRAW, 0 },
+
+ { "alphashadow", 0, 0, Q_SURF_ALPHASHADOW, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 },
+ { "lightfilter", 0, 0, Q_SURF_LIGHTFILTER, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 },
+ { "nolightmap", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 },
+ { "pointlight", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 },
+
+
+ /* game */
+ { "nonsolid", 0, Q_CONT_SOLID, Q_SURF_NONSOLID, 0, 0, C_SOLID },
+
+ { "trigger", Q_CONT_TRIGGER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+
+ { "water", Q_CONT_WATER, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID },
+ { "slime", Q_CONT_SLIME, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID },
+ { "lava", Q_CONT_LAVA, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID },
+
+ { "playerclip", Q_CONT_PLAYERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID },
+ { "monsterclip", Q_CONT_MONSTERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID },
+ { "nodrop", Q_CONT_NODROP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+
+ { "clusterportal", Q_CONT_CLUSTERPORTAL, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+ { "donotenter", Q_CONT_DONOTENTER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+ { "botclip", Q_CONT_BOTCLIP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+
+ { "fog", Q_CONT_FOG, Q_CONT_SOLID, 0, 0, C_FOG, C_SOLID },
+ { "sky", 0, 0, Q_SURF_SKY, 0, C_SKY, 0 },
+
+ { "slick", 0, 0, Q_SURF_SLICK, 0, 0, 0 },
+
+ { "noimpact", 0, 0, Q_SURF_NOIMPACT, 0, 0, 0 },
+ { "nomarks", 0, 0, Q_SURF_NOMARKS, 0, C_NOMARKS, 0 },
+ { "ladder", 0, 0, Q_SURF_LADDER, 0, 0, 0 },
+ { "nodamage", 0, 0, Q_SURF_NODAMAGE, 0, 0, 0 },
+ { "metalsteps", 0, 0, Q_SURF_METALSTEPS, 0, 0, 0 },
+ { "flesh", 0, 0, Q_SURF_FLESH, 0, 0, 0 },
+ { "nosteps", 0, 0, Q_SURF_NOSTEPS, 0, 0, 0 },
+ { "nodlight", 0, 0, Q_SURF_NODLIGHT, 0, 0, 0 },
+ { "dust", 0, 0, Q_SURF_DUST, 0, 0, 0 },
+
+
+ /* null */
+ { NULL, 0, 0, 0, 0, 0, 0 }
+ }
+}
+
+
+
+/* end marker */
+#endif
+
qfalse, /* wolf lighting model? */
512, /* lightmap width/height */
1.0f, /* lightmap gamma */
+ 1.0f, /* lightmap exposure */
1.0f, /* lightmap compensate */
+ 1.0f, /* lightgrid scale */
+ 1.0f, /* lightgrid ambient scale */
+ qtrue, /* light angle attenuation uses half-lambert curve */
+ qtrue, /* disable shader lightstyles hack */
+ qtrue, /* keep light entities on bsp */
+ 8, /* default patchMeta subdivisions tolerance */
+ qtrue, /* patch casting enabled */
+ qtrue, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 256, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_WHITE, /* minimap mode */
+ "../minimaps/%s.tga", /* minimap name format */
"FBSP", /* bsp file prefix */
1, /* bsp file version */
qfalse, /* cod-style lump len/ofs order */
qfalse, /* wolf lighting model? */
128, /* lightmap width/height */
1.0f, /* lightmap gamma */
+ 1.0f, /* lightmap exposure */
1.0f, /* lightmap compensate */
+ 1.0f, /* lightgrid scale */
+ 1.0f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qfalse, /* disable shader lightstyles hack */
+ qfalse, /* keep light entities on bsp */
+ 8, /* default patchMeta subdivisions tolerance */
+ qfalse, /* patch casting enabled */
+ qfalse, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "%s.tga", /* minimap name format */
"IBSP", /* bsp file prefix */
46, /* bsp file version */
qfalse, /* cod-style lump len/ofs order */
{
"quakelive", /* -game x */
- "baseq3", /* default base game data dir */
- ".q3a", /* unix home sub-dir */
- "quake", /* magic path word */
+ "baseq3", /* default base game data dir (FIXME what does quake live really use?) */
+ ".q3a", /* unix home sub-dir (FIXME what does quake live really use?) */
+ "quake", /* magic path word (FIXME where does quake live install to?) */
"scripts", /* shader directory */
64, /* max lightmapped surface verts */
999, /* max surface verts */
qfalse, /* wolf lighting model? */
128, /* lightmap width/height */
1.0f, /* lightmap gamma */
+ 1.0f, /* lightmap exposure */
1.0f, /* lightmap compensate */
+ 1.0f, /* lightgrid scale */
+ 1.0f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qfalse, /* disable shader lightstyles hack */
+ qfalse, /* keep light entities on bsp */
+ 8, /* default patchMeta subdivisions tolerance */
+ qfalse, /* patch casting enabled */
+ qfalse, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "%s.tga", /* minimap name format */
"IBSP", /* bsp file prefix */
47, /* bsp file version */
qfalse, /* cod-style lump len/ofs order */
qfalse, /* wolf lighting model? */
128, /* lightmap width/height */
1.0f, /* lightmap gamma */
+ 1.0f, /* lightmap exposure */
1.0f, /* lightmap compensate */
+ 1.0f, /* lightgrid scale */
+ 1.0f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qfalse, /* disable shader lightstyles hack */
+ qfalse, /* keep light entities on bsp */
+ 8, /* default patchMeta subdivisions tolerance */
+ qfalse, /* patch casting enabled */
+ qfalse, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "%s.tga", /* minimap name format */
"IBSP", /* bsp file prefix */
46, /* bsp file version */
qfalse, /* cod-style lump len/ofs order */
qfalse, /* wolf lighting model? */
128, /* lightmap width/height */
1.0f, /* lightmap gamma */
+ 1.0f, /* lightmap exposure */
1.0f, /* lightmap compensate */
+ 1.0f, /* lightgrid scale */
+ 1.0f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qfalse, /* disable shader lightstyles hack */
+ qfalse, /* keep light entities on bsp */
+ 8, /* default patchMeta subdivisions tolerance */
+ qfalse, /* patch casting enabled */
+ qfalse, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "%s.tga", /* minimap name format */
"RBSP", /* bsp file prefix */
1, /* bsp file version */
qfalse, /* cod-style lump len/ofs order */
qfalse, /* wolf lighting model? */
512, /* lightmap width/height */
2.0f, /* lightmap gamma */
+ 1.0f, /* lightmap exposure */
1.0f, /* lightmap compensate */
+ 1.0f, /* lightgrid scale */
+ 1.0f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qtrue, /* disable shader lightstyles hack */
+ qfalse, /* keep light entities on bsp */
+ 8, /* default patchMeta subdivisions tolerance */
+ qfalse, /* patch casting enabled */
+ qtrue, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "%s.tga", /* minimap name format */
"IBSP", /* bsp file prefix */
46, /* bsp file version */
qfalse, /* cod-style lump len/ofs order */
qfalse, /* wolf lighting model? */
128, /* lightmap width/height */
1.0f, /* lightmap gamma */
+ 1.0f, /* lightmap exposure */
1.0f, /* lightmap compensate */
+ 1.0f, /* lightgrid scale */
+ 1.0f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qfalse, /* disable shader lightstyles hack */
+ qfalse, /* keep light entities on bsp */
+ 8, /* default patchMeta subdivisions tolerance */
+ qfalse, /* patch casting enabled */
+ qfalse, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "%s.tga", /* minimap name format */
"IBSP", /* bsp file prefix */
46, /* bsp file version */
qfalse, /* cod-style lump len/ofs order */
qtrue, /* wolf lighting model? */
128, /* lightmap width/height */
1.0f, /* lightmap gamma */
+ 1.0f, /* lightmap exposure */
1.0f, /* lightmap compensate */
+ 1.0f, /* lightgrid scale */
+ 1.0f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qfalse, /* disable shader lightstyles hack */
+ qfalse, /* keep light entities on bsp */
+ 8, /* default patchMeta subdivisions tolerance */
+ qfalse, /* patch casting enabled */
+ qfalse, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "%s.tga", /* minimap name format */
"IBSP", /* bsp file prefix */
47, /* bsp file version */
qfalse, /* cod-style lump len/ofs order */
qtrue, /* wolf lighting model? */
128, /* lightmap width/height */
1.0f, /* lightmap gamma */
+ 1.0f, /* lightmap exposure */
1.0f, /* lightmap compensate */
+ 1.0f, /* lightgrid scale */
+ 1.0f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qfalse, /* disable shader lightstyles hack */
+ qfalse, /* keep light entities on bsp */
+ 8, /* default patchMeta subdivisions tolerance */
+ qfalse, /* patch casting enabled */
+ qfalse, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 0.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "%s.tga", /* minimap name format */
"IBSP", /* bsp file prefix */
47, /* bsp file version */
qfalse, /* cod-style lump len/ofs order */
--- /dev/null
+/* -------------------------------------------------------------------------------
+
+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
+
+----------------------------------------------------------------------------------
+
+This code has been altered significantly from its original form, to support
+several games based on the Quake III Arena engine, in the form of "Q3Map2."
+
+------------------------------------------------------------------------------- */
+
+
+
+/* marker */
+#ifndef GAME_XONOTIC_H
+#define GAME_XONOTIC_H
+
+
+
+/* -------------------------------------------------------------------------------
+
+content and surface flags
+are in game_quake3.h
+
+------------------------------------------------------------------------------- */
+
+
+
+/* -------------------------------------------------------------------------------
+
+game_t struct
+
+------------------------------------------------------------------------------- */
+
+{
+ "xonotic", /* -game x */
+ "data", /* default base game data dir */
+ ".xonotic", /* unix home sub-dir */
+ "xonotic", /* magic path word */
+ "scripts", /* shader directory */
+ 1048575, /* max lightmapped surface verts */
+ 1048575, /* max surface verts */
+ 1048575, /* max surface indexes */
+ qfalse, /* flares */
+ "flareshader", /* default flare shader */
+ qfalse, /* wolf lighting model? */
+ 128, /* lightmap width/height */
+ 1.0f, /* lightmap gamma */
+ 1.0f, /* lightmap exposure */
+ 1.0f, /* lightmap compensate */
+ 1.0f, /* lightgrid scale */
+ 1.0f, /* lightgrid ambient scale */
+ qfalse, /* light angle attenuation uses half-lambert curve */
+ qtrue, /* disable shader lightstyles hack */
+ qtrue, /* keep light entities on bsp */
+ 4, /* default patchMeta subdivisions tolerance */
+ qtrue, /* patch casting enabled */
+ qtrue, /* compile deluxemaps */
+ 0, /* deluxemaps default mode */
+ 512, /* minimap size */
+ 1.0f, /* minimap sharpener */
+ 1.0f/66.0f, /* minimap border */
+ qtrue, /* minimap keep aspect */
+ MINIMAP_MODE_GRAY, /* minimap mode */
+ "../gfx/%s_mini.tga", /* minimap name format */
+ "IBSP", /* bsp file prefix */
+ 46, /* bsp file version */
+ qfalse, /* cod-style lump len/ofs order */
+ LoadIBSPFile, /* bsp load function */
+ WriteIBSPFile, /* bsp write function */
+
+ {
+ /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */
+
+ /* default */
+ { "default", Q_CONT_SOLID, -1, 0, -1, C_SOLID, -1 },
+
+ /* ydnar */
+ { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 },
+ { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 },
+ { "skip", 0, 0, 0, 0, C_SKIP, 0 },
+
+ /* compiler */
+ { "origin", Q_CONT_ORIGIN, Q_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID },
+ { "areaportal", Q_CONT_AREAPORTAL, Q_CONT_SOLID, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID },
+ { "trans", Q_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 },
+ { "detail", Q_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 },
+ { "structural", Q_CONT_STRUCTURAL, 0, 0, 0, C_STRUCTURAL, 0 },
+ { "hint", 0, 0, Q_SURF_HINT, 0, C_HINT, 0 },
+ { "nodraw", 0, 0, Q_SURF_NODRAW, 0, C_NODRAW, 0 },
+
+ { "alphashadow", 0, 0, Q_SURF_ALPHASHADOW, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 },
+ { "lightfilter", 0, 0, Q_SURF_LIGHTFILTER, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 },
+ { "nolightmap", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 },
+ { "pointlight", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 },
+
+ /* game */
+ { "nonsolid", 0, Q_CONT_SOLID, Q_SURF_NONSOLID, 0, 0, C_SOLID },
+
+ { "trigger", Q_CONT_TRIGGER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+
+ { "water", Q_CONT_WATER, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID },
+ { "slime", Q_CONT_SLIME, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID },
+ { "lava", Q_CONT_LAVA, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID },
+
+ { "playerclip", Q_CONT_PLAYERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID },
+ { "monsterclip", Q_CONT_MONSTERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID },
+ { "nodrop", Q_CONT_NODROP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+
+ { "clusterportal", Q_CONT_CLUSTERPORTAL, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+ { "donotenter", Q_CONT_DONOTENTER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+ { "botclip", Q_CONT_BOTCLIP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID },
+
+ { "fog", Q_CONT_FOG, Q_CONT_SOLID, 0, 0, C_FOG, C_SOLID },
+ { "sky", 0, 0, Q_SURF_SKY, 0, C_SKY, 0 },
+
+ { "slick", 0, 0, Q_SURF_SLICK, 0, 0, 0 },
+
+ { "noimpact", 0, 0, Q_SURF_NOIMPACT, 0, 0, 0 },
+ { "nomarks", 0, 0, Q_SURF_NOMARKS, 0, C_NOMARKS, 0 },
+ { "ladder", 0, 0, Q_SURF_LADDER, 0, 0, 0 },
+ { "nodamage", 0, 0, Q_SURF_NODAMAGE, 0, 0, 0 },
+ { "metalsteps", 0, 0, Q_SURF_METALSTEPS, 0, 0, 0 },
+ { "flesh", 0, 0, Q_SURF_FLESH, 0, 0, 0 },
+ { "nosteps", 0, 0, Q_SURF_NOSTEPS, 0, 0, 0 },
+ { "nodlight", 0, 0, Q_SURF_NODLIGHT, 0, 0, 0 },
+ { "dust", 0, 0, Q_SURF_DUST, 0, 0, 0 },
+
+ /* null */
+ { NULL, 0, 0, 0, 0, 0, 0 }
+ }
+}
+
+
+
+/* end marker */
+#endif
+
typedef struct pngBuffer_s
{
byte *buffer;
- int size, offset;
+ png_size_t size, offset;
}
pngBuffer_t;
png_struct *png;
png_info *info, *end;
pngBuffer_t pb;
- int i, bitDepth, colorType, channels;
- png_uint_32 w, h;
+ int bitDepth, colorType, channels;
+ png_uint_32 w, h, i;
byte **rowPointers;
if (!linefile)
Error ("Couldn't open %s\n", filename);
- xml_node = xmlNewNode (NULL, "polyline");
+ xml_node = xmlNewNode (NULL, (xmlChar*)"polyline");
count = 0;
node = &tree->outside_node;
while (node->occupied > 1)
{
int next;
- portal_t *p, *nextportal;
- node_t *nextnode;
+ portal_t *p, *nextportal = NULL;
+ node_t *nextnode = NULL;
int s;
// find the best portal exit
flags |= LIGHT_GRID;
flags &= ~LIGHT_SURFACES;
}
-
+
+ /* vortex: unnormalized? */
+ if (spawnflags & 32)
+ flags |= LIGHT_UNNORMALIZED;
+
+ /* vortex: distance atten? */
+ if (spawnflags & 64)
+ flags |= LIGHT_ATTEN_DISTANCE;
+
/* store the flags */
light->flags = flags;
if( _color && _color[ 0 ] )
{
sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] );
- ColorNormalize( light->color, light->color );
+ if (!(light->flags & LIGHT_UNNORMALIZED))
+ {
+ ColorNormalize( light->color, light->color );
+ }
}
else
light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f;
+
+ light->extraDist = FloatForKey( e, "_extradist" );
+ if(light->extraDist == 0.0f)
+ light->extraDist = extraDist;
intensity = intensity * pointScale;
light->photons = intensity;
-
+
light->type = EMIT_POINT;
/* set falloff threshold */
float angle;
float add;
float dist;
-
+ float addDeluxe = 0.0f, addDeluxeBounceScale = 0.25f;
+ qboolean angledDeluxe = qtrue;
+ float colorBrightness;
+ qboolean doAddDeluxe = qtrue;
/* get light */
light = trace->light;
/* clear color */
+ trace->forceSubsampling = 0.0f; /* to make sure */
VectorClear( trace->color );
+ VectorClear( trace->colorNoShadow );
+ VectorClear( trace->directionContribution );
+
+ colorBrightness = RGBTOGRAY( light->color ) * ( 1.0f/255.0f );
/* ydnar: early out */
if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f )
float d;
vec3_t pushedOrigin;
-
/* project sample point into light plane */
d = DotProduct( trace->origin, light->normal ) - light->dist;
if( d < 3.0f )
}
/* nudge the point so that it is clearly forward of the light */
- /* so that surfaces meeting a light emiter don't get black edges */
+ /* so that surfaces meeting a light emitter don't get black edges */
if( d > -8.0f && d < 8.0f )
VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin );
else
angle = DotProduct( trace->normal, trace->direction );
/* twosided lighting */
- if( trace->twoSided )
- angle = fabs( angle );
+ if( trace->twoSided && angle < 0 )
+ {
+ angle = -angle;
+
+ /* no deluxemap contribution from "other side" light */
+ doAddDeluxe = qfalse;
+ }
/* attenuate */
angle *= -DotProduct( light->normal, trace->direction );
return 0;
else if( angle < 0.0f &&
(trace->twoSided || (light->flags & LIGHT_TWOSIDED)) )
+ {
angle = -angle;
+
+ /* no deluxemap contribution from "other side" light */
+ doAddDeluxe = qfalse;
+ }
+
+ /* clamp the distance to prevent super hot spots */
+ dist = sqrt(dist * dist + light->extraDist * light->extraDist);
+ if( dist < 16.0f )
+ dist = 16.0f;
+
add = light->photons / (dist * dist) * angle;
+
+ if( deluxemap )
+ {
+ if( angledDeluxe )
+ addDeluxe = light->photons / (dist * dist) * angle;
+ else
+ addDeluxe = light->photons / (dist * dist);
+ }
}
else
{
dist = SetupTrace( trace );
if( dist >= light->envelope )
return 0;
+
+ /* no deluxemap contribution from "other side" light */
+ doAddDeluxe = qfalse;
}
else
return 0;
}
+
+ /* also don't deluxe if the direction is on the wrong side */
+ if(DotProduct(trace->normal, trace->direction) < 0)
+ {
+ /* no deluxemap contribution from "other side" light */
+ doAddDeluxe = qfalse;
+ }
/* ydnar: moved to here */
add = factor * light->add;
+
+ if( deluxemap )
+ addDeluxe = add;
}
}
dist = SetupTrace( trace );
if( dist >= light->envelope )
return 0;
-
+
/* clamp the distance to prevent super hot spots */
+ dist = sqrt(dist * dist + light->extraDist * light->extraDist);
if( dist < 16.0f )
dist = 16.0f;
-
+
/* angle attenuation */
- angle = (light->flags & LIGHT_ATTEN_ANGLE) ? DotProduct( trace->normal, trace->direction ) : 1.0f;
+ if( light->flags & LIGHT_ATTEN_ANGLE )
+ {
+ /* standard Lambert attenuation */
+ float dot = DotProduct( trace->normal, trace->direction );
+
+ /* twosided lighting */
+ if( trace->twoSided && dot < 0 )
+ {
+ dot = -dot;
+
+ /* no deluxemap contribution from "other side" light */
+ doAddDeluxe = qfalse;
+ }
+
+ /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
+ if( lightAngleHL )
+ {
+ if( dot > 0.001f ) // skip coplanar
+ {
+ if( dot > 1.0f ) dot = 1.0f;
+ dot = ( dot * 0.5f ) + 0.5f;
+ dot *= dot;
+ }
+ else
+ dot = 0;
+ }
+
+ angle = dot;
+ }
+ else
+ angle = 1.0f;
+
if( light->angleScale != 0.0f )
{
angle /= light->angleScale;
angle = 1.0f;
}
- /* twosided lighting */
- if( trace->twoSided )
- angle = fabs( angle );
-
/* attenuate */
if( light->flags & LIGHT_ATTEN_LINEAR )
{
add = angle * light->photons * linearScale - (dist * light->fade);
if( add < 0.0f )
add = 0.0f;
+
+ if( deluxemap )
+ {
+ if( angledDeluxe )
+ addDeluxe = angle * light->photons * linearScale - (dist * light->fade);
+ else
+ addDeluxe = light->photons * linearScale - (dist * light->fade);
+
+ if( addDeluxe < 0.0f )
+ addDeluxe = 0.0f;
+ }
}
else
- add = light->photons / (dist * dist) * angle;
+ {
+ add = (light->photons / (dist * dist)) * angle;
+ if( add < 0.0f )
+ add = 0.0f;
+
+ if( deluxemap )
+ {
+ if( angledDeluxe )
+ addDeluxe = (light->photons / (dist * dist)) * angle;
+ else
+ addDeluxe = (light->photons / (dist * dist));
+ }
+
+ if( addDeluxe < 0.0f )
+ addDeluxe = 0.0f;
+ }
/* handle spotlights */
if( light->type == EMIT_SPOT )
{
float distByNormal, radiusAtDist, sampleRadius;
vec3_t pointAtDist, distToSample;
-
-
+
/* do cone calculation */
distByNormal = -DotProduct( trace->displacement, light->normal );
if( distByNormal < 0.0f )
/* attenuate */
if( sampleRadius > (radiusAtDist - 32.0f) )
+ {
add *= ((radiusAtDist - sampleRadius) / 32.0f);
+ if( add < 0.0f )
+ add = 0.0f;
+
+ addDeluxe *= ((radiusAtDist - sampleRadius) / 32.0f);
+
+ if( addDeluxe < 0.0f )
+ addDeluxe = 0.0f;
+ }
}
}
/* get origin and direction */
VectorAdd( trace->origin, light->origin, trace->end );
dist = SetupTrace( trace );
-
+
/* angle attenuation */
- angle = (light->flags & LIGHT_ATTEN_ANGLE)
- ? DotProduct( trace->normal, trace->direction )
- : 1.0f;
-
- /* twosided lighting */
- if( trace->twoSided )
- angle = fabs( angle );
+ if( light->flags & LIGHT_ATTEN_ANGLE )
+ {
+ /* standard Lambert attenuation */
+ float dot = DotProduct( trace->normal, trace->direction );
+
+ /* twosided lighting */
+ if( trace->twoSided && dot < 0 )
+ {
+ dot = -dot;
+
+ /* no deluxemap contribution from "other side" light */
+ doAddDeluxe = qfalse;
+ }
+
+ /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */
+ if( lightAngleHL )
+ {
+ if( dot > 0.001f ) // skip coplanar
+ {
+ if( dot > 1.0f ) dot = 1.0f;
+ dot = ( dot * 0.5f ) + 0.5f;
+ dot *= dot;
+ }
+ else
+ dot = 0;
+ }
+
+ angle = dot;
+ }
+ else
+ angle = 1.0f;
/* attenuate */
add = light->photons * angle;
+
+ if( deluxemap )
+ {
+ if( angledDeluxe )
+ addDeluxe = light->photons * angle;
+ else
+ addDeluxe = light->photons;
+
+ if( addDeluxe < 0.0f )
+ addDeluxe = 0.0f;
+ }
+
if( add <= 0.0f )
return 0;
+
+ /* VorteX: set noShadow color */
+ VectorScale(light->color, add, trace->colorNoShadow);
+
+ addDeluxe *= colorBrightness;
+
+ if( bouncing )
+ {
+ addDeluxe *= addDeluxeBounceScale;
+ if( addDeluxe < 0.00390625f )
+ addDeluxe = 0.00390625f;
+ }
+
+ VectorScale( trace->direction, addDeluxe, trace->directionContribution );
/* setup trace */
trace->testAll = qtrue;
{
/* trace */
TraceLine( trace );
+ trace->forceSubsampling *= add;
if( !(trace->compileFlags & C_SKY) || trace->opaque )
{
VectorClear( trace->color );
+ VectorClear( trace->directionContribution );
+
return -1;
}
}
/* return to sender */
return 1;
}
+ else
+ Error("Light of undefined type!");
+
+ /* VorteX: set noShadow color */
+ VectorScale(light->color, add, trace->colorNoShadow);
/* ydnar: changed to a variable number */
if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) )
return 0;
+
+ addDeluxe *= colorBrightness;
+
+ /* hack land: scale down the radiosity contribution to light directionality.
+ Deluxemaps fusion many light directions into one. In a rtl process all lights
+ would contribute individually to the bump map, so several light sources together
+ would make it more directional (example: a yellow and red lights received from
+ opposing sides would light one side in red and the other in blue, adding
+ the effect of 2 directions applied. In the deluxemapping case, this 2 lights would
+ neutralize each other making it look like having no direction.
+ Same thing happens with radiosity. In deluxemapping case the radiosity contribution
+ is modifying the direction applied from directional lights, making it go closer and closer
+ to the surface normal the bigger is the amount of radiosity received.
+ So, for preserving the directional lights contributions, we scale down the radiosity
+ contribution. It's a hack, but there's a reason behind it */
+ if( bouncing )
+ {
+ addDeluxe *= addDeluxeBounceScale;
+ /* better NOT increase it beyond the original value
+ if( addDeluxe < 0.00390625f )
+ addDeluxe = 0.00390625f;
+ */
+ }
+
+ if(doAddDeluxe)
+ {
+ VectorScale( trace->direction, addDeluxe, trace->directionContribution );
+ }
/* setup trace */
trace->testAll = qfalse;
/* raytrace */
TraceLine( trace );
+ trace->forceSubsampling *= add;
if( trace->passSolid || trace->opaque )
{
VectorClear( trace->color );
+ VectorClear( trace->directionContribution );
+
return -1;
}
if( light->type == EMIT_AREA && faster )
{
/* clamp the distance to prevent super hot spots */
+ dist = sqrt(dist * dist + light->extraDist * light->extraDist);
if( dist < 16.0f )
dist = 16.0f;
-
+
/* attenuate */
add = light->photons / (dist * dist);
}
else if( light->type == EMIT_POINT || light->type == EMIT_SPOT )
{
/* clamp the distance to prevent super hot spots */
+ dist = sqrt(dist * dist + light->extraDist * light->extraDist);
if( dist < 16.0f )
dist = 16.0f;
of dynamically placed entities in the world
*/
-#define MAX_CONTRIBUTIONS 1024
+#define MAX_CONTRIBUTIONS 32768
typedef struct
{
vec3_t dir;
vec3_t color;
+ vec3_t ambient;
int style;
}
contribution_t;
void TraceGrid( int num )
{
- int i, j, x, y, z, mod, step, numCon, numStyles;
- float d;
- vec3_t baseOrigin, cheapColor, color;
+ int i, j, x, y, z, mod, numCon, numStyles;
+ float d, step;
+ vec3_t baseOrigin, cheapColor, color, thisdir;
rawGridPoint_t *gp;
bspGridPoint_t *bgp;
contribution_t contributions[ MAX_CONTRIBUTIONS ];
trace_t trace;
-
/* get grid points */
gp = &rawGridPoints[ num ];
bgp = &bspGridPoints[ num ];
{
/* try to nudge the origin around to find a valid point */
VectorCopy( trace.origin, baseOrigin );
- for( step = 9; step <= 18; step += 9 )
+ for( step = 0; (step += 0.005) <= 1.0; )
{
- for( i = 0; i < 8; i++ )
- {
- VectorCopy( baseOrigin, trace.origin );
- if( i & 1 )
- trace.origin[ 0 ] += step;
- else
- trace.origin[ 0 ] -= step;
-
- if( i & 2 )
- trace.origin[ 1 ] += step;
- else
- trace.origin[ 1 ] -= step;
+ VectorCopy( baseOrigin, trace.origin );
+ trace.origin[ 0 ] += step * (Random() - 0.5) * gridSize[0];
+ trace.origin[ 1 ] += step * (Random() - 0.5) * gridSize[1];
+ trace.origin[ 2 ] += step * (Random() - 0.5) * gridSize[2];
- if( i & 4 )
- trace.origin[ 2 ] += step;
- else
- trace.origin[ 2 ] -= step;
-
- /* ydnar: changed to find cluster num */
- trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
- if( trace.cluster >= 0 )
- break;
- }
-
- if( i != 8 )
+ /* ydnar: changed to find cluster num */
+ trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON );
+ if( trace.cluster >= 0 )
break;
}
/* can't find a valid point at all */
- if( step > 18 )
+ if( step > 1.0 )
return;
}
/* add a contribution */
VectorCopy( trace.color, contributions[ numCon ].color );
VectorCopy( trace.direction, contributions[ numCon ].dir );
+ VectorClear( contributions[ numCon ].ambient );
contributions[ numCon ].style = trace.light->style;
numCon++;
break;
}
+ /////// Floodlighting for point //////////////////
+ //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
+ if( floodlighty )
+ {
+ int k;
+ float addSize, f;
+ vec3_t dir = { 0, 0, 1 };
+ float ambientFrac = 0.25f;
+
+ trace.testOcclusion = qtrue;
+ trace.forceSunlight = qfalse;
+ trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
+ trace.testAll = qtrue;
+
+ for( k = 0; k < 2; k++ )
+ {
+ if( k == 0 ) // upper hemisphere
+ {
+ trace.normal[0] = 0;
+ trace.normal[1] = 0;
+ trace.normal[2] = 1;
+ }
+ else //lower hemisphere
+ {
+ trace.normal[0] = 0;
+ trace.normal[1] = 0;
+ trace.normal[2] = -1;
+ }
+
+ f = FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
+
+ /* add a fraction as pure ambient, half as top-down direction */
+ contributions[ numCon ].color[0]= floodlightRGB[0] * floodlightIntensity * f * ( 1.0f - ambientFrac );
+ contributions[ numCon ].color[1]= floodlightRGB[1] * floodlightIntensity * f * ( 1.0f - ambientFrac );
+ contributions[ numCon ].color[2]= floodlightRGB[2] * floodlightIntensity * f * ( 1.0f - ambientFrac );
+
+ contributions[ numCon ].ambient[0]= floodlightRGB[0] * floodlightIntensity * f * ambientFrac;
+ contributions[ numCon ].ambient[1]= floodlightRGB[1] * floodlightIntensity * f * ambientFrac;
+ contributions[ numCon ].ambient[2]= floodlightRGB[2] * floodlightIntensity * f * ambientFrac;
+
+ contributions[ numCon ].dir[0] = dir[0];
+ contributions[ numCon ].dir[1] = dir[1];
+ contributions[ numCon ].dir[2] = dir[2];
+
+ contributions[ numCon ].style = 0;
+
+ /* push average direction around */
+ addSize = VectorLength( contributions[ numCon ].color );
+ VectorMA( gp->dir, addSize, dir, gp->dir );
+
+ numCon++;
+ }
+ }
+ /////////////////////
+
/* normalize to get primary light direction */
- VectorNormalize( gp->dir, gp->dir );
+ VectorNormalize( gp->dir, thisdir );
/* now that we have identified the primary light direction,
go back and separate all the light into directed and ambient */
+
numStyles = 1;
for( i = 0; i < numCon; i++ )
{
/* get relative directed strength */
- d = DotProduct( contributions[ i ].dir, gp->dir );
+ d = DotProduct( contributions[ i ].dir, thisdir );
+ /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */
+ d = gridAmbientDirectionality + d * (gridDirectionality - gridAmbientDirectionality);
if( d < 0.0f )
d = 0.0f;
/* ambient light will be at 1/4 the value of directed light */
/* (ydnar: nuke this in favor of more dramatic lighting?) */
+ /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */
+// d = 0.25f;
+ /* (Hobbes: always setting it to .25 is hardly any better) */
d = 0.25f * (1.0f - d);
VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] );
+
+ VectorAdd( gp->ambient[ j ], contributions[ i ].ambient, gp->ambient[ j ] );
+
+/*
+ * div0:
+ * the total light average = ambient value + 0.25 * sum of all directional values
+ * we can also get the total light average as 0.25 * the sum of all contributions
+ *
+ * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i)
+ *
+ * THIS YIELDS:
+ * ambient == 0.25 * sum((1 - d_i) contribution_i)
+ *
+ * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE.
+ */
}
/* store off sample */
for( i = 0; i < MAX_LIGHTMAPS; i++ )
{
+#if 0
/* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */
if( !bouncing )
VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] );
+#endif
/* set minimum light and copy off to bytes */
VectorCopy( gp->ambient[ i ], color );
for( j = 0; j < 3; j++ )
if( color[ j ] < minGridLight[ j ] )
color[ j ] = minGridLight[ j ];
- ColorToBytes( color, bgp->ambient[ i ], 1.0f );
- ColorToBytes( gp->directed[ i ], bgp->directed[ i ], 1.0f );
+
+ /* vortex: apply gridscale and gridambientscale here */
+ ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale );
+ ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale );
}
/* debug code */
#endif
/* store direction */
- if( !bouncing )
- NormalToLatLong( gp->dir, bgp->latLong );
+ NormalToLatLong( thisdir, bgp->latLong );
}
SetupEnvelopes( qtrue, fastgrid );
Sys_Printf( "--- TraceGrid ---\n" );
+ inGrid = qtrue;
RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
+ inGrid = qfalse;
Sys_Printf( "%d x %d x %d = %d grid\n",
gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints );
if( dirty )
{
Sys_Printf( "--- DirtyRawLightmap ---\n" );
-
-
-
-
RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
}
+ /* floodlight pass */
+ FloodlightRawLightmaps();
/* ydnar: set up light envelopes */
SetupEnvelopes( qfalse, fast );
{
/* store off the bsp between bounces */
StoreSurfaceLightmaps();
+ UnparseEntities();
Sys_Printf( "Writing %s\n", source );
WriteBSPFile( source );
/* flag bouncing */
bouncing = qtrue;
VectorClear( ambientColor );
+ floodlighty = qfalse;
/* generate diffuse lights */
RadFreeLights();
gridBoundsCulled = 0;
Sys_Printf( "--- BounceGrid ---\n" );
+ inGrid = qtrue;
RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid );
+ inGrid = qfalse;
Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled );
Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled );
}
float f;
char mapSource[ 1024 ];
const char *value;
+ int lightmapMergeSize = 0;
+ qboolean lightSamplesInsist = qfalse;
/* note it */
Sys_Printf( "--- Light ---\n" );
-
+ Sys_Printf( "--- ProcessGameSpecific ---\n" );
+
/* set standard game flags */
wolfLight = game->wolfLight;
+ if (wolfLight == qtrue)
+ Sys_Printf( " lightning model: wolf\n" );
+ else
+ Sys_Printf( " lightning model: quake3\n" );
+
lmCustomSize = game->lightmapSize;
+ Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize );
+
lightmapGamma = game->lightmapGamma;
+ Sys_Printf( " lightning gamma: %f\n", lightmapGamma );
+
lightmapCompensate = game->lightmapCompensate;
+ Sys_Printf( " lightning compensation: %f\n", lightmapCompensate );
+
+ lightmapExposure = game->lightmapExposure;
+ Sys_Printf( " lightning exposure: %f\n", lightmapExposure );
+
+ gridScale = game->gridScale;
+ Sys_Printf( " lightgrid scale: %f\n", gridScale );
+
+ gridAmbientScale = game->gridAmbientScale;
+ Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale );
+
+ lightAngleHL = game->lightAngleHL;
+ if( lightAngleHL )
+ Sys_Printf( " half lambert light angle attenuation enabled \n" );
+
+ noStyles = game->noStyles;
+ if (noStyles == qtrue)
+ Sys_Printf( " shader lightstyles hack: disabled\n" );
+ else
+ Sys_Printf( " shader lightstyles hack: enabled\n" );
+
+ keepLights = game->keepLights;
+ if (keepLights == qtrue)
+ Sys_Printf( " keep lights: enabled\n" );
+ else
+ Sys_Printf( " keep lights: disabled\n" );
+
+ patchShadows = game->patchShadows;
+ if (patchShadows == qtrue)
+ Sys_Printf( " patch shadows: enabled\n" );
+ else
+ Sys_Printf( " patch shadows: disabled\n" );
+
+ deluxemap = game->deluxeMap;
+ deluxemode = game->deluxeMode;
+ if (deluxemap == qtrue)
+ {
+ if (deluxemode)
+ Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" );
+ else
+ Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" );
+ }
+ else
+ Sys_Printf( " deluxemapping: disabled\n" );
+
+ Sys_Printf( "--- ProcessCommandLine ---\n" );
/* process commandline arguments */
for( i = 1; i < (argc - 1); i++ )
Sys_Printf( "All light scaled by %f\n", f );
i++;
}
+
+ else if( !strcmp( argv[ i ], "-gridscale" ) )
+ {
+ f = atof( argv[ i + 1 ] );
+ Sys_Printf( "Grid lightning scaled by %f\n", f );
+ gridScale *= f;
+ i++;
+ }
+
+ else if( !strcmp( argv[ i ], "-gridambientscale" ) )
+ {
+ f = atof( argv[ i + 1 ] );
+ Sys_Printf( "Grid ambient lightning scaled by %f\n", f );
+ gridAmbientScale *= f;
+ i++;
+ }
+
+ else if( !strcmp( argv[ i ], "-griddirectionality" ) )
+ {
+ f = atof( argv[ i + 1 ] );
+ if(f > 1) f = 1;
+ if(f < gridAmbientDirectionality) gridAmbientDirectionality = f;
+ Sys_Printf( "Grid directionality is %f\n", f );
+ gridDirectionality = f;
+ i++;
+ }
+
+ else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) )
+ {
+ f = atof( argv[ i + 1 ] );
+ if(f < -1) f = -1;
+ if(f > gridDirectionality) gridDirectionality = f;
+ Sys_Printf( "Grid ambient directionality is %f\n", f );
+ gridAmbientDirectionality = f;
+ i++;
+ }
else if( !strcmp( argv[ i ], "-gamma" ) )
{
i++;
}
+ else if( !strcmp( argv[ i ], "-exposure" ) )
+ {
+ f = atof( argv[ i + 1 ] );
+ lightmapExposure = f;
+ Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
+ i++;
+ }
+
else if( !strcmp( argv[ i ], "-compensate" ) )
{
f = atof( argv[ i + 1 ] );
i++;
}
+ else if( !strcmp( argv[ i ], "-randomsamples" ) )
+ {
+ lightRandomSamples = qtrue;
+ Sys_Printf( "Random sampling enabled\n", lightRandomSamples );
+ }
+
else if( !strcmp( argv[ i ], "-samples" ) )
{
+ if(*argv[i+1] == '+')
+ lightSamplesInsist = qtrue;
+ else
+ lightSamplesInsist = qfalse;
lightSamples = atoi( argv[ i + 1 ] );
if( lightSamples < 1 )
lightSamples = 1;
i++;
}
+ else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) )
+ {
+ lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] );
+ if( lightSamplesSearchBoxSize <= 0 )
+ lightSamplesSearchBoxSize = 1;
+ if( lightSamplesSearchBoxSize > 4 )
+ lightSamplesSearchBoxSize = 4; /* more makes no sense */
+ else if( lightSamplesSearchBoxSize != 1 )
+ Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize );
+ i++;
+ }
+
else if( !strcmp( argv[ i ], "-filter" ) )
{
filter = qtrue;
Sys_Printf( "Dark lightmap seams enabled\n" );
}
-
-
-
-
-
-
else if( !strcmp( argv[ i ], "-shadeangle" ) )
{
shadeAngleDegrees = atof( argv[ i + 1 ] );
Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance );
i++;
}
-
else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) )
{
deluxemap = qtrue;
Sys_Printf( "Generating deluxemaps for average light direction\n" );
}
-
+ else if( !strcmp( argv[ i ], "-deluxemode" ))
+ {
+ deluxemode = atoi( argv[ i + 1 ] );
+ if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0)
+ {
+ Sys_Printf( "Generating modelspace deluxemaps\n" );
+ deluxemode = 0;
+ }
+ else
+ Sys_Printf( "Generating tangentspace deluxemaps\n" );
+ i++;
+ }
+ else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) )
+ {
+ deluxemap = qfalse;
+ Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" );
+ }
else if( !strcmp( argv[ i ], "-external" ) )
{
externalLightmaps = qtrue;
}
}
+ else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) )
+ {
+ lmLimitSize = atoi( argv[ i + 1 ] );
+
+ i++;
+ Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize );
+ }
+
+ else if( !strcmp( argv[ i ], "-lightmapdir" ) )
+ {
+ lmCustomDir = argv[i + 1];
+ i++;
+ Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir );
+ externalLightmaps = qtrue;
+ Sys_Printf( "Storing all lightmaps externally\n" );
+ }
+
/* ydnar: add this to suppress warnings */
else if( !strcmp( argv[ i ], "-custinfoparms") )
{
wolfLight = qfalse;
Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" );
}
+
+ else if( !strcmp( argv[ i ], "-extradist" ) )
+ {
+ extraDist = atof( argv[ i + 1 ] );
+ if( extraDist < 0 )
+ extraDist = 0;
+ i++;
+ Sys_Printf( "Default extra radius set to %f units\n", extraDist );
+ }
else if( !strcmp( argv[ i ], "-sunonly" ) )
{
noCollapse = qtrue;
Sys_Printf( "Identical lightmap collapsing disabled\n" );
}
+
+ else if( !strcmp( argv[ i ], "-nolightmapsearch" ) )
+ {
+ lightmapSearchBlockSize = 1;
+ Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" );
+ }
+
+ else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) )
+ {
+ lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1]));
+ ++i;
+ Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize );
+ }
+
+ else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) )
+ {
+ lightmapSearchBlockSize = atoi(argv[i+1]);
+ ++i;
+ Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize );
+ }
else if( !strcmp( argv[ i ], "-shade" ) )
{
i++;
Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize );
}
+ else if( !strcmp( argv[ i ], "-minsamplesize" ) )
+ {
+ minSampleSize = atoi( argv[ i + 1 ] );
+ if( minSampleSize < 1 )
+ minSampleSize = 1;
+ i++;
+ Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize );
+ }
+ else if( !strcmp( argv[ i ], "-samplescale" ) )
+ {
+ sampleScale = atoi( argv[ i + 1 ] );
+ i++;
+ Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale);
+ }
else if( !strcmp( argv[ i ], "-novertex" ) )
{
noVertexLighting = qtrue;
loMem = qtrue;
Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
}
+ else if( !strcmp( argv[ i ], "-lightanglehl" ) )
+ {
+ if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL )
+ {
+ lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 );
+ if( lightAngleHL )
+ Sys_Printf( "Enabling half lambert light angle attenuation\n" );
+ else
+ Sys_Printf( "Disabling half lambert light angle attenuation\n" );
+ }
+ }
else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) )
{
noStyles = qtrue;
Sys_Printf( "Disabling lightstyles\n" );
}
+ else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) )
+ {
+ noStyles = qfalse;
+ Sys_Printf( "Enabling lightstyles\n" );
+ }
+ else if( !strcmp( argv[ i ], "-keeplights" ))
+ {
+ keepLights = qtrue;
+ Sys_Printf( "Leaving light entities on map after compile\n" );
+ }
else if( !strcmp( argv[ i ], "-cpma" ) )
{
cpmaHack = qtrue;
Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
}
+ else if( !strcmp( argv[ i ], "-floodlight" ) )
+ {
+ floodlighty = qtrue;
+ Sys_Printf( "FloodLighting enabled\n" );
+ }
+ else if( !strcmp( argv[ i ], "-debugnormals" ) )
+ {
+ debugnormals = qtrue;
+ Sys_Printf( "DebugNormals enabled\n" );
+ }
+ else if( !strcmp( argv[ i ], "-lowquality" ) )
+ {
+ floodlight_lowquality = qtrue;
+ Sys_Printf( "Low Quality FloodLighting enabled\n" );
+ }
/* r7: dirtmapping */
else if( !strcmp( argv[ i ], "-dirty" ) )
Sys_Printf( "Enabling randomized dirtmapping\n" );
else
Sys_Printf( "Enabling ordered dir mapping\n" );
+ i++;
}
else if( !strcmp( argv[ i ], "-dirtdepth" ) )
{
if( dirtDepth <= 0.0f )
dirtDepth = 128.0f;
Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth );
+ i++;
}
else if( !strcmp( argv[ i ], "-dirtscale" ) )
{
if( dirtScale <= 0.0f )
dirtScale = 1.0f;
Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale );
+ i++;
}
else if( !strcmp( argv[ i ], "-dirtgain" ) )
{
if( dirtGain <= 0.0f )
dirtGain = 1.0f;
Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain );
+ i++;
+ }
+ else if( !strcmp( argv[ i ], "-trianglecheck" ) )
+ {
+ lightmapTriangleCheck = qtrue;
+ }
+ else if( !strcmp( argv[ i ], "-extravisnudge" ) )
+ {
+ lightmapExtraVisClusterNudge = qtrue;
+ }
+ else if( !strcmp( argv[ i ], "-fill" ) )
+ {
+ lightmapFill = qtrue;
+ Sys_Printf( "Filling lightmap colors from surrounding pixels to improve JPEG compression\n" );
}
-
/* unhandled args */
else
+ {
Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] );
+ }
}
+
+ /* fix up samples count */
+ if(lightRandomSamples)
+ {
+ if(!lightSamplesInsist)
+ {
+ /* approximately match -samples in quality */
+ switch(lightSamples)
+ {
+ /* somewhat okay */
+ case 1:
+ case 2:
+ lightSamples = 16;
+ Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
+ break;
+
+ /* good */
+ case 3:
+ lightSamples = 64;
+ Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
+ break;
+
+ /* perfect */
+ case 4:
+ lightSamples = 256;
+ Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples );
+ break;
+
+ default: break;
+ }
+ }
+ }
+
+ /* fix up lightmap search power */
+ if(lightmapMergeSize)
+ {
+ lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize);
+ if(lightmapSearchBlockSize < 1)
+ lightmapSearchBlockSize = 1;
+
+ Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize );
+ }
/* clean up map name */
strcpy( source, ExpandArg( argv[ i ] ) );
/* parse bsp entities */
ParseEntities();
+
+ /* inject command line parameters */
+ InjectCommandLine(argv, 0, argc - 1);
/* load map file */
value = ValueForKey( &entities[ 0 ], "_keepLights" );
if( value[ 0 ] != '1' )
- LoadMapFile( mapSource, qtrue );
+ LoadMapFile( mapSource, qtrue, qfalse );
/* set the entity/model origins and init yDrawVerts */
SetEntityOrigins();
/* ydnar: set up optimization */
SetupBrushes();
SetupDirt();
+ SetupFloodLight();
SetupSurfaceLightmaps();
/* initialize the surface facet tracing */
static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, shaderInfo_t *si,
float scale, float subdivide, qboolean original, radWinding_t *rw, clipWork_t *cw )
{
- int i, style;
+ int i, style = 0;
float dist, area, value;
vec3_t mins, maxs, normal, d1, d2, cross, color, gradient;
light_t *light, *splash;
light->falloffTolerance = falloffTolerance;
/* bouncing light? */
- if( bouncing == qfalse )
+ if( !bouncing )
{
/* handle first-pass lights in normal q3a style */
value = si->value;
/* find nodraw bit */
contentFlags = surfaceFlags = compileFlags = 0;
ApplySurfaceParm( "nodraw", &contentFlags, &surfaceFlags, &compileFlags );
+
+ // jal : avoid bouncing on trans surfaces
+ ApplySurfaceParm( "trans", &contentFlags, &surfaceFlags, &compileFlags );
/* early outs? */
if( scale <= 0.0f || (si->compileFlags & C_SKY) || si->autosprite ||
#define GROW_TRACE_NODES 16384 //% 16384
#define GROW_NODE_ITEMS 16 //% 256
-#define MAX_TW_VERTS 12
+#define MAX_TW_VERTS 24 // vortex: increased from 12 to 24 for ability co compile some insane maps with large curve count
#define TRACE_ON_EPSILON 0.1f
typedef struct traceInfo_s
{
shaderInfo_t *si;
- int surfaceNum, castShadows;
+ int surfaceNum, castShadows, skipGrid;
}
traceInfo_t;
{
if( traceInfos[ num ].si == ti->si &&
traceInfos[ num ].surfaceNum == ti->surfaceNum &&
- traceInfos[ num ].castShadows == ti->castShadows )
+ traceInfos[ num ].castShadows == ti->castShadows &&
+ traceInfos[ num ].skipGrid == ti->skipGrid )
return num;
}
memset( &traceNodes[ numTraceNodes ], 0, sizeof( traceNode_t ) );
traceNodes[ numTraceNodes ].type = TRACE_LEAF;
ClearBounds( traceNodes[ numTraceNodes ].mins, traceNodes[ numTraceNodes ].maxs );
+
+ /* Sys_Printf("alloc node %d\n", numTraceNodes); */
+
numTraceNodes++;
/* return the count */
static int SetupTraceNodes_r( int bspNodeNum )
{
- int i, nodeNum, bspLeafNum;
+ int i, nodeNum, bspLeafNum, newNode;
bspPlane_t *plane;
bspNode_t *bspNode;
bspLeafNum = -bspNode->children[ i ] - 1;
/* new code */
- traceNodes[ nodeNum ].children[ i ] = AllocTraceNode();
+ newNode = AllocTraceNode();
+ traceNodes[ nodeNum ].children[ i ] = newNode;
+ /* have to do this separately, as gcc first executes LHS, then RHS, and if a realloc took place, this fails */
+
if( bspLeafs[ bspLeafNum ].cluster == -1 )
traceNodes[ traceNodes[ nodeNum ].children[ i ] ].type = TRACE_LEAF_SOLID;
}
/* normal node */
else
- traceNodes[ nodeNum ].children[ i ] = SetupTraceNodes_r( bspNode->children[ i ] );
+ {
+ newNode = SetupTraceNodes_r( bspNode->children[ i ] );
+ traceNodes[ nodeNum ].children[ i ] = newNode;
+ }
+
+ if(traceNodes[ nodeNum ].children[ i ] == 0)
+ Error( "Invalid tracenode allocated" );
}
+
+ /* Sys_Printf("node %d children: %d %d\n", nodeNum, traceNodes[ nodeNum ].children[0], traceNodes[ nodeNum ].children[1]); */
/* return node number */
return nodeNum;
mid.xyz[ k ] = -plane[ 3 ];
else
mid.xyz[ k ] = a->xyz[ k ] + frac * (b->xyz[ k ] - a->xyz[ k ]);
-
- /* set texture coordinates */
- if( k > 1 )
- continue;
- mid.st[ 0 ] = a->st[ 0 ] + frac * (b->st[ 0 ] - a->st[ 0 ]);
- mid.st[ 1 ] = a->st[ 1 ] + frac * (b->st[ 1 ] - a->st[ 1 ]);
}
+ /* set texture coordinates */
+ mid.st[ 0 ] = a->st[ 0 ] + frac * (b->st[ 0 ] - a->st[ 0 ]);
+ mid.st[ 1 ] = a->st[ 1 ] + frac * (b->st[ 1 ] - a->st[ 1 ]);
/* copy midpoint to front and back polygons */
front->v[ front->numVerts++ ] = mid;
-/*
-FilterPointToTraceNodes_r() - ydnar
-debugging tool
-*/
-
-static int FilterPointToTraceNodes_r( vec3_t pt, int nodeNum )
-{
- float dot;
- traceNode_t *node;
-
-
- if( nodeNum < 0 || nodeNum >= numTraceNodes )
- return -1;
-
- node = &traceNodes[ nodeNum ];
-
- if( node->type >= 0 )
- {
- dot = DotProduct( pt, node->plane ) - node->plane[ 3 ];
- if( dot > -0.001f )
- FilterPointToTraceNodes_r( pt, node->children[ 0 ] );
- if( dot < 0.001f )
- FilterPointToTraceNodes_r( pt, node->children[ 1 ] );
- return -1;
- }
-
- Sys_Printf( "%d ", nodeNum );
-
- return nodeNum;
-}
-
-
-
/*
FilterTraceWindingIntoNodes_r() - ydnar
filters a trace winding into the raytracing tree
ti.si = info->si;
ti.castShadows = info->castShadows;
ti.surfaceNum = model->firstBSPBrush + i;
+ ti.skipGrid = (ds->surfaceType == MST_PATCH);
/* choose which node (normal or skybox) */
if( info->parentSurfaceNum >= 0 )
/* setup trace info */
ti.castShadows = castShadows;
ti.surfaceNum = -1;
+ ti.skipGrid = qtrue; // also ignore picomodels when skipping patches
/* setup trace winding */
memset( &tw, 0, sizeof( tw ) );
/* external model */
default:
frame = IntForKey( e, "_frame" );
- model = LoadModel( (char*) value, frame );
+ model = LoadModel( value, frame );
if( model == NULL )
continue;
PopulateWithPicoModel( castShadows, model, transform );
/* external model */
default:
frame = IntForKey( e, "_frame2" );
- model = LoadModel( (char*) value, frame );
+ model = LoadModel( value, frame );
if( model == NULL )
continue;
PopulateWithPicoModel( castShadows, model, transform );
if( ti->castShadows != 1 )
return qfalse;
}
-
+
/* receive shadows from same group and worldspawn group */
else if( trace->recvShadows > 1 )
{
return qfalse;
}
+ /* skip patches when doing the grid (FIXME this is an ugly hack) */
+ if( inGrid )
+ {
+ if (ti->skipGrid)
+ return qfalse;
+ }
+
/* begin calculating determinant - also used to calculate u parameter */
CrossProduct( trace->direction, tt->edge2, pvec );
trace->opaque = qtrue;
return qtrue;
}
+
+ /* force subsampling because the lighting is texture dependent */
+ trace->forceSubsampling = 1.0;
/* try to avoid double shadows near triangle seams */
if( u < -ASLF_EPSILON || u > (1.0f + ASLF_EPSILON) ||
/* check filter for opaque */
if( trace->color[ 0 ] <= 0.001f && trace->color[ 1 ] <= 0.001f && trace->color[ 2 ] <= 0.001f )
{
+ VectorClear( trace->color );
VectorMA( trace->origin, depth, trace->direction, trace->hit );
trace->opaque = qtrue;
return qtrue;
int i;
float max, gamma;
vec3_t sample;
+ float inv, dif;
/* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */
/* gamma */
sample[ i ] = pow( sample[ i ] / 255.0f, gamma ) * 255.0f;
}
-
- /* clamp with color normalization */
- max = sample[ 0 ];
- if( sample[ 1 ] > max )
- max = sample[ 1 ];
- if( sample[ 2 ] > max )
- max = sample[ 2 ];
- if( max > 255.0f )
- VectorScale( sample, (255.0f / max), sample );
+
+ if (lightmapExposure == 1)
+ {
+ /* clamp with color normalization */
+ max = sample[ 0 ];
+ if( sample[ 1 ] > max )
+ max = sample[ 1 ];
+ if( sample[ 2 ] > max )
+ max = sample[ 2 ];
+ if( max > 255.0f )
+ VectorScale( sample, (255.0f / max), sample );
+ }
+ else
+ {
+ if (lightmapExposure==0)
+ {
+ lightmapExposure=1.0f;
+ }
+ inv=1.f/lightmapExposure;
+ //Exposure
+
+ max = sample[ 0 ];
+ if( sample[ 1 ] > max )
+ max = sample[ 1 ];
+ if( sample[ 2 ] > max )
+ max = sample[ 2 ];
+
+ dif = (1- exp(-max * inv) ) * 255;
+
+ if (max >0)
+ {
+ dif = dif / max;
+ }
+ else
+ {
+ dif = 0;
+ }
+
+ for (i=0;i<3;i++)
+ {
+ sample[i]*=dif;
+ }
+ }
+
/* compensate for ingame overbrighting/bitshifting */
VectorScale( sample, (1.0f / lightmapCompensate), sample );
#define NUDGE 0.5f
#define BOGUS_NUDGE -99999.0f
-static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )
+static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
{
int i, x, y, numClusters, *clusters, pointCluster, *cluster;
float *luxel, *origin, *normal, d, lightmapSampleOffset;
vec3_t pNormal;
vec3_t vecs[ 3 ];
vec3_t nudged;
+ vec3_t cverts[ 3 ];
+ vec3_t temp;
+ vec4_t sideplane, hostplane;
+ vec3_t origintwo;
+ int j, next;
+ float e;
float *nudge;
static float nudges[][ 2 ] =
{
/* non axial lightmap projection (explicit xyz) */
else
VectorCopy( dv->xyz, origin );
+
+ //////////////////////
+ //27's test to make sure samples stay within the triangle boundaries
+ //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
+ //2) if it does, nudge it onto the correct side.
+
+ if (worldverts!=NULL && lightmapTriangleCheck)
+ {
+ for (j=0;j<3;j++)
+ {
+ VectorCopy(worldverts[j],cverts[j]);
+ }
+ PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
+
+ for (j=0;j<3;j++)
+ {
+ for (i=0;i<3;i++)
+ {
+ //build plane using 2 edges and a normal
+ next=(i+1)%3;
+
+ VectorCopy(cverts[next],temp);
+ VectorAdd(temp,hostplane,temp);
+ PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
+
+ //planetest sample point
+ e=DotProduct(origin,sideplane);
+ e=e-sideplane[3];
+ if (e>0)
+ {
+ //we're bad.
+ //VectorClear(origin);
+ //Move the sample point back inside triangle bounds
+ origin[0]-=sideplane[0]*(e+1);
+ origin[1]-=sideplane[1]*(e+1);
+ origin[2]-=sideplane[2]*(e+1);
+#ifdef DEBUG_27_1
+ VectorClear(origin);
+#endif
+ }
+ }
+ }
+ }
+
+ ////////////////////////
/* planar surfaces have precalculated lightmap vectors for nudging */
if( lm->plane != NULL )
else
origin[ lm->axisNum ] += lightmapSampleOffset;
+ VectorCopy(origin,origintwo);
+ if(lightmapExtraVisClusterNudge)
+ {
+ origintwo[0]+=vecs[2][0];
+ origintwo[1]+=vecs[2][1];
+ origintwo[2]+=vecs[2][2];
+ }
+
/* get cluster */
- pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters );
+ pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
/* another retarded hack, storing nudge count in luxel[ 1 ] */
luxel[ 1 ] = 0.0f;
for( i = 0; i < 3; i++ )
{
/* set nudged point*/
- nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
+ nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
}
nudge += 2;
/* get pvs cluster */
pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
- if( pointCluster >= 0 )
- VectorCopy( nudged, origin );
+ if( pointCluster >= 0 )
+ VectorCopy( nudged, origin );
luxel[ 1 ] += 1.0f;
}
}
than the distance between two luxels (thanks jc :)
*/
-static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )
+static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
{
bspDrawVert_t mid, *dv2[ 3 ];
int max;
/* split the longest edge and map it */
LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
- MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv );
+ MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
/* push the point up a little bit to account for fp creep (fixme: revisit this) */
//% VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
/* recurse to first triangle */
VectorCopy( dv, dv2 );
dv2[ max ] = ∣
- MapTriangle_r( lm, info, dv2, plane, stv, ttv );
+ MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
/* recurse to second triangle */
VectorCopy( dv, dv2 );
dv2[ (max + 1) % 3 ] = ∣
- MapTriangle_r( lm, info, dv2, plane, stv, ttv );
+ MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
}
int i;
vec4_t plane;
vec3_t *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
+ vec3_t worldverts[ 3 ];
/* get plane if possible */
ttv = NULL;
}
+ VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
+ VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
+ VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
+
/* map the vertexes */
- MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
- MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
- MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
+ MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
+ MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
+ MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
/* 2002-11-20: prefer axial triangle edges */
if( mapNonAxial )
{
/* subdivide the triangle */
- MapTriangle_r( lm, info, dv, plane, stv, ttv );
+ MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
return qtrue;
}
dv2[ 2 ] = dv[ (i + 1) % 3 ];
/* map the degenerate triangle */
- MapTriangle_r( lm, info, dv2, plane, stv, ttv );
+ MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
}
}
LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
/* map the vertexes */
- MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv );
- MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv );
+ MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
+ MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
/* 0 and 2 */
if( max == 0 )
}
/* map the vertexes */
- MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
- MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
- MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
- MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv );
+ MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
+ MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
+ MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
+ MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
/* subdivide the quad */
MapQuad_r( lm, info, dv, plane, stv, ttv );
if( MapQuad( lm, info, dv ) )
continue;
- /* get drawverts and map first triangle */
- MapTriangle( lm, info, dv, mapNonAxial );
-
- /* get drawverts and map second triangle */
- dv[ 1 ] = &verts[ pw[ r + 2 ] ];
- dv[ 2 ] = &verts[ pw[ r + 3 ] ];
- MapTriangle( lm, info, dv, mapNonAxial );
+ for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
+ {
+ /* get drawverts and map first triangle */
+ dv[ 1 ] = &verts[ pw[ r + 1 ] ];
+ dv[ 2 ] = &verts[ pw[ r + 2 ] ];
+ MapTriangle( lm, info, dv, mapNonAxial );
+
+ /* get drawverts and map second triangle */
+ dv[ 1 ] = &verts[ pw[ r + 2 ] ];
+ dv[ 2 ] = &verts[ pw[ r + 3 ] ];
+ MapTriangle( lm, info, dv, mapNonAxial );
+ }
}
}
continue;
/* map the fake vert */
- MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL );
+ MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
}
}
}
VectorCopy( trace->normal, normal );
/* check if the normal is aligned to the world-up */
- if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f )
+ if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && ( normal[ 2 ] == 1.0f || normal[ 2 ] == -1.0f ) )
{
if( normal[ 2 ] == 1.0f )
{
/* trace */
TraceLine( trace );
- if( trace->opaque )
+ if( trace->opaque && !(trace->compileFlags & C_SKY) )
{
VectorSubtract( trace->hit, trace->origin, displacement );
gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
rawLightmap_t *lm;
surfaceInfo_t *info;
trace_t trace;
-
+ qboolean noDirty;
+
/* bail if this number exceeds the number of raw lightmaps */
if( rawLightmapNum >= numRawLightmaps )
trace.recvShadows = lm->recvShadows;
trace.numSurfaces = lm->numLightSurfaces;
trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
- trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
+ trace.inhibitRadius = 0.0f;
trace.testAll = qfalse;
/* twosided lighting (may or may not be a good idea for lightmapped stuff) */
break;
}
}
+
+ noDirty = qfalse;
+ for( i = 0; i < trace.numSurfaces; i++ )
+ {
+ /* get surface */
+ info = &surfaceInfos[ trace.surfaces[ i ] ];
+
+ /* check twosidedness */
+ if( info->si->noDirty )
+ {
+ noDirty = qtrue;
+ break;
+ }
+ }
/* gather dirt */
for( y = 0; y < lm->sh; y++ )
/* only look at mapped luxels */
if( *cluster < 0 )
continue;
+
+ /* don't apply dirty on this surface */
+ if( noDirty )
+ {
+ *dirt = 1.0f;
+ continue;
+ }
/* copy to trace */
trace.cluster = *cluster;
//% normal2 = SUPER_NORMAL( x, y );
}
else
- Sys_Printf( "WARNING: Spurious lightmap S vector\n" );
+ {
+ Error( "Spurious lightmap S vector\n" );
+ }
VectorSubtract( origin2, origin, originVecs[ 0 ] );
//% VectorSubtract( normal2, normal, normalVecs[ 0 ] );
recursively subsamples a luxel until its color gradient is low enough or subsampling limit is reached
*/
-static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel )
+static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel, float *lightDeluxel )
{
int b, samples, mapped, lighted;
int cluster[ 4 ];
vec4_t luxel[ 4 ];
+ vec3_t deluxel[ 3 ];
vec3_t origin[ 4 ], normal[ 4 ];
float biasDirs[ 4 ][ 2 ] = { { -1.0f, -1.0f }, { 1.0f, -1.0f }, { -1.0f, 1.0f }, { 1.0f, 1.0f } };
- vec3_t color, total;
+ vec3_t color, direction, total;
/* limit check */
/* sample light */
LightContributionToSample( trace );
+ if(trace->forceSubsampling > 1.0f)
+ {
+ /* alphashadow: we subsample as deep as we can */
+ ++lighted;
+ ++mapped;
+ ++mapped;
+ }
/* add to totals (fixme: make contrast function) */
VectorCopy( trace->color, luxel[ b ] );
+ if(lightDeluxel)
+ {
+ VectorCopy( trace->directionContribution, deluxel[ b ] );
+ }
VectorAdd( total, trace->color, total );
if( (luxel[ b ][ 0 ] + luxel[ b ][ 1 ] + luxel[ b ][ 2 ]) > 0.0f )
lighted++;
{
if( cluster[ b ] < 0 )
continue;
- SubsampleRawLuxel_r( lm, trace, origin[ b ], x, y, (bias * 0.25f), luxel[ b ] );
+ SubsampleRawLuxel_r( lm, trace, origin[ b ], x, y, (bias * 0.5f), luxel[ b ], lightDeluxel ? deluxel[ b ] : NULL );
}
}
//% VectorClear( color );
//% samples = 0;
VectorCopy( lightLuxel, color );
+ if(lightDeluxel)
+ {
+ VectorCopy( lightDeluxel, direction );
+ }
samples = 1;
for( b = 0; b < 4; b++ )
{
if( cluster[ b ] < 0 )
continue;
VectorAdd( color, luxel[ b ], color );
+ if(lightDeluxel)
+ {
+ VectorAdd( direction, deluxel[ b ], direction );
+ }
samples++;
}
color[ 0 ] /= samples;
color[ 1 ] /= samples;
color[ 2 ] /= samples;
-
+
/* add to color */
VectorCopy( color, lightLuxel );
lightLuxel[ 3 ] += 1.0f;
+
+ if(lightDeluxel)
+ {
+ direction[ 0 ] /= samples;
+ direction[ 1 ] /= samples;
+ direction[ 2 ] /= samples;
+ VectorCopy( direction, lightDeluxel );
+ }
+ }
+}
+
+/* A mostly Gaussian-like bounded random distribution (sigma is expected standard deviation) */
+static void GaussLikeRandom(float sigma, float *x, float *y)
+{
+ float r;
+ r = Random() * 2 * Q_PI;
+ *x = sigma * 2.73861278752581783822 * cos(r);
+ *y = sigma * 2.73861278752581783822 * sin(r);
+ r = Random();
+ r = 1 - sqrt(r);
+ r = 1 - sqrt(r);
+ *x *= r;
+ *y *= r;
+}
+static void RandomSubsampleRawLuxel( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel, float *lightDeluxel )
+{
+ int b, mapped;
+ int cluster;
+ vec3_t origin, normal;
+ vec3_t total, totaldirection;
+ float dx, dy;
+
+ VectorClear( total );
+ VectorClear( totaldirection );
+ mapped = 0;
+ for(b = 0; b < lightSamples; ++b)
+ {
+ /* set origin */
+ VectorCopy( sampleOrigin, origin );
+ GaussLikeRandom(bias, &dx, &dy);
+
+ /* calculate position */
+ if( !SubmapRawLuxel( lm, x, y, dx, dy, &cluster, origin, normal ) )
+ {
+ cluster = -1;
+ continue;
+ }
+ mapped++;
+
+ trace->cluster = cluster;
+ VectorCopy( origin, trace->origin );
+ VectorCopy( normal, trace->normal );
+
+ LightContributionToSample( trace );
+ VectorAdd( total, trace->color, total );
+ if(lightDeluxel)
+ {
+ VectorAdd( totaldirection, trace->directionContribution, totaldirection );
+ }
+ }
+
+ /* add to luxel */
+ if( mapped > 0 )
+ {
+ /* average */
+ lightLuxel[ 0 ] = total[ 0 ] / mapped;
+ lightLuxel[ 1 ] = total[ 1 ] / mapped;
+ lightLuxel[ 2 ] = total[ 2 ] / mapped;
+
+ if(lightDeluxel)
+ {
+ lightDeluxel[ 0 ] = totaldirection[ 0 ] / mapped;
+ lightDeluxel[ 1 ] = totaldirection[ 1 ] / mapped;
+ lightDeluxel[ 2 ] = totaldirection[ 2 ] / mapped;
+ }
}
}
#define STACK_LL_SIZE (SUPER_LUXEL_SIZE * 64 * 64)
#define LIGHT_LUXEL( x, y ) (lightLuxels + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE))
+#define LIGHT_DELUXEL( x, y ) (lightDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE))
void IlluminateRawLightmap( int rawLightmapNum )
{
- int i, t, x, y, sx, sy, size, llSize, luxelFilterRadius, lightmapNum;
+ int i, t, x, y, sx, sy, size, luxelFilterRadius, lightmapNum;
int *cluster, *cluster2, mapped, lighted, totalLighted;
+ size_t llSize, ldSize;
rawLightmap_t *lm;
surfaceInfo_t *info;
qboolean filterColor, filterDir;
float brightness;
float *origin, *normal, *dirt, *luxel, *luxel2, *deluxel, *deluxel2;
- float *lightLuxels, *lightLuxel, samples, filterRadius, weight;
- vec3_t color, averageColor, averageDir, total, temp, temp2;
+ unsigned char *flag;
+ float *lightLuxels, *lightDeluxels, *lightLuxel, *lightDeluxel, samples, filterRadius, weight;
+ vec3_t color, direction, averageColor, averageDir, total, temp, temp2;
float tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
trace_t trace;
float stackLightLuxels[ STACK_LL_SIZE ];
{
/* allocate temporary per-light luxel storage */
llSize = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
+ ldSize = lm->sw * lm->sh * SUPER_DELUXEL_SIZE * sizeof( float );
if( llSize <= (STACK_LL_SIZE * sizeof( float )) )
lightLuxels = stackLightLuxels;
else
lightLuxels = safe_malloc( llSize );
+ if(deluxemap)
+ lightDeluxels = safe_malloc( ldSize );
+ else
+ lightDeluxels = NULL;
/* clear luxels */
//% memset( lm->superLuxels[ 0 ], 0, llSize );
{
VectorCopy( ambientColor, luxel );
if( deluxemap )
- VectorScale( normal, 0.00390625f, deluxel );
+ {
+ brightness = RGBTOGRAY( ambientColor ) * ( 1.0f/255.0f );
+
+ // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light
+ if(brightness < 0.00390625f)
+ brightness = 0.00390625f;
+
+ VectorScale( normal, brightness, deluxel );
+ }
luxel[ 3 ] = 1.0f;
}
}
/* setup */
memset( lightLuxels, 0, llSize );
+ if(deluxemap)
+ memset( lightDeluxels, 0, ldSize );
totalLighted = 0;
+ /* determine filter radius */
+ filterRadius = lm->filterRadius > trace.light->filterRadius
+ ? lm->filterRadius
+ : trace.light->filterRadius;
+ if( filterRadius < 0.0f )
+ filterRadius = 0.0f;
+
+ /* set luxel filter radius */
+ luxelFilterRadius = superSample * filterRadius / lm->sampleSize;
+ if( luxelFilterRadius == 0 && (filterRadius > 0.0f || filter) )
+ luxelFilterRadius = 1;
+
+ /* allocate sampling flags storage */
+ if((lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0)
+ {
+ size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( unsigned char );
+ if(lm->superFlags == NULL)
+ lm->superFlags = safe_malloc( size );
+ memset( (void *) lm->superFlags, 0, size );
+ }
+
/* initial pass, one sample per luxel */
for( y = 0; y < lm->sh; y++ )
{
/* get particulars */
lightLuxel = LIGHT_LUXEL( x, y );
- deluxel = SUPER_DELUXEL( x, y );
+ lightDeluxel = LIGHT_DELUXEL( x, y );
origin = SUPER_ORIGIN( x, y );
normal = SUPER_NORMAL( x, y );
-
- /* set contribution count */
- lightLuxel[ 3 ] = 1.0f;
-
- /* setup trace */
- trace.cluster = *cluster;
- VectorCopy( origin, trace.origin );
- VectorCopy( normal, trace.normal );
-
- /* get light for this sample */
- LightContributionToSample( &trace );
- VectorCopy( trace.color, lightLuxel );
-
- /* add to count */
- if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
+ flag = SUPER_FLAG( x, y );
+
+#if 0
+ ////////// 27's temp hack for testing edge clipping ////
+ if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
+ {
+ lightLuxel[ 1 ] = 255;
+ lightLuxel[ 3 ] = 1.0f;
totalLighted++;
-
- /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
- if( deluxemap )
+ }
+ else
+#endif
{
- /* color to grayscale (photoshop rgb weighting) */
- brightness = trace.color[ 0 ] * 0.3f + trace.color[ 1 ] * 0.59f + trace.color[ 2 ] * 0.11f;
- brightness *= (1.0 / 255.0);
- VectorScale( trace.direction, brightness, trace.direction );
- VectorAdd( deluxel, trace.direction, deluxel );
+ /* set contribution count */
+ lightLuxel[ 3 ] = 1.0f;
+
+ /* setup trace */
+ trace.cluster = *cluster;
+ VectorCopy( origin, trace.origin );
+ VectorCopy( normal, trace.normal );
+
+ /* get light for this sample */
+ LightContributionToSample( &trace );
+ VectorCopy( trace.color, lightLuxel );
+
+ /* add the contribution to the deluxemap */
+ if( deluxemap )
+ {
+ VectorCopy( trace.directionContribution, lightDeluxel );
+ }
+
+ /* check for evilness */
+ if(trace.forceSubsampling > 1.0f && (lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0)
+ {
+ totalLighted++;
+ *flag |= FLAG_FORCE_SUBSAMPLING; /* force */
+ }
+ /* add to count */
+ else if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
+ totalLighted++;
}
}
}
if( totalLighted == 0 )
continue;
- /* determine filter radius */
- filterRadius = lm->filterRadius > trace.light->filterRadius
- ? lm->filterRadius
- : trace.light->filterRadius;
- if( filterRadius < 0.0f )
- filterRadius = 0.0f;
-
- /* set luxel filter radius */
- luxelFilterRadius = superSample * filterRadius / lm->sampleSize;
- if( luxelFilterRadius == 0 && (filterRadius > 0.0f || filter) )
- luxelFilterRadius = 1;
-
/* secondary pass, adaptive supersampling (fixme: use a contrast function to determine if subsampling is necessary) */
/* 2003-09-27: changed it so filtering disamples supersampling, as it would waste time */
- if( lightSamples > 1 && luxelFilterRadius == 0 )
+ if( (lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0 )
{
/* walk luxels */
for( y = 0; y < (lm->sh - 1); y++ )
mapped++;
/* get luxel */
+ flag = SUPER_FLAG( sx, sy );
+ if(*flag & FLAG_FORCE_SUBSAMPLING)
+ {
+ /* force a lighted/mapped discrepancy so we subsample */
+ ++lighted;
+ ++mapped;
+ ++mapped;
+ }
lightLuxel = LIGHT_LUXEL( sx, sy );
VectorAdd( total, lightLuxel, total );
if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) > 0.0f )
cluster = SUPER_CLUSTER( sx, sy );
if( *cluster < 0 )
continue;
+ flag = SUPER_FLAG( sx, sy );
+ if(*flag & FLAG_ALREADY_SUBSAMPLED) // already subsampled
+ continue;
lightLuxel = LIGHT_LUXEL( sx, sy );
+ lightDeluxel = LIGHT_DELUXEL( sx, sy );
origin = SUPER_ORIGIN( sx, sy );
/* only subsample shadowed luxels */
//% continue;
/* subsample it */
- SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f, lightLuxel );
+ if(lightRandomSamples)
+ RandomSubsampleRawLuxel( lm, &trace, origin, sx, sy, 0.5f * lightSamplesSearchBoxSize, lightLuxel, deluxemap ? lightDeluxel : NULL );
+ else
+ SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f * lightSamplesSearchBoxSize, lightLuxel, deluxemap ? lightDeluxel : NULL );
+
+ *flag |= FLAG_ALREADY_SUBSAMPLED;
/* debug code to colorize subsampled areas to yellow */
//% luxel = SUPER_LUXEL( lightmapNum, sx, sy );
lm->superLuxels[ lightmapNum ] = safe_malloc( size );
memset( lm->superLuxels[ lightmapNum ], 0, size );
}
-
+
/* set style */
if( lightmapNum > 0 )
{
{
/* setup */
VectorClear( averageColor );
+ VectorClear( averageDir );
samples = 0.0f;
/* cheaper distance-based filtering */
if( *cluster < 0 )
continue;
lightLuxel = LIGHT_LUXEL( sx, sy );
+ lightDeluxel = LIGHT_DELUXEL( sx, sy );
/* create weight */
weight = (abs( sx - x ) == luxelFilterRadius ? 0.5f : 1.0f);
/* scale luxel by filter weight */
VectorScale( lightLuxel, weight, color );
VectorAdd( averageColor, color, averageColor );
+ if(deluxemap)
+ {
+ VectorScale( lightDeluxel, weight, direction );
+ VectorAdd( averageDir, direction, averageDir );
+ }
samples += weight;
}
}
luxel[ 1 ] += averageColor[ 1 ] / samples;
luxel[ 2 ] += averageColor[ 2 ] / samples;
}
+
+ if(deluxemap)
+ {
+ /* scale into luxel */
+ deluxel = SUPER_DELUXEL( x, y );
+ deluxel[ 0 ] += averageDir[ 0 ] / samples;
+ deluxel[ 1 ] += averageDir[ 1 ] / samples;
+ deluxel[ 2 ] += averageDir[ 2 ] / samples;
+ }
}
/* single sample */
{
/* get particulars */
lightLuxel = LIGHT_LUXEL( x, y );
+ lightDeluxel = LIGHT_DELUXEL( x, y );
luxel = SUPER_LUXEL( lightmapNum, x, y );
+ deluxel = SUPER_DELUXEL( x, y );
/* handle negative light */
if( trace.light->flags & LIGHT_NEGATIVE )
/* handle normal light */
else
VectorAdd( luxel, lightLuxel, luxel );
+
+ if(deluxemap)
+ {
+ VectorAdd( deluxel, lightDeluxel, deluxel );
+ }
}
}
}
/* free temporary luxels */
if( lightLuxels != stackLightLuxels )
free( lightLuxels );
+
+ if(deluxemap)
+ free( lightDeluxels );
}
/* free light list */
FreeTraceLights( &trace );
+ /* floodlight pass */
+ if( floodlighty )
+ FloodlightIlluminateLightmap(lm);
+
+ if (debugnormals)
+ {
+ for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+ {
+ /* early out */
+ if( lm->superLuxels[ lightmapNum ] == NULL )
+ continue;
+
+ for( y = 0; y < lm->sh; y++ )
+ {
+ for( x = 0; x < lm->sw; x++ )
+ {
+ /* get cluster */
+ cluster = SUPER_CLUSTER( x, y );
+ //% if( *cluster < 0 )
+ //% continue;
+
+ /* get particulars */
+ luxel = SUPER_LUXEL( lightmapNum, x, y );
+ normal = SUPER_NORMAL ( x, y );
+
+ luxel[0]=(normal[0]*127)+127;
+ luxel[1]=(normal[1]*127)+127;
+ luxel[2]=(normal[2]*127)+127;
+ }
+ }
+ }
+ }
+
/* -----------------------------------------------------------------
dirt pass
----------------------------------------------------------------- */
{
/* get cluster */
cluster = SUPER_CLUSTER( x, y );
- //% if( *cluster < 0 )
+ //% if( *cluster < 0 ) // TODO why not do this check? These pixels should be zero anyway
//% continue;
/* get particulars */
if( *cluster < 0 ||
(lm->splotchFix && (luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ])) )
filterColor = qtrue;
+
if( deluxemap && lightmapNum == 0 && (*cluster < 0 || filter) )
filterDir = qtrue;
}
}
}
+
+
+#if 0
+ // audit pass
+ for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+ {
+ /* early out */
+ if( lm->superLuxels[ lightmapNum ] == NULL )
+ continue;
+ for( y = 0; y < lm->sh; y++ )
+ for( x = 0; x < lm->sw; x++ )
+ {
+ /* get cluster */
+ cluster = SUPER_CLUSTER( x, y );
+ luxel = SUPER_LUXEL( lightmapNum, x, y );
+ deluxel = SUPER_DELUXEL( x, y );
+ if(!luxel || !deluxel || !cluster)
+ {
+ Sys_FPrintf(SYS_VRB, "WARNING: I got NULL'd.\n");
+ continue;
+ }
+ else if(*cluster < 0)
+ {
+ // unmapped pixel
+ // should have neither deluxemap nor lightmap
+ if(deluxel[3])
+ Sys_FPrintf(SYS_VRB, "WARNING: I have written deluxe to an unmapped luxel. Sorry.\n");
+ }
+ else
+ {
+ // mapped pixel
+ // should have both deluxemap and lightmap
+ if(deluxel[3])
+ Sys_FPrintf(SYS_VRB, "WARNING: I forgot to write deluxe to a mapped luxel. Sorry.\n");
+ }
+ }
+ }
+#endif
}
rawLightmap_t *lm;
bspDrawVert_t *verts;
trace_t trace;
+ float floodLightAmount;
+ vec3_t floodColor;
/* get surface, info, and raw lightmap */
VectorCopy( verts[ i ].normal, trace.normal );
/* r7 dirt */
- if( dirty )
+ if( dirty && !bouncing )
dirt = DirtForSample( &trace );
else
dirt = 1.0f;
+ /* jal: floodlight */
+ floodLightAmount = 0.0f;
+ VectorClear( floodColor );
+ if( floodlighty && !bouncing )
+ {
+ floodLightAmount = floodlightIntensity * FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
+ VectorScale( floodlightRGB, floodLightAmount, floodColor );
+ }
+
/* trace */
LightingAtSample( &trace, ds->vertexStyles, colors );
{
/* r7 dirt */
VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] );
+
+ /* jal: floodlight */
+ VectorAdd( colors[ lightmapNum ], floodColor, colors[ lightmapNum ] );
/* store */
radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
radVertLuxel[ 2 ] <= ambientColor[ 2 ] )
{
/* nudge the sample point around a bit */
- for( x = 0; x < 4; x++ )
+ for( x = 0; x < 5; x++ )
{
/* two's complement 0, 1, -1, 2, -2, etc */
x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1);
- for( y = 0; y < 4; y++ )
+ for( y = 0; y < 5; y++ )
{
y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1);
- for( z = 0; z < 4; z++ )
+ for( z = 0; z < 5; z++ )
{
z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1);
trace.cluster = ClusterForPointExtFilter( origin, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );
if( trace.cluster < 0 )
continue;
+
+ /* r7 dirt */
+ if( dirty && !bouncing )
+ dirt = DirtForSample( &trace );
+ else
+ dirt = 1.0f;
+
+ /* jal: floodlight */
+ floodLightAmount = 0.0f;
+ VectorClear( floodColor );
+ if( floodlighty && !bouncing )
+ {
+ floodLightAmount = floodlightIntensity * FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
+ VectorScale( floodlightRGB, floodLightAmount, floodColor );
+ }
/* trace */
LightingAtSample( &trace, ds->vertexStyles, colors );
{
/* r7 dirt */
VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] );
+
+ /* jal: floodlight */
+ VectorAdd( colors[ lightmapNum ], floodColor, colors[ lightmapNum ] );
/* store */
radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
int i, x, y, z, x1, y1, z1;
light_t *light, *light2, **owner;
bspLeaf_t *leaf;
- vec3_t origin, dir, mins, maxs, nullVector = { 0, 0, 0 };
+ vec3_t origin, dir, mins, maxs;
float radius, intensity;
light_t *buckets[ 256 ];
/* check for fast mode */
if( !(light->flags & LIGHT_FAST) && !(light->flags & LIGHT_FAST_TEMP) )
light->envelope = MAX_WORLD_COORD * 8.0f;
+ intensity = light->photons; /* hopefully not used */
}
else
{
CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
}
+/////////////////////////////////////////////////////////////
+
+#define FLOODLIGHT_CONE_ANGLE 88 /* degrees */
+#define FLOODLIGHT_NUM_ANGLE_STEPS 16
+#define FLOODLIGHT_NUM_ELEVATION_STEPS 4
+#define FLOODLIGHT_NUM_VECTORS (FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS)
+
+static vec3_t floodVectors[ FLOODLIGHT_NUM_VECTORS ];
+static int numFloodVectors = 0;
+
+void SetupFloodLight( void )
+{
+ int i, j;
+ float angle, elevation, angleStep, elevationStep;
+ const char *value;
+ double v1,v2,v3,v4,v5,v6;
+
+ /* note it */
+ Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
+
+ /* calculate angular steps */
+ angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
+ elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
+
+ /* iterate angle */
+ angle = 0.0f;
+ for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
+ {
+ /* iterate elevation */
+ for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
+ {
+ floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
+ floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
+ floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
+ numFloodVectors++;
+ }
+ }
+
+ /* emit some statistics */
+ Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
+
+ /* floodlight */
+ value = ValueForKey( &entities[ 0 ], "_floodlight" );
+
+ if( value[ 0 ] != '\0' )
+ {
+ v1=v2=v3=0;
+ v4=floodlightDistance;
+ v5=floodlightIntensity;
+ v6=floodlightDirectionScale;
+
+ sscanf( value, "%lf %lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5);
+
+ floodlightRGB[0]=v1;
+ floodlightRGB[1]=v2;
+ floodlightRGB[2]=v3;
+
+ if (VectorLength(floodlightRGB)==0)
+ {
+ VectorSet(floodlightRGB,240,240,255);
+ }
+
+ if (v4<1) v4=1024;
+ if (v5<1) v5=128;
+ if (v6<0) v6=1;
+
+ floodlightDistance=v4;
+ floodlightIntensity=v5;
+ floodlightDirectionScale=v6;
+
+ floodlighty = qtrue;
+ Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
+ }
+ else
+ {
+ VectorSet(floodlightRGB,240,240,255);
+ //floodlighty = qtrue;
+ //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
+ }
+ VectorNormalize(floodlightRGB,floodlightRGB);
+}
+
+/*
+FloodLightForSample()
+calculates floodlight value for a given sample
+once again, kudos to the dirtmapping coder
+*/
+
+float FloodLightForSample( trace_t *trace , float floodLightDistance, qboolean floodLightLowQuality)
+{
+ int i;
+ float d;
+ float contribution;
+ int sub = 0;
+ float gatherLight, outLight;
+ vec3_t normal, worldUp, myUp, myRt, direction, displacement;
+ float dd;
+ int vecs = 0;
+
+ gatherLight=0;
+ /* dummy check */
+ //if( !dirty )
+ // return 1.0f;
+ if( trace == NULL || trace->cluster < 0 )
+ return 0.0f;
+
+
+ /* setup */
+ dd = floodLightDistance;
+ VectorCopy( trace->normal, normal );
+
+ /* check if the normal is aligned to the world-up */
+ if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && ( normal[ 2 ] == 1.0f || normal[ 2 ] == -1.0f ) )
+ {
+ if( normal[ 2 ] == 1.0f )
+ {
+ VectorSet( myRt, 1.0f, 0.0f, 0.0f );
+ VectorSet( myUp, 0.0f, 1.0f, 0.0f );
+ }
+ else if( normal[ 2 ] == -1.0f )
+ {
+ VectorSet( myRt, -1.0f, 0.0f, 0.0f );
+ VectorSet( myUp, 0.0f, 1.0f, 0.0f );
+ }
+ }
+ else
+ {
+ VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
+ CrossProduct( normal, worldUp, myRt );
+ VectorNormalize( myRt, myRt );
+ CrossProduct( myRt, normal, myUp );
+ VectorNormalize( myUp, myUp );
+ }
+
+ /* vortex: optimise floodLightLowQuality a bit */
+ if ( floodLightLowQuality == qtrue )
+ {
+ /* iterate through ordered vectors */
+ for( i = 0; i < numFloodVectors; i++ )
+ if (rand()%10 != 0 ) continue;
+ }
+ else
+ {
+ /* iterate through ordered vectors */
+ for( i = 0; i < numFloodVectors; i++ )
+ {
+ vecs++;
+
+ /* transform vector into tangent space */
+ direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
+ direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
+ direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
+
+ /* set endpoint */
+ VectorMA( trace->origin, dd, direction, trace->end );
+ //VectorMA( trace->origin, 1, direction, trace->origin );
+
+ SetupTrace( trace );
+ /* trace */
+ TraceLine( trace );
+ contribution=1;
+ if ( trace->compileFlags & C_SKY || trace->compileFlags & C_TRANSLUCENT )
+ {
+ contribution=1.0f;
+ }
+ else if ( trace->opaque )
+ {
+ VectorSubtract( trace->hit, trace->origin, displacement );
+ d=VectorLength( displacement );
+
+ // d=trace->distance;
+ //if (d>256) gatherDirt+=1;
+ contribution=d/dd;
+ if (contribution>1) contribution=1.0f;
+
+ //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
+ }
+
+ gatherLight+=contribution;
+ }
+ }
+
+ /* early out */
+ if( gatherLight <= 0.0f )
+ return 0.0f;
+
+ sub=vecs;
+ if (sub<1) sub=1;
+ gatherLight/=(sub);
+ outLight=gatherLight;
+ if( outLight > 1.0f )
+ outLight = 1.0f;
+
+ /* return to sender */
+ return outLight;
+}
+
+/*
+FloodLightRawLightmap
+lighttracer style ambient occlusion light hack.
+Kudos to the dirtmapping author for most of this source.
+VorteX: modified to floodlight up custom surfaces (q3map_floodLight)
+VorteX: fixed problems with deluxemapping
+*/
+
+// floodlight pass on a lightmap
+void FloodLightRawLightmapPass( rawLightmap_t *lm , vec3_t lmFloodLightRGB, float lmFloodLightIntensity, float lmFloodLightDistance, qboolean lmFloodLightLowQuality, float floodlightDirectionScale)
+{
+ int i, x, y, *cluster;
+ float *origin, *normal, *floodlight, floodLightAmount;
+ surfaceInfo_t *info;
+ trace_t trace;
+ // int sx, sy;
+ // float samples, average, *floodlight2;
+
+ memset(&trace,0,sizeof(trace_t));
+
+ /* setup trace */
+ trace.testOcclusion = qtrue;
+ trace.forceSunlight = qfalse;
+ trace.twoSided = qtrue;
+ trace.recvShadows = lm->recvShadows;
+ trace.numSurfaces = lm->numLightSurfaces;
+ trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
+ trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
+ trace.testAll = qfalse;
+ trace.distance = 1024;
+
+ /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
+ //trace.twoSided = qfalse;
+ for( i = 0; i < trace.numSurfaces; i++ )
+ {
+ /* get surface */
+ info = &surfaceInfos[ trace.surfaces[ i ] ];
+
+ /* check twosidedness */
+ if( info->si->twoSided )
+ {
+ trace.twoSided = qtrue;
+ break;
+ }
+ }
+
+ /* gather floodlight */
+ for( y = 0; y < lm->sh; y++ )
+ {
+ for( x = 0; x < lm->sw; x++ )
+ {
+ /* get luxel */
+ cluster = SUPER_CLUSTER( x, y );
+ origin = SUPER_ORIGIN( x, y );
+ normal = SUPER_NORMAL( x, y );
+ floodlight = SUPER_FLOODLIGHT( x, y );
+
+ /* set default dirt */
+ *floodlight = 0.0f;
+
+ /* only look at mapped luxels */
+ if( *cluster < 0 )
+ continue;
+
+ /* copy to trace */
+ trace.cluster = *cluster;
+ VectorCopy( origin, trace.origin );
+ VectorCopy( normal, trace.normal );
+
+ /* get floodlight */
+ floodLightAmount = FloodLightForSample( &trace , lmFloodLightDistance, lmFloodLightLowQuality)*lmFloodLightIntensity;
+
+ /* add floodlight */
+ floodlight[0] += lmFloodLightRGB[0]*floodLightAmount;
+ floodlight[1] += lmFloodLightRGB[1]*floodLightAmount;
+ floodlight[2] += lmFloodLightRGB[2]*floodLightAmount;
+ floodlight[3] += floodlightDirectionScale;
+ }
+ }
+
+ /* testing no filtering */
+ return;
+
+#if 0
+
+ /* filter "dirt" */
+ for( y = 0; y < lm->sh; y++ )
+ {
+ for( x = 0; x < lm->sw; x++ )
+ {
+ /* get luxel */
+ cluster = SUPER_CLUSTER( x, y );
+ floodlight = SUPER_FLOODLIGHT(x, y );
+
+ /* filter dirt by adjacency to unmapped luxels */
+ average = *floodlight;
+ samples = 1.0f;
+ for( sy = (y - 1); sy <= (y + 1); sy++ )
+ {
+ if( sy < 0 || sy >= lm->sh )
+ continue;
+
+ for( sx = (x - 1); sx <= (x + 1); sx++ )
+ {
+ if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
+ continue;
+
+ /* get neighboring luxel */
+ cluster = SUPER_CLUSTER( sx, sy );
+ floodlight2 = SUPER_FLOODLIGHT( sx, sy );
+ if( *cluster < 0 || *floodlight2 <= 0.0f )
+ continue;
+
+ /* add it */
+ average += *floodlight2;
+ samples += 1.0f;
+ }
+
+ /* bail */
+ if( samples <= 0.0f )
+ break;
+ }
+
+ /* bail */
+ if( samples <= 0.0f )
+ continue;
+
+ /* scale dirt */
+ *floodlight = average / samples;
+ }
+ }
+#endif
+}
+
+void FloodLightRawLightmap( int rawLightmapNum )
+{
+ rawLightmap_t *lm;
+
+ /* bail if this number exceeds the number of raw lightmaps */
+ if( rawLightmapNum >= numRawLightmaps )
+ return;
+ /* get lightmap */
+ lm = &rawLightmaps[ rawLightmapNum ];
+
+ /* global pass */
+ if (floodlighty && floodlightIntensity)
+ FloodLightRawLightmapPass(lm, floodlightRGB, floodlightIntensity, floodlightDistance, floodlight_lowquality, floodlightDirectionScale);
+
+ /* custom pass */
+ if (lm->floodlightIntensity)
+ {
+ FloodLightRawLightmapPass(lm, lm->floodlightRGB, lm->floodlightIntensity, lm->floodlightDistance, qfalse, lm->floodlightDirectionScale);
+ numSurfacesFloodlighten += 1;
+ }
+}
+
+void FloodlightRawLightmaps()
+{
+ Sys_Printf( "--- FloodlightRawLightmap ---\n" );
+ numSurfacesFloodlighten = 0;
+ RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
+ Sys_Printf( "%9d custom lightmaps floodlighted\n", numSurfacesFloodlighten );
+}
+
+/*
+FloodLightIlluminate()
+illuminate floodlight into lightmap luxels
+*/
+
+void FloodlightIlluminateLightmap( rawLightmap_t *lm )
+{
+ float *luxel, *floodlight, *deluxel, *normal;
+ int *cluster;
+ float brightness;
+ int x, y, lightmapNum;
+
+ /* walk lightmaps */
+ for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+ {
+ /* early out */
+ if( lm->superLuxels[ lightmapNum ] == NULL )
+ continue;
+
+ /* apply floodlight to each luxel */
+ for( y = 0; y < lm->sh; y++ )
+ {
+ for( x = 0; x < lm->sw; x++ )
+ {
+ /* get floodlight */
+ floodlight = SUPER_FLOODLIGHT( x, y );
+ if (!floodlight[0] && !floodlight[1] && !floodlight[2])
+ continue;
+
+ /* get cluster */
+ cluster = SUPER_CLUSTER( x, y );
+
+ /* only process mapped luxels */
+ if( *cluster < 0 )
+ continue;
+
+ /* get particulars */
+ luxel = SUPER_LUXEL( lightmapNum, x, y );
+ deluxel = SUPER_DELUXEL( x, y );
+
+ /* add to lightmap */
+ luxel[0]+=floodlight[0];
+ luxel[1]+=floodlight[1];
+ luxel[2]+=floodlight[2];
+
+ if (luxel[3]==0) luxel[3]=1;
+
+ /* add to deluxemap */
+ if (deluxemap && floodlight[3] > 0)
+ {
+ vec3_t lightvector;
+
+ normal = SUPER_NORMAL( x, y );
+ brightness = RGBTOGRAY( floodlight ) * ( 1.0f/255.0f ) * floodlight[3];
+
+ // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light
+ if(brightness < 0.00390625f)
+ brightness = 0.00390625f;
+
+ VectorScale( normal, brightness, lightvector );
+ VectorAdd( deluxel, lightvector, deluxel );
+ }
+ }
+ }
+ }
+}
*/
int numSortShaders;
-mapDrawSurface_t *surfsOnShader[ MAX_MAP_SHADERS ];
+mapDrawSurface_t **surfsOnShader;
+int allocatedSurfsOnShader;
int allocated[ LIGHTMAP_WIDTH ];
*/
//#define LIGHTMAP_PATCHSHIFT
-void AllocateLightmapForPatch( mapDrawSurface_t *ds )
-{
- int i, j, k;
- drawVert_t *verts;
- int w, h;
- int x, y;
- float s, t;
- mesh_t mesh, *subdividedMesh, *tempMesh, *newmesh;
- int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_HEIGHT], ssize;
-
- verts = ds->verts;
-
- mesh.width = ds->patchWidth;
- mesh.height = ds->patchHeight;
- mesh.verts = verts;
- newmesh = SubdivideMesh( mesh, 8, 999 );
-
- PutMeshOnCurve( *newmesh );
- tempMesh = RemoveLinearMeshColumnsRows( newmesh );
- FreeMesh(newmesh);
-
- /* get sample size */
- ssize = ds->sampleSize;
-
-
-#ifdef LIGHTMAP_PATCHSHIFT
- subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH-1, widthtable, heighttable );
-#else
- subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH, widthtable, heighttable );
-#endif
-
- w = subdividedMesh->width;
- h = subdividedMesh->height;
-
-#ifdef LIGHTMAP_PATCHSHIFT
- w++;
- h++;
-#endif
-
- FreeMesh(subdividedMesh);
-
- // allocate the lightmap
- c_exactLightmap += w * h;
-
- if ( !AllocLMBlock( w, h, &x, &y ) ) {
- PrepareNewLightmap();
- if ( !AllocLMBlock( w, h, &x, &y ) )
- {
- Error("Entity %i, brush %i: Lightmap allocation failed",
- ds->mapBrush->entitynum, ds->mapBrush->brushnum );
- }
- }
-
-#ifdef LIGHTMAP_PATCHSHIFT
- w--;
- h--;
-#endif
-
- // set the lightmap texture coordinates in the drawVerts
- ds->lightmapNum = numLightmaps - 1;
- ds->lightmapWidth = w;
- ds->lightmapHeight = h;
- ds->lightmapX = x;
- ds->lightmapY = y;
-
- for ( i = 0 ; i < ds->patchWidth ; i++ ) {
- for ( k = 0 ; k < w ; k++ ) {
- if ( originalWidths[k] >= i ) {
- break;
- }
- }
- if (k >= w)
- k = w-1;
- s = x + k;
- for ( j = 0 ; j < ds->patchHeight ; j++ ) {
- for ( k = 0 ; k < h ; k++ ) {
- if ( originalHeights[k] >= j ) {
- break;
- }
- }
- if (k >= h)
- k = h-1;
- t = y + k;
- verts[i + j * ds->patchWidth].lightmap[0] = ( s + 0.5 ) / LIGHTMAP_WIDTH;
- verts[i + j * ds->patchWidth].lightmap[1] = ( t + 0.5 ) / LIGHTMAP_HEIGHT;
- }
- }
-}
/*
//#define LIGHTMAP_BLOCK 16
-void AllocateLightmapForSurface( mapDrawSurface_t *ds )
-{
- vec3_t mins, maxs, size, exactSize, delta;
- int i;
- drawVert_t *verts;
- int w, h;
- int x, y, ssize;
- int axis;
- vec3_t vecs[ 2 ];
- float s, t;
- vec3_t origin;
- vec4_t plane;
- float d;
-
-
- /* debug code */
- #if 0
- if( ds->type == SURF_META && ds->planar == qfalse )
- Sys_Printf( "NPMS: %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader );
- else if( ds->type == SURF_META && ds->planar == qtrue )
- Sys_Printf( "PMS: %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader );
- #endif
-
- /* ydnar: handle planar patches */
- if( noPatchFix == qtrue || (ds->type == SURF_PATCH && ds->planeNum < 0) )
- {
- AllocateLightmapForPatch( ds );
- return;
- }
-
- /* get sample size */
- ssize = ds->sampleSize;
-
- /* bound the surface */
- ClearBounds( mins, maxs );
- verts = ds->verts;
- for ( i = 0 ; i < ds->numVerts ; i++ )
- AddPointToBounds( verts[i].xyz, mins, maxs );
-
- /* round to the lightmap resolution */
- for( i = 0; i < 3; i++ )
- {
- exactSize[i] = maxs[i] - mins[i];
- mins[i] = ssize * floor( mins[i] / ssize );
- maxs[i] = ssize * ceil( maxs[i] / ssize );
- size[i] = (maxs[i] - mins[i]) / ssize + 1;
- }
-
- /* ydnar: lightmap projection axis is already stored */
- memset( vecs, 0, sizeof( vecs ) );
-
- /* classify the plane (x y or z major) (ydnar: biased to z axis projection) */
- if( ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 0 ] && ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 1 ] )
- {
- w = size[ 0 ];
- h = size[ 1 ];
- axis = 2;
- vecs[ 0 ][ 0 ] = 1.0 / ssize;
- vecs[ 1 ][ 1 ] = 1.0 / ssize;
- }
- else if( ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 1 ] && ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 2 ] )
- {
- w = size[ 1 ];
- h = size[ 2 ];
- axis = 0;
- vecs[ 0 ][ 1 ] = 1.0 / ssize;
- vecs[ 1 ][ 2 ] = 1.0 / ssize;
- }
- else
- {
- w = size[ 0 ];
- h = size[ 2 ];
- axis = 1;
- vecs[ 0 ][ 0 ] = 1.0 / ssize;
- vecs[ 1 ][ 2 ] = 1.0 / ssize;
- }
-
- /* odd check, given projection is now precalculated */
- if( ds->lightmapAxis[ axis ] == 0 )
- Error( "Chose a 0 valued axis" );
-
- /* clamp to lightmap texture resolution */
- if( w > LIGHTMAP_WIDTH )
- {
- VectorScale ( vecs[0], (float) LIGHTMAP_WIDTH / w, vecs[0] );
- w = LIGHTMAP_WIDTH;
- }
- if( h > LIGHTMAP_HEIGHT )
- {
- VectorScale ( vecs[1], (float) LIGHTMAP_HEIGHT / h, vecs[1] );
- h = LIGHTMAP_HEIGHT;
- }
-
-
- /* ydnar */
- if( ds->planar == qfalse )
- c_nonplanarLightmap += w * h;
- c_exactLightmap += w * h;
-
-
- if( !AllocLMBlock( w, h, &x, &y ) )
- {
- PrepareNewLightmap();
- if ( !AllocLMBlock( w, h, &x, &y ) )
- {
- Error( "Entity %i, brush %i: Lightmap allocation failed",
- ds->mapBrush->entitynum, ds->mapBrush->brushnum );
- }
- }
-
- /* set the lightmap texture coordinates in the drawVerts */
- ds->lightmapNum = numLightmaps - 1;
- ds->lightmapWidth = w;
- ds->lightmapHeight = h;
- ds->lightmapX = x;
- ds->lightmapY = y;
- for ( i = 0 ; i < ds->numVerts ; i++ )
- {
- VectorSubtract( verts[i].xyz, mins, delta );
- s = DotProduct( delta, vecs[0] ) + x + 0.5;
- t = DotProduct( delta, vecs[1] ) + y + 0.5;
- verts[i].lightmap[0] = s / LIGHTMAP_WIDTH;
- verts[i].lightmap[1] = t / LIGHTMAP_HEIGHT;
- }
-
- /* calculate the world coordinates of the lightmap samples */
-
- /* construct a plane from the first vert and clear bounding box */
-
- /* project mins onto plane to get origin */
- VectorCopy( ds->lightmapVecs[ 2 ], plane );
- plane[ 3 ] = DotProduct( ds->verts[ 0 ].xyz, plane );
- d = DotProduct( mins, plane ) - plane[ 3 ];
- d /= plane[ axis ];
-
- //% d = DotProduct( mins, plane->normal ) - plane->dist;
- //% d /= plane->normal[ axis ];
- VectorCopy( mins, origin );
- origin[ axis ] -= d;
-
- /* project stepped lightmap blocks and subtract to get planevecs */
- for( i = 0; i < 2; i++ )
- {
- vec3_t normalized;
- float len;
-
- len = VectorNormalize( vecs[i], normalized );
- VectorScale( normalized, (1.0/len), vecs[i] );
- d = DotProduct( vecs[i], plane );
- d /= plane[ axis ];
- //%d = DotProduct( vecs[i], plane->normal );
- //%d /= plane->normal[ axis ];
- vecs[i][axis] -= d;
- }
-
- /* store lightmap origin and vectors (fixme: make this work right) */
- VectorCopy( origin, ds->lightmapOrigin );
- //% VectorCopy( plane->normal, ds->lightmapVecs[ 2 ] );
-
- /* ydnar: lightmap vectors 0 and 1 are used for lod bounds, so don't overwrite */
- if( ds->type == SURF_PATCH )
- c_planarPatch++;
-
- /* store lightmap vectors */
- VectorCopy( vecs[ 0 ], ds->lightmapVecs[ 0 ] );
- VectorCopy( vecs[ 1 ], ds->lightmapVecs[ 1 ] );
-
- /* ydnar: print some stats */
- //Sys_FPrintf( SYS_VRB, "Lightmap block %3d (%3d, %3d) (%3d x %3d) emitted\n", (numLightmaps - 1), x, y, w, h );
-}
/*
AllocateLightmaps
===================
*/
-void AllocateLightmaps( entity_t *e )
-{
- int i, j;
- mapDrawSurface_t *ds;
- shaderInfo_t *si;
-
-
- /* note it */
- Sys_FPrintf( SYS_VRB,"--- AllocateLightmaps ---\n" );
-
-
- /* sort all surfaces by shader so common shaders will usually be in the same lightmap */
- /* ydnar: this is done in two passes, because of an odd bug with lightmapped terrain */
- numSortShaders = 0;
- for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
- {
- /* get surface and early out if possible */
- ds = &mapDrawSurfs[ i ];
- si = ds->shaderInfo;
- if( si->surfaceFlags & SURF_VERTEXLIT )
- continue;
- if( ds->numVerts <= 0 )
- continue;
-
- /* ydnar: handle brush faces and patches first */
- if( ds->type != SURF_FACE && ds->type != SURF_PATCH )
- continue;
-
- /* ydnar: this is unecessary because it should already be set */
- //% VectorCopy( ds->plane.normal, ds->lightmapVecs[ 2 ] );
-
- /* search for this shader */
- for( j = 0 ; j < numSortShaders; j++ )
- {
- if( ds->shaderInfo == surfsOnShader[ j ]->shaderInfo )
- {
- ds->nextOnShader = surfsOnShader[ j ];
- surfsOnShader[ j ] = ds;
- break;
- }
- }
-
- /* new shader */
- if( j == numSortShaders )
- {
- if( numSortShaders >= MAX_MAP_SHADERS )
- Error( "MAX_MAP_SHADERS" );
- surfsOnShader[ j ] = ds;
- ds->nextOnShader = NULL;
- numSortShaders++;
- }
- }
-
- /* second pass, to allocate lightmapped terrain last */
- for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
- {
- /* get surface and early out if possible */
- ds = &mapDrawSurfs[ i ];
- si = ds->shaderInfo;
- if( si->surfaceFlags & SURF_VERTEXLIT )
- continue;
- if( ds->numVerts <= 0 )
- continue;
-
- /* ydnar: this only handles metasurfaces and terrain */
- if( ds->type != SURF_TERRAIN && ds->type != SURF_META )
- continue;
-
- /* ydnar: a lightmap projection should be pre-stored for anything but excessively curved patches */
- if( VectorLength( ds->lightmapAxis ) <= 0 )
- continue;
-
- /* search for this shader */
- for( j = 0; j < numSortShaders; j++ )
- {
- if( ds->shaderInfo == surfsOnShader[ j ]->shaderInfo )
- {
- ds->nextOnShader = surfsOnShader[ j ];
- surfsOnShader[ j ] = ds;
- break;
- }
- }
-
- /* new shader */
- if( j == numSortShaders )
- {
- if( numSortShaders >= MAX_MAP_SHADERS )
- Error( "MAX_MAP_SHADERS" );
- surfsOnShader[ j ] = ds;
- ds->nextOnShader = NULL;
- numSortShaders++;
- }
- }
-
- /* tot up shader count */
- Sys_FPrintf( SYS_VRB, "%9d unique shaders\n", numSortShaders );
-
- /* for each shader, allocate lightmaps for each surface */
- for( i = 0; i < numSortShaders; i++ )
- {
- si = surfsOnShader[ i ]->shaderInfo;
- for( ds = surfsOnShader[ i ]; ds; ds = ds->nextOnShader )
- {
- /* ydnar: promoting pointlight above nolightmap */
- if( si->surfaceFlags & SURF_POINTLIGHT )
- ds->lightmapNum = -3;
- else if( si->surfaceFlags & SURF_NOLIGHTMAP )
- ds->lightmapNum = -1;
- else
- AllocateLightmapForSurface( ds );
- }
- }
-
- /* emit some statistics */
- Sys_FPrintf( SYS_VRB, "%9d exact lightmap texels\n", c_exactLightmap );
- Sys_FPrintf( SYS_VRB, "%9d block lightmap texels\n", numLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT );
- Sys_FPrintf( SYS_VRB, "%9d non-planar or terrain lightmap texels\n", c_nonplanarLightmap );
- Sys_FPrintf( SYS_VRB, "%9d planar patch lightmaps\n", c_planarPatch );
- Sys_FPrintf( SYS_VRB, "%9d lightmap textures, size: %d Kbytes\n", numLightmaps, (numLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3) / 1024 );
-}
/* get shaders */
- asi = surfaceInfos[ *((int*) a) ].si;
- bsi = surfaceInfos[ *((int*) b) ].si;
+ asi = surfaceInfos[ *((const int*) a) ].si;
+ bsi = surfaceInfos[ *((const int*) b) ].si;
/* dummy check */
if( asi == NULL )
lm->superNormals = safe_malloc( size );
memset( lm->superNormals, 0, size );
+ /* allocate floodlight map storage */
+ size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float );
+ if( lm->superFloodLight == NULL )
+ lm->superFloodLight = safe_malloc( size );
+ memset( lm->superFloodLight, 0, size );
+
/* allocate cluster map storage */
size = lm->sw * lm->sh * sizeof( int );
if( lm->superClusters == NULL )
size[ i ] = (maxs[ i ] - mins[ i ]) / sampleSize + 1.0f;
/* hack (god this sucks) */
- if( size[ i ] > lm->customWidth || size[ i ] > lm->customHeight )
+ if( size[ i ] > lm->customWidth || size[ i ] > lm->customHeight || (lmLimitSize && size[i] > lmLimitSize))
{
i = -1;
sampleSize += 1.0f;
}
}
+
+ if(sampleSize != lm->sampleSize && lmLimitSize == 0)
+ {
+ Sys_FPrintf(SYS_VRB,"WARNING: surface at (%6.0f %6.0f %6.0f) (%6.0f %6.0f %6.0f) too large for desired samplesize/lightmapsize/lightmapscale combination, increased samplesize from %d to %d\n",
+ info->mins[0],
+ info->mins[1],
+ info->mins[2],
+ info->maxs[0],
+ info->maxs[1],
+ info->maxs[2],
+ lm->sampleSize,
+ (int) sampleSize);
+ }
/* set actual sample size */
lm->actualSampleSize = sampleSize;
/* get surface info */
- aInfo = &surfaceInfos[ *((int*) a) ];
- bInfo = &surfaceInfos[ *((int*) b) ];
+ aInfo = &surfaceInfos[ *((const int*) a) ];
+ bInfo = &surfaceInfos[ *((const int*) b) ];
/* model first */
- if( aInfo->model < bInfo->model )
+ if( aInfo->modelindex < bInfo->modelindex )
return 1;
- else if( aInfo->model > bInfo->model )
+ else if( aInfo->modelindex > bInfo->modelindex )
return -1;
/* then lightmap status */
return 1;
else if( aInfo->hasLightmap > bInfo->hasLightmap )
return -1;
+
+ /* 27: then shader! */
+ if (aInfo->si < bInfo->si)
+ return 1;
+ else if (aInfo->si > bInfo->si)
+ return -1;
+
/* then lightmap sample size */
if( aInfo->sampleSize < bInfo->sampleSize )
VectorClear( entityOrigin );
/* basic setup */
- info->model = model;
+ info->modelindex = i;
info->lm = NULL;
info->plane = NULL;
info->firstSurfaceCluster = numSurfaceClusters;
lm->splotchFix = info->si->splotchFix;
lm->firstLightSurface = numLightSurfaces;
lm->numLightSurfaces = 0;
- lm->sampleSize = info->sampleSize;
- lm->actualSampleSize = info->sampleSize;
+ /* vortex: multiply lightmap sample size by -samplescale */
+ if (sampleScale > 0)
+ lm->sampleSize = info->sampleSize*sampleScale;
+ else
+ lm->sampleSize = info->sampleSize;
+ lm->actualSampleSize = lm->sampleSize;
lm->entityNum = info->entityNum;
lm->recvShadows = info->recvShadows;
lm->brightness = info->si->lmBrightness;
lm->filterRadius = info->si->lmFilterRadius;
+ VectorCopy(info->si->floodlightRGB, lm->floodlightRGB);
+ lm->floodlightDistance = info->si->floodlightDistance;
+ lm->floodlightIntensity = info->si->floodlightIntensity;
+ lm->floodlightDirectionScale = info->si->floodlightDirectionScale;
VectorCopy( info->axis, lm->axis );
lm->plane = info->plane;
VectorCopy( info->mins, lm->mins );
for a given surface lightmap, find output lightmap pages and positions for it
*/
+#define LIGHTMAP_RESERVE_COUNT 1
static void FindOutLightmaps( rawLightmap_t *lm )
{
- int i, j, lightmapNum, xMax, yMax, x, y, sx, sy, ox, oy, offset, temp;
+ int i, j, k, lightmapNum, xMax, yMax, x, y, sx, sy, ox, oy, offset;
outLightmap_t *olm;
surfaceInfo_t *info;
float *luxel, *deluxel;
y = 0;
/* walk the list of lightmap pages */
- for( i = 0; i < numOutLightmaps; i++ )
+ if(lightmapSearchBlockSize <= 0 || numOutLightmaps < LIGHTMAP_RESERVE_COUNT)
+ i = 0;
+ else
+ i = ((numOutLightmaps - LIGHTMAP_RESERVE_COUNT) / lightmapSearchBlockSize) * lightmapSearchBlockSize;
+ for( ; i < numOutLightmaps; i++ )
{
/* get the output lightmap */
olm = &outLightmaps[ i ];
/* no match? */
if( ok == qfalse )
{
- /* allocate two new output lightmaps */
- numOutLightmaps += 2;
+ /* allocate LIGHTMAP_RESERVE_COUNT new output lightmaps */
+ numOutLightmaps += LIGHTMAP_RESERVE_COUNT;
olm = safe_malloc( numOutLightmaps * sizeof( outLightmap_t ) );
- if( outLightmaps != NULL && numOutLightmaps > 2 )
+ if( outLightmaps != NULL && numOutLightmaps > LIGHTMAP_RESERVE_COUNT )
{
- memcpy( olm, outLightmaps, (numOutLightmaps - 2) * sizeof( outLightmap_t ) );
+ memcpy( olm, outLightmaps, (numOutLightmaps - LIGHTMAP_RESERVE_COUNT) * sizeof( outLightmap_t ) );
free( outLightmaps );
}
outLightmaps = olm;
/* initialize both out lightmaps */
- SetupOutLightmap( lm, &outLightmaps[ numOutLightmaps - 2 ] );
- SetupOutLightmap( lm, &outLightmaps[ numOutLightmaps - 1 ] );
+ for(k = numOutLightmaps - LIGHTMAP_RESERVE_COUNT; k < numOutLightmaps; ++k)
+ SetupOutLightmap( lm, &outLightmaps[ k ] );
/* set out lightmap */
- i = numOutLightmaps - 2;
+ i = numOutLightmaps - LIGHTMAP_RESERVE_COUNT;
olm = &outLightmaps[ i ];
/* set stamp xy origin to the first surface lightmap */
if( deluxemap )
{
/* normalize average light direction */
- if( VectorNormalize( deluxel, direction ) )
- {
- /* encode [-1,1] in [0,255] */
- pixel = olm->bspDirBytes + (((oy * olm->customWidth) + ox) * 3);
- for( i = 0; i < 3; i++ )
- {
- temp = (direction[ i ] + 1.0f) * 127.5f;
- if( temp < 0 )
- pixel[ i ] = 0;
- else if( temp > 255 )
- pixel[ i ] = 255;
- else
- pixel[ i ] = temp;
- }
- }
+ pixel = olm->bspDirBytes + (((oy * olm->customWidth) + ox) * 3);
+ VectorScale( deluxel, 1000.0f, direction );
+ VectorNormalize( direction, direction );
+ VectorScale( direction, 127.5f, direction );
+ for( i = 0; i < 3; i++ )
+ pixel[ i ] = (byte)( 127.5f + direction[ i ] );
}
}
}
/* get lightmaps */
- alm = &rawLightmaps[ *((int*) a) ];
- blm = &rawLightmaps[ *((int*) b) ];
+ alm = &rawLightmaps[ *((const int*) a) ];
+ blm = &rawLightmaps[ *((const int*) b) ];
/* get min number of surfaces */
min = (alm->numLightSurfaces < blm->numLightSurfaces ? alm->numLightSurfaces : blm->numLightSurfaces);
return 0;
}
+void FillOutLightmap(outLightmap_t *olm)
+{
+ int x, y;
+ int ofs;
+ vec3_t dir_sum, light_sum;
+ int cnt, filled;
+ byte *lightBitsNew = NULL;
+ byte *lightBytesNew = NULL;
+ byte *dirBytesNew = NULL;
+
+ lightBitsNew = safe_malloc((olm->customWidth * olm->customHeight + 8) / 8);
+ lightBytesNew = safe_malloc(olm->customWidth * olm->customHeight * 3);
+ if(deluxemap)
+ dirBytesNew = safe_malloc(olm->customWidth * olm->customHeight * 3);
+
+ /*
+ memset(olm->lightBits, 0, (olm->customWidth * olm->customHeight + 8) / 8);
+ olm->lightBits[0] |= 1;
+ olm->lightBits[(10 * olm->customWidth + 30) >> 3] |= 1 << ((10 * olm->customWidth + 30) & 7);
+ memset(olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3);
+ olm->bspLightBytes[0] = 255;
+ olm->bspLightBytes[(10 * olm->customWidth + 30) * 3 + 2] = 255;
+ */
+
+ memcpy(lightBitsNew, olm->lightBits, (olm->customWidth * olm->customHeight + 8) / 8);
+ memcpy(lightBytesNew, olm->bspLightBytes, olm->customWidth * olm->customHeight * 3);
+ if(deluxemap)
+ memcpy(dirBytesNew, olm->bspDirBytes, olm->customWidth * olm->customHeight * 3);
+
+ for(;;)
+ {
+ filled = 0;
+ for(y = 0; y < olm->customHeight; ++y)
+ {
+ for(x = 0; x < olm->customWidth; ++x)
+ {
+ ofs = y * olm->customWidth + x;
+ if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */
+ continue;
+ cnt = 0;
+ VectorClear(dir_sum);
+ VectorClear(light_sum);
+
+ /* try all four neighbors */
+ ofs = ((y + olm->customHeight - 1) % olm->customHeight) * olm->customWidth + x;
+ if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */
+ {
+ ++cnt;
+ VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum);
+ if(deluxemap)
+ VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum);
+ }
+
+ ofs = ((y + 1) % olm->customHeight) * olm->customWidth + x;
+ if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */
+ {
+ ++cnt;
+ VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum);
+ if(deluxemap)
+ VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum);
+ }
+
+ ofs = y * olm->customWidth + (x + olm->customWidth - 1) % olm->customWidth;
+ if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */
+ {
+ ++cnt;
+ VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum);
+ if(deluxemap)
+ VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum);
+ }
+
+ ofs = y * olm->customWidth + (x + 1) % olm->customWidth;
+ if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */
+ {
+ ++cnt;
+ VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum);
+ if(deluxemap)
+ VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum);
+ }
+
+ if(cnt)
+ {
+ ++filled;
+ ofs = y * olm->customWidth + x;
+ lightBitsNew[ofs >> 3] |= (1 << (ofs & 7));
+ VectorScale(light_sum, 1.0/cnt, lightBytesNew + ofs * 3);
+ if(deluxemap)
+ VectorScale(dir_sum, 1.0/cnt, dirBytesNew + ofs * 3);
+ }
+ }
+ }
+
+ if(!filled)
+ break;
+
+ memcpy(olm->lightBits, lightBitsNew, (olm->customWidth * olm->customHeight + 8) / 8);
+ memcpy(olm->bspLightBytes, lightBytesNew, olm->customWidth * olm->customHeight * 3);
+ if(deluxemap)
+ memcpy(olm->bspDirBytes, dirBytesNew, olm->customWidth * olm->customHeight * 3);
+ }
+ free(lightBitsNew);
+ free(lightBytesNew);
+ if(deluxemap)
+ free(dirBytesNew);
+}
/*
StoreSurfaceLightmaps()
char dirname[ 1024 ], filename[ 1024 ];
shaderInfo_t *csi;
char lightmapName[ 128 ];
- char *rgbGenValues[ 256 ];
- char *alphaGenValues[ 256 ];
+ const char *rgbGenValues[ 256 ];
+ const char *alphaGenValues[ 256 ];
/* note it */
Sys_Printf( "--- StoreSurfaceLightmaps ---\n");
/* setup */
- strcpy( dirname, source );
- StripExtension( dirname );
+ if(lmCustomDir)
+ {
+ strcpy( dirname, lmCustomDir );
+ }
+ else
+ {
+ strcpy( dirname, source );
+ StripExtension( dirname );
+ }
memset( rgbGenValues, 0, sizeof( rgbGenValues ) );
memset( alphaGenValues, 0, sizeof( alphaGenValues ) );
----------------------------------------------------------------- */
/* note it */
- Sys_FPrintf( SYS_VRB, "Subsampling..." );
+ Sys_Printf( "Subsampling..." );
/* walk the list of raw lightmaps */
numUsed = 0;
}
}
+ /* -----------------------------------------------------------------
+ convert modelspace deluxemaps to tangentspace
+ ----------------------------------------------------------------- */
+ /* note it */
+ if( !bouncing )
+ {
+ if( deluxemap && deluxemode == 1)
+ {
+ vec3_t worldUp, myNormal, myTangent, myBinormal;
+ float dist;
+
+ Sys_Printf( "converting..." );
+
+ for( i = 0; i < numRawLightmaps; i++ )
+ {
+ /* get lightmap */
+ lm = &rawLightmaps[ i ];
+
+ /* walk lightmap samples */
+ for( y = 0; y < lm->sh; y++ )
+ {
+ for( x = 0; x < lm->sw; x++ )
+ {
+ /* get normal and deluxel */
+ normal = SUPER_NORMAL(x, y);
+ cluster = SUPER_CLUSTER(x, y);
+ bspDeluxel = BSP_DELUXEL( x, y );
+ deluxel = SUPER_DELUXEL( x, y );
+
+ /* get normal */
+ VectorSet( myNormal, normal[0], normal[1], normal[2] );
+
+ /* get tangent vectors */
+ if( myNormal[ 0 ] == 0.0f && myNormal[ 1 ] == 0.0f )
+ {
+ if( myNormal[ 2 ] == 1.0f )
+ {
+ VectorSet( myTangent, 1.0f, 0.0f, 0.0f );
+ VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
+ }
+ else if( myNormal[ 2 ] == -1.0f )
+ {
+ VectorSet( myTangent, -1.0f, 0.0f, 0.0f );
+ VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
+ }
+ }
+ else
+ {
+ VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
+ CrossProduct( myNormal, worldUp, myTangent );
+ VectorNormalize( myTangent, myTangent );
+ CrossProduct( myTangent, myNormal, myBinormal );
+ VectorNormalize( myBinormal, myBinormal );
+ }
+
+ /* project onto plane */
+ dist = -DotProduct(myTangent, myNormal);
+ VectorMA(myTangent, dist, myNormal, myTangent);
+ dist = -DotProduct(myBinormal, myNormal);
+ VectorMA(myBinormal, dist, myNormal, myBinormal);
+
+ /* renormalize */
+ VectorNormalize( myTangent, myTangent );
+ VectorNormalize( myBinormal, myBinormal );
+
+ /* convert modelspace deluxel to tangentspace */
+ dirSample[0] = bspDeluxel[0];
+ dirSample[1] = bspDeluxel[1];
+ dirSample[2] = bspDeluxel[2];
+ VectorNormalize(dirSample, dirSample);
+
+ /* fix tangents to world matrix */
+ if (myNormal[0] > 0 || myNormal[1] < 0 || myNormal[2] < 0)
+ VectorNegate(myTangent, myTangent);
+
+ /* build tangentspace vectors */
+ bspDeluxel[0] = DotProduct(dirSample, myTangent);
+ bspDeluxel[1] = DotProduct(dirSample, myBinormal);
+ bspDeluxel[2] = DotProduct(dirSample, myNormal);
+ }
+ }
+ }
+ }
+ }
+
+ /* -----------------------------------------------------------------
+ blend lightmaps
+ ----------------------------------------------------------------- */
+
+#ifdef sdfsdfwq312323
+ /* note it */
+ Sys_Printf( "blending..." );
+
+ for( i = 0; i < numRawLightmaps; i++ )
+ {
+ vec3_t myColor;
+ float myBrightness;
+
+ /* get lightmap */
+ lm = &rawLightmaps[ i ];
+
+ /* walk individual lightmaps */
+ for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+ {
+ /* early outs */
+ if( lm->superLuxels[ lightmapNum ] == NULL )
+ continue;
+
+ /* walk lightmap samples */
+ for( y = 0; y < lm->sh; y++ )
+ {
+ for( x = 0; x < lm->sw; x++ )
+ {
+ /* get luxel */
+ bspLuxel = BSP_LUXEL( lightmapNum, x, y );
+
+ /* get color */
+ VectorNormalize(bspLuxel, myColor);
+ myBrightness = VectorLength(bspLuxel);
+ myBrightness *= (1 / 127.0f);
+ myBrightness = myBrightness*myBrightness;
+ myBrightness *= 127.0f;
+ VectorScale(myColor, myBrightness, bspLuxel);
+ }
+ }
+ }
+ }
+#endif
+
/* -----------------------------------------------------------------
collapse non-unique lightmaps
----------------------------------------------------------------- */
if( noCollapse == qfalse && deluxemap == qfalse )
{
/* note it */
- Sys_FPrintf( SYS_VRB, "collapsing..." );
+ Sys_Printf( "collapsing..." );
/* set all twin refs to null */
for( i = 0; i < numRawLightmaps; i++ )
----------------------------------------------------------------- */
/* note it */
- Sys_FPrintf( SYS_VRB, "sorting..." );
+ Sys_Printf( "sorting..." );
/* allocate a new sorted list */
if( sortLightmaps == NULL )
----------------------------------------------------------------- */
/* note it */
- Sys_FPrintf( SYS_VRB, "allocating..." );
+ Sys_Printf( "allocating..." );
/* kill all existing output lightmaps */
if( outLightmaps != NULL )
----------------------------------------------------------------- */
/* note it */
- Sys_FPrintf( SYS_VRB, "storing..." );
+ Sys_Printf( "storing..." );
/* count the bsp lightmaps and allocate space */
if( bspLightBytes != NULL )
{
/* get output lightmap */
olm = &outLightmaps[ i ];
+
+ /* fill output lightmap */
+ if(lightmapFill)
+ FillOutLightmap(olm);
/* is this a valid bsp lightmap? */
if( olm->lightmapNum >= 0 && !externalLightmaps )
}
if( numExtLightmaps > 0 )
- Sys_FPrintf( SYS_VRB, "\n" );
+ Sys_Printf( "\n" );
/* delete unused external lightmaps */
for( i = numExtLightmaps; i; i++ )
----------------------------------------------------------------- */
/* note it */
- Sys_FPrintf( SYS_VRB, "projecting..." );
+ Sys_Printf( "projecting..." );
/* walk the list of surfaces */
for( i = 0; i < numBSPDrawSurfaces; i++ )
if( rgbGenValues[ style ] == NULL )
{
sprintf( key, "_style%drgbgen", style );
- rgbGenValues[ style ] = (char*) ValueForKey( &entities[ 0 ], key );
+ rgbGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
if( rgbGenValues[ style ][ 0 ] == '\0' )
rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37";
}
if( alphaGenValues[ style ] == NULL )
{
sprintf( key, "_style%dalphagen", style );
- alphaGenValues[ style ] = (char*) ValueForKey( &entities[ 0 ], key );
+ alphaGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
}
if( alphaGenValues[ style ][ 0 ] != '\0' )
sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style );
}
/* finish */
- Sys_FPrintf( SYS_VRB, "done.\n" );
+ Sys_Printf( "done.\n" );
/* calc num stored */
numStored = numBSPLightBytes / 3;
-/* -------------------------------------------------------------------------------
+/* -------------------------------------------------------------------------------;
Copyright (C) 1999-2007 id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.
/* dependencies */
#include "q3map2.h"
+
+
/*
Random()
returns a pseudorandom number between 0 and 1
free( mapDrawSurfs );
}
-static int MD4BlockChecksum( void * buffer, int length ) {
- unsigned char digest[16];
- int checksum;
-
- md4_get_digest( buffer, length, digest );
- /* I suppose it has to be done that way for legacy reasons? */
- checksum = digest[0] & ( digest[1] << 8 ) & ( digest[2] << 16 ) & ( digest[3] << 24 );
- checksum ^= digest[4] & ( digest[5] << 8 ) & ( digest[6] << 16 ) & ( digest[7] << 24 );
- checksum ^= digest[8] & ( digest[9] << 8 ) & ( digest[10] << 16 ) & ( digest[11] << 24 );
- checksum ^= digest[12] & ( digest[13] << 8 ) & ( digest[14] << 16 ) & ( digest[15] << 24 );
- return checksum;
+
+
+/* minimap stuff */
+
+typedef struct minimap_s
+{
+ bspModel_t *model;
+ int width;
+ int height;
+ int samples;
+ float *sample_offsets;
+ float sharpen_boxmult;
+ float sharpen_centermult;
+ float boost;
+ float *data1f;
+ float *sharpendata1f;
+ vec3_t mins, size;
+}
+minimap_t;
+static minimap_t minimap;
+
+qboolean BrushIntersectionWithLine(bspBrush_t *brush, vec3_t start, vec3_t dir, float *t_in, float *t_out)
+{
+ int i;
+ qboolean in = qfalse, out = qfalse;
+ bspBrushSide_t *sides = &bspBrushSides[brush->firstSide];
+
+ for(i = 0; i < brush->numSides; ++i)
+ {
+ bspPlane_t *p = &bspPlanes[sides[i].planeNum];
+ float sn = DotProduct(start, p->normal);
+ float dn = DotProduct(dir, p->normal);
+ if(dn == 0)
+ {
+ if(sn > p->dist)
+ return qfalse; // outside!
+ }
+ else
+ {
+ float t = (p->dist - sn) / dn;
+ if(dn < 0)
+ {
+ if(!in || t > *t_in)
+ {
+ *t_in = t;
+ in = qtrue;
+ // as t_in can only increase, and t_out can only decrease, early out
+ if(out && *t_in >= *t_out)
+ return qfalse;
+ }
+ }
+ else
+ {
+ if(!out || t < *t_out)
+ {
+ *t_out = t;
+ out = qtrue;
+ // as t_in can only increase, and t_out can only decrease, early out
+ if(in && *t_in >= *t_out)
+ return qfalse;
+ }
+ }
+ }
+ }
+ return in && out;
+}
+
+static float MiniMapSample(float x, float y)
+{
+ vec3_t org, dir;
+ int i, bi;
+ float t0, t1;
+ float samp;
+ bspBrush_t *b;
+ bspBrushSide_t *s;
+ int cnt;
+
+ org[0] = x;
+ org[1] = y;
+ org[2] = 0;
+ dir[0] = 0;
+ dir[1] = 0;
+ dir[2] = 1;
+
+ cnt = 0;
+ samp = 0;
+ for(i = 0; i < minimap.model->numBSPBrushes; ++i)
+ {
+ bi = minimap.model->firstBSPBrush + i;
+ if(opaqueBrushes[bi >> 3] & (1 << (bi & 7)))
+ {
+ b = &bspBrushes[bi];
+
+ // sort out mins/maxs of the brush
+ s = &bspBrushSides[b->firstSide];
+ if(x < -bspPlanes[s[0].planeNum].dist)
+ continue;
+ if(x > +bspPlanes[s[1].planeNum].dist)
+ continue;
+ if(y < -bspPlanes[s[2].planeNum].dist)
+ continue;
+ if(y > +bspPlanes[s[3].planeNum].dist)
+ continue;
+
+ if(BrushIntersectionWithLine(b, org, dir, &t0, &t1))
+ {
+ samp += t1 - t0;
+ ++cnt;
+ }
+ }
+ }
+
+ return samp;
+}
+
+void RandomVector2f(float v[2])
+{
+ do
+ {
+ v[0] = 2 * Random() - 1;
+ v[1] = 2 * Random() - 1;
+ }
+ while(v[0] * v[0] + v[1] * v[1] > 1);
+}
+
+static void MiniMapRandomlySupersampled(int y)
+{
+ int x, i;
+ float *p = &minimap.data1f[y * minimap.width];
+ float ymin = minimap.mins[1] + minimap.size[1] * (y / (float) minimap.height);
+ float dx = minimap.size[0] / (float) minimap.width;
+ float dy = minimap.size[1] / (float) minimap.height;
+ float uv[2];
+ float thisval;
+
+ for(x = 0; x < minimap.width; ++x)
+ {
+ float xmin = minimap.mins[0] + minimap.size[0] * (x / (float) minimap.width);
+ float val = 0;
+
+ for(i = 0; i < minimap.samples; ++i)
+ {
+ RandomVector2f(uv);
+ thisval = MiniMapSample(
+ xmin + (uv[0] + 0.5) * dx, /* exaggerated random pattern for better results */
+ ymin + (uv[1] + 0.5) * dy /* exaggerated random pattern for better results */
+ );
+ val += thisval;
+ }
+ val /= minimap.samples * minimap.size[2];
+ *p++ = val;
+ }
+}
+
+static void MiniMapSupersampled(int y)
+{
+ int x, i;
+ float *p = &minimap.data1f[y * minimap.width];
+ float ymin = minimap.mins[1] + minimap.size[1] * (y / (float) minimap.height);
+ float dx = minimap.size[0] / (float) minimap.width;
+ float dy = minimap.size[1] / (float) minimap.height;
+
+ for(x = 0; x < minimap.width; ++x)
+ {
+ float xmin = minimap.mins[0] + minimap.size[0] * (x / (float) minimap.width);
+ float val = 0;
+
+ for(i = 0; i < minimap.samples; ++i)
+ {
+ float thisval = MiniMapSample(
+ xmin + minimap.sample_offsets[2*i+0] * dx,
+ ymin + minimap.sample_offsets[2*i+1] * dy
+ );
+ val += thisval;
+ }
+ val /= minimap.samples * minimap.size[2];
+ *p++ = val;
+ }
+}
+
+static void MiniMapNoSupersampling(int y)
+{
+ int x;
+ float *p = &minimap.data1f[y * minimap.width];
+ float ymin = minimap.mins[1] + minimap.size[1] * ((y + 0.5) / (float) minimap.height);
+
+ for(x = 0; x < minimap.width; ++x)
+ {
+ float xmin = minimap.mins[0] + minimap.size[0] * ((x + 0.5) / (float) minimap.width);
+ *p++ = MiniMapSample(xmin, ymin) / minimap.size[2];
+ }
+}
+
+static void MiniMapSharpen(int y)
+{
+ int x;
+ qboolean up = (y > 0);
+ qboolean down = (y < minimap.height - 1);
+ float *p = &minimap.data1f[y * minimap.width];
+ float *q = &minimap.sharpendata1f[y * minimap.width];
+
+ for(x = 0; x < minimap.width; ++x)
+ {
+ qboolean left = (x > 0);
+ qboolean right = (x < minimap.width - 1);
+ float val = p[0] * minimap.sharpen_centermult;
+
+ if(left && up)
+ val += p[-1 -minimap.width] * minimap.sharpen_boxmult;
+ if(left && down)
+ val += p[-1 +minimap.width] * minimap.sharpen_boxmult;
+ if(right && up)
+ val += p[+1 -minimap.width] * minimap.sharpen_boxmult;
+ if(right && down)
+ val += p[+1 +minimap.width] * minimap.sharpen_boxmult;
+
+ if(left)
+ val += p[-1] * minimap.sharpen_boxmult;
+ if(right)
+ val += p[+1] * minimap.sharpen_boxmult;
+ if(up)
+ val += p[-minimap.width] * minimap.sharpen_boxmult;
+ if(down)
+ val += p[+minimap.width] * minimap.sharpen_boxmult;
+
+ ++p;
+ *q++ = val;
+ }
+}
+
+static void MiniMapContrastBoost(int y)
+{
+ int x;
+ float *q = &minimap.data1f[y * minimap.width];
+ for(x = 0; x < minimap.width; ++x)
+ {
+ *q = *q * minimap.boost / ((minimap.boost - 1) * *q + 1);
+ ++q;
+ }
+}
+
+void MiniMapMakeMinsMaxs(vec3_t mins_in, vec3_t maxs_in, float border, qboolean keepaspect)
+{
+ vec3_t mins, maxs, extend;
+ VectorCopy(mins_in, mins);
+ VectorCopy(maxs_in, maxs);
+
+ // line compatible to nexuiz mapinfo
+ Sys_Printf("size %f %f %f %f %f %f\n", mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2]);
+
+ if(keepaspect)
+ {
+ VectorSubtract(maxs, mins, extend);
+ if(extend[1] > extend[0])
+ {
+ mins[0] -= (extend[1] - extend[0]) * 0.5;
+ maxs[0] += (extend[1] - extend[0]) * 0.5;
+ }
+ else
+ {
+ mins[1] -= (extend[0] - extend[1]) * 0.5;
+ maxs[1] += (extend[0] - extend[1]) * 0.5;
+ }
+ }
+
+ /* border: amount of black area around the image */
+ /* input: border, 1-2*border, border but we need border/(1-2*border) */
+
+ VectorSubtract(maxs, mins, extend);
+ VectorScale(extend, border / (1 - 2 * border), extend);
+
+ VectorSubtract(mins, extend, mins);
+ VectorAdd(maxs, extend, maxs);
+
+ VectorCopy(mins, minimap.mins);
+ VectorSubtract(maxs, mins, minimap.size);
+
+ // line compatible to nexuiz mapinfo
+ Sys_Printf("size_texcoords %f %f %f %f %f %f\n", mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2]);
+}
+
+/*
+MiniMapSetupBrushes()
+determines solid non-sky brushes in the world
+*/
+
+void MiniMapSetupBrushes( void )
+{
+ int i, b, compileFlags;
+ bspBrush_t *brush;
+ bspShader_t *shader;
+ shaderInfo_t *si;
+
+
+ /* note it */
+ Sys_FPrintf( SYS_VRB, "--- MiniMapSetupBrushes ---\n" );
+
+ /* allocate */
+ if( opaqueBrushes == NULL )
+ opaqueBrushes = safe_malloc( numBSPBrushes / 8 + 1 );
+
+ /* clear */
+ memset( opaqueBrushes, 0, numBSPBrushes / 8 + 1 );
+ numOpaqueBrushes = 0;
+
+ /* walk the list of worldspawn brushes */
+ for( i = 0; i < minimap.model->numBSPBrushes; i++ )
+ {
+ /* get brush */
+ b = minimap.model->firstBSPBrush + i;
+ brush = &bspBrushes[ b ];
+
+#if 0
+ /* check all sides */
+ compileFlags = 0;
+ for( j = 0; j < brush->numSides; j++ )
+ {
+ /* do bsp shader calculations */
+ side = &bspBrushSides[ brush->firstSide + j ];
+ shader = &bspShaders[ side->shaderNum ];
+
+ /* get shader info */
+ si = ShaderInfoForShader( shader->shader );
+ if( si == NULL )
+ continue;
+
+ /* or together compile flags */
+ compileFlags |= si->compileFlags;
+ }
+#else
+ shader = &bspShaders[ brush->shaderNum ];
+ si = ShaderInfoForShader( shader->shader );
+ if( si == NULL )
+ compileFlags = 0;
+ else
+ compileFlags = si->compileFlags;
+#endif
+
+ /* determine if this brush is solid */
+ if( (compileFlags & (C_SOLID | C_SKY)) == C_SOLID )
+ {
+ opaqueBrushes[ b >> 3 ] |= (1 << (b & 7));
+ numOpaqueBrushes++;
+ maxOpaqueBrush = i;
+ }
+ }
+
+ /* emit some statistics */
+ Sys_FPrintf( SYS_VRB, "%9d solid brushes\n", numOpaqueBrushes );
+}
+
+qboolean MiniMapEvaluateSampleOffsets(int *bestj, int *bestk, float *bestval)
+{
+ float val, dx, dy;
+ int j, k;
+
+ *bestj = *bestk = -1;
+ *bestval = 3; /* max possible val is 2 */
+
+ for(j = 0; j < minimap.samples; ++j)
+ for(k = j + 1; k < minimap.samples; ++k)
+ {
+ dx = minimap.sample_offsets[2*j+0] - minimap.sample_offsets[2*k+0];
+ dy = minimap.sample_offsets[2*j+1] - minimap.sample_offsets[2*k+1];
+ if(dx > +0.5) dx -= 1;
+ if(dx < -0.5) dx += 1;
+ if(dy > +0.5) dy -= 1;
+ if(dy < -0.5) dy += 1;
+ val = dx * dx + dy * dy;
+ if(val < *bestval)
+ {
+ *bestj = j;
+ *bestk = k;
+ *bestval = val;
+ }
+ }
+
+ return *bestval < 3;
+}
+
+void MiniMapMakeSampleOffsets()
+{
+ int i, j, k, jj, kk;
+ float val, valj, valk, sx, sy, rx, ry;
+
+ Sys_Printf( "Generating good sample offsets (this may take a while)...\n" );
+
+ /* start with entirely random samples */
+ for(i = 0; i < minimap.samples; ++i)
+ {
+ minimap.sample_offsets[2*i+0] = Random();
+ minimap.sample_offsets[2*i+1] = Random();
+ }
+
+ for(i = 0; i < 1000; ++i)
+ {
+ if(MiniMapEvaluateSampleOffsets(&j, &k, &val))
+ {
+ sx = minimap.sample_offsets[2*j+0];
+ sy = minimap.sample_offsets[2*j+1];
+ minimap.sample_offsets[2*j+0] = rx = Random();
+ minimap.sample_offsets[2*j+1] = ry = Random();
+ if(!MiniMapEvaluateSampleOffsets(&jj, &kk, &valj))
+ valj = -1;
+ minimap.sample_offsets[2*j+0] = sx;
+ minimap.sample_offsets[2*j+1] = sy;
+
+ sx = minimap.sample_offsets[2*k+0];
+ sy = minimap.sample_offsets[2*k+1];
+ minimap.sample_offsets[2*k+0] = rx;
+ minimap.sample_offsets[2*k+1] = ry;
+ if(!MiniMapEvaluateSampleOffsets(&jj, &kk, &valk))
+ valk = -1;
+ minimap.sample_offsets[2*k+0] = sx;
+ minimap.sample_offsets[2*k+1] = sy;
+
+ if(valj > valk)
+ {
+ if(valj > val)
+ {
+ /* valj is the greatest */
+ minimap.sample_offsets[2*j+0] = rx;
+ minimap.sample_offsets[2*j+1] = ry;
+ i = -1;
+ }
+ else
+ {
+ /* valj is the greater and it is useless - forget it */
+ }
+ }
+ else
+ {
+ if(valk > val)
+ {
+ /* valk is the greatest */
+ minimap.sample_offsets[2*k+0] = rx;
+ minimap.sample_offsets[2*k+1] = ry;
+ i = -1;
+ }
+ else
+ {
+ /* valk is the greater and it is useless - forget it */
+ }
+ }
+ }
+ else
+ break;
+ }
+}
+
+void MergeRelativePath(char *out, const char *absolute, const char *relative)
+{
+ const char *endpos = absolute + strlen(absolute);
+ while(endpos != absolute && (endpos[-1] == '/' || endpos[-1] == '\\'))
+ --endpos;
+ while(relative[0] == '.' && relative[1] == '.' && (relative[2] == '/' || relative[2] == '\\'))
+ {
+ relative += 3;
+ while(endpos != absolute)
+ {
+ --endpos;
+ if(*endpos == '/' || *endpos == '\\')
+ break;
+ }
+ while(endpos != absolute && (endpos[-1] == '/' || endpos[-1] == '\\'))
+ --endpos;
+ }
+ memcpy(out, absolute, endpos - absolute);
+ out[endpos - absolute] = '/';
+ strcpy(out + (endpos - absolute + 1), relative);
+}
+
+int MiniMapBSPMain( int argc, char **argv )
+{
+ char minimapFilename[1024];
+ char basename[1024];
+ char path[1024];
+ char relativeMinimapFilename[1024];
+ float minimapSharpen;
+ float border;
+ byte *data4b, *p;
+ float *q;
+ int x, y;
+ int i;
+ miniMapMode_t mode;
+ vec3_t mins, maxs;
+ qboolean keepaspect;
+
+ /* arg checking */
+ if( argc < 2 )
+ {
+ Sys_Printf( "Usage: q3map [-v] -minimap [-size n] [-sharpen f] [-samples n | -random n] [-o filename.tga] [-minmax Xmin Ymin Zmin Xmax Ymax Zmax] <mapname>\n" );
+ return 0;
+ }
+
+ /* load the BSP first */
+ strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
+ StripExtension( source );
+ DefaultExtension( source, ".bsp" );
+ Sys_Printf( "Loading %s\n", source );
+ BeginMapShaderFile( source );
+ LoadShaderInfo();
+ LoadBSPFile( source );
+
+ minimap.model = &bspModels[0];
+ VectorCopy(minimap.model->mins, mins);
+ VectorCopy(minimap.model->maxs, maxs);
+
+ *minimapFilename = 0;
+ minimapSharpen = game->miniMapSharpen;
+ minimap.width = minimap.height = game->miniMapSize;
+ border = game->miniMapBorder;
+ keepaspect = game->miniMapKeepAspect;
+ mode = game->miniMapMode;
+
+ minimap.samples = 1;
+ minimap.sample_offsets = NULL;
+ minimap.boost = 1.0;
+
+ /* process arguments */
+ for( i = 1; i < (argc - 1); i++ )
+ {
+ if( !strcmp( argv[ i ], "-size" ) )
+ {
+ minimap.width = minimap.height = atoi(argv[i + 1]);
+ i++;
+ Sys_Printf( "Image size set to %i\n", minimap.width );
+ }
+ else if( !strcmp( argv[ i ], "-sharpen" ) )
+ {
+ minimapSharpen = atof(argv[i + 1]);
+ i++;
+ Sys_Printf( "Sharpening coefficient set to %f\n", minimapSharpen );
+ }
+ else if( !strcmp( argv[ i ], "-samples" ) )
+ {
+ minimap.samples = atoi(argv[i + 1]);
+ i++;
+ Sys_Printf( "Samples set to %i\n", minimap.samples );
+ if(minimap.sample_offsets)
+ free(minimap.sample_offsets);
+ minimap.sample_offsets = malloc(2 * sizeof(*minimap.sample_offsets) * minimap.samples);
+ MiniMapMakeSampleOffsets();
+ }
+ else if( !strcmp( argv[ i ], "-random" ) )
+ {
+ minimap.samples = atoi(argv[i + 1]);
+ i++;
+ Sys_Printf( "Random samples set to %i\n", minimap.samples );
+ if(minimap.sample_offsets)
+ free(minimap.sample_offsets);
+ minimap.sample_offsets = NULL;
+ }
+ else if( !strcmp( argv[ i ], "-border" ) )
+ {
+ border = atof(argv[i + 1]);
+ i++;
+ Sys_Printf( "Border set to %f\n", border );
+ }
+ else if( !strcmp( argv[ i ], "-keepaspect" ) )
+ {
+ keepaspect = qtrue;
+ Sys_Printf( "Keeping aspect ratio by letterboxing\n", border );
+ }
+ else if( !strcmp( argv[ i ], "-nokeepaspect" ) )
+ {
+ keepaspect = qfalse;
+ Sys_Printf( "Not keeping aspect ratio\n", border );
+ }
+ else if( !strcmp( argv[ i ], "-o" ) )
+ {
+ strcpy(minimapFilename, argv[i + 1]);
+ i++;
+ Sys_Printf( "Output file name set to %s\n", minimapFilename );
+ }
+ else if( !strcmp( argv[ i ], "-minmax" ) && i < (argc - 7) )
+ {
+ mins[0] = atof(argv[i + 1]);
+ mins[1] = atof(argv[i + 2]);
+ mins[2] = atof(argv[i + 3]);
+ maxs[0] = atof(argv[i + 4]);
+ maxs[1] = atof(argv[i + 5]);
+ maxs[2] = atof(argv[i + 6]);
+ i += 6;
+ Sys_Printf( "Map mins/maxs overridden\n" );
+ }
+ else if( !strcmp( argv[ i ], "-gray" ) )
+ {
+ mode = MINIMAP_MODE_GRAY;
+ Sys_Printf( "Writing as white-on-black image\n" );
+ }
+ else if( !strcmp( argv[ i ], "-black" ) )
+ {
+ mode = MINIMAP_MODE_BLACK;
+ Sys_Printf( "Writing as black alpha image\n" );
+ }
+ else if( !strcmp( argv[ i ], "-white" ) )
+ {
+ mode = MINIMAP_MODE_WHITE;
+ Sys_Printf( "Writing as white alpha image\n" );
+ }
+ else if( !strcmp( argv[ i ], "-boost" ) )
+ {
+ minimap.boost = atof(argv[i + 1]);
+ i++;
+ Sys_Printf( "Contrast boost set to %f\n", minimap.boost );
+ }
+ }
+
+ MiniMapMakeMinsMaxs(mins, maxs, border, keepaspect);
+
+ if(!*minimapFilename)
+ {
+ ExtractFileBase(source, basename);
+ ExtractFilePath(source, path);
+ sprintf(relativeMinimapFilename, game->miniMapNameFormat, basename);
+ MergeRelativePath(minimapFilename, path, relativeMinimapFilename);
+ Sys_Printf("Output file name automatically set to %s\n", minimapFilename);
+ }
+ ExtractFilePath(minimapFilename, path);
+ Q_mkdir(path);
+
+ if(minimapSharpen >= 0)
+ {
+ minimap.sharpen_centermult = 8 * minimapSharpen + 1;
+ minimap.sharpen_boxmult = -minimapSharpen;
+ }
+
+ minimap.data1f = safe_malloc(minimap.width * minimap.height * sizeof(*minimap.data1f));
+ data4b = safe_malloc(minimap.width * minimap.height * 4);
+ if(minimapSharpen >= 0)
+ minimap.sharpendata1f = safe_malloc(minimap.width * minimap.height * sizeof(*minimap.data1f));
+
+ MiniMapSetupBrushes();
+
+ if(minimap.samples <= 1)
+ {
+ Sys_Printf( "\n--- MiniMapNoSupersampling (%d) ---\n", minimap.height );
+ RunThreadsOnIndividual(minimap.height, qtrue, MiniMapNoSupersampling);
+ }
+ else
+ {
+ if(minimap.sample_offsets)
+ {
+ Sys_Printf( "\n--- MiniMapSupersampled (%d) ---\n", minimap.height );
+ RunThreadsOnIndividual(minimap.height, qtrue, MiniMapSupersampled);
+ }
+ else
+ {
+ Sys_Printf( "\n--- MiniMapRandomlySupersampled (%d) ---\n", minimap.height );
+ RunThreadsOnIndividual(minimap.height, qtrue, MiniMapRandomlySupersampled);
+ }
+ }
+
+ if(minimap.boost != 1.0)
+ {
+ Sys_Printf( "\n--- MiniMapContrastBoost (%d) ---\n", minimap.height );
+ RunThreadsOnIndividual(minimap.height, qtrue, MiniMapContrastBoost);
+ }
+
+ if(minimap.sharpendata1f)
+ {
+ Sys_Printf( "\n--- MiniMapSharpen (%d) ---\n", minimap.height );
+ RunThreadsOnIndividual(minimap.height, qtrue, MiniMapSharpen);
+ q = minimap.sharpendata1f;
+ }
+ else
+ {
+ q = minimap.data1f;
+ }
+
+ Sys_Printf( "\nConverting...");
+
+ switch(mode)
+ {
+ case MINIMAP_MODE_GRAY:
+ p = data4b;
+ for(y = 0; y < minimap.height; ++y)
+ for(x = 0; x < minimap.width; ++x)
+ {
+ byte b;
+ float v = *q++;
+ if(v < 0) v = 0;
+ if(v > 255.0/256.0) v = 255.0/256.0;
+ b = v * 256;
+ *p++ = b;
+ }
+ Sys_Printf( " writing to %s...", minimapFilename );
+ WriteTGAGray(minimapFilename, data4b, minimap.width, minimap.height);
+ break;
+ case MINIMAP_MODE_BLACK:
+ p = data4b;
+ for(y = 0; y < minimap.height; ++y)
+ for(x = 0; x < minimap.width; ++x)
+ {
+ byte b;
+ float v = *q++;
+ if(v < 0) v = 0;
+ if(v > 255.0/256.0) v = 255.0/256.0;
+ b = v * 256;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = b;
+ }
+ Sys_Printf( " writing to %s...", minimapFilename );
+ WriteTGA(minimapFilename, data4b, minimap.width, minimap.height);
+ break;
+ case MINIMAP_MODE_WHITE:
+ p = data4b;
+ for(y = 0; y < minimap.height; ++y)
+ for(x = 0; x < minimap.width; ++x)
+ {
+ byte b;
+ float v = *q++;
+ if(v < 0) v = 0;
+ if(v > 255.0/256.0) v = 255.0/256.0;
+ b = v * 256;
+ *p++ = 255;
+ *p++ = 255;
+ *p++ = 255;
+ *p++ = b;
+ }
+ Sys_Printf( " writing to %s...", minimapFilename );
+ WriteTGA(minimapFilename, data4b, minimap.width, minimap.height);
+ break;
+ }
+
+ Sys_Printf( " done.\n" );
+
+ /* return to sender */
+ return 0;
+}
+
+
+
+
+
+/*
+MD4BlockChecksum()
+calculates an md4 checksum for a block of data
+*/
+
+static int MD4BlockChecksum( void *buffer, int length )
+{
+ return Com_BlockChecksum(buffer, length);
}
/*
lump = (byte*) header + offset;
lumpInt = LittleLong( (int) *((int*) lump) );
lumpFloat = LittleFloat( (float) *((float*) lump) );
- memcpy( lumpString, (char*) lump, (length < 1024 ? length : 1024) );
- lumpString[ 1024 ] = '\0';
+ memcpy( lumpString, (char*) lump, (length < sizeof(lumpString) ? length : sizeof(lumpString)-1) );
+ lumpString[ sizeof(lumpString)-1 ] = '\0';
/* print basic lump info */
Sys_Printf( "Lump: %d\n", i );
}
+static void ExtrapolateTexcoords(const float *axyz, const float *ast, const float *bxyz, const float *bst, const float *cxyz, const float *cst, const float *axyz_new, float *ast_out, const float *bxyz_new, float *bst_out, const float *cxyz_new, float *cst_out)
+{
+ vec4_t scoeffs, tcoeffs;
+ float md;
+ m4x4_t solvematrix;
+
+ vec3_t norm;
+ vec3_t dab, dac;
+ VectorSubtract(bxyz, axyz, dab);
+ VectorSubtract(cxyz, axyz, dac);
+ CrossProduct(dab, dac, norm);
+
+ // assume:
+ // s = f(x, y, z)
+ // s(v + norm) = s(v) when n ortho xyz
+
+ // s(v) = DotProduct(v, scoeffs) + scoeffs[3]
+
+ // solve:
+ // scoeffs * (axyz, 1) == ast[0]
+ // scoeffs * (bxyz, 1) == bst[0]
+ // scoeffs * (cxyz, 1) == cst[0]
+ // scoeffs * (norm, 0) == 0
+ // scoeffs * [axyz, 1 | bxyz, 1 | cxyz, 1 | norm, 0] = [ast[0], bst[0], cst[0], 0]
+ solvematrix[0] = axyz[0];
+ solvematrix[4] = axyz[1];
+ solvematrix[8] = axyz[2];
+ solvematrix[12] = 1;
+ solvematrix[1] = bxyz[0];
+ solvematrix[5] = bxyz[1];
+ solvematrix[9] = bxyz[2];
+ solvematrix[13] = 1;
+ solvematrix[2] = cxyz[0];
+ solvematrix[6] = cxyz[1];
+ solvematrix[10] = cxyz[2];
+ solvematrix[14] = 1;
+ solvematrix[3] = norm[0];
+ solvematrix[7] = norm[1];
+ solvematrix[11] = norm[2];
+ solvematrix[15] = 0;
+
+ md = m4_det(solvematrix);
+ if(md*md < 1e-10)
+ {
+ Sys_Printf("Cannot invert some matrix, some texcoords aren't extrapolated!");
+ return;
+ }
+
+ m4x4_invert(solvematrix);
+
+ scoeffs[0] = ast[0];
+ scoeffs[1] = bst[0];
+ scoeffs[2] = cst[0];
+ scoeffs[3] = 0;
+ m4x4_transform_vec4(solvematrix, scoeffs);
+ tcoeffs[0] = ast[1];
+ tcoeffs[1] = bst[1];
+ tcoeffs[2] = cst[1];
+ tcoeffs[3] = 0;
+ m4x4_transform_vec4(solvematrix, tcoeffs);
+
+ ast_out[0] = scoeffs[0] * axyz_new[0] + scoeffs[1] * axyz_new[1] + scoeffs[2] * axyz_new[2] + scoeffs[3];
+ ast_out[1] = tcoeffs[0] * axyz_new[0] + tcoeffs[1] * axyz_new[1] + tcoeffs[2] * axyz_new[2] + tcoeffs[3];
+ bst_out[0] = scoeffs[0] * bxyz_new[0] + scoeffs[1] * bxyz_new[1] + scoeffs[2] * bxyz_new[2] + scoeffs[3];
+ bst_out[1] = tcoeffs[0] * bxyz_new[0] + tcoeffs[1] * bxyz_new[1] + tcoeffs[2] * bxyz_new[2] + tcoeffs[3];
+ cst_out[0] = scoeffs[0] * cxyz_new[0] + scoeffs[1] * cxyz_new[1] + scoeffs[2] * cxyz_new[2] + scoeffs[3];
+ cst_out[1] = tcoeffs[0] * cxyz_new[0] + tcoeffs[1] * cxyz_new[1] + tcoeffs[2] * cxyz_new[2] + tcoeffs[3];
+}
/*
ScaleBSPMain()
int ScaleBSPMain( int argc, char **argv )
{
- int i;
- float f, scale;
+ int i, j;
+ float f, a;
+ vec3_t scale;
vec3_t vec;
char str[ 1024 ];
+ int uniform, axis;
+ qboolean texscale;
+ float *old_xyzst = NULL;
+ float spawn_ref = 0;
/* arg checking */
- if( argc < 2 )
+ if( argc < 3 )
{
- Sys_Printf( "Usage: q3map -scale <value> [-v] <mapname>\n" );
+ Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref <value>] <value> <mapname>\n" );
return 0;
}
+ texscale = qfalse;
+ for(i = 1; i < argc-2; ++i)
+ {
+ if(!strcmp(argv[i], "-tex"))
+ {
+ texscale = qtrue;
+ }
+ else if(!strcmp(argv[i], "-spawn_ref"))
+ {
+ spawn_ref = atof(argv[i+1]);
+ ++i;
+ }
+ else
+ break;
+ }
+
/* get scale */
- scale = atof( argv[ argc - 2 ] );
- if( scale == 0.0f )
+ // if(argc-2 >= i) // always true
+ scale[2] = scale[1] = scale[0] = atof( argv[ argc - 2 ] );
+ if(argc-3 >= i)
+ scale[1] = scale[0] = atof( argv[ argc - 3 ] );
+ if(argc-4 >= i)
+ scale[0] = atof( argv[ argc - 4 ] );
+
+ uniform = ((scale[0] == scale[1]) && (scale[1] == scale[2]));
+
+ if( scale[0] == 0.0f || scale[1] == 0.0f || scale[2] == 0.0f )
{
- Sys_Printf( "Usage: q3map -scale <value> [-v] <mapname>\n" );
+ Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref <value>] <value> <mapname>\n" );
Sys_Printf( "Non-zero scale value required.\n" );
return 0;
}
{
/* scale origin */
GetVectorForKey( &entities[ i ], "origin", vec );
- if( (vec[ 0 ] + vec[ 1 ] + vec[ 2 ]) )
+ if( (vec[ 0 ] || vec[ 1 ] || vec[ 2 ]) )
{
- VectorScale( vec, scale, vec );
+ if(!strncmp(ValueForKey(&entities[i], "classname"), "info_player_", 12))
+ vec[2] += spawn_ref;
+ vec[0] *= scale[0];
+ vec[1] *= scale[1];
+ vec[2] *= scale[2];
+ if(!strncmp(ValueForKey(&entities[i], "classname"), "info_player_", 12))
+ vec[2] -= spawn_ref;
sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
SetKeyValue( &entities[ i ], "origin", str );
}
+
+ a = FloatForKey( &entities[ i ], "angle" );
+ if(a == -1 || a == -2) // z scale
+ axis = 2;
+ else if(fabs(sin(DEG2RAD(a))) < 0.707)
+ axis = 0;
+ else
+ axis = 1;
/* scale door lip */
f = FloatForKey( &entities[ i ], "lip" );
if( f )
{
- f *= scale;
+ f *= scale[axis];
sprintf( str, "%f", f );
SetKeyValue( &entities[ i ], "lip", str );
}
+
+ /* scale plat height */
+ f = FloatForKey( &entities[ i ], "height" );
+ if( f )
+ {
+ f *= scale[2];
+ sprintf( str, "%f", f );
+ SetKeyValue( &entities[ i ], "height", str );
+ }
+
+ // TODO maybe allow a definition file for entities to specify which values are scaled how?
}
/* scale models */
for( i = 0; i < numBSPModels; i++ )
{
- VectorScale( bspModels[ i ].mins, scale, bspModels[ i ].mins );
- VectorScale( bspModels[ i ].maxs, scale, bspModels[ i ].maxs );
+ bspModels[ i ].mins[0] *= scale[0];
+ bspModels[ i ].mins[1] *= scale[1];
+ bspModels[ i ].mins[2] *= scale[2];
+ bspModels[ i ].maxs[0] *= scale[0];
+ bspModels[ i ].maxs[1] *= scale[1];
+ bspModels[ i ].maxs[2] *= scale[2];
}
/* scale nodes */
for( i = 0; i < numBSPNodes; i++ )
{
- VectorScale( bspNodes[ i ].mins, scale, bspNodes[ i ].mins );
- VectorScale( bspNodes[ i ].maxs, scale, bspNodes[ i ].maxs );
+ bspNodes[ i ].mins[0] *= scale[0];
+ bspNodes[ i ].mins[1] *= scale[1];
+ bspNodes[ i ].mins[2] *= scale[2];
+ bspNodes[ i ].maxs[0] *= scale[0];
+ bspNodes[ i ].maxs[1] *= scale[1];
+ bspNodes[ i ].maxs[2] *= scale[2];
}
/* scale leafs */
for( i = 0; i < numBSPLeafs; i++ )
{
- VectorScale( bspLeafs[ i ].mins, scale, bspLeafs[ i ].mins );
- VectorScale( bspLeafs[ i ].maxs, scale, bspLeafs[ i ].maxs );
+ bspLeafs[ i ].mins[0] *= scale[0];
+ bspLeafs[ i ].mins[1] *= scale[1];
+ bspLeafs[ i ].mins[2] *= scale[2];
+ bspLeafs[ i ].maxs[0] *= scale[0];
+ bspLeafs[ i ].maxs[1] *= scale[1];
+ bspLeafs[ i ].maxs[2] *= scale[2];
}
+ if(texscale)
+ {
+ Sys_Printf("Using texture unlocking (and probably breaking texture alignment a lot)\n");
+ old_xyzst = safe_malloc(sizeof(*old_xyzst) * numBSPDrawVerts * 5);
+ for(i = 0; i < numBSPDrawVerts; i++)
+ {
+ old_xyzst[5*i+0] = bspDrawVerts[i].xyz[0];
+ old_xyzst[5*i+1] = bspDrawVerts[i].xyz[1];
+ old_xyzst[5*i+2] = bspDrawVerts[i].xyz[2];
+ old_xyzst[5*i+3] = bspDrawVerts[i].st[0];
+ old_xyzst[5*i+4] = bspDrawVerts[i].st[1];
+ }
+ }
+
/* scale drawverts */
for( i = 0; i < numBSPDrawVerts; i++ )
- VectorScale( bspDrawVerts[ i ].xyz, scale, bspDrawVerts[ i ].xyz );
+ {
+ bspDrawVerts[i].xyz[0] *= scale[0];
+ bspDrawVerts[i].xyz[1] *= scale[1];
+ bspDrawVerts[i].xyz[2] *= scale[2];
+ bspDrawVerts[i].normal[0] /= scale[0];
+ bspDrawVerts[i].normal[1] /= scale[1];
+ bspDrawVerts[i].normal[2] /= scale[2];
+ VectorNormalize(bspDrawVerts[i].normal, bspDrawVerts[i].normal);
+ }
+
+ if(texscale)
+ {
+ for(i = 0; i < numBSPDrawSurfaces; i++)
+ {
+ switch(bspDrawSurfaces[i].surfaceType)
+ {
+ case SURFACE_FACE:
+ case SURFACE_META:
+ if(bspDrawSurfaces[i].numIndexes % 3)
+ Error("Not a triangulation!");
+ for(j = bspDrawSurfaces[i].firstIndex; j < bspDrawSurfaces[i].firstIndex + bspDrawSurfaces[i].numIndexes; j += 3)
+ {
+ int ia = bspDrawIndexes[j] + bspDrawSurfaces[i].firstVert, ib = bspDrawIndexes[j+1] + bspDrawSurfaces[i].firstVert, ic = bspDrawIndexes[j+2] + bspDrawSurfaces[i].firstVert;
+ bspDrawVert_t *a = &bspDrawVerts[ia], *b = &bspDrawVerts[ib], *c = &bspDrawVerts[ic];
+ float *oa = &old_xyzst[ia*5], *ob = &old_xyzst[ib*5], *oc = &old_xyzst[ic*5];
+ // extrapolate:
+ // a->xyz -> oa
+ // b->xyz -> ob
+ // c->xyz -> oc
+ ExtrapolateTexcoords(
+ &oa[0], &oa[3],
+ &ob[0], &ob[3],
+ &oc[0], &oc[3],
+ a->xyz, a->st,
+ b->xyz, b->st,
+ c->xyz, c->st);
+ }
+ break;
+ }
+ }
+ }
/* scale planes */
- for( i = 0; i < numBSPPlanes; i++ )
- bspPlanes[ i ].dist *= scale;
+ if(uniform)
+ {
+ for( i = 0; i < numBSPPlanes; i++ )
+ {
+ bspPlanes[ i ].dist *= scale[0];
+ }
+ }
+ else
+ {
+ for( i = 0; i < numBSPPlanes; i++ )
+ {
+ bspPlanes[ i ].normal[0] /= scale[0];
+ bspPlanes[ i ].normal[1] /= scale[1];
+ bspPlanes[ i ].normal[2] /= scale[2];
+ f = 1/VectorLength(bspPlanes[i].normal);
+ VectorScale(bspPlanes[i].normal, f, bspPlanes[i].normal);
+ bspPlanes[ i ].dist *= f;
+ }
+ }
/* scale gridsize */
GetVectorForKey( &entities[ 0 ], "gridsize", vec );
if( (vec[ 0 ] + vec[ 1 ] + vec[ 2 ]) == 0.0f )
VectorCopy( gridSize, vec );
- VectorScale( vec, scale, vec );
+ vec[0] *= scale[0];
+ vec[1] *= scale[1];
+ vec[2] *= scale[2];
sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
SetKeyValue( &entities[ 0 ], "gridsize", str );
+
+ /* inject command line parameters */
+ InjectCommandLine(argv, 0, argc - 1);
/* write the bsp */
UnparseEntities();
}
+/*
+PseudoCompileBSP()
+a stripped down ProcessModels
+*/
+void PseudoCompileBSP(qboolean need_tree)
+{
+ int models;
+ char modelValue[10];
+ entity_t *entity;
+ face_t *faces;
+ tree_t *tree;
+ node_t *node;
+ brush_t *brush;
+ side_t *side;
+ int i;
+
+ SetDrawSurfacesBuffer();
+ mapDrawSurfs = safe_malloc( sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS );
+ memset( mapDrawSurfs, 0, sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS );
+ numMapDrawSurfs = 0;
+
+ BeginBSPFile();
+ models = 1;
+ for( mapEntityNum = 0; mapEntityNum < numEntities; mapEntityNum++ )
+ {
+ /* get entity */
+ entity = &entities[ mapEntityNum ];
+ if( entity->brushes == NULL && entity->patches == NULL )
+ continue;
+
+ if(mapEntityNum != 0)
+ {
+ sprintf( modelValue, "*%d", models++);
+ SetKeyValue(entity, "model", modelValue);
+ }
+
+ /* process the model */
+ Sys_FPrintf( SYS_VRB, "############### model %i ###############\n", numBSPModels );
+ BeginModel();
+
+ entity->firstDrawSurf = numMapDrawSurfs;
+
+ ClearMetaTriangles();
+ PatchMapDrawSurfs(entity);
+
+ if(mapEntityNum == 0 && need_tree)
+ {
+ faces = MakeStructuralBSPFaceList(entities[0].brushes);
+ tree = FaceBSP(faces);
+ node = tree->headnode;
+ }
+ else
+ {
+ node = AllocNode();
+ node->planenum = PLANENUM_LEAF;
+ tree = AllocTree();
+ tree->headnode = node;
+ }
+
+ /* a minimized ClipSidesIntoTree */
+ for( brush = entity->brushes; brush; brush = brush->next )
+ {
+ /* walk the brush sides */
+ for( i = 0; i < brush->numsides; i++ )
+ {
+ /* get side */
+ side = &brush->sides[ i ];
+ if( side->winding == NULL )
+ continue;
+ /* shader? */
+ if( side->shaderInfo == NULL )
+ continue;
+ /* save this winding as a visible surface */
+ DrawSurfaceForSide(entity, brush, side, side->winding);
+ }
+ }
+
+ if(meta)
+ {
+ ClassifyEntitySurfaces(entity);
+ MakeEntityDecals(entity);
+ MakeEntityMetaTriangles(entity);
+ SmoothMetaTriangles();
+ MergeMetaTriangles();
+ }
+ FilterDrawsurfsIntoTree(entity, tree);
+
+ FilterStructuralBrushesIntoTree(entity, tree);
+ FilterDetailBrushesIntoTree(entity, tree);
+
+ EmitBrushes(entity->brushes, &entity->firstBrush, &entity->numBrushes );
+ EndModel(entity, node);
+ }
+ EndBSPFile(qfalse);
+}
/*
ConvertBSPMain()
int i;
int (*convertFunc)( char * );
game_t *convertGame;
+ char ext[1024];
+ qboolean map_allowed, force_bsp, force_map;
/* set default */
convertFunc = ConvertBSPToASE;
convertGame = NULL;
+ map_allowed = qfalse;
+ force_bsp = qfalse;
+ force_map = qfalse;
/* arg checking */
if( argc < 1 )
{
- Sys_Printf( "Usage: q3map -scale <value> [-v] <mapname>\n" );
+ Sys_Printf( "Usage: q3map -convert -format <ase|obj|map_bp|map> [-shadesasbitmap|-lightmapsastexcoord|-deluxemapsastexcoord] [-readbsp|-readmap [-meta|-patchmeta]] <mapname>\n" );
return 0;
}
{
i++;
if( !Q_stricmp( argv[ i ], "ase" ) )
+ {
convertFunc = ConvertBSPToASE;
+ map_allowed = qfalse;
+ }
+ else if( !Q_stricmp( argv[ i ], "obj" ) )
+ {
+ convertFunc = ConvertBSPToOBJ;
+ map_allowed = qfalse;
+ }
+ else if( !Q_stricmp( argv[ i ], "map_bp" ) )
+ {
+ convertFunc = ConvertBSPToMap_BP;
+ map_allowed = qtrue;
+ }
else if( !Q_stricmp( argv[ i ], "map" ) )
+ {
convertFunc = ConvertBSPToMap;
+ map_allowed = qtrue;
+ }
else
{
convertGame = GetGame( argv[ i ] );
+ map_allowed = qfalse;
if( convertGame == NULL )
Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
}
}
+ else if( !strcmp( argv[ i ], "-ne" ) )
+ {
+ normalEpsilon = atof( argv[ i + 1 ] );
+ i++;
+ Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
+ }
+ else if( !strcmp( argv[ i ], "-de" ) )
+ {
+ distanceEpsilon = atof( argv[ i + 1 ] );
+ i++;
+ Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
+ }
+ else if( !strcmp( argv[ i ], "-shadersasbitmap" ) )
+ shadersAsBitmap = qtrue;
+ else if( !strcmp( argv[ i ], "-lightmapsastexcoord" ) )
+ lightmapsAsTexcoord = qtrue;
+ else if( !strcmp( argv[ i ], "-deluxemapsastexcoord" ) )
+ {
+ lightmapsAsTexcoord = qtrue;
+ deluxemap = qtrue;
+ }
+ else if( !strcmp( argv[ i ], "-readbsp" ) )
+ force_bsp = qtrue;
+ else if( !strcmp( argv[ i ], "-readmap" ) )
+ force_map = qtrue;
+ else if( !strcmp( argv[ i ], "-meta" ) )
+ meta = qtrue;
+ else if( !strcmp( argv[ i ], "-patchmeta" ) )
+ {
+ meta = qtrue;
+ patchMeta = qtrue;
+ }
}
-
- /* clean up map name */
- strcpy( source, ExpandArg( argv[ i ] ) );
- StripExtension( source );
- DefaultExtension( source, ".bsp" );
-
+
LoadShaderInfo();
- Sys_Printf( "Loading %s\n", source );
-
- /* ydnar: load surface file */
- //% LoadSurfaceExtraFile( source );
-
- LoadBSPFile( source );
-
- /* parse bsp entities */
- ParseEntities();
+ /* clean up map name */
+ strcpy(source, ExpandArg(argv[i]));
+ ExtractFileExtension(source, ext);
+
+ if(!map_allowed && !force_map)
+ force_bsp = qtrue;
+
+ if(force_map || (!force_bsp && !Q_stricmp(ext, "map") && map_allowed))
+ {
+ if(!map_allowed)
+ Sys_Printf("WARNING: the requested conversion should not be done from .map files. Compile a .bsp first.\n");
+ StripExtension(source);
+ DefaultExtension(source, ".map");
+ Sys_Printf("Loading %s\n", source);
+ LoadMapFile(source, qfalse, convertGame == NULL);
+ PseudoCompileBSP(convertGame != NULL);
+ }
+ else
+ {
+ StripExtension(source);
+ DefaultExtension(source, ".bsp");
+ Sys_Printf("Loading %s\n", source);
+ LoadBSPFile(source);
+ ParseEntities();
+ }
/* bsp format convert? */
if( convertGame != NULL )
/* set exit call */
atexit( ExitQ3Map );
-
+
/* read general options first */
for( i = 1; i < argc; i++ )
{
/* verbose */
else if( !strcmp( argv[ i ], "-v" ) )
{
- verbose = qtrue;
- argv[ i ] = NULL;
+ if(!verbose)
+ {
+ verbose = qtrue;
+ argv[ i ] = NULL;
+ }
}
/* force */
argv[ i ] = NULL;
}
}
-
+
/* init model library */
PicoInit();
PicoSetMallocFunc( safe_malloc );
Sys_Printf( "Q3Map - v1.0r (c) 1999 Id Software Inc.\n" );
Sys_Printf( "Q3Map (ydnar) - v" Q3MAP_VERSION "\n" );
- Sys_Printf( "GtkRadiant - v" RADIANT_VERSION " " __DATE__ " " __TIME__ "\n" );
+ Sys_Printf( "NetRadiant - v" RADIANT_VERSION " " __DATE__ " " __TIME__ "\n" );
Sys_Printf( "%s\n", Q3MAP_MOTD );
/* ydnar: new path initialization */
InitPaths( &argc, argv );
+
+ /* set game options */
+ if (!patchSubdivisions)
+ patchSubdivisions = game->patchSubdivisions;
/* check if we have enough options left to attempt something */
if( argc < 2 )
else if( !strcmp( argv[ 1 ], "-convert" ) )
r = ConvertBSPMain( argc - 1, argv + 1 );
+ /* div0: minimap */
+ else if( !strcmp( argv[ 1 ], "-minimap" ) )
+ r = MiniMapBSPMain(argc - 1, argv + 1);
+
/* ydnar: otherwise create a bsp */
else
r = BSPMain( argc, argv );
#define USE_HASHING
#define PLANE_HASHES 8192
-plane_t *planehash[ PLANE_HASHES ];
+int planehash[ PLANE_HASHES ];
int c_boxbevels;
int c_edgebevels;
hash = (PLANE_HASHES - 1) & (int) fabs( p->dist );
p->hash_chain = planehash[hash];
- planehash[hash] = p;
+ planehash[hash] = p - mapplanes + 1;
}
/*
}
// create a new plane
- if (nummapplanes+2 > MAX_MAP_PLANES)
- Error ("MAX_MAP_PLANES");
+ AUTOEXPAND_BY_REALLOC(mapplanes, nummapplanes+1, allocatedmapplanes, 1024);
p = &mapplanes[nummapplanes];
VectorCopy (normal, p->normal);
snaps a plane to normal/distance epsilons
*/
-void SnapPlane( vec3_t normal, vec_t *dist )
+void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center )
{
// SnapPlane disabled by LordHavoc because it often messes up collision
// brushes made from triangles of embedded models, and it has little effect
}
+
/*
FindFloatPlane()
ydnar: changed to allow a number of test points to be supplied that
must be within an epsilon distance of the plane
*/
-int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
+int FindFloatPlane( vec3_t innormal, vec_t dist, int numPoints, vec3_t *points ) // NOTE: this has a side effect on the normal. Good or bad?
#ifdef USE_HASHING
{
int i, j, hash, h;
+ int pidx;
plane_t *p;
vec_t d;
-
-
+ vec3_t normal;
+
+ VectorCopy(innormal, normal);
#if Q3MAP2_EXPERIMENTAL_SNAP_PLANE_FIX
SnapPlaneImproved(normal, &dist, numPoints, (const vec3_t *) points);
#else
for( i = -1; i <= 1; i++ )
{
h = (hash + i) & (PLANE_HASHES - 1);
- for( p = planehash[ h ]; p != NULL; p = p->hash_chain )
+ for( pidx = planehash[ h ] - 1; pidx != -1; pidx = mapplanes[pidx].hash_chain - 1 )
{
+ p = &mapplanes[pidx];
+
/* do standard plane compare */
if( !PlaneEqual( p, normal, dist ) )
continue;
// very small when world coordinates extend to 2^16. Making the
// dot product here in 64 bit land will not really help the situation
// because the error will already be carried in dist.
- d = DotProduct( points[ j ], normal ) - dist;
+ d = DotProduct( points[ j ], p->normal ) - p->dist;
d = fabs(d);
if (d != 0.0 && d >= distanceEpsilon)
break; // Point is too far from plane.
{
int i;
plane_t *p;
+ vec3_t normal;
+ VectorCopy(innormal, normal);
#if Q3MAP2_EXPERIMENTAL_SNAP_PLANE_FIX
SnapPlaneImproved(normal, &dist, numPoints, (const vec3_t *) points);
#else
- SnapPlane( normal, &dist );
+ SnapPlane( normal, &dist );
#endif
for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
{
- if( PlaneEqual( p, normal, dist ) )
+ if( !PlaneEqual( p, normal, dist ) )
+ continue;
+
+ /* ydnar: uncomment the following line for old-style plane finding */
+ //% return i;
+
+ /* ydnar: test supplied points against this plane */
+ for( j = 0; j < numPoints; j++ )
+ {
+ d = DotProduct( points[ j ], p->normal ) - p->dist;
+ if( fabs( d ) > distanceEpsilon )
+ break;
+ }
+
+ /* found a matching plane */
+ if( j >= numPoints )
return i;
// TODO: Note that the non-USE_HASHING code does not compute epsilons
// for the provided points. It should do that. I think this code
continue;
if( s->contentFlags != contentFlags || s->compileFlags != compileFlags )
mixed = qtrue;
+
+ contentFlags |= s->contentFlags;
+ compileFlags |= s->compileFlags;
}
/* ydnar: getting rid of this stupid warning */
and links it to the current entity
*/
-brush_t *FinishBrush( void )
+static void MergeOrigin(entity_t *ent, vec3_t origin)
+{
+ vec3_t adjustment;
+ char string[128];
+
+ /* we have not parsed the brush completely yet... */
+ GetVectorForKey( ent, "origin", ent->origin );
+
+ VectorMA(origin, -1, ent->originbrush_origin, adjustment);
+ VectorAdd(adjustment, ent->origin, ent->origin);
+ VectorCopy(origin, ent->originbrush_origin);
+
+ sprintf(string, "%f %f %f", ent->origin[0], ent->origin[1], ent->origin[2]);
+ SetKeyValue(ent, "origin", string);
+}
+
+brush_t *FinishBrush( qboolean noCollapseGroups )
{
brush_t *b;
after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */
if( buildBrush->compileFlags & C_ORIGIN )
{
- char string[ 32 ];
vec3_t origin;
+ Sys_Printf( "Entity %i, Brush %i: origin brush detected\n",
+ mapEnt->mapEntityNum, entitySourceBrushes );
+
if( numEntities == 1 )
{
Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n",
VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
VectorScale (origin, 0.5, origin);
- sprintf( string, "%i %i %i", (int) origin[ 0 ], (int) origin[ 1 ], (int) origin[ 2 ] );
- SetKeyValue( &entities[ numEntities - 1 ], "origin", string);
-
- VectorCopy( origin, entities[ numEntities - 1 ].origin);
+ MergeOrigin(&entities[ numEntities - 1 ], origin);
/* don't keep this brush */
return NULL;
}
/* add bevel planes */
- AddBrushBevels();
+ if(!noCollapseGroups)
+ AddBrushBevels();
/* keep it */
b = CopyBrush( buildBrush );
int planenum;
shaderInfo_t *si;
vec_t shift[ 2 ];
- vec_t rotate;
+ vec_t rotate = 0;
vec_t scale[ 2 ];
char name[ MAX_QPATH ];
char shader[ MAX_QPATH ];
parses a brush out of a map file and sets it up
*/
-static void ParseBrush( qboolean onlyLights )
+static void ParseBrush( qboolean onlyLights, qboolean noCollapseGroups )
{
brush_t *b;
}
/* finish the brush */
- b = FinishBrush();
+ b = FinishBrush(noCollapseGroups);
}
(used by func_group)
*/
+void AdjustBrushesForOrigin( entity_t *ent );
void MoveBrushesToWorld( entity_t *ent )
{
brush_t *b, *next;
parseMesh_t *pm;
+ /* we need to undo the common/origin adjustment, and instead shift them by the entity key origin */
+ VectorScale(ent->origin, -1, ent->originbrush_origin);
+ AdjustBrushesForOrigin(ent);
+ VectorClear(ent->originbrush_origin);
/* move brushes */
for( b = ent->brushes; b != NULL; b = next )
brush_t *b;
parseMesh_t *p;
-
/* walk brush list */
for( b = ent->brushes; b != NULL; b = b->next )
{
s = &b->sides[ i ];
/* offset side plane */
- newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->origin );
+ newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->originbrush_origin );
/* find a new plane */
s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL );
for( p = ent->patches; p != NULL; p = p->next )
{
for( i = 0; i < (p->mesh.width * p->mesh.height); i++ )
- VectorSubtract( p->mesh.verts[ i ].xyz, ent->origin, p->mesh.verts[ i ].xyz );
+ VectorSubtract( p->mesh.verts[ i ].xyz, ent->originbrush_origin, p->mesh.verts[ i ].xyz );
}
}
parses a single entity out of a map file
*/
-static qboolean ParseMapEntity( qboolean onlyLights )
+static qboolean ParseMapEntity( qboolean onlyLights, qboolean noCollapseGroups )
{
epair_t *ep;
const char *classname, *value;
- float lightmapScale;
+ float lightmapScale, shadeAngle;
+ int lightmapSampleSize;
char shader[ MAX_QPATH ];
shaderInfo_t *celShader = NULL;
brush_t *brush;
g_bBrushPrimit = BPRIMIT_NEWBRUSHES;
/* parse brush primitive */
- ParseBrush( onlyLights );
+ ParseBrush( onlyLights, noCollapseGroups );
}
else
{
/* parse old brush format */
UnGetToken();
- ParseBrush( onlyLights );
+ ParseBrush( onlyLights, noCollapseGroups );
}
entitySourceBrushes++;
}
/* get explicit shadow flags */
GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
+ /* vortex: added _ls key (short name of lightmapscale) */
/* ydnar: get lightmap scaling value for this entity */
+ lightmapScale = 0.0f;
if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) ||
- strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) )
+ strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) ||
+ strcmp( "", ValueForKey( mapEnt, "_ls" ) ) )
{
/* get lightmap scale from entity */
lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
if( lightmapScale <= 0.0f )
lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
+ if( lightmapScale <= 0.0f )
+ lightmapScale = FloatForKey( mapEnt, "_ls" );
+ if( lightmapScale < 0.0f )
+ lightmapScale = 0.0f;
if( lightmapScale > 0.0f )
Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
}
- else
- lightmapScale = 0.0f;
/* ydnar: get cel shader :) for this entity */
value = ValueForKey( mapEnt, "_celshader" );
value = ValueForKey( &entities[ 0 ], "_celshader" );
if( value[ 0 ] != '\0' )
{
- sprintf( shader, "textures/%s", value );
- celShader = ShaderInfoForShader( shader );
- Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
+ if(strcmp(value, "none"))
+ {
+ sprintf( shader, "textures/%s", value );
+ celShader = ShaderInfoForShader( shader );
+ Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
+ }
+ else
+ {
+ celShader = NULL;
+ }
}
else
- celShader = NULL;
+ celShader = (*globalCelShader ? ShaderInfoForShader(globalCelShader) : NULL);
+
+ /* jal : entity based _shadeangle */
+ shadeAngle = 0.0f;
+ if ( strcmp( "", ValueForKey( mapEnt, "_shadeangle" ) ) )
+ shadeAngle = FloatForKey( mapEnt, "_shadeangle" );
+ /* vortex' aliases */
+ else if ( strcmp( "", ValueForKey( mapEnt, "_smoothnormals" ) ) )
+ shadeAngle = FloatForKey( mapEnt, "_smoothnormals" );
+ else if ( strcmp( "", ValueForKey( mapEnt, "_sn" ) ) )
+ shadeAngle = FloatForKey( mapEnt, "_sn" );
+ else if ( strcmp( "", ValueForKey( mapEnt, "_smooth" ) ) )
+ shadeAngle = FloatForKey( mapEnt, "_smooth" );
+
+ if( shadeAngle < 0.0f )
+ shadeAngle = 0.0f;
+
+ if( shadeAngle > 0.0f )
+ Sys_Printf( "Entity %d (%s) has shading angle of %.4f\n", mapEnt->mapEntityNum, classname, shadeAngle );
+
+ /* jal : entity based _samplesize */
+ lightmapSampleSize = 0;
+ if ( strcmp( "", ValueForKey( mapEnt, "_lightmapsamplesize" ) ) )
+ lightmapSampleSize = IntForKey( mapEnt, "_lightmapsamplesize" );
+ else if ( strcmp( "", ValueForKey( mapEnt, "_samplesize" ) ) )
+ lightmapSampleSize = IntForKey( mapEnt, "_samplesize" );
+
+ if( lightmapSampleSize < 0 )
+ lightmapSampleSize = 0;
+
+ if( lightmapSampleSize > 0 )
+ Sys_Printf( "Entity %d (%s) has lightmap sample size of %d\n", mapEnt->mapEntityNum, classname, lightmapSampleSize );
/* attach stuff to everything in the entity */
for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
brush->entityNum = mapEnt->mapEntityNum;
brush->castShadows = castShadows;
brush->recvShadows = recvShadows;
+ brush->lightmapSampleSize = lightmapSampleSize;
brush->lightmapScale = lightmapScale;
brush->celShader = celShader;
+ brush->shadeAngleDegrees = shadeAngle;
}
for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
patch->entityNum = mapEnt->mapEntityNum;
patch->castShadows = castShadows;
patch->recvShadows = recvShadows;
+ patch->lightmapSampleSize = lightmapSampleSize;
patch->lightmapScale = lightmapScale;
patch->celShader = celShader;
}
/* get entity origin and adjust brushes */
GetVectorForKey( mapEnt, "origin", mapEnt->origin );
- if( mapEnt->origin[ 0 ] || mapEnt->origin[ 1 ] || mapEnt->origin[ 2 ] )
+ if( mapEnt->originbrush_origin[ 0 ] || mapEnt->originbrush_origin[ 1 ] || mapEnt->originbrush_origin[ 2 ] )
AdjustBrushesForOrigin( mapEnt );
/* group_info entities are just for editor grouping (fixme: leak!) */
- if( !Q_stricmp( "group_info", classname ) )
+ if( !noCollapseGroups && !Q_stricmp( "group_info", classname ) )
{
numEntities--;
return qtrue;
}
/* group entities are just for editor convenience, toss all brushes into worldspawn */
- if( funcGroup )
+ if( !noCollapseGroups && funcGroup )
{
MoveBrushesToWorld( mapEnt );
numEntities--;
loads a map file into a list of entities
*/
-void LoadMapFile( char *filename, qboolean onlyLights )
+void LoadMapFile( char *filename, qboolean onlyLights, qboolean noCollapseGroups )
{
FILE *file;
brush_t *b;
- int oldNumEntities, numMapBrushes;
+ int oldNumEntities = 0, numMapBrushes;
/* note it */
buildBrush = AllocBrush( MAX_BUILD_SIDES );
/* parse the map file */
- while( ParseMapEntity( onlyLights ) );
+ while( ParseMapEntity( onlyLights, noCollapseGroups ) );
/* light loading */
if( onlyLights )
callback for picomodel.lib
*/
-void PicoLoadFileFunc( char *name, byte **buffer, int *bufSize )
+void PicoLoadFileFunc( const char *name, byte **buffer, int *bufSize )
{
- *bufSize = vfsLoadFile( (const char*) name, (void**) buffer, 0 );
+ *bufSize = vfsLoadFile( name, (void**) buffer, 0 );
}
finds an existing picoModel and returns a pointer to the picoModel_t struct or NULL if not found
*/
-picoModel_t *FindModel( char *name, int frame )
+picoModel_t *FindModel( const char *name, int frame )
{
int i;
loads a picoModel and returns a pointer to the picoModel_t struct or NULL if not found
*/
-picoModel_t *LoadModel( char *name, int frame )
+picoModel_t *LoadModel( const char *name, int frame )
{
int i;
picoModel_t *model, **pm;
Error( "MAX_MODELS (%d) exceeded, there are too many model files referenced by the map.", MAX_MODELS );
/* attempt to parse model */
- *pm = PicoLoadModel( (char*) name, frame );
+ *pm = PicoLoadModel( name, frame );
/* if loading failed, make a bogus model to silence the rest of the warnings */
if( *pm == NULL )
adds a picomodel into the bsp
*/
-void InsertModel( char *name, int frame, m4x4_t transform, remap_t *remap, shaderInfo_t *celShader, int eNum, int castShadows, int recvShadows, int spawnFlags, float lightmapScale )
+void InsertModel( const char *name, int skin, int frame, m4x4_t transform, remap_t *remap, shaderInfo_t *celShader, int eNum, int castShadows, int recvShadows, int spawnFlags, float lightmapScale, int lightmapSampleSize, float shadeAngle )
{
int i, j, k, s, numSurfaces;
m4x4_t identity, nTransform;
byte *color;
picoIndex_t *indexes;
remap_t *rm, *glob;
+ skinfile_t *sf, *sf2;
+ double normalEpsilon_save;
+ double distanceEpsilon_save;
+ char skinfilename[ MAX_QPATH ];
+ char *skinfilecontent;
+ int skinfilesize;
+ char *skinfileptr, *skinfilenextptr;
/* get model */
model = LoadModel( name, frame );
if( model == NULL )
return;
+
+ /* load skin file */
+ snprintf(skinfilename, sizeof(skinfilename), "%s_%d.skin", name, skin);
+ skinfilename[sizeof(skinfilename)-1] = 0;
+ skinfilesize = vfsLoadFile(skinfilename, (void**) &skinfilecontent, 0);
+ if(skinfilesize < 0 && skin != 0)
+ {
+ /* fallback to skin 0 if invalid */
+ snprintf(skinfilename, sizeof(skinfilename), "%s_0.skin", name);
+ skinfilename[sizeof(skinfilename)-1] = 0;
+ skinfilesize = vfsLoadFile(skinfilename, (void**) &skinfilecontent, 0);
+ if(skinfilesize >= 0)
+ Sys_Printf( "Skin %d of %s does not exist, using 0 instead\n", skin, name );
+ }
+ sf = NULL;
+ if(skinfilesize >= 0)
+ {
+ Sys_Printf( "Using skin %d of %s\n", skin, name );
+ int pos;
+ for(skinfileptr = skinfilecontent; *skinfileptr; skinfileptr = skinfilenextptr)
+ {
+ // for fscanf
+ char format[64];
+
+ skinfilenextptr = strchr(skinfileptr, '\r');
+ if(skinfilenextptr)
+ {
+ *skinfilenextptr++ = 0;
+ }
+ else
+ {
+ skinfilenextptr = strchr(skinfileptr, '\n');
+ if(skinfilenextptr)
+ *skinfilenextptr++ = 0;
+ else
+ skinfilenextptr = skinfileptr + strlen(skinfileptr);
+ }
+
+ /* create new item */
+ sf2 = sf;
+ sf = safe_malloc( sizeof( *sf ) );
+ sf->next = sf2;
+
+ sprintf(format, "replace %%%ds %%%ds", (int)sizeof(sf->name)-1, (int)sizeof(sf->to)-1);
+ if(sscanf(skinfileptr, format, sf->name, sf->to) == 2)
+ continue;
+ sprintf(format, " %%%d[^, ] ,%%%ds", (int)sizeof(sf->name)-1, (int)sizeof(sf->to)-1);
+ if((pos = sscanf(skinfileptr, format, sf->name, sf->to)) == 2)
+ continue;
+
+ /* invalid input line -> discard sf struct */
+ Sys_Printf( "Discarding skin directive in %s: %s\n", skinfilename, skinfileptr );
+ free(sf);
+ sf = sf2;
+ }
+ free(skinfilecontent);
+ }
/* handle null matrix */
if( transform == NULL )
/* fix bogus lightmap scale */
if( lightmapScale <= 0.0f )
lightmapScale = 1.0f;
+
+ /* fix bogus shade angle */
+ if( shadeAngle <= 0.0f )
+ shadeAngle = 0.0f;
/* each surface on the model will become a new map drawsurface */
numSurfaces = PicoGetModelNumSurfaces( model );
if( PicoGetSurfaceType( surface ) != PICO_TRIANGLES )
continue;
- /* fix the surface's normals */
- PicoFixSurfaceNormals( surface );
-
/* allocate a surface (ydnar: gs mods) */
ds = AllocDrawSurface( SURFACE_TRIANGLES );
ds->entityNum = eNum;
picoShaderName = "";
else
picoShaderName = PicoGetShaderName( shader );
-
+
+ /* handle .skin file */
+ if(sf)
+ {
+ picoShaderName = NULL;
+ for(sf2 = sf; sf2 != NULL; sf2 = sf2->next)
+ {
+ if( !Q_stricmp( surface->name, sf2->name ) )
+ {
+ Sys_FPrintf( SYS_VRB, "Skin file: mapping %s to %s\n", surface->name, sf2->to );
+ picoShaderName = sf2->to;
+ break;
+ }
+ }
+ if(!picoShaderName)
+ {
+ Sys_FPrintf( SYS_VRB, "Skin file: not mapping %s\n", surface->name );
+ continue;
+ }
+ }
+
/* handle shader remapping */
glob = NULL;
for( rm = remap; rm != NULL; rm = rm->next )
/* set shader */
ds->shaderInfo = si;
-
- /* set lightmap scale */
- ds->lightmapScale = lightmapScale;
-
+
/* force to meta? */
if( (si != NULL && si->forceMeta) || (spawnFlags & 4) ) /* 3rd bit */
ds->type = SURFACE_FORCED_META;
+
+ /* fix the surface's normals (jal: conditioned by shader info) */
+ if( !(spawnFlags & 64) && ( shadeAngle == 0.0f || ds->type != SURFACE_FORCED_META ) )
+ PicoFixSurfaceNormals( surface );
+
+ /* set sample size */
+ if( lightmapSampleSize > 0.0f )
+ ds->sampleSize = lightmapSampleSize;
+
+ /* set lightmap scale */
+ if( lightmapScale > 0.0f )
+ ds->lightmapScale = lightmapScale;
+
+ /* set shading angle */
+ if( shadeAngle > 0.0f )
+ ds->shadeAngleDegrees = shadeAngle;
/* set particulars */
ds->numVerts = PicoGetSurfaceNumVertexes( surface );
{
dv->lightmap[ j ][ 0 ] = 0.0f;
dv->lightmap[ j ][ 1 ] = 0.0f;
- dv->color[ j ][ 0 ] = color[ 0 ];
- dv->color[ j ][ 1 ] = color[ 1 ];
- dv->color[ j ][ 2 ] = color[ 2 ];
- dv->color[ j ][ 3 ] = color[ 3 ];
+ if(spawnFlags & 32) // spawnflag 32: model color -> alpha hack
+ {
+ dv->color[ j ][ 0 ] = 255.0f;
+ dv->color[ j ][ 1 ] = 255.0f;
+ dv->color[ j ][ 2 ] = 255.0f;
+ dv->color[ j ][ 3 ] = RGBTOGRAY( color );
+ }
+ else
+ {
+ dv->color[ j ][ 0 ] = color[ 0 ];
+ dv->color[ j ][ 1 ] = color[ 1 ];
+ dv->color[ j ][ 2 ] = color[ 2 ];
+ dv->color[ j ][ 3 ] = color[ 3 ];
+ }
}
}
/* ydnar: giant hack land: generate clipping brushes for model triangles */
if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */
{
- vec3_t points[ 3 ], backs[ 3 ];
+ vec3_t points[ 4 ], backs[ 3 ];
vec4_t plane, reverse, pa, pb, pc;
- vec3_t nadir;
/* temp hack */
- if( !si->clipModel &&
- ((si->compileFlags & C_TRANSLUCENT) || !(si->compileFlags & C_SOLID)) )
- continue;
-
- /* overflow check */
- if( (nummapplanes + 64) >= (MAX_MAP_PLANES >> 1) )
+ if( !si->clipModel && !(si->compileFlags & C_SOLID) )
continue;
/* walk triangle list */
for( i = 0; i < ds->numIndexes; i += 3 )
{
/* overflow hack */
- if( (nummapplanes + 64) >= (MAX_MAP_PLANES >> 1) )
- {
- Sys_Printf( "WARNING: MAX_MAP_PLANES (%d) hit generating clip brushes for model %s.\n",
- MAX_MAP_PLANES, name );
- break;
- }
+ AUTOEXPAND_BY_REALLOC(mapplanes, (nummapplanes+64) << 1, allocatedmapplanes, 1024);
/* make points and back points */
for( j = 0; j < 3; j++ )
/* copy xyz */
VectorCopy( dv->xyz, points[ j ] );
-#if ! Q3MAP2_EXPERIMENTAL_MODEL_CLIPPING_FIX
- // The code below is totally unneeded regardless of Q3MAP2_EXPERIMENTAL_MODEL_CLIPPING_FIX.
- // backs is reinitialized further below. However, the extra code does not hurt anything.
- VectorCopy( dv->xyz, backs[ j ] );
-
- /* find nearest axial to normal and push back points opposite */
- /* note: this doesn't work as well as simply using the plane of the triangle, below */
- for( k = 0; k < 3; k++ )
- {
- if( fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 1) % 3 ] ) &&
- fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 2) % 3 ] ) )
- {
- backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f;
- break;
- }
- }
-#endif
}
+
+ VectorCopy( points[0], points[3] ); // for cyclic usage
/* make plane for triangle */
+ // div0: add some extra spawnflags:
+ // 0: snap normals to axial planes for extrusion
+ // 8: extrude with the original normals
+ // 16: extrude only with up/down normals (ideal for terrain)
+ // 24: extrude by distance zero (may need engine changes)
if( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) )
{
+ vec3_t bestNormal;
+ float backPlaneDistance = 2;
+
+ if(spawnFlags & 8) // use a DOWN normal
+ {
+ if(spawnFlags & 16)
+ {
+ // 24: normal as is, and zero width (broken)
+ VectorCopy(plane, bestNormal);
+ }
+ else
+ {
+ // 8: normal as is
+ VectorCopy(plane, bestNormal);
+ }
+ }
+ else
+ {
+ if(spawnFlags & 16)
+ {
+ // 16: UP/DOWN normal
+ VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
+ }
+ else
+ {
+ // 0: axial normal
+ if(fabs(plane[0]) > fabs(plane[1])) // x>y
+ if(fabs(plane[1]) > fabs(plane[2])) // x>y, y>z
+ VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
+ else // x>y, z>=y
+ if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y
+ VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
+ else // z>=x, x>y
+ VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
+ else // y>=x
+ if(fabs(plane[1]) > fabs(plane[2])) // y>z, y>=x
+ VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0);
+ else // z>=y, y>=x
+ VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
+ }
+ }
+
+ /* build a brush */
+ buildBrush = AllocBrush( 48 );
+ buildBrush->entityNum = mapEntityNum;
+ buildBrush->original = buildBrush;
+ buildBrush->contentShader = si;
+ buildBrush->compileFlags = si->compileFlags;
+ buildBrush->contentFlags = si->contentFlags;
+ normalEpsilon_save = normalEpsilon;
+ distanceEpsilon_save = distanceEpsilon;
+ if(si->compileFlags & C_STRUCTURAL) // allow forced structural brushes here
+ {
+ buildBrush->detail = qfalse;
+
+ // only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model)
+ if(normalEpsilon > 0)
+ normalEpsilon = 0;
+ if(distanceEpsilon > 0)
+ distanceEpsilon = 0;
+ }
+ else
+ buildBrush->detail = qtrue;
+
/* regenerate back points */
for( j = 0; j < 3; j++ )
{
/* get vertex */
dv = &ds->verts[ ds->indexes[ i + j ] ];
-
- /* copy xyz */
- VectorCopy( dv->xyz, backs[ j ] );
-
- /* find nearest axial to plane normal and push back points opposite */
- for( k = 0; k < 3; k++ )
- {
-#if Q3MAP2_EXPERIMENTAL_MODEL_CLIPPING_FIX
- if( fabs( plane[ k ] ) >= fabs( plane[ (k + 1) % 3 ] ) &&
- fabs( plane[ k ] ) >= fabs( plane[ (k + 2) % 3 ] ) )
-#else
- // This code is broken for 45 degree angles where there
- // is no clear winner.
- if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) &&
- fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) )
-#endif
- {
- backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f;
- break;
- }
- }
+
+ // shift by some units
+ VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit
}
-
+
/* make back plane */
VectorScale( plane, -1.0f, reverse );
- reverse[ 3 ] = -(plane[ 3 ] - 1);
-
- /* make back pyramid point */
- VectorCopy( points[ 0 ], nadir );
- VectorAdd( nadir, points[ 1 ], nadir );
- VectorAdd( nadir, points[ 2 ], nadir );
- VectorScale( nadir, 0.3333333333333f, nadir );
- VectorMA( nadir, -2.0f, plane, nadir );
-
- /* make 3 more planes */
- //% if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], nadir ) &&
- //% PlaneFromPoints( pb, points[ 1 ], points[ 0 ], nadir ) &&
- //% PlaneFromPoints( pc, points[ 0 ], points[ 2 ], nadir ) )
+ reverse[ 3 ] = -plane[ 3 ];
+ if((spawnFlags & 24) != 24)
+ reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance;
+ // that's at least sqrt(1/3) backPlaneDistance, unless in DOWN mode; in DOWN mode, we are screwed anyway if we encounter a plane that's perpendicular to the xy plane)
+
if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], backs[ 1 ] ) &&
- PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
- PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
+ PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
+ PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
{
- /* build a brush */
- buildBrush = AllocBrush( 48 );
-
- buildBrush->entityNum = mapEntityNum;
- buildBrush->original = buildBrush;
- buildBrush->contentShader = si;
- buildBrush->compileFlags = si->compileFlags;
- buildBrush->contentFlags = si->contentFlags;
- buildBrush->detail = qtrue;
-
/* set up brush sides */
buildBrush->numsides = 5;
- for( j = 0; j < buildBrush->numsides; j++ )
- buildBrush->sides[ j ].shaderInfo = si;
+ buildBrush->sides[ 0 ].shaderInfo = si;
+ for( j = 1; j < buildBrush->numsides; j++ )
+ buildBrush->sides[ j ].shaderInfo = NULL; // don't emit these faces as draw surfaces, should make smaller BSPs; hope this works
+
buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
- buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 1, &points[ 2 ] );
- buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 1, &points[ 1 ] );
- buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 1, &points[ 0 ] );
- buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, points );
-
- /* add to entity */
- if( CreateBrushWindings( buildBrush ) )
- {
- AddBrushBevels();
- //% EmitBrushes( buildBrush, NULL, NULL );
- buildBrush->next = entities[ mapEntityNum ].brushes;
- entities[ mapEntityNum ].brushes = buildBrush;
- entities[ mapEntityNum ].numBrushes++;
- }
- else
- free( buildBrush );
+ buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 2, &points[ 1 ] ); // pa contains points[1] and points[2]
+ buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 2, &points[ 0 ] ); // pb contains points[0] and points[1]
+ buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 2, &points[ 2 ] ); // pc contains points[2] and points[0] (copied to points[3]
+ buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, backs );
+ }
+ else
+ {
+ free(buildBrush);
+ continue;
}
+
+ normalEpsilon = normalEpsilon_save;
+ distanceEpsilon = distanceEpsilon_save;
+
+ /* add to entity */
+ if( CreateBrushWindings( buildBrush ) )
+ {
+ AddBrushBevels();
+ //% EmitBrushes( buildBrush, NULL, NULL );
+ buildBrush->next = entities[ mapEntityNum ].brushes;
+ entities[ mapEntityNum ].brushes = buildBrush;
+ entities[ mapEntityNum ].numBrushes++;
+ }
+ else
+ free( buildBrush );
}
}
}
void AddTriangleModels( entity_t *e )
{
- int num, frame, castShadows, recvShadows, spawnFlags;
+ int num, frame, skin, castShadows, recvShadows, spawnFlags;
entity_t *e2;
const char *targetName;
const char *target, *model, *value;
char shader[ MAX_QPATH ];
shaderInfo_t *celShader;
float temp, baseLightmapScale, lightmapScale;
+ float shadeAngle;
+ int lightmapSampleSize;
vec3_t origin, scale, angles;
m4x4_t transform;
epair_t *ep;
}
/* get lightmap scale */
- baseLightmapScale = FloatForKey( e, "_lightmapscale" );
- if( baseLightmapScale <= 0.0f )
- baseLightmapScale = 0.0f;
+ /* vortex: added _ls key (short name of lightmapscale) */
+ baseLightmapScale = 0.0f;
+ if( strcmp( "", ValueForKey( e, "lightmapscale" ) ) ||
+ strcmp( "", ValueForKey( e, "_lightmapscale" ) ) ||
+ strcmp( "", ValueForKey( e, "_ls" ) ) )
+ {
+ baseLightmapScale = FloatForKey( e, "lightmapscale" );
+ if( baseLightmapScale <= 0.0f )
+ baseLightmapScale = FloatForKey( e, "_lightmapscale" );
+ if( baseLightmapScale <= 0.0f )
+ baseLightmapScale = FloatForKey( e, "_ls" );
+ if( baseLightmapScale < 0.0f )
+ baseLightmapScale = 0.0f;
+ if( baseLightmapScale > 0.0f )
+ Sys_Printf( "World Entity has lightmap scale of %.4f\n", baseLightmapScale );
+ }
+
/* walk the entity list */
for( num = 1; num < numEntities; num++ )
celShader = ShaderInfoForShader( shader );
}
else
- celShader = NULL;
-
+ celShader = *globalCelShader ? ShaderInfoForShader(globalCelShader) : NULL;
+
+ /* jal : entity based _samplesize */
+ lightmapSampleSize = 0;
+ if ( strcmp( "", ValueForKey( e2, "_lightmapsamplesize" ) ) )
+ lightmapSampleSize = IntForKey( e2, "_lightmapsamplesize" );
+ else if ( strcmp( "", ValueForKey( e2, "_samplesize" ) ) )
+ lightmapSampleSize = IntForKey( e2, "_samplesize" );
+
+ if( lightmapSampleSize < 0 )
+ lightmapSampleSize = 0;
+
+ if( lightmapSampleSize > 0.0f )
+ Sys_Printf( "misc_model has lightmap sample size of %.d\n", lightmapSampleSize );
+
/* get lightmap scale */
- lightmapScale = FloatForKey( e2, "_lightmapscale" );
- if( lightmapScale <= 0.0f )
- lightmapScale = baseLightmapScale;
-
+ /* vortex: added _ls key (short name of lightmapscale) */
+ lightmapScale = 0.0f;
+ if( strcmp( "", ValueForKey( e2, "lightmapscale" ) ) ||
+ strcmp( "", ValueForKey( e2, "_lightmapscale" ) ) ||
+ strcmp( "", ValueForKey( e2, "_ls" ) ) )
+ {
+ lightmapScale = FloatForKey( e2, "lightmapscale" );
+ if( lightmapScale <= 0.0f )
+ lightmapScale = FloatForKey( e2, "_lightmapscale" );
+ if( lightmapScale <= 0.0f )
+ lightmapScale = FloatForKey( e2, "_ls" );
+ if( lightmapScale < 0.0f )
+ lightmapScale = 0.0f;
+ if( lightmapScale > 0.0f )
+ Sys_Printf( "misc_model has lightmap scale of %.4f\n", lightmapScale );
+ }
+
+ /* jal : entity based _shadeangle */
+ shadeAngle = 0.0f;
+ if ( strcmp( "", ValueForKey( e2, "_shadeangle" ) ) )
+ shadeAngle = FloatForKey( e2, "_shadeangle" );
+ /* vortex' aliases */
+ else if ( strcmp( "", ValueForKey( e2, "_smoothnormals" ) ) )
+ shadeAngle = FloatForKey( e2, "_smoothnormals" );
+ else if ( strcmp( "", ValueForKey( e2, "_sn" ) ) )
+ shadeAngle = FloatForKey( e2, "_sn" );
+ else if ( strcmp( "", ValueForKey( e2, "_smooth" ) ) )
+ shadeAngle = FloatForKey( e2, "_smooth" );
+
+ if( shadeAngle < 0.0f )
+ shadeAngle = 0.0f;
+
+ if( shadeAngle > 0.0f )
+ Sys_Printf( "misc_model has shading angle of %.4f\n", shadeAngle );
+
+ skin = IntForKey(e2, "skin");
+
/* insert the model */
- InsertModel( (char*) model, frame, transform, remap, celShader, mapEntityNum, castShadows, recvShadows, spawnFlags, lightmapScale );
+ InsertModel( model, skin, frame, transform, remap, celShader, mapEntityNum, castShadows, recvShadows, spawnFlags, lightmapScale, lightmapSampleSize, shadeAngle );
/* free shader remappings */
while( remap != NULL )
float longestCurve;
int maxIterations;
-
MatchToken( "{" );
/* get texture */
char *basePaths[ MAX_BASE_PATHS ];
int numGamePaths;
char *gamePaths[ MAX_GAME_PATHS ];
-
+char *homeBasePath = NULL;
/*
strcpy( installPath, "../" );
#else
char temp[ MAX_OS_PATH ];
+ char last0[ 2 ];
char *home;
char *path;
char *last;
/* do some path divining */
strcpy( temp, argv0 );
- if( strrchr( temp, '/' ) )
+ if( strrchr( argv0, '/' ) )
argv0 = strrchr( argv0, '/' ) + 1;
else
{
path = getenv( "PATH" );
/* minor setup */
+ last = last0;
last[ 0 ] = path[ 0 ];
last[ 1 ] = '\0';
found = qfalse;
return;
/* make a hole */
- for( i = 0; i < (MAX_BASE_PATHS - 1); i++ )
+ for( i = (MAX_BASE_PATHS - 2); i >= 0; i-- )
basePaths[ i + 1 ] = basePaths[ i ];
/* concatenate home dir and path */
argv[ i ] = NULL;
}
+ /* -fs_forbiddenpath */
+ else if( strcmp( argv[ i ], "-fs_forbiddenpath" ) == 0 )
+ {
+ if( ++i >= *argc )
+ Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
+ argv[ i - 1 ] = NULL;
+ if(g_numForbiddenDirs < VFS_MAXDIRS)
+ {
+ strncpy(g_strForbiddenDirs[g_numForbiddenDirs], argv[i], PATH_MAX);
+ g_strForbiddenDirs[g_numForbiddenDirs][PATH_MAX] = 0;
+ ++g_numForbiddenDirs;
+ }
+ argv[ i ] = NULL;
+ }
+
/* -fs_basepath */
else if( strcmp( argv[ i ], "-fs_basepath" ) == 0 )
{
AddGamePath( argv[ i ] );
argv[ i ] = NULL;
}
+
+ /* -fs_nohomebase */
+ else if( strcmp( argv[ i ], "-fs_homebase" ) == 0 )
+ {
+ if( ++i >= *argc )
+ Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] );
+ argv[ i - 1 ] = NULL;
+ homeBasePath = argv[i];
+ argv[ i ] = NULL;
+ }
}
/* remove processed arguments */
}
/* this only affects unix */
- AddHomeBasePath( game->homeBasePath );
+ if(homeBasePath)
+ AddHomeBasePath( homeBasePath );
+ else
+ AddHomeBasePath( game->homeBasePath );
/* initialize vfs paths */
if( numBasePaths > MAX_BASE_PATHS )
/* get origin */
GetVectorForKey( e, "origin", origin );
+
+ /* as a special case, allow origin-less entities */
if( VectorCompare( origin, vec3_origin ) )
continue;
+ /* also allow bmodel entities outside, as they could be on a moving path that will go into the map */
+ if( e->brushes != NULL || e->patches != NULL )
+ continue;
+
/* handle skybox entities */
value = ValueForKey( e, "classname" );
if( !Q_stricmp( value, "_skybox" ) )
r = PlaceOccupant( headnode, origin, e, skybox );
if( r )
inside = qtrue;
- if( (!r || tree->outside_node.occupied) && !tripped )
+ if( !r )
+ {
+ Sys_Printf( "Entity %i, Brush %i: Entity in solid\n", e->mapEntityNum, 0);
+ }
+ else if( tree->outside_node.occupied && !tripped )
{
xml_Select( "Entity leaked", e->mapEntityNum, 0, qfalse );
tripped = qtrue;
fprintf (f,"%f ",v);
}
+void CountVisportals_r(node_t *node)
+{
+ int s;
+ portal_t *p;
+ winding_t *w;
+
+ // decision node
+ if (node->planenum != PLANENUM_LEAF) {
+ CountVisportals_r (node->children[0]);
+ CountVisportals_r (node->children[1]);
+ return;
+ }
+
+ if (node->opaque) {
+ return;
+ }
+
+ for (p = node->portals ; p ; p=p->next[s])
+ {
+ w = p->winding;
+ s = (p->nodes[1] == node);
+ if (w && p->nodes[0] == node)
+ {
+ if (!PortalPassable(p))
+ continue;
+ if(p->nodes[0]->cluster == p->nodes[1]->cluster)
+ continue;
+ ++num_visportals;
+ }
+ }
+}
+
/*
=================
WritePortalFile_r
{
if (!PortalPassable(p))
continue;
+ if(p->nodes[0]->cluster == p->nodes[1]->cluster)
+ continue;
+ --num_visportals;
// write out to the file
// sometimes planes get turned around when they are very near
// plane the same way vis will, and flip the side orders if needed
// FIXME: is this still relevent?
WindingPlane (w, normal, &dist);
+
if ( DotProduct (p->plane.normal, normal) < 0.99 )
{ // backwards...
fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster);
}
+void CountSolidFaces_r (node_t *node)
+{
+ int s;
+ portal_t *p;
+ winding_t *w;
+
+ // decision node
+ if (node->planenum != PLANENUM_LEAF) {
+ CountSolidFaces_r (node->children[0]);
+ CountSolidFaces_r (node->children[1]);
+ return;
+ }
+
+ if (node->opaque) {
+ return;
+ }
+
+ for (p = node->portals ; p ; p=p->next[s])
+ {
+ w = p->winding;
+ s = (p->nodes[1] == node);
+ if (w)
+ {
+ if (PortalPassable(p))
+ continue;
+ if(p->nodes[0]->cluster == p->nodes[1]->cluster)
+ continue;
+ // write out to the file
+
+ ++num_solidfaces;
+ }
+ }
+}
+
/*
=================
WriteFaceFile_r
{
if (PortalPassable(p))
continue;
+ if(p->nodes[0]->cluster == p->nodes[1]->cluster)
+ continue;
// write out to the file
if (p->nodes[0] == node)
NumberLeafs_r
================
*/
-void NumberLeafs_r (node_t *node)
+void NumberLeafs_r (node_t *node, int c)
{
+#if 0
portal_t *p;
-
+#endif
if ( node->planenum != PLANENUM_LEAF ) {
// decision node
node->cluster = -99;
- NumberLeafs_r (node->children[0]);
- NumberLeafs_r (node->children[1]);
+
+ if(node->has_structural_children)
+ {
+#if 0
+ if(c >= 0)
+ Sys_FPrintf (SYS_ERR,"THIS CANNOT HAPPEN\n");
+#endif
+ NumberLeafs_r (node->children[0], c);
+ NumberLeafs_r (node->children[1], c);
+ }
+ else
+ {
+ if(c < 0)
+ c = num_visclusters++;
+ NumberLeafs_r (node->children[0], c);
+ NumberLeafs_r (node->children[1], c);
+ }
return;
}
return;
}
- node->cluster = num_visclusters;
- num_visclusters++;
+ if(c < 0)
+ c = num_visclusters++;
+
+ node->cluster = c;
+#if 0
// count the portals
for (p = node->portals ; p ; )
{
p = p->next[1];
}
}
+#endif
}
Sys_FPrintf (SYS_VRB,"--- NumberClusters ---\n");
// set the cluster field in every leaf and count the total number of portals
- NumberLeafs_r (tree->headnode);
+ NumberLeafs_r (tree->headnode, -1);
+ CountVisportals_r (tree->headnode);
+ CountSolidFaces_r (tree->headnode);
Sys_FPrintf( SYS_VRB, "%9d visclusters\n", num_visclusters );
Sys_FPrintf( SYS_VRB, "%9d visportals\n", num_visportals );
/* version */
-#define Q3MAP_VERSION "2.5.17"
-#define Q3MAP_MOTD "Last one turns the lights off"
+#ifndef Q3MAP_VERSION
+#error no Q3MAP_VERSION defined
+#endif
+#define Q3MAP_MOTD "Your map saw the pretty lights from q3map2's BFG"
+
#include "cmdlib.h"
#include "mathlib.h"
#include "md5lib.h"
-#include "md4lib.h"
#include "ddslib.h"
#include "picomodel.h"
#include "inout.h"
#include "vfs.h"
#include "png.h"
-
+#include "md4.h"
+#include "radiant_jpeglib.h"
#include <stdlib.h>
#define Q3MAP2_EXPERIMENTAL_HIGH_PRECISION_MATH_FIXES 1
#define Q3MAP2_EXPERIMENTAL_SNAP_NORMAL_FIX 1
#define Q3MAP2_EXPERIMENTAL_SNAP_PLANE_FIX 1
-#define Q3MAP2_EXPERIMENTAL_MODEL_CLIPPING_FIX 1
/* general */
#define MAX_QPATH 64
/* bsp */
#define MAX_PATCH_SIZE 32
#define MAX_BRUSH_SIDES 1024
-#define MAX_BUILD_SIDES 300
+#define MAX_BUILD_SIDES 1024
#define MAX_EXPANDED_AXIS 128
#define HINT_PRIORITY 1000 /* ydnar: force hint splits first and antiportal/areaportal splits last */
#define ANTIPORTAL_PRIORITY -1000
#define AREAPORTAL_PRIORITY -1000
+#define DETAIL_PRIORITY -3000
#define PSIDE_FRONT 1
#define PSIDE_BACK 2
#define PORTALFILE "PRT1"
-#define MAX_PORTALS 32768
+#define MAX_PORTALS 0x20000 /* same as MAX_MAP_PORTALS */
#define MAX_SEPERATORS MAX_POINTS_ON_WINDING
#define MAX_POINTS_ON_FIXED_WINDING 24 /* ydnar: increased this from 12 at the expense of more memory */
-#define MAX_PORTALS_ON_LEAF 128
+#define MAX_PORTALS_ON_LEAF 1024
/* light */
#define LIGHT_FAST_TEMP 512
#define LIGHT_FAST_ACTUAL (LIGHT_FAST | LIGHT_FAST_TEMP)
#define LIGHT_NEGATIVE 1024
+#define LIGHT_UNNORMALIZED 2048 /* vortex: do not normalize _color */
#define LIGHT_SUN_DEFAULT (LIGHT_ATTEN_ANGLE | LIGHT_GRID | LIGHT_SURFACES)
#define LIGHT_AREA_DEFAULT (LIGHT_ATTEN_ANGLE | LIGHT_ATTEN_DISTANCE | LIGHT_GRID | LIGHT_SURFACES) /* q3a and wolf are the same */
#define GRID_EPSILON 0.0f
#define DEFAULT_LIGHTMAP_SAMPLE_SIZE 16
+#define DEFAULT_LIGHTMAP_MIN_SAMPLE_SIZE 0
#define DEFAULT_LIGHTMAP_SAMPLE_OFFSET 1.0f
#define DEFAULT_SUBDIVIDE_THRESHOLD 1.0f
#define BSP_LUXEL_SIZE 3
#define RAD_LUXEL_SIZE 3
#define SUPER_LUXEL_SIZE 4
+#define SUPER_FLAG_SIZE 4
+#define FLAG_FORCE_SUBSAMPLING 1
+#define FLAG_ALREADY_SUBSAMPLED 2
#define SUPER_ORIGIN_SIZE 3
#define SUPER_NORMAL_SIZE 4
#define SUPER_DELUXEL_SIZE 3
#define BSP_DELUXEL_SIZE 3
+#define SUPER_FLOODLIGHT_SIZE 4
#define VERTEX_LUXEL( s, v ) (vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
#define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
#define BSP_LUXEL( s, x, y ) (lm->bspLuxels[ s ] + ((((y) * lm->w) + (x)) * BSP_LUXEL_SIZE))
#define RAD_LUXEL( s, x, y ) (lm->radLuxels[ s ] + ((((y) * lm->w) + (x)) * RAD_LUXEL_SIZE))
#define SUPER_LUXEL( s, x, y ) (lm->superLuxels[ s ] + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE))
+#define SUPER_FLAG( x, y ) (lm->superFlags + ((((y) * lm->sw) + (x)) * SUPER_FLAG_SIZE))
#define SUPER_DELUXEL( x, y ) (lm->superDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE))
#define BSP_DELUXEL( x, y ) (lm->bspDeluxels + ((((y) * lm->w) + (x)) * BSP_DELUXEL_SIZE))
#define SUPER_CLUSTER( x, y ) (lm->superClusters + (((y) * lm->sw) + (x)))
#define SUPER_ORIGIN( x, y ) (lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE))
#define SUPER_NORMAL( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE))
#define SUPER_DIRT( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE) + 3) /* stash dirtyness in normal[ 3 ] */
+#define SUPER_FLOODLIGHT( x, y ) (lm->superFloodLight + ((((y) * lm->sw) + (x)) * SUPER_FLOODLIGHT_SIZE) )
#define MAX_LIGHTMAP_SHADERS 256
/* ok to increase these at the expense of more memory */
-#define MAX_MAP_MODELS 0x400
-#define MAX_MAP_BRUSHES 0x10000
#define MAX_MAP_ENTITIES 0x1000 //% 0x800 /* ydnar */
#define MAX_MAP_ENTSTRING 0x80000 //% 0x40000 /* ydnar */
-#define MAX_MAP_SHADERS 0x800 //% 0x400 /* ydnar */
#define MAX_MAP_AREAS 0x100 /* MAX_MAP_AREA_BYTES in q_shared must match! */
#define MAX_MAP_FOGS 30 //& 0x100 /* RBSP (32 - world fog - goggles) */
-#define MAX_MAP_PLANES 0x100000 //% 0x20000 /* ydnar for md */
-#define MAX_MAP_NODES 0x20000
-#define MAX_MAP_BRUSHSIDES 0x100000 //% 0x20000 /* ydnar */
#define MAX_MAP_LEAFS 0x20000
-#define MAX_MAP_LEAFFACES 0x100000 //% 0x20000 /* ydnar */
-#define MAX_MAP_LEAFBRUSHES 0x40000
#define MAX_MAP_PORTALS 0x20000
#define MAX_MAP_LIGHTING 0x800000
#define MAX_MAP_LIGHTGRID 0x100000 //% 0x800000 /* ydnar: set to points, not bytes */
-#define MAX_MAP_VISIBILITY 0x200000
+#define MAX_MAP_VISCLUSTERS 0x4000 // <= MAX_MAP_LEAFS
+#define MAX_MAP_VISIBILITY (VIS_HEADER_SIZE + MAX_MAP_VISCLUSTERS * (((MAX_MAP_VISCLUSTERS + 63) & ~63) >> 3))
#define MAX_MAP_DRAW_SURFS 0x20000
-#define MAX_MAP_DRAW_VERTS 0x100000
#define MAX_MAP_DRAW_INDEXES 0x80000
#define MAX_MAP_ADVERTISEMENTS 30
------------------------------------------------------------------------------- */
/* ydnar: for smaller structs */
-typedef char qb_t;
+typedef unsigned char qb_t;
/* ydnar: for q3map_tcMod */
}
surfaceParm_t;
+typedef enum
+{
+ MINIMAP_MODE_GRAY,
+ MINIMAP_MODE_BLACK,
+ MINIMAP_MODE_WHITE
+}
+miniMapMode_t;
typedef struct game_s
{
qboolean wolfLight; /* when true, lights work like wolf q3map */
int lightmapSize; /* bsp lightmap width/height */
float lightmapGamma; /* default lightmap gamma */
+ float lightmapExposure; /* default lightmap exposure */
float lightmapCompensate; /* default lightmap compensate value */
+ float gridScale; /* vortex: default lightgrid scale (affects both directional and ambient spectres) */
+ float gridAmbientScale; /* vortex: default lightgrid ambient spectre scale */
+ qboolean lightAngleHL; /* jal: use half-lambert curve for light angle attenuation */
+ qboolean noStyles; /* use lightstyles hack or not */
+ qboolean keepLights; /* keep light entities on bsp */
+ int patchSubdivisions; /* default patch subdivisions tolerance */
+ qboolean patchShadows; /* patch casting enabled */
+ qboolean deluxeMap; /* compile deluxemaps */
+ int deluxeMode; /* deluxemap mode (0 - modelspace, 1 - tangentspace with renormalization, 2 - tangentspace without renormalization) */
+ int miniMapSize; /* minimap size */
+ float miniMapSharpen; /* minimap sharpening coefficient */
+ float miniMapBorder; /* minimap border amount */
+ qboolean miniMapKeepAspect; /* minimap keep aspect ratio by letterboxing */
+ miniMapMode_t miniMapMode; /* minimap mode */
+ char *miniMapNameFormat; /* minimap name format */
char *bspIdent; /* 4-letter bsp file prefix */
int bspVersion; /* bsp version to use */
qboolean lumpSwap; /* cod-style len/ofs order */
}
remap_t;
+typedef struct skinfile_s
+{
+ struct skinfile_s *next;
+ char name[ 1024 ];
+ char to[ MAX_QPATH ];
+}
+skinfile_t;
+
/* wingdi.h hack, it's the same: 0 */
#undef CM_NONE
CM_ALPHA_SCALE,
CM_COLOR_DOT_PRODUCT,
CM_ALPHA_DOT_PRODUCT,
+ CM_COLOR_DOT_PRODUCT_SCALE,
+ CM_ALPHA_DOT_PRODUCT_SCALE,
CM_COLOR_DOT_PRODUCT_2,
- CM_ALPHA_DOT_PRODUCT_2
+ CM_ALPHA_DOT_PRODUCT_2,
+ CM_COLOR_DOT_PRODUCT_2_SCALE,
+ CM_ALPHA_DOT_PRODUCT_2_SCALE
}
colorModType_t;
char *backShader; /* for surfaces that generate different front and back passes */
char *cloneShader; /* ydnar: for cloning of a surface */
char *remapShader; /* ydnar: remap a shader in final stage */
+ char *deprecateShader; /* vortex: shader is deprecated and replaced by this on use */
surfaceModel_t *surfaceModel; /* ydnar: for distribution of models */
foliage_t *foliage; /* ydnar/splash damage: wolf et foliage */
qb_t noFog; /* ydnar: supress fogging */
qb_t clipModel; /* ydnar: solid model hack */
qb_t noVertexLight; /* ydnar: leave vertex color alone */
-
+ qb_t noDirty; /* jal: do not apply the dirty pass to this surface */
+
byte styleMarker; /* ydnar: light styles hack */
float vertexScale; /* vertex light scale */
vec3_t color; /* normalized color */
vec3_t averageColor;
- byte lightStyle;
+ byte lightStyle;
+
+ /* vortex: per-surface floodlight */
+ float floodlightDirectionScale;
+ vec3_t floodlightRGB;
+ float floodlightIntensity;
+ float floodlightDistance;
qb_t lmMergable; /* ydnar */
int lmCustomWidth, lmCustomHeight; /* ydnar */
struct face_s *next;
int planenum;
int priority;
- qboolean checked;
+ //qboolean checked;
int compileFlags;
winding_t *w;
}
vec3_t normal;
vec_t dist;
int type;
- struct plane_s *hash_chain;
+ int counter;
+ int hash_chain;
}
plane_t;
shaderInfo_t *celShader; /* :) */
/* ydnar: gs mods */
+ int lightmapSampleSize; /* jal : entity based _lightmapsamplesize */
float lightmapScale;
+ float shadeAngleDegrees; /* jal : entity based _shadeangle */
vec3_t eMins, eMaxs;
indexMap_t *im;
shaderInfo_t *celShader; /* :) */
/* ydnar: gs mods */
+ int lightmapSampleSize; /* jal : entity based _lightmapsamplesize */
float lightmapScale;
vec3_t eMins, eMaxs;
indexMap_t *im;
/* ydnar: per-surface (per-entity, actually) lightmap sample size scaling */
float lightmapScale;
+
+ /* jal: per-surface (per-entity, actually) shadeangle */
+ float shadeAngleDegrees;
/* ydnar: surface classification */
vec3_t mins, maxs;
int maxIterations;
int patchWidth, patchHeight;
vec3_t bounds[ 2 ];
-
+
/* ydnar/sd: for foliage */
int numFoliageInstances;
shaderInfo_t *si;
side_t *side;
int entityNum, surfaceNum, planeNum, fogNum, sampleSize, castShadows, recvShadows;
+ float shadeAngleDegrees;
vec4_t plane;
vec3_t lightmapAxis;
int indexes[ 3 ];
int mapEntityNum, firstDrawSurf;
int firstBrush, numBrushes; /* only valid during BSP compile */
epair_t *epairs;
+ vec3_t originbrush_origin;
}
entity_t;
entity_t *occupant; /* for leak file testing */
struct portal_s *portals; /* also on nodes during construction */
+
+ qboolean has_structural_children;
}
node_t;
float radiusByDist; /* for spotlights */
float fade; /* ydnar: from wolf, for linear lights */
float angleScale; /* ydnar: stolen from vlight for K */
+ float extraDist; /* "extra dimension" distance of the light, to kill hot spots */
float add; /* ydnar: used for area lights */
float envelope; /* ydnar: units until falloff < tolerance */
/* input and output */
vec3_t color; /* starts out at full color, may be reduced if transparent surfaces are crossed */
-
+ vec3_t colorNoShadow; /* result color with no shadow casting */
+ vec3_t directionContribution; /* result contribution to the deluxe map */
+
/* output */
vec3_t hit;
int compileFlags; /* for determining surface compile flags traced through */
qboolean passSolid;
qboolean opaque;
+ vec_t forceSubsampling; /* needs subsampling (alphashadow), value = max color contribution possible from it */
/* working data */
int numTestNodes;
int numLightClusters, *lightClusters;
int sampleSize, actualSampleSize, axisNum;
+
+ /* vortex: per-surface floodlight */
+ float floodlightDirectionScale;
+ vec3_t floodlightRGB;
+ float floodlightIntensity;
+ float floodlightDistance;
+
int entityNum;
int recvShadows;
vec3_t mins, maxs, axis, origin, *vecs;
float *bspLuxels[ MAX_LIGHTMAPS ];
float *radLuxels[ MAX_LIGHTMAPS ];
float *superLuxels[ MAX_LIGHTMAPS ];
+ unsigned char *superFlags;
float *superOrigins;
float *superNormals;
int *superClusters;
float *superDeluxels; /* average light direction */
float *bspDeluxels;
+ float *superFloodLight;
}
rawLightmap_t;
typedef struct surfaceInfo_s
{
- bspModel_t *model;
+ int modelindex;
shaderInfo_t *si;
rawLightmap_t *lm;
int parentSurfaceNum, childSurfaceNum;
}
surfaceInfo_t;
-
-
/* -------------------------------------------------------------------------------
prototypes
/* convert_map.c */
int ConvertBSPToMap( char *bspName );
+int ConvertBSPToMap_BP( char *bspName );
/* convert_ase.c */
int ConvertBSPToASE( char *bspName );
+/* convert_obj.c */
+int ConvertBSPToOBJ( char *bspName );
+
/* brush.c */
sideRef_t *AllocSideRef( side_t *side, sideRef_t *next );
/* map.c */
-void LoadMapFile( char *filename, qboolean onlyLights );
+void LoadMapFile( char *filename, qboolean onlyLights, qboolean noCollapseGroups );
int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points );
int PlaneTypeForNormal( vec3_t normal );
void AddBrushBevels( void );
-brush_t *FinishBrush( void );
+brush_t *FinishBrush(qboolean noCollapseGroups);
/* portals.c */
int EmitShader( const char *shader, int *contentFlags, int *surfaceFlags );
void BeginBSPFile( void );
-void EndBSPFile( void );
+void EndBSPFile( qboolean do_write );
void EmitBrushes( brush_t *brushes, int *firstBrush, int *numBrushes );
void EmitFogs( void );
void ParsePatch( qboolean onlyLights );
mesh_t *SubdivideMesh( mesh_t in, float maxError, float minLength );
void PatchMapDrawSurfs( entity_t *e );
+void TriangulatePatchSurface( entity_t *e , mapDrawSurface_t *ds );
/* tjunction.c */
/* model.c */
void PicoPrintFunc( int level, const char *str );
-void PicoLoadFileFunc( char *name, byte **buffer, int *bufSize );
-picoModel_t *FindModel( char *name, int frame );
-picoModel_t *LoadModel( char *name, int frame );
-void InsertModel( char *name, int frame, m4x4_t transform, remap_t *remap, shaderInfo_t *celShader, int eNum, int castShadows, int recvShadows, int spawnFlags, float lightmapScale );
+void PicoLoadFileFunc( const char *name, byte **buffer, int *bufSize );
+picoModel_t *FindModel( const char *name, int frame );
+picoModel_t *LoadModel( const char *name, int frame );
+void InsertModel( const char *name, int skin, int frame, m4x4_t transform, remap_t *remap, shaderInfo_t *celShader, int eNum, int castShadows, int recvShadows, int spawnFlags, float lightmapScale, int lightmapSampleSize, float shadeAngle );
void AddTriangleModels( entity_t *e );
mapDrawSurface_t *AllocDrawSurface( surfaceType_t type );
void FinishSurface( mapDrawSurface_t *ds );
void StripFaceSurface( mapDrawSurface_t *ds );
+void MaxAreaFaceSurface( mapDrawSurface_t *ds );
qboolean CalcSurfaceTextureRange( mapDrawSurface_t *ds );
qboolean CalcLightmapAxis( vec3_t normal, vec3_t axis );
void ClassifySurfaces( int numSurfs, mapDrawSurface_t *ds );
void AddEntitySurfaceModels( entity_t *e );
mapDrawSurface_t *DrawSurfaceForSide( entity_t *e, brush_t *b, side_t *s, winding_t *w );
mapDrawSurface_t *DrawSurfaceForMesh( entity_t *e, parseMesh_t *p, mesh_t *mesh );
-mapDrawSurface_t *DrawSurfaceForFlare( int entNum, vec3_t origin, vec3_t normal, vec3_t color, char *flareShader, int lightStyle );
+mapDrawSurface_t *DrawSurfaceForFlare( int entNum, vec3_t origin, vec3_t normal, vec3_t color, const char *flareShader, int lightStyle );
mapDrawSurface_t *DrawSurfaceForShader( char *shader );
void ClipSidesIntoTree( entity_t *e, tree_t *tree );
void MakeDebugPortalSurfs( tree_t *tree );
void AddEntitySurfaceModels( entity_t *e );
int AddSurfaceModels( mapDrawSurface_t *ds );
void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree );
+void EmitPatchSurface( entity_t *e, mapDrawSurface_t *ds );
+void EmitTriangleSurface( mapDrawSurface_t *ds );
/* surface_fur.c */
void FixMetaTJunctions( void );
void SmoothMetaTriangles( void );
void MergeMetaTriangles( void );
+void EmitMetaStats(); // vortex: print meta statistics even in no-verbose mode
/* surface_extra.c */
int GetSurfaceExtraCastShadows( int num );
int GetSurfaceExtraRecvShadows( int num );
int GetSurfaceExtraSampleSize( int num );
+int GetSurfaceExtraMinSampleSize( int num );
float GetSurfaceExtraLongestCurve( int num );
void GetSurfaceExtraLightmapAxis( int num, vec3_t lightmapAxis );
void ProcessDecals( void );
void MakeEntityDecals( entity_t *e );
+/* map.c */
+void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv );
/* brush_primit.c */
void ComputeAxisBase( vec3_t normal, vec3_t texX, vec3_t texY);
float DirtForSample( trace_t *trace );
void DirtyRawLightmap( int num );
+void SetupFloodLight();
+void FloodlightRawLightmaps();
+void FloodlightIlluminateLightmap( rawLightmap_t *lm );
+float FloodLightForSample( trace_t *trace , float floodLightDistance, qboolean floodLightLowQuality);
+void FloodLightRawLightmap( int num );
+
void IlluminateRawLightmap( int num );
void IlluminateVertexes( int num );
int GetLumpElements( bspHeader_t *header, int lump, int size );
void *GetLump( bspHeader_t *header, int lump );
int CopyLump( bspHeader_t *header, int lump, void *dest, int size );
+int CopyLump_Allocate( bspHeader_t *header, int lump, void **dest, int size, int *allocationVariable );
void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length );
void LoadBSPFile( const char *filename );
void UnparseEntities( void );
void PrintEntity( const entity_t *ent );
void SetKeyValue( entity_t *ent, const char *key, const char *value );
+qboolean KeyExists( const entity_t *ent, const char *key ); /* VorteX: check if key exists */
const char *ValueForKey( const entity_t *ent, const char *key );
int IntForKey( const entity_t *ent, const char *key );
vec_t FloatForKey( const entity_t *ent, const char *key );
void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec );
entity_t *FindTargetEntity( const char *target );
void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows );
+void InjectCommandLine(char **argv, int beginArgs, int endArgs);
+
/* bspfile_ibsp.c */
,
#include "game_nexuiz.h"/* most be after game_quake3.h as they share defines! */
,
+ #include "game_xonotic.h"/* most be after game_quake3.h as they share defines! */
+ ,
#include "game_tremulous.h" /*LinuxManMikeC: must be after game_quake3.h, depends on #define's set in it */
,
#include "game_tenebrae.h"
,
#include "game_reaction.h" /* must be after game_quake3.h */
,
- { NULL } /* null game */
+ #include "game_darkplaces.h" /* vortex: darkplaces q1 engine */
+ ,
+ #include "game_dq.h" /* vortex: deluxe quake game ( darkplaces q1 engine) */
+ ,
+ #include "game_prophecy.h" /* vortex: prophecy game ( darkplaces q1 engine) */
+ ,
+ #include "game__null.h" /* null game (must be last item) */
};
#endif
Q_EXTERN game_t *game Q_ASSIGN( &games[ 0 ] );
Q_EXTERN qboolean noHint Q_ASSIGN( qfalse ); /* ydnar */
Q_EXTERN qboolean renameModelShaders Q_ASSIGN( qfalse ); /* ydnar */
Q_EXTERN qboolean skyFixHack Q_ASSIGN( qfalse ); /* ydnar */
+Q_EXTERN qboolean bspAlternateSplitWeights Q_ASSIGN( qfalse ); /* 27 */
+Q_EXTERN qboolean deepBSP Q_ASSIGN( qfalse ); /* div0 */
+Q_EXTERN qboolean maxAreaFaceSurface Q_ASSIGN( qfalse ); /* divVerent */
Q_EXTERN int patchSubdivisions Q_ASSIGN( 8 ); /* ydnar: -patchmeta subdivisions */
Q_EXTERN qboolean debugSurfaces Q_ASSIGN( qfalse );
Q_EXTERN qboolean debugInset Q_ASSIGN( qfalse );
Q_EXTERN qboolean debugPortals Q_ASSIGN( qfalse );
+Q_EXTERN qboolean lightmapTriangleCheck Q_ASSIGN(qfalse);
+Q_EXTERN qboolean lightmapExtraVisClusterNudge Q_ASSIGN(qfalse);
+Q_EXTERN qboolean lightmapFill Q_ASSIGN(qfalse);
#if Q3MAP2_EXPERIMENTAL_SNAP_NORMAL_FIX
// Increasing the normalEpsilon to compensate for new logic in SnapNormal(), where
Q_EXTERN char outbase[ 32 ];
Q_EXTERN int sampleSize; /* lightmap sample size in units */
+Q_EXTERN int minSampleSize; /* minimum sample size to use at all */
+Q_EXTERN int sampleScale; /* vortex: lightmap sample scale (ie quality)*/
Q_EXTERN int mapEntityNum Q_ASSIGN( 0 );
Q_EXTERN int entitySourceBrushes;
-Q_EXTERN plane_t mapplanes[ MAX_MAP_PLANES ]; /* mapplanes[ num ^ 1 ] will always be the mirror or mapplanes[ num ] */
-Q_EXTERN int nummapplanes; /* nummapplanes will always be even */
+Q_EXTERN plane_t *mapplanes Q_ASSIGN(NULL); /* mapplanes[ num ^ 1 ] will always be the mirror or mapplanes[ num ] */
+Q_EXTERN int nummapplanes Q_ASSIGN(0); /* nummapplanes will always be even */
+Q_EXTERN int allocatedmapplanes Q_ASSIGN(0);
Q_EXTERN int numMapPatches;
Q_EXTERN vec3_t mapMins, mapMaxs;
Q_EXTERN int numSurfacesByType[ NUM_SURFACE_TYPES ];
Q_EXTERN int numClearedSurfaces;
Q_EXTERN int numStripSurfaces;
+Q_EXTERN int numMaxAreaSurfaces;
Q_EXTERN int numFanSurfaces;
Q_EXTERN int numMergedSurfaces;
Q_EXTERN int numMergedVerts;
Q_EXTERN qboolean noPassageVis;
Q_EXTERN qboolean passageVisOnly;
Q_EXTERN qboolean mergevis;
+Q_EXTERN qboolean mergevisportals;
Q_EXTERN qboolean nosort;
Q_EXTERN qboolean saveprt;
Q_EXTERN qboolean hint; /* ydnar */
Q_EXTERN char inbase[ MAX_QPATH ];
-
-/* other bits */
-Q_EXTERN int totalvis;
+Q_EXTERN char globalCelShader[ MAX_QPATH ];
Q_EXTERN float farPlaneDist; /* rr2do2, rf, mre, ydnar all contributed to this one... */
/* commandline arguments */
Q_EXTERN qboolean wolfLight Q_ASSIGN( qfalse );
+Q_EXTERN float extraDist Q_ASSIGN( 0.0f );
Q_EXTERN qboolean loMem Q_ASSIGN( qfalse );
Q_EXTERN qboolean noStyles Q_ASSIGN( qfalse );
+Q_EXTERN qboolean keepLights Q_ASSIGN( qfalse );
Q_EXTERN int sampleSize Q_ASSIGN( DEFAULT_LIGHTMAP_SAMPLE_SIZE );
+Q_EXTERN int minSampleSize Q_ASSIGN( DEFAULT_LIGHTMAP_MIN_SAMPLE_SIZE );
Q_EXTERN qboolean noVertexLighting Q_ASSIGN( qfalse );
Q_EXTERN qboolean noGridLighting Q_ASSIGN( qfalse );
Q_EXTERN qboolean deluxemap Q_ASSIGN( qfalse );
Q_EXTERN qboolean debugDeluxemap Q_ASSIGN( qfalse );
+Q_EXTERN int deluxemode Q_ASSIGN( 0 ); /* deluxemap format (0 - modelspace, 1 - tangentspace with renormalization, 2 - tangentspace without renormalization) */
Q_EXTERN qboolean fast Q_ASSIGN( qfalse );
Q_EXTERN qboolean faster Q_ASSIGN( qfalse );
Q_EXTERN float shadeAngleDegrees Q_ASSIGN( 0.0f );
Q_EXTERN int superSample Q_ASSIGN( 0 );
Q_EXTERN int lightSamples Q_ASSIGN( 1 );
+Q_EXTERN qboolean lightRandomSamples Q_ASSIGN( qfalse );
+Q_EXTERN int lightSamplesSearchBoxSize Q_ASSIGN( 1 );
Q_EXTERN qboolean filter Q_ASSIGN( qfalse );
Q_EXTERN qboolean dark Q_ASSIGN( qfalse );
Q_EXTERN qboolean sunOnly Q_ASSIGN( qfalse );
Q_EXTERN int approximateTolerance Q_ASSIGN( 0 );
Q_EXTERN qboolean noCollapse Q_ASSIGN( qfalse );
+Q_EXTERN int lightmapSearchBlockSize Q_ASSIGN( 0 );
Q_EXTERN qboolean exportLightmaps Q_ASSIGN( qfalse );
Q_EXTERN qboolean externalLightmaps Q_ASSIGN( qfalse );
Q_EXTERN int lmCustomSize Q_ASSIGN( LIGHTMAP_WIDTH );
+Q_EXTERN char * lmCustomDir Q_ASSIGN( NULL );
+Q_EXTERN int lmLimitSize Q_ASSIGN( 0 );
Q_EXTERN qboolean dirty Q_ASSIGN( qfalse );
Q_EXTERN qboolean dirtDebug Q_ASSIGN( qfalse );
Q_EXTERN float dirtScale Q_ASSIGN( 1.0f );
Q_EXTERN float dirtGain Q_ASSIGN( 1.0f );
+/* 27: floodlighting */
+Q_EXTERN qboolean debugnormals Q_ASSIGN( qfalse );
+Q_EXTERN qboolean floodlighty Q_ASSIGN( qfalse );
+Q_EXTERN qboolean floodlight_lowquality Q_ASSIGN( qfalse );
+Q_EXTERN vec3_t floodlightRGB;
+Q_EXTERN float floodlightIntensity Q_ASSIGN( 512.0f );
+Q_EXTERN float floodlightDistance Q_ASSIGN( 1024.0f );
+Q_EXTERN float floodlightDirectionScale Q_ASSIGN( 1.0f );
+
Q_EXTERN qboolean dump Q_ASSIGN( qfalse );
Q_EXTERN qboolean debug Q_ASSIGN( qfalse );
Q_EXTERN qboolean debugUnused Q_ASSIGN( qfalse );
Q_EXTERN float skyScale Q_ASSIGN( 1.0f );
Q_EXTERN float bounceScale Q_ASSIGN( 0.25f );
+/* jal: alternative angle attenuation curve */
+Q_EXTERN qboolean lightAngleHL Q_ASSIGN( qfalse );
+
+/* vortex: gridscale and gridambientscale */
+Q_EXTERN float gridScale Q_ASSIGN( 1.0f );
+Q_EXTERN float gridAmbientScale Q_ASSIGN( 1.0f );
+Q_EXTERN float gridDirectionality Q_ASSIGN( 1.0f );
+Q_EXTERN float gridAmbientDirectionality Q_ASSIGN( 0.0f );
+Q_EXTERN qboolean inGrid Q_ASSIGN(0);
+
/* ydnar: lightmap gamma/compensation */
Q_EXTERN float lightmapGamma Q_ASSIGN( 1.0f );
+Q_EXTERN float lightmapExposure Q_ASSIGN( 1.0f );
Q_EXTERN float lightmapCompensate Q_ASSIGN( 1.0f );
/* ydnar: for runtime tweaking of falloff tolerance */
Q_EXTERN float formFactorValueScale Q_ASSIGN( 3.0f );
Q_EXTERN float linearScale Q_ASSIGN( 1.0f / 8000.0f );
+// for .ase conversion
+Q_EXTERN qboolean shadersAsBitmap Q_ASSIGN( qfalse );
+Q_EXTERN qboolean lightmapsAsTexcoord Q_ASSIGN( qfalse );
+
Q_EXTERN light_t *lights;
Q_EXTERN int numPointLights;
Q_EXTERN int numSpotLights;
Q_EXTERN int numExtLightmaps Q_ASSIGN( 0 );
Q_EXTERN outLightmap_t *outLightmaps Q_ASSIGN( NULL );
+/* vortex: per surface floodlight statictics */
+Q_EXTERN int numSurfacesFloodlighten Q_ASSIGN( 0 );
+
/* grid points */
Q_EXTERN int numRawGridPoints Q_ASSIGN( 0 );
Q_EXTERN rawGridPoint_t *rawGridPoints Q_ASSIGN( NULL );
Q_EXTERN entity_t entities[ MAX_MAP_ENTITIES ];
Q_EXTERN int numBSPModels Q_ASSIGN( 0 );
-Q_EXTERN bspModel_t bspModels[ MAX_MAP_MODELS ];
+Q_EXTERN int allocatedBSPModels Q_ASSIGN( 0 );
+Q_EXTERN bspModel_t* bspModels Q_ASSIGN(NULL);
Q_EXTERN int numBSPShaders Q_ASSIGN( 0 );
-Q_EXTERN bspShader_t bspShaders[ MAX_MAP_MODELS ];
+Q_EXTERN int allocatedBSPShaders Q_ASSIGN( 0 );
+Q_EXTERN bspShader_t* bspShaders Q_ASSIGN(0);
Q_EXTERN int bspEntDataSize Q_ASSIGN( 0 );
-Q_EXTERN char bspEntData[ MAX_MAP_ENTSTRING ];
+Q_EXTERN int allocatedBSPEntData Q_ASSIGN( 0 );
+Q_EXTERN char *bspEntData Q_ASSIGN(0);
Q_EXTERN int numBSPLeafs Q_ASSIGN( 0 );
Q_EXTERN bspLeaf_t bspLeafs[ MAX_MAP_LEAFS ];
Q_EXTERN int numBSPPlanes Q_ASSIGN( 0 );
-Q_EXTERN bspPlane_t bspPlanes[ MAX_MAP_PLANES ];
+Q_EXTERN int allocatedBSPPlanes Q_ASSIGN(0);
+Q_EXTERN bspPlane_t *bspPlanes;
Q_EXTERN int numBSPNodes Q_ASSIGN( 0 );
-Q_EXTERN bspNode_t bspNodes[ MAX_MAP_NODES ];
+Q_EXTERN int allocatedBSPNodes Q_ASSIGN( 0 );
+Q_EXTERN bspNode_t* bspNodes Q_ASSIGN(NULL);
Q_EXTERN int numBSPLeafSurfaces Q_ASSIGN( 0 );
-Q_EXTERN int bspLeafSurfaces[ MAX_MAP_LEAFFACES ];
+Q_EXTERN int allocatedBSPLeafSurfaces Q_ASSIGN( 0 );
+Q_EXTERN int* bspLeafSurfaces Q_ASSIGN(NULL);
Q_EXTERN int numBSPLeafBrushes Q_ASSIGN( 0 );
-Q_EXTERN int bspLeafBrushes[ MAX_MAP_LEAFBRUSHES ];
+Q_EXTERN int allocatedBSPLeafBrushes Q_ASSIGN( 0 );
+Q_EXTERN int* bspLeafBrushes Q_ASSIGN(NULL);
Q_EXTERN int numBSPBrushes Q_ASSIGN( 0 );
-Q_EXTERN bspBrush_t bspBrushes[ MAX_MAP_BRUSHES ];
+Q_EXTERN int allocatedBSPBrushes Q_ASSIGN( 0 );
+Q_EXTERN bspBrush_t* bspBrushes Q_ASSIGN(NULL);
Q_EXTERN int numBSPBrushSides Q_ASSIGN( 0 );
-Q_EXTERN bspBrushSide_t bspBrushSides[ MAX_MAP_BRUSHSIDES ];
+Q_EXTERN int allocatedBSPBrushSides Q_ASSIGN( 0 );
+Q_EXTERN bspBrushSide_t* bspBrushSides Q_ASSIGN(NULL);
Q_EXTERN int numBSPLightBytes Q_ASSIGN( 0 );
Q_EXTERN byte *bspLightBytes Q_ASSIGN( NULL );
Q_EXTERN int numBSPAds Q_ASSIGN( 0 );
Q_EXTERN bspAdvertisement_t bspAds[ MAX_MAP_ADVERTISEMENTS ];
+#define AUTOEXPAND_BY_REALLOC(ptr, reqitem, allocated, def) \
+ do \
+ { \
+ if(reqitem >= allocated) \
+ { \
+ if(allocated == 0) \
+ allocated = def; \
+ while(reqitem >= allocated && allocated) \
+ allocated *= 2; \
+ if(!allocated || allocated > 2147483647 / (int)sizeof(*ptr)) \
+ { \
+ Error(#ptr " over 2 GB"); \
+ } \
+ ptr = realloc(ptr, sizeof(*ptr) * allocated); \
+ if(!ptr) \
+ Error(#ptr " out of memory"); \
+ } \
+ } \
+ while(0)
+
+#define AUTOEXPAND_BY_REALLOC_BSP(suffix, def) AUTOEXPAND_BY_REALLOC(bsp##suffix, numBSP##suffix, allocatedBSP##suffix, def)
/* end marker */
#endif
-101 ICON DISCARDABLE "q3map2.ico"\r
+101 ICON DISCARDABLE "q3map2.ico"
VectorSet( mult, c, c, c );
break;
+ case CM_COLOR_DOT_PRODUCT_SCALE:
+ c = DotProduct( dv->normal, cm2->data );
+ c = (c - cm2->data[3]) / (cm2->data[4] - cm2->data[3]);
+ VectorSet( mult, c, c, c );
+ break;
+
case CM_ALPHA_DOT_PRODUCT:
mult[ 3 ] = DotProduct( dv->normal, cm2->data );
break;
+ case CM_ALPHA_DOT_PRODUCT_SCALE:
+ c = DotProduct( dv->normal, cm2->data );
+ c = (c - cm2->data[3]) / (cm2->data[4] - cm2->data[3]);
+ mult[ 3 ] = c;
+ break;
+
case CM_COLOR_DOT_PRODUCT_2:
c = DotProduct( dv->normal, cm2->data );
c *= c;
VectorSet( mult, c, c, c );
break;
+ case CM_COLOR_DOT_PRODUCT_2_SCALE:
+ c = DotProduct( dv->normal, cm2->data );
+ c *= c;
+ c = (c - cm2->data[3]) / (cm2->data[4] - cm2->data[3]);
+ VectorSet( mult, c, c, c );
+ break;
+
case CM_ALPHA_DOT_PRODUCT_2:
mult[ 3 ] = DotProduct( dv->normal, cm2->data );
mult[ 3 ] *= mult[ 3 ];
break;
+ case CM_ALPHA_DOT_PRODUCT_2_SCALE:
+ c = DotProduct( dv->normal, cm2->data );
+ c *= c;
+ c = (c - cm2->data[3]) / (cm2->data[4] - cm2->data[3]);
+ mult[ 3 ] = c;
+ break;
+
default:
break;
}
char shader[ MAX_QPATH ];
char *s;
int loc;
- md5_state_t mh;
byte digest[ 16 ];
char *srcShaderText, temp[ 8192 ], shaderText[ 8192 ]; /* ydnar: fixme (make this bigger?) */
strcat( shaderText, &srcShaderText[ loc + strlen( find ) ] );
}
- /* make md5 hash of the shader text */
- md5_init( &mh );
- md5_append( &mh, shaderText, strlen( shaderText ) );
- md5_finish( &mh, digest );
+ /* make md4 hash of the shader text */
+ Com_BlockFullChecksum(shaderText, strlen(shaderText), digest);
/* mangle hash into a shader name */
sprintf( shader, "%s/%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", mapName,
void EmitVertexRemapShader( char *from, char *to )
{
- md5_state_t mh;
byte digest[ 16 ];
char key[ 64 ], value[ 256 ];
/* build value */
sprintf( value, "%s;%s", from, to );
- /* make md5 hash */
- md5_init( &mh );
- md5_append( &mh, value, strlen( value ) );
- md5_finish( &mh, digest );
+ /* make md4 hash */
+ Com_BlockFullChecksum(value, strlen(value), digest);
/* make key (this is annoying, as vertexremapshader is precisely 17 characters,
which is one too long, so we leave off the last byte of the md5 digest) */
}
if( VectorLength( si->color ) <= 0.0f )
+ {
ColorNormalize( color, si->color );
- VectorScale( color, (1.0f / count), si->averageColor );
+ VectorScale( color, (1.0f / count), si->averageColor );
+ }
+ else
+ {
+ VectorCopy( si->color, si->averageColor );
+ }
}
finds a shaderinfo for a named shader
*/
+#define MAX_SHADER_DEPRECATION_DEPTH 16
+
shaderInfo_t *ShaderInfoForShader( const char *shaderName )
{
int i;
+ int deprecationDepth;
shaderInfo_t *si;
char shader[ MAX_QPATH ];
-
-
+
/* dummy check */
if( shaderName == NULL || shaderName[ 0 ] == '\0' )
{
StripExtension( shader );
/* search for it */
+ deprecationDepth = 0;
for( i = 0; i < numShaderInfo; i++ )
{
si = &shaderInfo[ i ];
if( !Q_stricmp( shader, si->shader ) )
{
+ /* check if shader is deprecated */
+ if (deprecationDepth < MAX_SHADER_DEPRECATION_DEPTH && si->deprecateShader && si->deprecateShader[ 0 ] )
+ {
+ /* override name */
+ strcpy( shader, si->deprecateShader );
+ StripExtension( shader );
+ /* increase deprecation depth */
+ deprecationDepth++;
+ if (deprecationDepth == MAX_SHADER_DEPRECATION_DEPTH)
+ Sys_Printf("WARNING: Max deprecation depth of %i is reached on shader '%s'\n", MAX_SHADER_DEPRECATION_DEPTH, shader);
+ /* search again from beginning */
+ i = -1;
+ continue;
+ }
+
/* load image if necessary */
if( si->finished == qfalse )
{
{
surfaceModel_t *model;
-
/* allocate new model and attach it */
model = safe_malloc( sizeof( *model ) );
memset( model, 0, sizeof( *model ) );
GetTokenAppend( shaderText, qfalse );
si->backsplashDistance = atof( token );
}
+
+ /* q3map_floodLight <r> <g> <b> <diste> <intensity> <light_direction_power> */
+ else if( !Q_stricmp( token, "q3map_floodLight" ) )
+ {
+ /* get color */
+ GetTokenAppend( shaderText, qfalse );
+ si->floodlightRGB[ 0 ] = atof( token );
+ GetTokenAppend( shaderText, qfalse );
+ si->floodlightRGB[ 1 ] = atof( token );
+ GetTokenAppend( shaderText, qfalse );
+ si->floodlightRGB[ 2 ] = atof( token );
+ GetTokenAppend( shaderText, qfalse );
+ si->floodlightDistance = atof( token );
+ GetTokenAppend( shaderText, qfalse );
+ si->floodlightIntensity = atof( token );
+ GetTokenAppend( shaderText, qfalse );
+ si->floodlightDirectionScale = atof( token );
+ }
+
+ /* jal: q3map_nodirty : skip dirty */
+ else if( !Q_stricmp( token, "q3map_nodirty" ) )
+ {
+ si->noDirty = qtrue;
+ }
/* q3map_lightmapSampleSize <value> */
else if( !Q_stricmp( token, "q3map_lightmapSampleSize" ) )
si->lightmapSampleSize = atoi( token );
}
- /* q3map_lightmapSampleSffset <value> */
+ /* q3map_lightmapSampleOffset <value> */
else if( !Q_stricmp( token, "q3map_lightmapSampleOffset" ) )
{
GetTokenAppend( shaderText, qfalse );
strcpy( si->remapShader, token );
}
}
+
+ /* q3map_deprecateShader <shader> */
+ else if( !Q_stricmp( token, "q3map_deprecateShader" ) )
+ {
+ GetTokenAppend( shaderText, qfalse );
+ if( token[ 0 ] != '\0' )
+ {
+
+ si->deprecateShader = safe_malloc( strlen( token ) + 1 );
+ strcpy( si->deprecateShader, token );
+ }
+ }
/* ydnar: q3map_offset <value> */
else if( !Q_stricmp( token, "q3map_offset" ) )
si->offset = atof( token );
}
- /* ydnar: q3map_textureSize <width> <height> (substitute for q3map_lightimage derivation for terrain) */
+ /* ydnar: q3map_fur <numlayers> <offset> <fade> */
else if( !Q_stricmp( token, "q3map_fur" ) )
{
GetTokenAppend( shaderText, qfalse );
Parse1DMatrixAppend( shaderText, 3, cm->data );
}
+ /* dotProductScale ( X Y Z MIN MAX ) */
+ else if( !Q_stricmp( token, "dotProductScale" ) )
+ {
+ cm->type = CM_COLOR_DOT_PRODUCT_SCALE + alpha;
+ Parse1DMatrixAppend( shaderText, 5, cm->data );
+ }
+
/* dotProduct2 ( X Y Z ) */
else if( !Q_stricmp( token, "dotProduct2" ) )
{
Parse1DMatrixAppend( shaderText, 3, cm->data );
}
+ /* dotProduct2scale ( X Y Z MIN MAX ) */
+ else if( !Q_stricmp( token, "dotProduct2scale" ) )
+ {
+ cm->type = CM_COLOR_DOT_PRODUCT_2_SCALE + alpha;
+ Parse1DMatrixAppend( shaderText, 5, cm->data );
+ }
+
/* volume */
else if( !Q_stricmp( token, "volume" ) )
{
si->styleMarker = 2;
/* ydnar: default to searching for q3map_<surfaceparm> */
- else
+#if 0
+ else
{
- //% Sys_FPrintf( SYS_VRB, "Attempting to match %s with a known surfaceparm\n", token );
+ Sys_FPrintf( SYS_VRB, "Attempting to match %s with a known surfaceparm\n", token );
if( ApplySurfaceParm( &token[ 6 ], &si->contentFlags, &si->surfaceFlags, &si->compileFlags ) == qfalse )
- ;//% Sys_Printf( "WARNING: Unknown q3map_* directive \"%s\"\n", token );
+ Sys_Printf( "WARNING: Unknown q3map_* directive \"%s\"\n", token );
}
+#endif
}
/* do some fixups for celshading */
ds->planar = qfalse;
ds->planeNum = -1;
+ ds->celShader = NULL; /* don't cel shade cels :P */
/* return the surface */
return ds;
void TidyEntitySurfaces( entity_t *e )
{
int i, j, deleted;
- mapDrawSurface_t *out, *in;
+ mapDrawSurface_t *out, *in = NULL;
/* note it */
//% Sys_Printf( "Failed to map axis %d onto patch\n", bestAxis );
}
- /* get lightmap sample size */
- if( ds->sampleSize <= 0 )
+ /* calculate lightmap sample size */
+ if( ds->shaderInfo->lightmapSampleSize > 0 ) /* shader value overrides every other */
+ ds->sampleSize = ds->shaderInfo->lightmapSampleSize;
+ else if( ds->sampleSize <= 0 ) /* may contain the entity asigned value */
+ ds->sampleSize = sampleSize; /* otherwise use global default */
+
+ if( ds->lightmapScale > 0.0f ) /* apply surface lightmap scaling factor */
{
- ds->sampleSize = sampleSize;
- if( ds->shaderInfo->lightmapSampleSize )
- ds->sampleSize = ds->shaderInfo->lightmapSampleSize;
- if( ds->lightmapScale > 0 )
- ds->sampleSize *= ds->lightmapScale;
- if( ds->sampleSize <= 0 )
- ds->sampleSize = 1;
- else if( ds->sampleSize > 16384 ) /* powers of 2 are preferred */
- ds->sampleSize = 16384;
+ ds->sampleSize = ds->lightmapScale * (float)ds->sampleSize;
+ ds->lightmapScale = 0; /* applied */
}
+
+ if( ds->sampleSize < minSampleSize )
+ ds->sampleSize = minSampleSize;
+
+ if( ds->sampleSize < 1 )
+ ds->sampleSize = 1;
+
+ if( ds->sampleSize > 16384 ) /* powers of 2 are preferred */
+ ds->sampleSize = 16384;
}
}
ds->mapBrush = b;
ds->sideRef = AllocSideRef( s, NULL );
ds->fogNum = -1;
+ ds->sampleSize = b->lightmapSampleSize;
ds->lightmapScale = b->lightmapScale;
ds->numVerts = w->numpoints;
ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
/* set cel shader */
ds->celShader = b->celShader;
+
+ /* set shade angle */
+ if( b->shadeAngleDegrees > 0.0f )
+ ds->shadeAngleDegrees = b->shadeAngleDegrees;
/* ydnar: gs mods: moved st biasing elsewhere */
return ds;
ds->shaderInfo = si;
ds->mapMesh = p;
+ ds->sampleSize = p->lightmapSampleSize;
ds->lightmapScale = p->lightmapScale; /* ydnar */
ds->patchWidth = mesh->width;
ds->patchHeight = mesh->height;
creates a flare draw surface
*/
-mapDrawSurface_t *DrawSurfaceForFlare( int entNum, vec3_t origin, vec3_t normal, vec3_t color, char *flareShader, int lightStyle )
+mapDrawSurface_t *DrawSurfaceForFlare( int entNum, vec3_t origin, vec3_t normal, vec3_t color, const char *flareShader, int lightStyle )
{
mapDrawSurface_t *ds;
return AddReferenceToLeaf( ds, node );
}
+/*
+FilterPointConvexHullIntoTree_r() - ydnar
+filters the convex hull of multiple points from a surface into the tree
+*/
+
+int FilterPointConvexHullIntoTree_r( vec3_t **points, int npoints, mapDrawSurface_t *ds, node_t *node )
+{
+ float d, dmin, dmax;
+ plane_t *plane;
+ int refs = 0;
+ int i;
+
+ if(!points)
+ return 0;
+
+ /* is this a decision node? */
+ if( node->planenum != PLANENUM_LEAF )
+ {
+ /* classify the point in relation to the plane */
+ plane = &mapplanes[ node->planenum ];
+
+ dmin = dmax = DotProduct( *(points[0]), plane->normal ) - plane->dist;
+ for(i = 1; i < npoints; ++i)
+ {
+ d = DotProduct( *(points[i]), plane->normal ) - plane->dist;
+ if(d > dmax)
+ dmax = d;
+ if(d < dmin)
+ dmin = d;
+ }
+
+ /* filter by this plane */
+ refs = 0;
+ if( dmax >= -ON_EPSILON )
+ refs += FilterPointConvexHullIntoTree_r( points, npoints, ds, node->children[ 0 ] );
+ if( dmin <= ON_EPSILON )
+ refs += FilterPointConvexHullIntoTree_r( points, npoints, ds, node->children[ 1 ] );
+
+ /* return */
+ return refs;
+ }
+
+ /* add a reference */
+ return AddReferenceToLeaf( ds, node );
+}
/*
{
/* 'fatten' the winding by the shader mins/maxs (parsed from vertexDeform move) */
/* note this winding is completely invalid (concave, nonplanar, etc) */
- fat = AllocWinding( w->numpoints * 3 );
- fat->numpoints = w->numpoints * 3;
+ fat = AllocWinding( w->numpoints * 3 + 3 );
+ fat->numpoints = w->numpoints * 3 + 3;
for( i = 0; i < w->numpoints; i++ )
{
VectorCopy( w->p[ i ], fat->p[ i ] );
- VectorAdd( w->p[ i ], si->mins, fat->p[ i * 2 ] );
- VectorAdd( w->p[ i ], si->maxs, fat->p[ i * 3 ] );
+ VectorAdd( w->p[ i ], si->mins, fat->p[ i + (w->numpoints+1) ] );
+ VectorAdd( w->p[ i ], si->maxs, fat->p[ i + (w->numpoints+1) * 2 ] );
}
+ VectorCopy( w->p[ 0 ], fat->p[ i ] );
+ VectorAdd( w->p[ 0 ], si->mins, fat->p[ i + w->numpoints ] );
+ VectorAdd( w->p[ 0 ], si->maxs, fat->p[ i + w->numpoints * 2 ] );
+
+ /*
+ * note: this winding is STILL not suitable for ClipWindingEpsilon, and
+ * also does not really fulfill the intention as it only contains
+ * origin, +mins, +maxs, but thanks to the "closing" points I just
+ * added to the three sub-windings, the fattening at least doesn't make
+ * it worse
+ */
FreeWinding( w );
w = fat;
static int FilterPatchIntoTree( mapDrawSurface_t *ds, tree_t *tree )
{
- int i, x, y, refs;
- mesh_t src, *mesh;
- winding_t *w;
+ int x, y, refs;
-
- /* subdivide the surface */
- src.width = ds->patchWidth;
- src.height = ds->patchHeight;
- src.verts = ds->verts;
- mesh = SubdivideMesh( src, FILTER_SUBDIVISION, 32 );
-
-
- /* filter each quad into the tree (fixme: use new patch x-triangulation code?) */
- refs = 0;
- for( y = 0; y < (mesh->height - 1); y++ )
- {
- for( x = 0; x < (mesh->width - 1); x++ )
+ for(y = 0; y + 2 < ds->patchHeight; y += 2)
+ for(x = 0; x + 2 < ds->patchWidth; x += 2)
{
- /* triangle 1 */
- w = AllocWinding( 3 );
- w->numpoints = 3;
- VectorCopy( mesh->verts[ y * mesh->width + x ].xyz, w->p[ 0 ] );
- VectorCopy( mesh->verts[ y * mesh->width + x + 1 ].xyz, w->p[ 1 ] );
- VectorCopy( mesh->verts[ (y + 1) * mesh->width + x ].xyz, w->p[ 2 ] );
- refs += FilterWindingIntoTree_r( w, ds, tree->headnode );
-
- /* triangle 2 */
- w = AllocWinding( 3 );
- w->numpoints = 3;
- VectorCopy( mesh->verts[ y * mesh->width + x + 1 ].xyz, w->p[ 0 ] );
- VectorCopy( mesh->verts[ (y + 1 ) * mesh->width + x + 1 ].xyz, w->p[ 1 ] );
- VectorCopy( mesh->verts[ (y + 1 ) * mesh->width + x ].xyz, w->p[ 2 ] );
- refs += FilterWindingIntoTree_r( w, ds, tree->headnode );
+ vec3_t *points[9];
+ points[0] = &ds->verts[(y+0) * ds->patchWidth + (x+0)].xyz;
+ points[1] = &ds->verts[(y+0) * ds->patchWidth + (x+1)].xyz;
+ points[2] = &ds->verts[(y+0) * ds->patchWidth + (x+2)].xyz;
+ points[3] = &ds->verts[(y+1) * ds->patchWidth + (x+0)].xyz;
+ points[4] = &ds->verts[(y+1) * ds->patchWidth + (x+1)].xyz;
+ points[5] = &ds->verts[(y+1) * ds->patchWidth + (x+2)].xyz;
+ points[6] = &ds->verts[(y+2) * ds->patchWidth + (x+0)].xyz;
+ points[7] = &ds->verts[(y+2) * ds->patchWidth + (x+1)].xyz;
+ points[8] = &ds->verts[(y+2) * ds->patchWidth + (x+2)].xyz;
+ refs += FilterPointConvexHullIntoTree_r(points, 9, ds, tree->headnode);
}
- }
-
- /* use point filtering as well */
- for( i = 0; i < (mesh->width * mesh->height); i++ )
- refs += FilterPointIntoTree_r( mesh->verts[ i ].xyz, ds, tree->headnode );
-
- /* free the subdivided mesh and return */
- FreeMesh( mesh );
+
return refs;
}
for( i = 0; i < ds->numVerts; i++ )
{
/* allocate a new vert */
- if( numBSPDrawVerts == MAX_MAP_DRAW_VERTS )
- Error( "MAX_MAP_DRAW_VERTS" );
IncDrawVerts();
dv = &bspDrawVerts[ numBSPDrawVerts - 1 ];
numSurfacesByType[ ds->type ]++;
}
-
-
/*
EmitPatchSurface()
emits a bsp patch drawsurface
*/
-void EmitPatchSurface( mapDrawSurface_t *ds )
+void EmitPatchSurface( entity_t *e, mapDrawSurface_t *ds )
{
int i, j;
bspDrawSurface_t *out;
int surfaceFlags, contentFlags;
-
+ int forcePatchMeta;
+
+ /* vortex: _patchMeta support */
+ forcePatchMeta = IntForKey(e, "_patchMeta" );
+ if (!forcePatchMeta)
+ forcePatchMeta = IntForKey(e, "patchMeta" );
/* invert the surface if necessary */
if( ds->backSide || ds->shaderInfo->invert )
{
bspDrawVert_t *dv1, *dv2, temp;
-
/* walk the verts, flip the normal */
for( i = 0; i < ds->numVerts; i++ )
/* invert facing */
VectorScale( ds->lightmapVecs[ 2 ], -1.0f, ds->lightmapVecs[ 2 ] );
}
-
+
/* allocate a new surface */
if( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS )
Error( "MAX_MAP_DRAW_SURFS" );
ds->outputNum = numBSPDrawSurfaces;
numBSPDrawSurfaces++;
memset( out, 0, sizeof( *out ) );
-
+
/* set it up */
out->surfaceType = MST_PATCH;
if( debugSurfaces )
out->shaderNum = EmitShader( "debugsurfaces", NULL, NULL );
- else if( patchMeta )
+ else if( patchMeta || forcePatchMeta )
{
/* patch meta requires that we have nodraw patches for collision */
surfaceFlags = ds->shaderInfo->surfaceFlags;
numSurfacesByType[ ds->type ]++;
}
-
-
/*
OptimizeTriangleSurface() - ydnar
optimizes the vertex/index data in a triangle surface
creates a bsp drawsurface from arbitrary triangle surfaces
*/
-static void EmitTriangleSurface( mapDrawSurface_t *ds )
+void EmitTriangleSurface( mapDrawSurface_t *ds )
{
int i, temp;
bspDrawSurface_t *out;
-
-
+
/* invert the surface if necessary */
if( ds->backSide || ds->shaderInfo->invert )
{
ds->indexes[ i ] = ds->indexes[ i + 1 ];
ds->indexes[ i + 1 ] = temp;
}
-
+
/* walk the verts, flip the normal */
for( i = 0; i < ds->numVerts; i++ )
VectorScale( ds->verts[ i ].normal, -1.0f, ds->verts[ i ].normal );
-
+
/* invert facing */
VectorScale( ds->lightmapVecs[ 2 ], -1.0f, ds->lightmapVecs[ 2 ] );
}
-
+
/* allocate a new surface */
if( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS )
Error( "MAX_MAP_DRAW_SURFS" );
emits a bsp planar winding (brush face) drawsurface
*/
-static void EmitFaceSurface( mapDrawSurface_t *ds )
+static void EmitFaceSurface(mapDrawSurface_t *ds )
{
/* strip/fan finding was moved elsewhere */
- StripFaceSurface( ds );
- EmitTriangleSurface( ds );
+ if(maxAreaFaceSurface)
+ MaxAreaFaceSurface( ds );
+ else
+ StripFaceSurface( ds );
+ EmitTriangleSurface(ds);
}
-
/*
MakeDebugPortalSurfs_r() - ydnar
generates drawsurfaces for passable portals in the bsp
}
/* insert the model */
- InsertModel( (char *) model->model, 0, transform, NULL, ds->celShader, ds->entityNum, ds->castShadows, ds->recvShadows, 0, ds->lightmapScale );
+ InsertModel( (char *) model->model, 0, 0, transform, NULL, ds->celShader, ds->entityNum, ds->castShadows, ds->recvShadows, 0, ds->lightmapScale, 0, 0 );
/* return to sender */
return 1;
vec3_t origin, mins, maxs;
int refs;
int numSurfs, numRefs, numSkyboxSurfaces;
+ qboolean sb;
/* note it */
/* get shader */
si = ds->shaderInfo;
-
+
/* ydnar: skybox surfaces are special */
if( ds->skybox )
{
refs = AddReferenceToTree_r( ds, tree->headnode, qtrue );
ds->skybox = qfalse;
+ sb = qtrue;
}
else
{
+ sb = qfalse;
+
/* refs initially zero */
refs = 0;
if( refs == 0 )
refs = FilterPatchIntoTree( ds, tree );
if( refs > 0 )
- EmitPatchSurface( ds );
+ EmitPatchSurface( e, ds );
break;
/* handle triangle surfaces */
refs = 0;
break;
}
+
+ /* maybe surface got marked as skybox again */
+ /* if we keep that flag, it will get scaled up AGAIN */
+ if(sb)
+ ds->skybox = qfalse;
/* tot up the references */
if( refs > 0 )
Sys_FPrintf( SYS_VRB, "%9d (%d) emitted drawsurfs\n", numSurfs, numBSPDrawSurfaces );
Sys_FPrintf( SYS_VRB, "%9d stripped face surfaces\n", numStripSurfaces );
Sys_FPrintf( SYS_VRB, "%9d fanned face surfaces\n", numFanSurfaces );
+ Sys_FPrintf( SYS_VRB, "%9d maxarea'd face surfaces\n", numMaxAreaSurfaces );
Sys_FPrintf( SYS_VRB, "%9d surface models generated\n", numSurfaceModels );
Sys_FPrintf( SYS_VRB, "%9d skybox surfaces generated\n", numSkyboxSurfaces );
for( i = 0; i < NUM_SURFACE_TYPES; i++ )
}
/* parse the file */
- ParseFromMemory( buffer, size );
+ ParseFromMemory( (char *) buffer, size );
/* tokenize it */
while( 1 )
m4x4_scale_for_vec3( transform, scale );
/* add the model to the bsp */
- InsertModel( foliage->model, 0, transform, NULL, NULL, src->entityNum, src->castShadows, src->recvShadows, 0, src->lightmapScale );
+ InsertModel( foliage->model, 0, 0, transform, NULL, NULL, src->entityNum, src->castShadows, src->recvShadows, 0, src->lightmapScale, 0, 0 );
/* walk each new surface */
for( i = oldNumMapDrawSurfs; i < numMapDrawSurfs; i++ )
{
int i;
bspDrawVert_t *v, *temp;
-
+
/* try to find an existing drawvert */
for( i = firstSearchMetaVert, v = &metaVerts[ i ]; i < numMetaVerts; i++, v++ )
src.recvShadows = ds->recvShadows;
src.fogNum = ds->fogNum;
src.sampleSize = ds->sampleSize;
+ src.shadeAngleDegrees = ds->shadeAngleDegrees;
VectorCopy( ds->lightmapAxis, src.lightmapAxis );
/* copy drawverts */
creates triangles from a patch
*/
-void TriangulatePatchSurface( mapDrawSurface_t *ds )
+void TriangulatePatchSurface( entity_t *e , mapDrawSurface_t *ds )
{
int iterations, x, y, pw[ 5 ], r;
mapDrawSurface_t *dsNew;
mesh_t src, *subdivided, *mesh;
-
-
+ int forcePatchMeta;
+ int patchQuality;
+ int patchSubdivision;
+
+ /* vortex: _patchMeta, _patchQuality, _patchSubdivide support */
+ forcePatchMeta = IntForKey(e, "_patchMeta" );
+ if (!forcePatchMeta)
+ forcePatchMeta = IntForKey(e, "patchMeta" );
+ patchQuality = IntForKey(e, "_patchQuality" );
+ if (!patchQuality)
+ patchQuality = IntForKey(e, "patchQuality" );
+ if (!patchQuality)
+ patchQuality = 1.0;
+ patchSubdivision = IntForKey(e, "_patchSubdivide" );
+ if (!patchSubdivision)
+ patchSubdivision = IntForKey(e, "patchSubdivide" );
+
/* try to early out */
- if( ds->numVerts == 0 || ds->type != SURFACE_PATCH || patchMeta == qfalse )
+ if(ds->numVerts == 0 || ds->type != SURFACE_PATCH || ( patchMeta == qfalse && !forcePatchMeta) )
return;
-
/* make a mesh from the drawsurf */
src.width = ds->patchWidth;
src.height = ds->patchHeight;
src.verts = ds->verts;
//% subdivided = SubdivideMesh( src, 8, 999 );
- iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions );
+ if (patchSubdivision)
+ iterations = IterationsForCurve( ds->longestCurve, patchSubdivision );
+ else
+ iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions / patchQuality );
+
subdivided = SubdivideMesh2( src, iterations ); //% ds->maxIterations
/* fit it to the curve and remove colinear verts on rows/columns */
ClassifySurfaces( 1, ds );
}
+#define TINY_AREA 1.0f
+#define MAXAREA_MAXTRIES 8
+int MaxAreaIndexes(bspDrawVert_t *vert, int cnt, int *indexes)
+{
+ int r, s, t, bestR = 0, bestS = 1, bestT = 2;
+ int i, j, try;
+ double A, bestA = -1, V, bestV = -1;
+ vec3_t ab, ac, bc, cross;
+ bspDrawVert_t *buf;
+ double shiftWidth;
+
+ if(cnt < 3)
+ return 0;
+
+ /* calculate total area */
+ A = 0;
+ for(i = 1; i+1 < cnt; ++i)
+ {
+ VectorSubtract(vert[i].xyz, vert[0].xyz, ab);
+ VectorSubtract(vert[i+1].xyz, vert[0].xyz, ac);
+ CrossProduct(ab, ac, cross);
+ A += VectorLength(cross);
+ }
+ V = 0;
+ for(i = 0; i < cnt; ++i)
+ {
+ VectorSubtract(vert[(i+1)%cnt].xyz, vert[i].xyz, ab);
+ V += VectorLength(ab);
+ }
+
+ /* calculate shift width from the area sensibly, assuming the polygon
+ * fits about 25% of the screen in both dimensions
+ * we assume 1280x1024
+ * 1 pixel is then about sqrt(A) / (0.25 * screenwidth)
+ * 8 pixels are then about sqrt(A) / (0.25 * 1280) * 8
+ * 8 pixels are then about sqrt(A) * 0.025
+ * */
+ shiftWidth = sqrt(A) * 0.0125;
+ /* 3->1 6->2 12->3 ... */
+ if(A - ceil(log(cnt/1.5) / log(2)) * V * shiftWidth * 2 < 0)
+ {
+ /* printf("Small triangle detected (area %f, circumference %f), adjusting shiftWidth from %f to ", A, V, shiftWidth); */
+ shiftWidth = A / (ceil(log(cnt/1.5) / log(2)) * V * 2);
+ /* printf("%f\n", shiftWidth); */
+ }
+
+ /* find the triangle with highest area */
+ for(r = 0; r+2 < cnt; ++r)
+ for(s = r+1; s+1 < cnt; ++s)
+ for(t = s+1; t < cnt; ++t)
+ {
+ VectorSubtract(vert[s].xyz, vert[r].xyz, ab);
+ VectorSubtract(vert[t].xyz, vert[r].xyz, ac);
+ VectorSubtract(vert[t].xyz, vert[s].xyz, bc);
+ CrossProduct(ab, ac, cross);
+ A = VectorLength(cross);
+
+ V = A - (VectorLength(ab) - VectorLength(ac) - VectorLength(bc)) * shiftWidth;
+ /* value = A - circumference * shiftWidth, i.e. we back out by shiftWidth units from each side, to prevent too acute triangles */
+ /* this kind of simulates "number of shiftWidth*shiftWidth fragments in the triangle not touched by an edge" */
+
+ if(bestA < 0 || V > bestV)
+ {
+ bestA = A;
+ bestV = V;
+ bestR = r;
+ bestS = s;
+ bestT = t;
+ }
+ }
+
+ /*
+ if(bestV < 0)
+ printf("value was REALLY bad\n");
+ */
+
+ for(try = 0; try < MAXAREA_MAXTRIES; ++try)
+ {
+ if(try)
+ {
+ bestR = rand() % cnt;
+ bestS = rand() % cnt;
+ bestT = rand() % cnt;
+ if(bestR == bestS || bestR == bestT || bestS == bestT)
+ continue;
+ // bubblesort inline
+ // abc acb bac bca cab cba
+ if(bestR > bestS)
+ {
+ j = bestR;
+ bestR = bestS;
+ bestS = j;
+ }
+ // abc acb abc bca acb bca
+ if(bestS > bestT)
+ {
+ j = bestS;
+ bestS = bestT;
+ bestT = j;
+ }
+ // abc abc abc bac abc bac
+ if(bestR > bestS)
+ {
+ j = bestR;
+ bestR = bestS;
+ bestS = j;
+ }
+ // abc abc abc abc abc abc
+
+ VectorSubtract(vert[bestS].xyz, vert[bestR].xyz, ab);
+ VectorSubtract(vert[bestT].xyz, vert[bestR].xyz, ac);
+ CrossProduct(ab, ac, cross);
+ bestA = VectorLength(cross);
+ }
+
+ if(bestA < TINY_AREA)
+ /* the biggest triangle is degenerate - then every other is too, and the other algorithms wouldn't generate anything useful either */
+ continue;
+
+ i = 0;
+ indexes[i++] = bestR;
+ indexes[i++] = bestS;
+ indexes[i++] = bestT;
+ /* uses 3 */
+
+ /* identify the other fragments */
+
+ /* full polygon without triangle (bestR,bestS,bestT) = three new polygons:
+ * 1. bestR..bestS
+ * 2. bestS..bestT
+ * 3. bestT..bestR
+ */
+
+ j = MaxAreaIndexes(vert + bestR, bestS - bestR + 1, indexes + i);
+ if(j < 0)
+ continue;
+ j += i;
+ for(; i < j; ++i)
+ indexes[i] += bestR;
+ /* uses 3*(bestS-bestR+1)-6 */
+ j = MaxAreaIndexes(vert + bestS, bestT - bestS + 1, indexes + i);
+ if(j < 0)
+ continue;
+ j += i;
+ for(; i < j; ++i)
+ indexes[i] += bestS;
+ /* uses 3*(bestT-bestS+1)-6 */
+
+ /* can'bestT recurse this one directly... therefore, buffering */
+ if(cnt + bestR - bestT + 1 >= 3)
+ {
+ buf = safe_malloc(sizeof(*vert) * (cnt + bestR - bestT + 1));
+ memcpy(buf, vert + bestT, sizeof(*vert) * (cnt - bestT));
+ memcpy(buf + (cnt - bestT), vert, sizeof(*vert) * (bestR + 1));
+ j = MaxAreaIndexes(buf, cnt + bestR - bestT + 1, indexes + i);
+ if(j < 0)
+ {
+ free(buf);
+ continue;
+ }
+ j += i;
+ for(; i < j; ++i)
+ indexes[i] = (indexes[i] + bestT) % cnt;
+ /* uses 3*(cnt+bestR-bestT+1)-6 */
+ free(buf);
+ }
+
+ /* together 3 + 3*(cnt+3) - 18 = 3*cnt-6 q.e.d. */
+ return i;
+ }
+
+ return -1;
+}
+
+/*
+MaxAreaFaceSurface() - divVerent
+creates a triangle list using max area indexes
+*/
+
+void MaxAreaFaceSurface(mapDrawSurface_t *ds)
+{
+ int n;
+ /* try to early out */
+ if( !ds->numVerts || (ds->type != SURFACE_FACE && ds->type != SURFACE_DECAL) )
+ return;
+
+ /* is this a simple triangle? */
+ if( ds->numVerts == 3 )
+ {
+ ds->numIndexes = 3;
+ ds->indexes = safe_malloc( ds->numIndexes * sizeof( int ) );
+ VectorSet( ds->indexes, 0, 1, 2 );
+ numMaxAreaSurfaces++;
+ return;
+ }
+
+ /* do it! */
+ ds->numIndexes = 3 * ds->numVerts - 6;
+ ds->indexes = safe_malloc( ds->numIndexes * sizeof( int ) );
+ n = MaxAreaIndexes(ds->verts, ds->numVerts, ds->indexes);
+ if(n < 0)
+ {
+ /* whatever we do, it's degenerate */
+ free(ds->indexes);
+ ds->numIndexes = 0;
+ StripFaceSurface(ds);
+ return;
+ }
+ ds->numIndexes = n;
+
+ /* add to count */
+ numMaxAreaSurfaces++;
+
+ /* classify it */
+ ClassifySurfaces( 1, ds );
+}
/*
Error( "MAX_INDEXES exceeded for surface (%d > %d) (%d verts)", numIndexes, MAX_INDEXES, ds->numVerts );
/* try all possible orderings of the points looking for a non-degenerate strip order */
+ ni = 0;
for( r = 0; r < ds->numVerts; r++ )
{
/* set rotation */
/* classify it */
ClassifySurfaces( 1, ds );
}
+
+
+/*
+EmitMetaStatictics
+vortex: prints meta statistics in general output
+*/
-
+void EmitMetaStats()
+{
+ Sys_Printf( "--- EmitMetaStats ---\n" );
+ Sys_Printf( "%9d total meta surfaces\n", numMetaSurfaces );
+ Sys_Printf( "%9d stripped surfaces\n", numStripSurfaces );
+ Sys_Printf( "%9d fanned surfaces\n", numFanSurfaces );
+ Sys_Printf( "%9d maxarea'd surfaces\n", numMaxAreaSurfaces );
+ Sys_Printf( "%9d patch meta surfaces\n", numPatchMetaSurfaces );
+ Sys_Printf( "%9d meta verts\n", numMetaVerts );
+ Sys_Printf( "%9d meta triangles\n", numMetaTriangles );
+}
/*
MakeEntityMetaTriangles()
{
case SURFACE_FACE:
case SURFACE_DECAL:
- StripFaceSurface( ds );
+ if(maxAreaFaceSurface)
+ MaxAreaFaceSurface( ds );
+ else
+ StripFaceSurface( ds );
SurfaceToMetaTriangles( ds );
break;
case SURFACE_PATCH:
- TriangulatePatchSurface( ds );
+ TriangulatePatchSurface(e, ds );
break;
case SURFACE_TRIANGLES:
break;
-
+
case SURFACE_FORCED_META:
case SURFACE_META:
SurfaceToMetaTriangles( ds );
Sys_FPrintf( SYS_VRB, "%9d total meta surfaces\n", numMetaSurfaces );
Sys_FPrintf( SYS_VRB, "%9d stripped surfaces\n", numStripSurfaces );
Sys_FPrintf( SYS_VRB, "%9d fanned surfaces\n", numFanSurfaces );
+ Sys_FPrintf( SYS_VRB, "%9d maxarea'd surfaces\n", numMaxAreaSurfaces );
Sys_FPrintf( SYS_VRB, "%9d patch meta surfaces\n", numPatchMetaSurfaces );
Sys_FPrintf( SYS_VRB, "%9d meta verts\n", numMetaVerts );
Sys_FPrintf( SYS_VRB, "%9d meta triangles\n", numMetaTriangles );
-/*
-PointTriangleIntersect()
-assuming that all points lie in plane, determine if pt
-is inside the triangle abc
-code originally (c) 2001 softSurfer (www.softsurfer.com)
-*/
-
-#define MIN_OUTSIDE_EPSILON -0.01f
-#define MAX_OUTSIDE_EPSILON 1.01f
-
-static qboolean PointTriangleIntersect( vec3_t pt, vec4_t plane, vec3_t a, vec3_t b, vec3_t c, vec3_t bary )
-{
- vec3_t u, v, w;
- float uu, uv, vv, wu, wv, d;
-
-
- /* make vectors */
- VectorSubtract( b, a, u );
- VectorSubtract( c, a, v );
- VectorSubtract( pt, a, w );
-
- /* more setup */
- uu = DotProduct( u, u );
- uv = DotProduct( u, v );
- vv = DotProduct( v, v );
- wu = DotProduct( w, u );
- wv = DotProduct( w, v );
- d = uv * uv - uu * vv;
-
- /* calculate barycentric coordinates */
- bary[ 1 ] = (uv * wv - vv * wu) / d;
- if( bary[ 1 ] < MIN_OUTSIDE_EPSILON || bary[ 1 ] > MAX_OUTSIDE_EPSILON )
- return qfalse;
- bary[ 2 ] = (uv * wv - uu * wv) / d;
- if( bary[ 2 ] < MIN_OUTSIDE_EPSILON || bary[ 2 ] > MAX_OUTSIDE_EPSILON )
- return qfalse;
- bary[ 0 ] = 1.0f - (bary[ 1 ] + bary[ 2 ]);
-
- /* point is in triangle */
- return qtrue;
-}
-
-
-
/*
CreateEdge()
sets up an edge structure from a plane and 2 points that the edge ab falls lies in
/* get vert */
VectorCopy( metaVerts[ j ].xyz, pt );
- /* debug code: darken verts */
- if( i == 0 )
- VectorSet( metaVerts[ j ].color[ 0 ], 8, 8, 8 );
-
/* determine if point lies in the triangle's plane */
dist = DotProduct( pt, plane ) - plane[ 3 ];
if( fabs( dist ) > TJ_PLANE_EPSILON )
amount = dist / edges[ k ].length;
#endif
- /* debug code: brighten this point */
- //% metaVerts[ j ].color[ 0 ][ 0 ] += 5;
- //% metaVerts[ j ].color[ 0 ][ 1 ] += 4;
- VectorSet( metaVerts[ tri->indexes[ k ] ].color[ 0 ], 255, 204, 0 );
- VectorSet( metaVerts[ tri->indexes[ (k + 1) % 3 ] ].color[ 0 ], 255, 204, 0 );
-
-
/* the edge opposite the zero-weighted vertex was hit, so use that as an amount */
a = &metaVerts[ tri->indexes[ k % 3 ] ];
b = &metaVerts[ tri->indexes[ (k + 1) % 3 ] ];
int indexes[ MAX_SAMPLES ];
vec3_t votes[ MAX_SAMPLES ];
-
/* note it */
Sys_FPrintf( SYS_VRB, "--- SmoothMetaTriangles ---\n" );
and set per-vertex smoothing angle */
for( i = 0, tri = &metaTriangles[ i ]; i < numMetaTriangles; i++, tri++ )
{
- /* get shader for shade angle */
+ shadeAngle = defaultShadeAngle;
+
+ /* get shade angle from shader */
if( tri->si->shadeAngleDegrees > 0.0f )
shadeAngle = DEG2RAD( tri->si->shadeAngleDegrees );
- else
+ /* get shade angle from entity */
+ else if( tri->shadeAngleDegrees > 0.0f )
+ shadeAngle = DEG2RAD( tri->shadeAngleDegrees );
+
+ if( shadeAngle <= 0.0f )
shadeAngle = defaultShadeAngle;
+
if( shadeAngle > maxShadeAngle )
maxShadeAngle = shadeAngle;
#define ST_SCORE2 (2 * (ST_SCORE))
#define ADEQUATE_SCORE ((AXIS_MIN) + 1 * (VERT_SCORE))
-#define GOOD_SCORE ((AXIS_MIN) + 2 * (VERT_SCORE) + 4 * (ST_SCORE))
-#define PERFECT_SCORE ((AXIS_MIN) + + 3 * (VERT_SCORE) + (SURFACE_SCORE) + 4 * (ST_SCORE))
+#define GOOD_SCORE ((AXIS_MIN) + 2 * (VERT_SCORE) + 4 * (ST_SCORE))
+#define PERFECT_SCORE ((AXIS_MIN) + 3 * (VERT_SCORE) + (SURFACE_SCORE) + 4 * (ST_SCORE))
+//#define MAX_BBOX_DISTANCE 16
static int AddMetaTriangleToSurface( mapDrawSurface_t *ds, metaTriangle_t *tri, qboolean testAdd )
{
if( tri->planeNum >= 0 && tri->planeNum != ds->planeNum )
return 0;
}
+
+#if MAX_BBOX_DISTANCE > 0
+ VectorCopy( ds->mins, mins );
+ VectorCopy( ds->maxs, maxs );
+ mins[0] -= MAX_BBOX_DISTANCE;
+ mins[1] -= MAX_BBOX_DISTANCE;
+ mins[2] -= MAX_BBOX_DISTANCE;
+ maxs[0] += MAX_BBOX_DISTANCE;
+ maxs[1] += MAX_BBOX_DISTANCE;
+ maxs[2] += MAX_BBOX_DISTANCE;
+#define CHECK_1D(mins, v, maxs) ((mins) <= (v) && (v) <= (maxs))
+#define CHECK_3D(mins, v, maxs) (CHECK_1D((mins)[0], (v)[0], (maxs)[0]) && CHECK_1D((mins)[1], (v)[1], (maxs)[1]) && CHECK_1D((mins)[2], (v)[2], (maxs)[2]))
+ VectorCopy(metaVerts[ tri->indexes[ 0 ] ].xyz, p);
+ if(!CHECK_3D(mins, p, maxs))
+ {
+ VectorCopy(metaVerts[ tri->indexes[ 1 ] ].xyz, p);
+ if(!CHECK_3D(mins, p, maxs))
+ {
+ VectorCopy(metaVerts[ tri->indexes[ 2 ] ].xyz, p);
+ if(!CHECK_3D(mins, p, maxs))
+ return 0;
+ }
+ }
+#undef CHECK_3D
+#undef CHECK_1D
+#endif
/* set initial score */
score = tri->surfaceNum == ds->surfaceNum ? SURFACE_SCORE : 0;
ds->planeNum = seed->planeNum;
ds->fogNum = seed->fogNum;
ds->sampleSize = seed->sampleSize;
+ ds->shadeAngleDegrees = seed->shadeAngleDegrees;
ds->verts = verts;
ds->indexes = indexes;
VectorCopy( seed->lightmapAxis, ds->lightmapAxis );
/* shader first */
- if( ((metaTriangle_t*) a)->si < ((metaTriangle_t*) b)->si )
+ if( ((const metaTriangle_t*) a)->si < ((const metaTriangle_t*) b)->si )
return 1;
- else if( ((metaTriangle_t*) a)->si > ((metaTriangle_t*) b)->si )
+ else if( ((const metaTriangle_t*) a)->si > ((const metaTriangle_t*) b)->si )
return -1;
/* then fog */
- else if( ((metaTriangle_t*) a)->fogNum < ((metaTriangle_t*) b)->fogNum )
+ else if( ((const metaTriangle_t*) a)->fogNum < ((const metaTriangle_t*) b)->fogNum )
return 1;
- else if( ((metaTriangle_t*) a)->fogNum > ((metaTriangle_t*) b)->fogNum )
+ else if( ((const metaTriangle_t*) a)->fogNum > ((const metaTriangle_t*) b)->fogNum )
return -1;
/* then plane */
#if 0
- else if( npDegrees == 0.0f && ((metaTriangle_t*) a)->si->nonplanar == qfalse &&
- ((metaTriangle_t*) a)->planeNum >= 0 && ((metaTriangle_t*) a)->planeNum >= 0 )
+ else if( npDegrees == 0.0f && ((const metaTriangle_t*) a)->si->nonplanar == qfalse &&
+ ((const metaTriangle_t*) a)->planeNum >= 0 && ((const metaTriangle_t*) a)->planeNum >= 0 )
{
- if( ((metaTriangle_t*) a)->plane[ 3 ] < ((metaTriangle_t*) b)->plane[ 3 ] )
+ if( ((const metaTriangle_t*) a)->plane[ 3 ] < ((const metaTriangle_t*) b)->plane[ 3 ] )
return 1;
- else if( ((metaTriangle_t*) a)->plane[ 3 ] > ((metaTriangle_t*) b)->plane[ 3 ] )
+ else if( ((const metaTriangle_t*) a)->plane[ 3 ] > ((const metaTriangle_t*) b)->plane[ 3 ] )
return -1;
- else if( ((metaTriangle_t*) a)->plane[ 0 ] < ((metaTriangle_t*) b)->plane[ 0 ] )
+ else if( ((const metaTriangle_t*) a)->plane[ 0 ] < ((const metaTriangle_t*) b)->plane[ 0 ] )
return 1;
- else if( ((metaTriangle_t*) a)->plane[ 0 ] > ((metaTriangle_t*) b)->plane[ 0 ] )
+ else if( ((const metaTriangle_t*) a)->plane[ 0 ] > ((const metaTriangle_t*) b)->plane[ 0 ] )
return -1;
- else if( ((metaTriangle_t*) a)->plane[ 1 ] < ((metaTriangle_t*) b)->plane[ 1 ] )
+ else if( ((const metaTriangle_t*) a)->plane[ 1 ] < ((const metaTriangle_t*) b)->plane[ 1 ] )
return 1;
- else if( ((metaTriangle_t*) a)->plane[ 1 ] > ((metaTriangle_t*) b)->plane[ 1 ] )
+ else if( ((const metaTriangle_t*) a)->plane[ 1 ] > ((const metaTriangle_t*) b)->plane[ 1 ] )
return -1;
- else if( ((metaTriangle_t*) a)->plane[ 2 ] < ((metaTriangle_t*) b)->plane[ 2 ] )
+ else if( ((const metaTriangle_t*) a)->plane[ 2 ] < ((const metaTriangle_t*) b)->plane[ 2 ] )
return 1;
- else if( ((metaTriangle_t*) a)->plane[ 2 ] > ((metaTriangle_t*) b)->plane[ 2 ] )
+ else if( ((const metaTriangle_t*) a)->plane[ 2 ] > ((const metaTriangle_t*) b)->plane[ 2 ] )
return -1;
}
#endif
VectorSet( bMins, 999999, 999999, 999999 );
for( i = 0; i < 3; i++ )
{
- av = ((metaTriangle_t*) a)->indexes[ i ];
- bv = ((metaTriangle_t*) b)->indexes[ i ];
+ av = ((const metaTriangle_t*) a)->indexes[ i ];
+ bv = ((const metaTriangle_t*) b)->indexes[ i ];
for( j = 0; j < 3; j++ )
{
if( metaVerts[ av ].xyz[ j ] < aMins[ j ] )
vec3_t origin;
vec3_t dir;
- edgePoint_t chain; // unused element of doubly linked list
+ edgePoint_t *chain; // unused element of doubly linked list
} edgeLine_t;
typedef struct {
bspDrawVert_t *dv[2];
} originalEdge_t;
-#define MAX_ORIGINAL_EDGES 0x20000
-originalEdge_t originalEdges[MAX_ORIGINAL_EDGES];
+originalEdge_t *originalEdges = NULL;
int numOriginalEdges;
+int allocatedOriginalEdges = 0;
-#define MAX_EDGE_LINES 0x10000
-edgeLine_t edgeLines[MAX_EDGE_LINES];
+edgeLine_t *edgeLines = NULL;
int numEdgeLines;
+int allocatedEdgeLines = 0;
int c_degenerateEdges;
int c_addedVerts;
p->intercept = d;
VectorCopy( v, p->xyz );
- if ( e->chain.next == &e->chain ) {
- e->chain.next = e->chain.prev = p;
- p->next = p->prev = &e->chain;
+ if ( e->chain->next == e->chain ) {
+ e->chain->next = e->chain->prev = p;
+ p->next = p->prev = e->chain;
return;
}
- scan = e->chain.next;
- for ( ; scan != &e->chain ; scan = scan->next ) {
+ scan = e->chain->next;
+ for ( ; scan != e->chain ; scan = scan->next ) {
d = p->intercept - scan->intercept;
if ( d > -LINE_POSITION_EPSILON && d < LINE_POSITION_EPSILON ) {
free( p );
if ( !createNonAxial ) {
if ( fabs( dir[0] + dir[1] + dir[2] ) != 1.0 ) {
- if ( numOriginalEdges == MAX_ORIGINAL_EDGES ) {
- Error( "MAX_ORIGINAL_EDGES" );
- }
+ AUTOEXPAND_BY_REALLOC(originalEdges, numOriginalEdges, allocatedOriginalEdges, 1024);
originalEdges[ numOriginalEdges ].dv[0] = (bspDrawVert_t *)v1;
originalEdges[ numOriginalEdges ].dv[1] = (bspDrawVert_t *)v2;
originalEdges[ numOriginalEdges ].length = d;
}
// create a new edge
- if ( numEdgeLines >= MAX_EDGE_LINES ) {
- Error( "MAX_EDGE_LINES" );
- }
+ AUTOEXPAND_BY_REALLOC(edgeLines, numEdgeLines, allocatedEdgeLines, 1024);
e = &edgeLines[ numEdgeLines ];
numEdgeLines++;
- e->chain.next = e->chain.prev = &e->chain;
+ e->chain = safe_malloc( sizeof(edgePoint_t) );
+ e->chain->next = e->chain->prev = e->chain;
VectorCopy( v1, e->origin );
VectorCopy( dir, e->dir );
if ( start < end ) {
- p = e->chain.next;
+ p = e->chain->next;
} else {
- p = e->chain.prev;
+ p = e->chain->prev;
}
- for ( ; p != &e->chain ; ) {
+ for ( ; p != e->chain ; ) {
if ( start < end ) {
if ( p->intercept > end - ON_EPSILON ) {
break;
qboolean FixBrokenSurface( mapDrawSurface_t *ds )
{
- qboolean valid = qtrue;
bspDrawVert_t *dv1, *dv2, avg;
int i, j, k;
float dist;
/* check all verts */
for( i = 0; i < ds->numVerts; i++ )
{
- /* don't remove points if winding is a triangle */
- if( ds->numVerts == 3 )
- return valid;
-
/* get verts */
dv1 = &ds->verts[ i ];
dv2 = &ds->verts[ (i + 1) % ds->numVerts ];
dist = VectorLength( avg.xyz );
if( dist < DEGENERATE_EPSILON )
{
- valid = qfalse;
Sys_FPrintf( SYS_VRB, "WARNING: Degenerate T-junction edge found, fixing...\n" );
/* create an average drawvert */
memcpy( dv2, dv1, sizeof( bspDrawVert_t ) );
}
ds->numVerts--;
+
+ /* after welding, we have to consider the same vertex again, as it now has a new neighbor dv2 */
+ --i;
+
+ /* should ds->numVerts have become 0, then i is now -1. In the next iteration, the loop will abort. */
}
}
/* one last check and return */
- if( ds->numVerts < 3 )
- valid = qfalse;
- return valid;
+ return ds->numVerts >= 3;
}
int EdgeCompare( const void *elem1, const void *elem2 ) {
float d1, d2;
- d1 = ((originalEdge_t *)elem1)->length;
- d2 = ((originalEdge_t *)elem2)->length;
+ d1 = ((const originalEdge_t *)elem1)->length;
+ d2 = ((const originalEdge_t *)elem2)->length;
if ( d1 < d2 ) {
return -1;
shaderInfo_t *si;
int axialEdgeLines;
originalEdge_t *e;
-
+ bspDrawVert_t *dv;
/* meta mode has its own t-junction code (currently not as good as this code) */
//% if( meta )
// this gives the most accurate edge description
for ( i = 0 ; i < numOriginalEdges ; i++ ) {
e = &originalEdges[i];
- e->dv[ 0 ]->lightmap[ 0 ][ 0 ] = AddEdge( e->dv[ 0 ]->xyz, e->dv[ 1 ]->xyz, qtrue );
+ dv = e->dv[0]; // e might change during AddEdge
+ dv->lightmap[ 0 ][ 0 ] = AddEdge( e->dv[ 0 ]->xyz, e->dv[ 1 ]->xyz, qtrue );
}
Sys_FPrintf( SYS_VRB, "%9d axial edge lines\n", axialEdgeLines );
*/
int PComp (const void *a, const void *b)
{
- if ( (*(vportal_t **)a)->nummightsee == (*(vportal_t **)b)->nummightsee)
+ if ( (*(const vportal_t *const *)a)->nummightsee == (*(const vportal_t *const *)b)->nummightsee)
return 0;
- if ( (*(vportal_t **)a)->nummightsee < (*(vportal_t **)b)->nummightsee)
+ if ( (*(const vportal_t *const *)a)->nummightsee < (*(const vportal_t *const *)b)->nummightsee)
return -1;
return 1;
}
Merges the portal visibility for a leaf
===============
*/
+static int clustersizehistogram[MAX_MAP_LEAFS] = {0};
void ClusterMerge (int leafnum)
{
leaf_t *leaf;
numvis++; // count the leaf itself
- totalvis += numvis;
-
- Sys_FPrintf (SYS_VRB,"cluster %4i : %4i visible\n", leafnum, numvis);
+ //Sys_FPrintf (SYS_VRB,"cluster %4i : %4i visible\n", leafnum, numvis);
+ ++clustersizehistogram[numvis];
memcpy (bspVisBytes + VIS_HEADER_SIZE + leafnum*leafbytes, uncompressed, leafbytes);
}
*/
void CalcVis (void)
{
- int i;
+ int i, minvis, maxvis;
const char *value;
+ double mu, sigma, totalvis, totalvis2;
/* ydnar: rr2do2's farplane code */
Sys_Printf("creating leaf vis...\n");
for (i=0 ; i<portalclusters ; i++)
ClusterMerge (i);
-
- Sys_Printf( "Total visible clusters: %i\n", totalvis );
- Sys_Printf( "Average clusters visible: %i\n", totalvis / portalclusters );
+
+ totalvis = 0;
+ totalvis2 = 0;
+ minvis = -1;
+ maxvis = -1;
+ for(i = 0; i < MAX_MAP_LEAFS; ++i)
+ if(clustersizehistogram[i])
+ {
+ if(debugCluster)
+ Sys_FPrintf(SYS_VRB, "%4i clusters have exactly %4i visible clusters\n", clustersizehistogram[i], i);
+ /* cast is to prevent integer overflow */
+ totalvis += ((double) i) * ((double) clustersizehistogram[i]);
+ totalvis2 += ((double) i) * ((double) i) * ((double) clustersizehistogram[i]);
+
+ if(minvis < 0)
+ minvis = i;
+ maxvis = i;
+ }
+
+ mu = totalvis / portalclusters;
+ sigma = sqrt(totalvis2 / portalclusters - mu * mu);
+
+ Sys_Printf( "Total clusters: %i\n", portalclusters );
+ Sys_Printf( "Total visible clusters: %.0f\n", totalvis );
+ Sys_Printf( "Average clusters visible: %.2f (%.3f%%/total)\n", mu, mu / portalclusters * 100.0);
+ Sys_Printf( " Standard deviation: %.2f (%.3f%%/total, %.3f%%/avg)\n", sigma, sigma / portalclusters * 100.0, sigma / mu * 100.0);
+ Sys_Printf( " Minimum: %i (%.3f%%/total, %.3f%%/avg)\n", minvis, minvis / (double) portalclusters * 100.0, minvis / mu * 100.0);
+ Sys_Printf( " Maximum: %i (%.3f%%/total, %.3f%%/avg)\n", maxvis, maxvis / (double) portalclusters * 100.0, maxvis / mu * 100.0);
}
/*
Sys_Printf ("%6i portalclusters\n", portalclusters);
Sys_Printf ("%6i numportals\n", numportals);
Sys_Printf ("%6i numfaces\n", numfaces);
+
+ if(numportals > MAX_PORTALS)
+ Error("MAX_PORTALS");
// these counts should take advantage of 64 bit systems automatically
leafbytes = ((portalclusters+63)&~63)>>3;
Error ("LoadPortals: reading portal %i", i);
if (numpoints > MAX_POINTS_ON_WINDING)
Error ("LoadPortals: portal %i has too many points", i);
- if ( (unsigned)leafnums[0] > portalclusters
- || (unsigned)leafnums[1] > portalclusters)
+ if (leafnums[0] > portalclusters
+ || leafnums[1] > portalclusters)
Error ("LoadPortals: reading portal %i", i);
if (fscanf (f, "%i ", &hint) != 1)
Error ("LoadPortals: reading hint state");
for (k=0 ; k<3 ; k++)
w->points[j][k] = v[k];
}
- fscanf (f, "\n");
+ if(fscanf (f, "\n") != 0)
+ {
+ // silence gcc warning
+ }
// calc plane
PlaneFromWinding (w, &plane);
for (k=0 ; k<3 ; k++)
w->points[j][k] = v[k];
}
- fscanf (f, "\n");
+ if(fscanf (f, "\n") != 0)
+ {
+ // silence gcc warning
+ }
// calc plane
PlaneFromWinding (w, &plane);
} else if (!strcmp(argv[i], "-merge")) {
Sys_Printf ("merge = true\n");
mergevis = qtrue;
+ } else if (!strcmp(argv[i], "-mergeportals")) {
+ Sys_Printf ("mergeportals = true\n");
+ mergevisportals = qtrue;
} else if (!strcmp(argv[i], "-nopassage")) {
Sys_Printf ("nopassage = true\n");
noPassageVis = qtrue;
} else if (!strcmp (argv[i],"-saveprt")) {
Sys_Printf ("saveprt = true\n");
saveprt = qtrue;
+ } else if( !strcmp( argv[ i ], "-v" ) ) {
+ debugCluster = qtrue;
+ Sys_Printf( "Extra verbous mode enabled\n" );
} else if (!strcmp (argv[i],"-tmpin")) {
strcpy (inbase, "/tmp");
} else if (!strcmp (argv[i],"-tmpout")) {
}
else
+ {
Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] );
+ }
}
if( i != argc - 1 )
/* ydnar: for getting far plane */
ParseEntities();
+ /* inject command line parameters */
+ InjectCommandLine(argv, 0, argc - 1);
+ UnparseEntities();
+
if( mergevis )
- {
MergeLeaves();
+
+ if( mergevis || mergevisportals )
MergeLeafPortals();
- }
CountActivePortals();
/* WritePortals( "maps/hints.prs" );*/
if( !Q_stricmp( shader, bspShaders[ i ].shader ) )
return i;
}
+
+ // i == numBSPShaders
/* get shaderinfo */
si = ShaderInfoForShader( shader );
/* emit a new shader */
- if( i == MAX_MAP_SHADERS )
- Error( "MAX_MAP_SHADERS" );
+ AUTOEXPAND_BY_REALLOC_BSP(Shaders, 1024);
+
numBSPShaders++;
strcpy( bspShaders[ i ].shader, shader );
bspShaders[ i ].surfaceFlags = si->surfaceFlags;
mp = mapplanes;
for( i = 0; i < nummapplanes; i++, mp++ )
{
+ AUTOEXPAND_BY_REALLOC_BSP(Planes, 1024);
bp = &bspPlanes[ numBSPPlanes ];
VectorCopy( mp->normal, bp->normal );
bp->dist = mp->dist;
//% if( b->guard != 0xDEADBEEF )
//% Sys_Printf( "Brush %6d: 0x%08X Guard: 0x%08X Next: 0x%08X Original: 0x%08X Sides: %d\n", b->brushNum, b, b, b->next, b->original, b->numsides );
- if( numBSPLeafBrushes >= MAX_MAP_LEAFBRUSHES )
- Error( "MAX_MAP_LEAFBRUSHES" );
+ AUTOEXPAND_BY_REALLOC_BSP(LeafBrushes, 1024);
bspLeafBrushes[ numBSPLeafBrushes ] = b->original->outputNum;
numBSPLeafBrushes++;
}
leaf_p->firstBSPLeafSurface = numBSPLeafSurfaces;
for ( dsr = node->drawSurfReferences; dsr; dsr = dsr->nextRef )
{
- if( numBSPLeafSurfaces >= MAX_MAP_LEAFFACES )
- Error( "MAX_MAP_LEAFFACES" );
+ AUTOEXPAND_BY_REALLOC_BSP(LeafSurfaces, 1024);
bspLeafSurfaces[ numBSPLeafSurfaces ] = dsr->outputNum;
numBSPLeafSurfaces++;
}
int EmitDrawNode_r( node_t *node )
{
bspNode_t *n;
- int i;
+ int i, n0;
/* check for leafnode */
}
/* emit a node */
- if( numBSPNodes == MAX_MAP_NODES )
- Error( "MAX_MAP_NODES" );
- n = &bspNodes[ numBSPNodes ];
+ AUTOEXPAND_BY_REALLOC_BSP(Nodes, 1024);
+ n0 = numBSPNodes;
+ n = &bspNodes[ n0 ];
numBSPNodes++;
VectorCopy (node->mins, n->mins);
{
n->children[i] = numBSPNodes;
EmitDrawNode_r (node->children[i]);
+ // n may have become invalid here, so...
+ n = &bspNodes[ n0 ];
}
}
void SetLightStyles( void )
{
int i, j, style, numStyles;
- qboolean keepLights;
const char *t;
entity_t *e;
epair_t *ep, *next;
char value[ 10 ];
char lightTargets[ MAX_SWITCHED_LIGHTS ][ 64 ];
int lightStyles[ MAX_SWITCHED_LIGHTS ];
-
-
+
/* ydnar: determine if we keep lights in the bsp */
- t = ValueForKey( &entities[ 0 ], "_keepLights" );
- keepLights = (t[ 0 ] == '1') ? qtrue : qfalse;
+ if (KeyExists(&entities[ 0 ], "_keepLights") == qtrue)
+ {
+ t = ValueForKey( &entities[ 0 ], "_keepLights" );
+ keepLights = (t[ 0 ] == '1') ? qtrue : qfalse;
+ }
/* any light that is controlled (has a targetname) must have a unique style number generated for it */
numStyles = 0;
finishes a new bsp and writes to disk
*/
-void EndBSPFile( void )
+void EndBSPFile(qboolean do_write)
{
char path[ 1024 ];
numBSPEntities = numEntities;
UnparseEntities();
- /* write the surface extra file */
- WriteSurfaceExtraFile( source );
-
- /* write the bsp */
- sprintf( path, "%s.bsp", source );
- Sys_Printf( "Writing %s\n", path );
- WriteBSPFile( path );
+ if(do_write)
+ {
+ /* write the surface extra file */
+ WriteSurfaceExtraFile( source );
+
+ /* write the bsp */
+ sprintf( path, "%s.bsp", source );
+ Sys_Printf( "Writing %s\n", path );
+ WriteBSPFile( path );
+ }
}
for( b = brushes; b != NULL; b = b->next )
{
/* check limits */
- if( numBSPBrushes == MAX_MAP_BRUSHES )
- Error( "MAX_MAP_BRUSHES (%d)", numBSPBrushes );
+ AUTOEXPAND_BY_REALLOC_BSP(Brushes, 1024);
/* get bsp brush */
b->outputNum = numBSPBrushes;
b->sides[ j ].outputNum = -1;
/* check count */
- if( numBSPBrushSides == MAX_MAP_BRUSHSIDES )
- Error( "MAX_MAP_BRUSHSIDES ");
+ AUTOEXPAND_BY_REALLOC_BSP(BrushSides, 1024);
/* emit side */
b->sides[ j ].outputNum = numBSPBrushSides;
/* test limits */
- if( numBSPModels == MAX_MAP_MODELS )
- Error( "MAX_MAP_MODELS" );
+ AUTOEXPAND_BY_REALLOC_BSP(Models, 256);
/* get model and entity */
mod = &bspModels[ numBSPModels ];