@ -4,9 +4,12 @@
# include "ps1bsp.h"
# include "ps1bsp.h"
# include "lighting.h"
# include "lighting.h"
# include "texture.h"
# include "texture.h"
# include "gpc.h"
static char path [ _MAX_PATH ] ;
static char path [ _MAX_PATH ] ;
void gpc_test ( const world_t * world , const face_t * face ) ;
template < class TData > size_t writeMapData ( const std : : vector < TData > & data , ps1bsp_dentry_t & dentry , FILE * f )
template < class TData > size_t writeMapData ( const std : : vector < TData > & data , ps1bsp_dentry_t & dentry , FILE * f )
{
{
dentry . offset = ( unsigned int ) ftell ( f ) ;
dentry . offset = ( unsigned int ) ftell ( f ) ;
@ -204,6 +207,8 @@ int process_faces(const world_t* world, const std::vector<ps1bsp_texture_t>& tex
float area = computeFaceArea ( world , face ) ;
float area = computeFaceArea ( world , face ) ;
outFace . center . pad = ( short ) ( sqrt ( area ) ) ;
outFace . center . pad = ( short ) ( sqrt ( area ) ) ;
outFaces . push_back ( outFace ) ;
outFaces . push_back ( outFace ) ;
gpc_test ( world , face ) ;
}
}
// Iterate over all faces again; now that we know the bounds of each face, we can calculate lighting for all of them
// Iterate over all faces again; now that we know the bounds of each face, we can calculate lighting for all of them
@ -218,7 +223,7 @@ int process_faces(const world_t* world, const std::vector<ps1bsp_texture_t>& tex
ps1bsp_facevertex_t & faceVertex = outFaceVertices [ outFace . firstFaceVertex + faceVertIdx ] ;
ps1bsp_facevertex_t & faceVertex = outFaceVertices [ outFace . firstFaceVertex + faceVertIdx ] ;
const vertex_t * vertex = & world - > vertices [ faceVertex . index ] ;
const vertex_t * vertex = & world - > vertices [ faceVertex . index ] ;
faceVertex . light = compute_faceVertex_light5 ( world , face , faceBounds , vertex - > toVec ( ) ) ;
faceVertex . light = compute_faceVertex_light5 ( world , face , faceBounds , vertex - > toVec ( ) ) ;
faceVertex . light = ( short ) ( ( float ) faceVertex . light * 1.5f ) ;
faceVertex . light = ( short ) ( ( float ) faceVertex . light * 1.5f ) ; // Compromise between overbright and non-overbright lighting. Looks good in practice.
if ( faceVertex . light > 255 )
if ( faceVertex . light > 255 )
faceVertex . light = 255 ;
faceVertex . light = 255 ;
}
}
@ -298,6 +303,101 @@ int process_faces(const world_t* world, const std::vector<ps1bsp_texture_t>& tex
return 1 ;
return 1 ;
}
}
void gpc_test ( const world_t * world , const face_t * face )
{
const texinfo_t * texinfo = & world - > texInfos [ face - > texinfo_id ] ;
const miptex_t * miptex = & world - > miptexes [ texinfo - > texture_id ] ;
const plane_t * plane = & world - > planes [ face - > plane_id ] ;
double minS = DBL_MAX , minT = DBL_MAX ;
double maxS = DBL_MIN , maxT = DBL_MIN ;
gpc_polygon polygon = { 0 } ;
gpc_vertex_list contour ;
contour . num_vertices = face - > ledge_num ;
contour . vertex = ( gpc_vertex * ) malloc ( contour . num_vertices * sizeof ( gpc_vertex ) ) ;
if ( contour . vertex = = NULL )
return ;
std : : vector < Vec3 > originalVecs ;
for ( int edgeListIdx = 0 ; edgeListIdx < face - > ledge_num ; + + edgeListIdx )
{
int edgeIdx = world - > edgeList [ face - > ledge_id + edgeListIdx ] ;
unsigned short vertIndex = edgeIdx > 0 ?
world - > edges [ edgeIdx ] . vertex0 :
world - > edges [ - edgeIdx ] . vertex1 ;
const vertex_t * vertex = & world - > vertices [ vertIndex ] ;
Vec3 vertexPoint = vertex - > toVec ( ) ;
originalVecs . push_back ( vertexPoint ) ;
// Calculate texture UV bounds
double s = ( vertexPoint . dotProduct ( texinfo - > vectorS ) + texinfo - > distS ) / miptex - > width ;
double t = ( vertexPoint . dotProduct ( texinfo - > vectorT ) + texinfo - > distT ) / miptex - > height ;
if ( s > maxS ) maxS = s ; if ( s < minS ) minS = s ;
if ( t > maxT ) maxT = t ; if ( t < minT ) minT = t ;
contour . vertex [ edgeListIdx ] = gpc_vertex { s , t } ;
}
gpc_add_contour ( & polygon , & contour , 0 ) ;
std : : vector < Vec3 > vertices ;
std : : unordered_map < Vec3 , size_t > vertexIndices ;
// Create a virtual grid at the texture bounds and iterate over each cell to break up the face into repeating tiles
for ( double y = floor ( minT ) ; y < = ceil ( maxT ) ; y + = 1.0 )
{
for ( double x = floor ( minS ) ; x < = ceil ( maxS ) ; x + = 1.0 )
{
// Create a square polygon that covers the entire cell
gpc_polygon cell = { 0 } ;
gpc_vertex_list cell_bounds ;
cell_bounds . num_vertices = 4 ;
cell_bounds . vertex = ( gpc_vertex * ) malloc ( 4 * sizeof ( gpc_vertex ) ) ;
cell_bounds . vertex [ 0 ] = gpc_vertex { x , y } ;
cell_bounds . vertex [ 1 ] = gpc_vertex { x + 1.0 , y } ;
cell_bounds . vertex [ 2 ] = gpc_vertex { x + 1.0 , y + 1.0 } ;
cell_bounds . vertex [ 3 ] = gpc_vertex { x , y + 1.0 } ;
gpc_add_contour ( & cell , & cell_bounds , 0 ) ;
// Take the intersection to get the chunk of the face that's inside this cell
gpc_polygon result ;
gpc_polygon_clip ( GPC_INT , & polygon , & cell , & result ) ;
// We should get a polygon with exactly one contour as a result; if not, the face was not on this grid cell
if ( result . num_contours < = 0 )
continue ;
// Reconstruct the polygon's vertices in world space
for ( int v = 0 ; v < result . contour [ 0 ] . num_vertices ; + + v )
{
const auto vert = & result . contour [ 0 ] . vertex [ v ] ;
Vec3 newVert =
plane - > normal * plane - > dist +
texinfo - > vectorS * ( float ) ( vert - > x * miptex - > width - texinfo - > distS ) +
texinfo - > vectorT * ( float ) ( vert - > y * miptex - > height - texinfo - > distT ) ;
// Make sure we don't store duplicate vertices
auto vertIter = vertexIndices . find ( newVert ) ;
if ( vertIter = = vertexIndices . end ( ) )
{
vertexIndices [ newVert ] = vertices . size ( ) ;
vertices . push_back ( newVert ) ;
}
// Store the relevant (S, T) coordinates for each vertex-texinfo pair
}
gpc_free_polygon ( & result ) ;
gpc_free_polygon ( & cell ) ;
}
}
gpc_free_polygon ( & polygon ) ;
}
int process_bsp ( const world_t * world )
int process_bsp ( const world_t * world )
{
{
// Test exporting texture data
// Test exporting texture data