aboutsummaryrefslogtreecommitdiffstats
path: root/q3map/patch.c
diff options
context:
space:
mode:
Diffstat (limited to 'q3map/patch.c')
-rwxr-xr-xq3map/patch.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/q3map/patch.c b/q3map/patch.c
new file mode 100755
index 0000000..5dbd354
--- /dev/null
+++ b/q3map/patch.c
@@ -0,0 +1,286 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+#include "qbsp.h"
+
+
+void PrintCtrl( vec3_t ctrl[9] ) {
+ int i, j;
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ for ( j = 0 ; j < 3 ; j++ ) {
+ _printf("(%5.2f %5.2f %5.2f) ", ctrl[i*3+j][0], ctrl[i*3+j][1], ctrl[i*3+j][2] );
+ }
+ _printf("\n");
+ }
+}
+
+/*
+================
+DrawSurfaceForMesh
+================
+*/
+mapDrawSurface_t *DrawSurfaceForMesh( mesh_t *m ) {
+ mapDrawSurface_t *ds;
+ int i, j;
+ mesh_t *copy;
+
+ // to make valid normals for patches with degenerate edges,
+ // we need to make a copy of the mesh and put the aproximating
+ // points onto the curve
+ copy = CopyMesh( m );
+ PutMeshOnCurve( *copy );
+ MakeMeshNormals( *copy );
+ for ( j = 0 ; j < m->width ; j++ ) {
+ for ( i = 0 ; i < m->height ; i++ ) {
+ VectorCopy( copy->verts[i*m->width+j].normal, m->verts[i*m->width+j].normal );
+ }
+ }
+ FreeMesh( copy );
+
+ ds = AllocDrawSurf();
+ ds->mapBrush = NULL;
+ ds->side = NULL;
+
+ ds->patch = qtrue;
+ ds->patchWidth = m->width;
+ ds->patchHeight = m->height;
+ ds->numVerts = ds->patchWidth * ds->patchHeight;
+ ds->verts = malloc( ds->numVerts * sizeof( *ds->verts ) );
+ memcpy( ds->verts, m->verts, ds->numVerts * sizeof( *ds->verts ) );
+
+ ds->lightmapNum = -1;
+ ds->fogNum = -1;
+
+ return ds;
+}
+
+/*
+=================
+ParsePatch
+
+Creates a mapDrawSurface_t from the patch text
+=================
+*/
+void ParsePatch( void ) {
+ vec_t info[5];
+ int i, j;
+ parseMesh_t *pm;
+ char texture[MAX_QPATH];
+ char shader[MAX_QPATH];
+ mesh_t m;
+ drawVert_t *verts;
+ epair_t *ep;
+
+ MatchToken( "{" );
+
+ // get texture
+ GetToken (qtrue);
+ strcpy( texture, token );
+
+ // save the shader name for retexturing
+ if ( numMapIndexedShaders == MAX_MAP_BRUSHSIDES ) {
+ Error( "MAX_MAP_BRUSHSIDES" );
+ }
+ strcpy( mapIndexedShaders[numMapIndexedShaders], texture );
+ numMapIndexedShaders++;
+
+
+ Parse1DMatrix( 5, info );
+ m.width = info[0];
+ m.height = info[1];
+ m.verts = verts = malloc( m.width * m.height * sizeof( m.verts[0] ) );
+
+ if ( m.width < 0 || m.width > MAX_PATCH_SIZE
+ || m.height < 0 || m.height > MAX_PATCH_SIZE ) {
+ Error("ParsePatch: bad size");
+ }
+
+ MatchToken( "(" );
+ for ( j = 0 ; j < m.width ; j++ ) {
+ MatchToken( "(" );
+ for ( i = 0 ; i < m.height ; i++ ) {
+ Parse1DMatrix( 5, verts[i*m.width+j].xyz );
+ }
+ MatchToken( ")" );
+ }
+ MatchToken( ")" );
+
+ // if brush primitives format, we may have some epairs to ignore here
+ GetToken(qtrue);
+ if (g_bBrushPrimit!=BPRIMIT_OLDBRUSHES && strcmp(token,"}"))
+ {
+ // NOTE: we leak that!
+ ep = ParseEpair();
+ }
+ else
+ UnGetToken();
+
+ MatchToken( "}" );
+ MatchToken( "}" );
+
+ if ( noCurveBrushes ) {
+ return;
+ }
+
+ // find default flags and values
+ pm = malloc( sizeof( *pm ) );
+ memset( pm, 0, sizeof( *pm ) );
+
+ sprintf( shader, "textures/%s", texture );
+ pm->shaderInfo = ShaderInfoForShader( shader );
+ pm->mesh = m;
+
+ // link to the entity
+ pm->next = mapent->patches;
+ mapent->patches = pm;
+}
+
+
+void GrowGroup_r( int patchNum, int patchCount, const byte *bordering, byte *group ) {
+ int i;
+ const byte *row;
+
+ if ( group[patchNum] ) {
+ return;
+ }
+ group[patchNum] = 1;
+ row = bordering + patchNum * patchCount;
+ for ( i = 0 ; i < patchCount ; i++ ) {
+ if ( row[i] ) {
+ GrowGroup_r( i, patchCount, bordering, group );
+ }
+ }
+}
+
+
+/*
+=====================
+PatchMapDrawSurfs
+
+Any patches that share an edge need to choose their
+level of detail as a unit, otherwise the edges would
+pull apart.
+=====================
+*/
+void PatchMapDrawSurfs( entity_t *e ) {
+ parseMesh_t *pm;
+ parseMesh_t *check, *scan;
+ mapDrawSurface_t *ds;
+ int patchCount, groupCount;
+ int i, j, k, l, c1, c2;
+ drawVert_t *v1, *v2;
+ vec3_t bounds[2];
+ byte *bordering;
+ parseMesh_t *meshes[MAX_MAP_DRAW_SURFS];
+ qboolean grouped[MAX_MAP_DRAW_SURFS];
+ byte group[MAX_MAP_DRAW_SURFS];
+
+ qprintf( "----- PatchMapDrawSurfs -----\n" );
+
+ patchCount = 0;
+ for ( pm = e->patches ; pm ; pm = pm->next ) {
+ meshes[patchCount] = pm;
+ patchCount++;
+ }
+
+ if ( !patchCount ) {
+ return;
+ }
+ bordering = malloc( patchCount * patchCount );
+ memset( bordering, 0, patchCount * patchCount );
+
+ // build the bordering matrix
+ for ( k = 0 ; k < patchCount ; k++ ) {
+ bordering[k*patchCount+k] = 1;
+
+ for ( l = k+1 ; l < patchCount ; l++ ) {
+ check = meshes[k];
+ scan = meshes[l];
+ c1 = scan->mesh.width * scan->mesh.height;
+ v1 = scan->mesh.verts;
+
+ for ( i = 0 ; i < c1 ; i++, v1++ ) {
+ c2 = check->mesh.width * check->mesh.height;
+ v2 = check->mesh.verts;
+ for ( j = 0 ; j < c2 ; j++, v2++ ) {
+ if ( fabs( v1->xyz[0] - v2->xyz[0] ) < 1.0
+ && fabs( v1->xyz[1] - v2->xyz[1] ) < 1.0
+ && fabs( v1->xyz[2] - v2->xyz[2] ) < 1.0 ) {
+ break;
+ }
+ }
+ if ( j != c2 ) {
+ break;
+ }
+ }
+ if ( i != c1 ) {
+ // we have a connection
+ bordering[k*patchCount+l] =
+ bordering[l*patchCount+k] = 1;
+ } else {
+ // no connection
+ bordering[k*patchCount+l] =
+ bordering[l*patchCount+k] = 0;
+ }
+
+ }
+ }
+
+ // build groups
+ memset( grouped, 0, sizeof(grouped) );
+ groupCount = 0;
+ for ( i = 0 ; i < patchCount ; i++ ) {
+ if ( !grouped[i] ) {
+ groupCount++;
+ }
+
+ // recursively find all patches that belong in the same group
+ memset( group, 0, patchCount );
+ GrowGroup_r( i, patchCount, bordering, group );
+
+ // bound them
+ ClearBounds( bounds[0], bounds[1] );
+ for ( j = 0 ; j < patchCount ; j++ ) {
+ if ( group[j] ) {
+ grouped[j] = qtrue;
+ scan = meshes[j];
+ c1 = scan->mesh.width * scan->mesh.height;
+ v1 = scan->mesh.verts;
+ for ( k = 0 ; k < c1 ; k++, v1++ ) {
+ AddPointToBounds( v1->xyz, bounds[0], bounds[1] );
+ }
+ }
+ }
+
+ // create drawsurf
+ scan = meshes[i];
+ scan->grouped = qtrue;
+ ds = DrawSurfaceForMesh( &scan->mesh );
+ ds->shaderInfo = scan->shaderInfo;
+ VectorCopy( bounds[0], ds->lightmapVecs[0] );
+ VectorCopy( bounds[1], ds->lightmapVecs[1] );
+ }
+
+ qprintf( "%5i patches\n", patchCount );
+ qprintf( "%5i patch LOD groups\n", groupCount );
+}
+