1 /* -------------------------------------------------------------------------------
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
6 This file is part of GtkRadiant.
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 ----------------------------------------------------------------------------------
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
27 ------------------------------------------------------------------------------- */
43 callback for picomodel.lib
46 void PicoPrintFunc( int level, const char *str ){
53 Sys_Printf( "%s\n", str );
57 Sys_FPrintf( SYS_VRB, "%s\n", str );
61 Sys_FPrintf( SYS_WRN, "WARNING: %s\n", str );
65 Sys_FPrintf( SYS_ERR, "ERROR: %s\n", str );
69 Error( "ERROR: %s\n", str );
78 callback for picomodel.lib
81 void PicoLoadFileFunc( const char *name, byte **buffer, int *bufSize ){
82 *bufSize = vfsLoadFile( name, (void**) buffer, 0 );
89 finds an existing picoModel and returns a pointer to the picoModel_t struct or NULL if not found
92 picoModel_t *FindModel( const char *name, int frame ){
97 if ( numPicoModels <= 0 ) {
98 memset( picoModels, 0, sizeof( picoModels ) );
102 if ( name == NULL || name[ 0 ] == '\0' ) {
107 for ( i = 0; i < MAX_MODELS; i++ )
109 if ( picoModels[ i ] != NULL &&
110 !strcmp( PicoGetModelName( picoModels[ i ] ), name ) &&
111 PicoGetModelFrameNum( picoModels[ i ] ) == frame ) {
112 return picoModels[ i ];
116 /* no matching picoModel found */
124 loads a picoModel and returns a pointer to the picoModel_t struct or NULL if not found
127 picoModel_t *LoadModel( const char *name, int frame ){
129 picoModel_t *model, **pm;
133 if ( numPicoModels <= 0 ) {
134 memset( picoModels, 0, sizeof( picoModels ) );
138 if ( name == NULL || name[ 0 ] == '\0' ) {
142 /* try to find existing picoModel */
143 model = FindModel( name, frame );
144 if ( model != NULL ) {
148 /* none found, so find first non-null picoModel */
150 for ( i = 0; i < MAX_MODELS; i++ )
152 if ( picoModels[ i ] == NULL ) {
153 pm = &picoModels[ i ];
158 /* too many picoModels? */
160 Error( "MAX_MODELS (%d) exceeded, there are too many model files referenced by the map.", MAX_MODELS );
163 /* attempt to parse model */
164 *pm = PicoLoadModel( name, frame );
166 /* if loading failed, make a bogus model to silence the rest of the warnings */
168 /* allocate a new model */
169 *pm = PicoNewModel();
175 PicoSetModelName( *pm, name );
176 PicoSetModelFrameNum( *pm, frame );
182 int numSurfaces, numVertexes;
186 Sys_Printf( "Model %s\n", name );
187 numSurfaces = PicoGetModelNumSurfaces( *pm );
188 for ( i = 0; i < numSurfaces; i++ )
190 ps = PicoGetModelSurface( *pm, i );
191 numVertexes = PicoGetSurfaceNumVertexes( ps );
192 Sys_Printf( "Surface %d has %d vertexes\n", i, numVertexes );
202 /* return the picoModel */
209 InsertModel() - ydnar
210 adds a picomodel into the bsp
213 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, float clipDepth ){
214 int i, j, s, k, numSurfaces;
215 m4x4_t identity, nTransform;
217 picoShader_t *shader;
218 picoSurface_t *surface;
220 mapDrawSurface_t *ds;
222 char *picoShaderName;
223 char shaderName[ MAX_QPATH ];
224 picoVec_t *xyz, *normal, *st;
226 picoIndex_t *indexes;
228 skinfile_t *sf, *sf2;
229 char skinfilename[ MAX_QPATH ];
230 char *skinfilecontent;
232 char *skinfileptr, *skinfilenextptr;
234 int spf = ( spawnFlags & 8088 );
238 if ( clipDepth < 0 ){
239 limDepth = -clipDepth;
245 model = LoadModel( name, frame );
246 if ( model == NULL ) {
251 snprintf( skinfilename, sizeof( skinfilename ), "%s_%d.skin", name, skin );
252 skinfilename[sizeof( skinfilename ) - 1] = 0;
253 skinfilesize = vfsLoadFile( skinfilename, (void**) &skinfilecontent, 0 );
254 if ( skinfilesize < 0 && skin != 0 ) {
255 /* fallback to skin 0 if invalid */
256 snprintf( skinfilename, sizeof( skinfilename ), "%s_0.skin", name );
257 skinfilename[sizeof( skinfilename ) - 1] = 0;
258 skinfilesize = vfsLoadFile( skinfilename, (void**) &skinfilecontent, 0 );
259 if ( skinfilesize >= 0 ) {
260 Sys_Printf( "Skin %d of %s does not exist, using 0 instead\n", skin, name );
264 if ( skinfilesize >= 0 ) {
265 Sys_Printf( "Using skin %d of %s\n", skin, name );
267 for ( skinfileptr = skinfilecontent; *skinfileptr; skinfileptr = skinfilenextptr )
272 skinfilenextptr = strchr( skinfileptr, '\r' );
273 if ( skinfilenextptr ) {
274 *skinfilenextptr++ = 0;
278 skinfilenextptr = strchr( skinfileptr, '\n' );
279 if ( skinfilenextptr ) {
280 *skinfilenextptr++ = 0;
283 skinfilenextptr = skinfileptr + strlen( skinfileptr );
287 /* create new item */
289 sf = safe_malloc( sizeof( *sf ) );
292 sprintf( format, "replace %%%ds %%%ds", (int)sizeof( sf->name ) - 1, (int)sizeof( sf->to ) - 1 );
293 if ( sscanf( skinfileptr, format, sf->name, sf->to ) == 2 ) {
296 sprintf( format, " %%%d[^, ] ,%%%ds", (int)sizeof( sf->name ) - 1, (int)sizeof( sf->to ) - 1 );
297 if ( ( pos = sscanf( skinfileptr, format, sf->name, sf->to ) ) == 2 ) {
301 /* invalid input line -> discard sf struct */
302 Sys_Printf( "Discarding skin directive in %s: %s\n", skinfilename, skinfileptr );
306 free( skinfilecontent );
309 /* handle null matrix */
310 if ( transform == NULL ) {
311 m4x4_identity( identity );
312 transform = identity;
315 /* hack: Stable-1_2 and trunk have differing row/column major matrix order
316 this transpose is necessary with Stable-1_2
317 uncomment the following line with old m4x4_t (non 1.3/spog_branch) code */
318 //% m4x4_transpose( transform );
320 /* create transform matrix for normals */
321 memcpy( nTransform, transform, sizeof( m4x4_t ) );
322 if ( m4x4_invert( nTransform ) ) {
323 Sys_FPrintf( SYS_VRB, "WARNING: Can't invert model transform matrix, using transpose instead\n" );
325 m4x4_transpose( nTransform );
327 /* fix bogus lightmap scale */
328 if ( lightmapScale <= 0.0f ) {
329 lightmapScale = 1.0f;
332 /* fix bogus shade angle */
333 if ( shadeAngle <= 0.0f ) {
337 /* each surface on the model will become a new map drawsurface */
338 numSurfaces = PicoGetModelNumSurfaces( model );
339 //% Sys_FPrintf( SYS_VRB, "Model %s has %d surfaces\n", name, numSurfaces );
340 for ( s = 0; s < numSurfaces; s++ )
343 surface = PicoGetModelSurface( model, s );
344 if ( surface == NULL ) {
348 /* only handle triangle surfaces initially (fixme: support patches) */
349 if ( PicoGetSurfaceType( surface ) != PICO_TRIANGLES ) {
353 /* get shader name */
354 shader = PicoGetSurfaceShader( surface );
355 if ( shader == NULL ) {
359 picoShaderName = PicoGetShaderName( shader );
362 /* handle .skin file */
364 picoShaderName = NULL;
365 for ( sf2 = sf; sf2 != NULL; sf2 = sf2->next )
367 if ( !Q_stricmp( surface->name, sf2->name ) ) {
368 Sys_FPrintf( SYS_VRB, "Skin file: mapping %s to %s\n", surface->name, sf2->to );
369 picoShaderName = sf2->to;
373 if ( !picoShaderName ) {
374 Sys_FPrintf( SYS_VRB, "Skin file: not mapping %s\n", surface->name );
379 /* handle shader remapping */
381 for ( rm = remap; rm != NULL; rm = rm->next )
383 if ( rm->from[ 0 ] == '*' && rm->from[ 1 ] == '\0' ) {
386 else if ( !Q_stricmp( picoShaderName, rm->from ) ) {
387 Sys_FPrintf( SYS_VRB, "Remapping %s to %s\n", picoShaderName, rm->to );
388 picoShaderName = rm->to;
394 if ( glob != NULL ) {
395 Sys_FPrintf( SYS_VRB, "Globbing %s to %s\n", picoShaderName, glob->to );
396 picoShaderName = glob->to;
399 /* shader renaming for sof2 */
400 if ( renameModelShaders ) {
401 strcpy( shaderName, picoShaderName );
402 StripExtension( shaderName );
403 if ( spawnFlags & 1 ) {
404 strcat( shaderName, "_RMG_BSP" );
407 strcat( shaderName, "_BSP" );
409 si = ShaderInfoForShader( shaderName );
412 si = ShaderInfoForShader( picoShaderName );
415 /* allocate a surface (ydnar: gs mods) */
416 ds = AllocDrawSurface( SURFACE_TRIANGLES );
417 ds->entityNum = eNum;
418 ds->castShadows = castShadows;
419 ds->recvShadows = recvShadows;
425 if ( ( si != NULL && si->forceMeta ) || ( spawnFlags & 4 ) ) { /* 3rd bit */
426 ds->type = SURFACE_FORCED_META;
429 /* fix the surface's normals (jal: conditioned by shader info) */
430 if ( !( spawnFlags & 64 ) && ( shadeAngle == 0.0f || ds->type != SURFACE_FORCED_META ) ) {
431 PicoFixSurfaceNormals( surface );
434 /* set sample size */
435 if ( lightmapSampleSize > 0.0f ) {
436 ds->sampleSize = lightmapSampleSize;
439 /* set lightmap scale */
440 if ( lightmapScale > 0.0f ) {
441 ds->lightmapScale = lightmapScale;
444 /* set shading angle */
445 if ( shadeAngle > 0.0f ) {
446 ds->shadeAngleDegrees = shadeAngle;
449 /* set particulars */
450 ds->numVerts = PicoGetSurfaceNumVertexes( surface );
451 ds->verts = safe_malloc0( ds->numVerts * sizeof( ds->verts[ 0 ] ) );
453 ds->numIndexes = PicoGetSurfaceNumIndexes( surface );
454 ds->indexes = safe_malloc0( ds->numIndexes * sizeof( ds->indexes[ 0 ] ) );
457 for ( i = 0; i < ds->numVerts; i++ )
460 dv = &ds->verts[ i ];
463 xyz = PicoGetSurfaceXYZ( surface, i );
464 VectorCopy( xyz, dv->xyz );
465 m4x4_transform_point( transform, dv->xyz );
467 normal = PicoGetSurfaceNormal( surface, i );
468 VectorCopy( normal, dv->normal );
469 m4x4_transform_normal( nTransform, dv->normal );
470 VectorNormalize( dv->normal, dv->normal );
472 /* ydnar: tek-fu celshading support for flat shaded shit */
474 dv->st[ 0 ] = si->stFlat[ 0 ];
475 dv->st[ 1 ] = si->stFlat[ 1 ];
478 /* ydnar: gs mods: added support for explicit shader texcoord generation */
479 else if ( si->tcGen ) {
480 /* project the texture */
481 dv->st[ 0 ] = DotProduct( si->vecs[ 0 ], dv->xyz );
482 dv->st[ 1 ] = DotProduct( si->vecs[ 1 ], dv->xyz );
485 /* normal texture coordinates */
488 st = PicoGetSurfaceST( surface, 0, i );
489 dv->st[ 0 ] = st[ 0 ];
490 dv->st[ 1 ] = st[ 1 ];
493 /* set lightmap/color bits */
494 color = PicoGetSurfaceColor( surface, 0, i );
495 for ( j = 0; j < MAX_LIGHTMAPS; j++ )
497 dv->lightmap[ j ][ 0 ] = 0.0f;
498 dv->lightmap[ j ][ 1 ] = 0.0f;
499 if ( spawnFlags & 32 ) { // spawnflag 32: model color -> alpha hack
500 dv->color[ j ][ 0 ] = 255.0f;
501 dv->color[ j ][ 1 ] = 255.0f;
502 dv->color[ j ][ 2 ] = 255.0f;
503 dv->color[ j ][ 3 ] = RGBTOGRAY( color );
507 dv->color[ j ][ 0 ] = color[ 0 ];
508 dv->color[ j ][ 1 ] = color[ 1 ];
509 dv->color[ j ][ 2 ] = color[ 2 ];
510 dv->color[ j ][ 3 ] = color[ 3 ];
516 indexes = PicoGetSurfaceIndexes( surface, 0 );
517 for ( i = 0; i < ds->numIndexes; i++ )
518 ds->indexes[ i ] = indexes[ i ];
521 ds->celShader = celShader;
523 /* ydnar: giant hack land: generate clipping brushes for model triangles */
524 if ( ( si->clipModel && !( spf ) ) || //default CLIPMODEL
525 ( ( spawnFlags & 8090 ) == 2 ) || //default CLIPMODEL
526 ( spf == 8 ) || //EXTRUDE_FACE_NORMALS
527 ( spf == 16 ) || //EXTRUDE_TERRAIN
528 ( spf == 128 ) || //EXTRUDE_VERTEX_NORMALS
529 ( spf == 256 ) || //PYRAMIDAL_CLIP
530 ( spf == 512 ) || //EXTRUDE_DOWNWARDS
531 ( spf == 1024 ) || //EXTRUDE_UPWARDS
532 ( spf == 4096 ) || //default CLIPMODEL + AXIAL_BACKPLANE
533 ( spf == 264 ) || //EXTRUDE_FACE_NORMALS+PYRAMIDAL_CLIP (extrude 45)
534 ( spf == 2064 ) || //EXTRUDE_TERRAIN+MAX_EXTRUDE
535 ( spf == 4112 ) || //EXTRUDE_TERRAIN+AXIAL_BACKPLANE
536 ( spf == 384 ) || //EXTRUDE_VERTEX_NORMALS + PYRAMIDAL_CLIP - vertex normals + don't check for sides, sticking outwards
537 ( spf == 4352 ) || //PYRAMIDAL_CLIP+AXIAL_BACKPLANE
538 ( spf == 1536 ) || //EXTRUDE_DOWNWARDS+EXTRUDE_UPWARDS
539 ( spf == 2560 ) || //EXTRUDE_DOWNWARDS+MAX_EXTRUDE
540 ( spf == 4608 ) || //EXTRUDE_DOWNWARDS+AXIAL_BACKPLANE
541 ( spf == 3584 ) || //EXTRUDE_DOWNWARDS+EXTRUDE_UPWARDS+MAX_EXTRUDE
542 ( spf == 5632 ) || //EXTRUDE_DOWNWARDS+EXTRUDE_UPWARDS+AXIAL_BACKPLANE
543 ( spf == 3072 ) || //EXTRUDE_UPWARDS+MAX_EXTRUDE
544 ( spf == 5120 ) ){ //EXTRUDE_UPWARDS+AXIAL_BACKPLANE
545 vec3_t points[ 4 ], cnt, bestNormal, nrm, Vnorm[3], Enorm[3];
546 vec4_t plane, reverse, p[3];
547 double normalEpsilon_save;
549 vec3_t min = { 999999, 999999, 999999 }, max = { -999999, -999999, -999999 };
550 vec3_t avgDirection = { 0, 0, 0 };
552 #define nonax_clip_dbg 0
555 if ( !si->clipModel && !( si->compileFlags & C_SOLID ) ) {
559 //wont snap these in normal way, or will explode
560 normalEpsilon_save = normalEpsilon;
561 //normalEpsilon = 0.000001;
564 //MAX_EXTRUDE or EXTRUDE_TERRAIN
565 if ( ( spawnFlags & 2048 ) || ( spawnFlags & 16 ) ){
567 for ( i = 0; i < ds->numIndexes; i += 3 )
569 for ( j = 0; j < 3; j++ )
571 dv = &ds->verts[ ds->indexes[ i + j ] ];
572 VectorCopy( dv->xyz, points[ j ] );
574 if ( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) ){
575 if ( spawnFlags & 16 ) VectorAdd( avgDirection, plane, avgDirection ); //calculate average mesh facing direction
578 for ( k = 2; k > -1; k-- ){
580 for ( j = 0; j < 3; j++ ){ if ( points[j][k] < min[k] ) min[k] = points[j][k]; }
582 else if ( plane[k] < 0 ){
583 for ( j = 0; j < 3; j++ ){ if ( points[j][k] > max[k] ) max[k] = points[j][k]; }
585 //if EXTRUDE_DOWNWARDS or EXTRUDE_UPWARDS
586 if ( ( spawnFlags & 512 ) || ( spawnFlags & 1024 ) ){
592 //unify avg direction
593 if ( spawnFlags & 16 ){
594 for ( j = 0; j < 3; j++ ){
595 if ( fabs(avgDirection[j]) > fabs(avgDirection[(j+1)%3]) ){
596 avgDirection[(j+1)%3] = 0.0;
600 avgDirection[j] = 0.0;
603 if ( VectorNormalize( avgDirection, avgDirection ) == 0 ){
605 VectorSet( avgDirection, 0, 0, 1 );
610 /* walk triangle list */
611 for ( i = 0; i < ds->numIndexes; i += 3 )
614 AUTOEXPAND_BY_REALLOC( mapplanes, ( nummapplanes + 64 ) << 1, allocatedmapplanes, 1024 );
617 for ( j = 0; j < 3; j++ )
620 dv = &ds->verts[ ds->indexes[ i + j ] ];
623 VectorCopy( dv->xyz, points[ j ] );
626 /* make plane for triangle */
627 if ( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) ) {
630 buildBrush = AllocBrush( 48 );
631 buildBrush->entityNum = mapEntityNum;
632 buildBrush->original = buildBrush;
633 buildBrush->contentShader = si;
634 buildBrush->compileFlags = si->compileFlags;
635 buildBrush->contentFlags = si->contentFlags;
636 buildBrush->detail = qtrue;
638 //snap points before using them for further calculations
639 //precision suffers a lot, when two of normal values are under .00025 (often no collision, knocking up effect in ioq3)
640 //also broken drawsurfs in case of normal brushes
642 for ( j=0; j<3; j++ )
644 if ( fabs(plane[j]) < 0.00025 && fabs(plane[(j+1)%3]) < 0.00025 && ( plane[j] != 0.0 || plane[(j+1)%3] != 0.0 ) ){
645 VectorAdd( points[ 0 ], points[ 1 ], cnt );
646 VectorAdd( cnt, points[ 2 ], cnt );
647 VectorScale( cnt, 0.3333333333333f, cnt );
648 points[0][(j+2)%3]=points[1][(j+2)%3]=points[2][(j+2)%3]=cnt[(j+2)%3];
654 //snap pairs of points to prevent bad side planes
655 for ( j=0; j<3; j++ )
657 VectorSubtract( points[j], points[(j+1)%3], nrm );
658 VectorNormalize( nrm, nrm );
659 for ( k=0; k<3; k++ )
661 if ( nrm[k] != 0.0 && fabs(nrm[k]) < 0.00025 ){
662 //Sys_Printf( "b4(%6.6f %6.6f %6.6f)(%6.6f %6.6f %6.6f)\n", points[j][0], points[j][1], points[j][2], points[(j+1)%3][0], points[(j+1)%3][1], points[(j+1)%3][2] );
663 points[j][k]=points[(j+1)%3][k] = ( points[j][k] + points[(j+1)%3][k] ) / 2.0;
664 //Sys_Printf( "sn(%6.6f %6.6f %6.6f)(%6.6f %6.6f %6.6f)\n", points[j][0], points[j][1], points[j][2], points[(j+1)%3][0], points[(j+1)%3][1], points[(j+1)%3][2] );
671 PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] );
675 //vector-is-close-to-be-on-axis check again, happens after previous code sometimes
676 for ( j=0; j<3; j++ )
678 if ( fabs(plane[j]) < 0.00025 && fabs(plane[(j+1)%3]) < 0.00025 && ( plane[j] != 0.0 || plane[(j+1)%3] != 0.0 ) ){
679 VectorAdd( points[ 0 ], points[ 1 ], cnt );
680 VectorAdd( cnt, points[ 2 ], cnt );
681 VectorScale( cnt, 0.3333333333333f, cnt );
682 points[0][(j+2)%3]=points[1][(j+2)%3]=points[2][(j+2)%3]=cnt[(j+2)%3];
683 PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] );
688 //snap single snappable normal components
689 for ( j=0; j<3; j++ )
691 if ( plane[j] != 0.0 && fabs(plane[j]) < 0.00005 ){
699 VectorAdd( points[ 0 ], points[ 1 ], cnt );
700 VectorAdd( cnt, points[ 2 ], cnt );
701 VectorScale( cnt, 0.3333333333333f, cnt );
702 VectorNormalize( plane, plane );
703 plane[3] = DotProduct( plane, cnt );
705 //project points to resulting plane to keep intersections precision
706 for ( j=0; j<3; j++ )
708 //Sys_Printf( "b4 %i (%6.7f %6.7f %6.7f)\n", j, points[j][0], points[j][1], points[j][2] );
709 VectorMA( points[j], plane[3] - DotProduct( plane, points[j]), plane, points[j] );
710 //Sys_Printf( "sn %i (%6.7f %6.7f %6.7f)\n", j, points[j][0], points[j][1], points[j][2] );
712 //Sys_Printf( "sn pln (%6.7f %6.7f %6.7f %6.7f)\n", plane[0], plane[1], plane[2], plane[3] );
713 //PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] );
714 //Sys_Printf( "pts pln (%6.7f %6.7f %6.7f %6.7f)\n", plane[0], plane[1], plane[2], plane[3] );
718 if ( spf == 4352 ){ //PYRAMIDAL_CLIP+AXIAL_BACKPLANE
720 for ( j=0; j<3; j++ )
722 if ( fabs(plane[j]) < 0.05 && fabs(plane[(j+1)%3]) < 0.05 ){ //no way, close to lay on two axises
723 goto default_CLIPMODEL;
728 VectorCopy( plane, bestNormal );
729 for ( j = 0; j < 3; j++ ){
730 if ( fabs(bestNormal[j]) > fabs(bestNormal[(j+1)%3]) ){
731 bestNormal[(j+1)%3] = 0.0;
738 VectorNormalize( bestNormal, bestNormal );
741 float bestdist, currdist, bestangle, currangle, mindist = 999999;
743 for ( j = 0; j < 3; j++ ){//planes
746 for ( k = 0; k < 3; k++ ){//axises
747 VectorSubtract( points[ (j+1)%3 ], points[ j ], nrm );
749 CrossProduct( bestNormal, nrm, reverse );
752 VectorClear( Vnorm[0] );
753 if ( (k+1)%3 == axis ){
754 if ( nrm[ (k+2)%3 ] == 0 ) continue;
755 Vnorm[0][ (k+2)%3 ] = nrm[ (k+2)%3 ];
758 if ( nrm[ (k+1)%3 ] == 0 ) continue;
759 Vnorm[0][ (k+1)%3 ] = nrm[ (k+1)%3 ];
761 CrossProduct( bestNormal, Vnorm[0], Enorm[0] );
762 CrossProduct( Enorm[0], nrm, reverse );
764 VectorNormalize( reverse, reverse );
765 reverse[3] = DotProduct( points[ j ], reverse );
766 //check facing, thickness
767 currdist = reverse[3] - DotProduct( reverse, points[ (j+2)%3 ] );
768 currangle = DotProduct( reverse, plane );
769 if ( ( ( currdist > 0.1 ) && ( currdist < bestdist ) && ( currangle < 0 ) ) ||
770 ( ( currangle >= 0 ) && ( currangle <= bestangle ) ) ){
771 bestangle = currangle;
772 if ( currangle < 0 ) bestdist = currdist;
773 VectorCopy( reverse, p[j] );
774 p[j][3] = reverse[3];
777 //if ( bestdist == 999999 && bestangle == 1 ) Sys_Printf("default_CLIPMODEL\n");
778 if ( bestdist == 999999 && bestangle == 1 ) goto default_CLIPMODEL;
779 if ( bestdist < mindist ) mindist = bestdist;
781 if ( (limDepth != 0.0) && (mindist > limDepth) ) goto default_CLIPMODEL;
785 for ( j = 0; j < 3; j++ )
787 for ( k = 0; k < 3; k++ )
789 if ( fabs(p[j][k]) < 0.00025 && p[j][k] != 0.0 ){
790 Sys_Printf( "nonax nrm %6.17f %6.17f %6.17f\n", p[j][0], p[j][1], p[j][2] );
795 /* set up brush sides */
796 buildBrush->numsides = 4;
797 buildBrush->sides[ 0 ].shaderInfo = si;
798 for ( j = 1; j < buildBrush->numsides; j++ ) {
800 buildBrush->sides[ 0 ].shaderInfo = ShaderInfoForShader( "debugclip2" );
801 buildBrush->sides[ j ].shaderInfo = ShaderInfoForShader( "debugclip" );
804 buildBrush->sides[ j ].shaderInfo = NULL; // don't emit these faces as draw surfaces, should make smaller BSPs; hope this works
807 VectorCopy( points[0], points[3] ); // for cyclic usage
809 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
810 buildBrush->sides[ 1 ].planenum = FindFloatPlane( p[0], p[0][ 3 ], 2, &points[ 0 ] ); // p[0] contains points[0] and points[1]
811 buildBrush->sides[ 2 ].planenum = FindFloatPlane( p[1], p[1][ 3 ], 2, &points[ 1 ] ); // p[1] contains points[1] and points[2]
812 buildBrush->sides[ 3 ].planenum = FindFloatPlane( p[2], p[2][ 3 ], 2, &points[ 2 ] ); // p[2] contains points[2] and points[0] (copied to points[3]
816 else if ( ( spf == 16 ) || //EXTRUDE_TERRAIN
817 ( spf == 512 ) || //EXTRUDE_DOWNWARDS
818 ( spf == 1024 ) || //EXTRUDE_UPWARDS
819 ( spf == 4096 ) || //default CLIPMODEL + AXIAL_BACKPLANE
820 ( spf == 2064 ) || //EXTRUDE_TERRAIN+MAX_EXTRUDE
821 ( spf == 4112 ) || //EXTRUDE_TERRAIN+AXIAL_BACKPLANE
822 ( spf == 1536 ) || //EXTRUDE_DOWNWARDS+EXTRUDE_UPWARDS
823 ( spf == 2560 ) || //EXTRUDE_DOWNWARDS+MAX_EXTRUDE
824 ( spf == 4608 ) || //EXTRUDE_DOWNWARDS+AXIAL_BACKPLANE
825 ( spf == 3584 ) || //EXTRUDE_DOWNWARDS+EXTRUDE_UPWARDS+MAX_EXTRUDE
826 ( spf == 5632 ) || //EXTRUDE_DOWNWARDS+EXTRUDE_UPWARDS+AXIAL_BACKPLANE
827 ( spf == 3072 ) || //EXTRUDE_UPWARDS+MAX_EXTRUDE
828 ( spf == 5120 ) ){ //EXTRUDE_UPWARDS+AXIAL_BACKPLANE
830 if ( spawnFlags & 16 ){ //autodirection
831 VectorCopy( avgDirection, bestNormal );
835 if ( ( spawnFlags & 1536 ) == 1536 ){ //up+down
836 VectorSet( bestNormal, 0, 0, ( plane[2] >= 0 ? 1 : -1 ) );
838 else if ( spawnFlags & 512 ){ //down
839 VectorSet( bestNormal, 0, 0, 1 );
842 else if ( spawnFlags & 1024 ){ //up
843 VectorSet( bestNormal, 0, 0, -1 );
845 else{ // best axial normal
846 VectorCopy( plane, bestNormal );
847 for ( j = 0; j < 3; j++ ){
848 if ( fabs(bestNormal[j]) > fabs(bestNormal[(j+1)%3]) ){
849 bestNormal[(j+1)%3] = 0.0;
856 VectorNormalize( bestNormal, bestNormal );
860 if ( DotProduct( plane, bestNormal ) < 0.05 ){
861 goto default_CLIPMODEL;
865 /* make side planes */
866 for ( j = 0; j < 3; j++ )
868 VectorSubtract( points[(j+1)%3], points[ j ], nrm );
869 CrossProduct( bestNormal, nrm, p[ j ] );
870 VectorNormalize( p[ j ], p[ j ] );
871 p[j][3] = DotProduct( points[j], p[j] );
874 /* make back plane */
875 if ( spawnFlags & 2048 ){ //max extrude
876 VectorScale( bestNormal, -1.0f, reverse );
877 if ( bestNormal[axis] > 0 ){
878 reverse[3] = -min[axis] + clipDepth;
881 reverse[3] = max[axis] + clipDepth;
884 else if ( spawnFlags & 4096 ){ //axial backplane
885 VectorScale( bestNormal, -1.0f, reverse );
886 reverse[3] = points[0][axis];
887 if ( bestNormal[axis] > 0 ){
888 for ( j = 1; j < 3; j++ ){
889 if ( points[j][axis] < reverse[3] ){
890 reverse[3] = points[j][axis];
893 reverse[3] = -reverse[3] + clipDepth;
896 for ( j = 1; j < 3; j++ ){
897 if ( points[j][axis] > reverse[3] ){
898 reverse[3] = points[j][axis];
901 reverse[3] += clipDepth;
903 if (limDepth != 0.0){
904 VectorCopy( points[0], cnt );
905 if ( bestNormal[axis] > 0 ){
906 for ( j = 1; j < 3; j++ ){
907 if ( points[j][axis] > cnt[axis] ){
908 VectorCopy( points[j], cnt );
913 for ( j = 1; j < 3; j++ ){
914 if ( points[j][axis] < cnt[axis] ){
915 VectorCopy( points[j], cnt );
919 VectorMA( cnt, reverse[3] - DotProduct( reverse, cnt ), reverse, cnt );
920 if ( ( plane[3] - DotProduct( plane, cnt ) ) > limDepth ){
921 VectorScale( plane, -1.0f, reverse );
922 reverse[ 3 ] = -plane[ 3 ];
923 reverse[3] += clipDepth;
927 else{ //normal backplane
928 VectorScale( plane, -1.0f, reverse );
929 reverse[ 3 ] = -plane[ 3 ];
930 reverse[3] += clipDepth;
933 for ( j = 0; j < 3; j++ )
935 for ( k = 0; k < 3; k++ )
937 if ( fabs(p[j][k]) < 0.00025 && p[j][k] != 0.0 ){
938 Sys_Printf( "nonax nrm %6.17f %6.17f %6.17f\n", p[j][0], p[j][1], p[j][2] );
943 /* set up brush sides */
944 buildBrush->numsides = 5;
945 buildBrush->sides[ 0 ].shaderInfo = si;
946 for ( j = 1; j < buildBrush->numsides; j++ ) {
948 buildBrush->sides[ 0 ].shaderInfo = ShaderInfoForShader( "debugclip2" );
949 buildBrush->sides[ j ].shaderInfo = ShaderInfoForShader( "debugclip" );
952 buildBrush->sides[ j ].shaderInfo = NULL; // don't emit these faces as draw surfaces, should make smaller BSPs; hope this works
955 VectorCopy( points[0], points[3] ); // for cyclic usage
957 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
958 buildBrush->sides[ 1 ].planenum = FindFloatPlane( p[0], p[0][ 3 ], 2, &points[ 0 ] ); // p[0] contains points[0] and points[1]
959 buildBrush->sides[ 2 ].planenum = FindFloatPlane( p[1], p[1][ 3 ], 2, &points[ 1 ] ); // p[1] contains points[1] and points[2]
960 buildBrush->sides[ 3 ].planenum = FindFloatPlane( p[2], p[2][ 3 ], 2, &points[ 2 ] ); // p[2] contains points[2] and points[0] (copied to points[3]
961 buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 0, NULL );
965 else if ( spf == 264 ){ //EXTRUDE_FACE_NORMALS+PYRAMIDAL_CLIP (extrude 45)
967 //45 degrees normals for side planes
968 for ( j = 0; j < 3; j++ )
970 VectorSubtract( points[(j+1)%3], points[ j ], nrm );
971 CrossProduct( plane, nrm, Enorm[ j ] );
972 VectorNormalize( Enorm[ j ], Enorm[ j ] );
973 VectorAdd( plane, Enorm[ j ], Enorm[ j ] );
974 VectorNormalize( Enorm[ j ], Enorm[ j ] );
975 /* make side planes */
976 CrossProduct( Enorm[ j ], nrm, p[ j ] );
977 VectorNormalize( p[ j ], p[ j ] );
978 p[j][3] = DotProduct( points[j], p[j] );
979 //snap nearly axial side planes
981 for ( k = 0; k < 3; k++ )
983 if ( fabs(p[j][k]) < 0.00025 && p[j][k] != 0.0 ){
989 VectorNormalize( p[j], p[j] );
990 VectorAdd( points[j], points[(j+1)%3], cnt );
991 VectorScale( cnt, 0.5f, cnt );
992 p[j][3] = DotProduct( cnt, p[j] );
996 /* make back plane */
997 VectorScale( plane, -1.0f, reverse );
998 reverse[ 3 ] = -plane[ 3 ];
999 reverse[3] += clipDepth;
1001 /* set up brush sides */
1002 buildBrush->numsides = 5;
1003 buildBrush->sides[ 0 ].shaderInfo = si;
1004 for ( j = 1; j < buildBrush->numsides; j++ ) {
1006 buildBrush->sides[ 0 ].shaderInfo = ShaderInfoForShader( "debugclip2" );
1007 buildBrush->sides[ j ].shaderInfo = ShaderInfoForShader( "debugclip" );
1010 buildBrush->sides[ j ].shaderInfo = NULL; // don't emit these faces as draw surfaces, should make smaller BSPs; hope this works
1013 VectorCopy( points[0], points[3] ); // for cyclic usage
1015 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
1016 buildBrush->sides[ 1 ].planenum = FindFloatPlane( p[0], p[0][ 3 ], 2, &points[ 0 ] ); // p[0] contains points[0] and points[1]
1017 buildBrush->sides[ 2 ].planenum = FindFloatPlane( p[1], p[1][ 3 ], 2, &points[ 1 ] ); // p[1] contains points[1] and points[2]
1018 buildBrush->sides[ 3 ].planenum = FindFloatPlane( p[2], p[2][ 3 ], 2, &points[ 2 ] ); // p[2] contains points[2] and points[0] (copied to points[3]
1019 buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 0, NULL );
1023 else if ( ( spf == 128 ) || //EXTRUDE_VERTEX_NORMALS
1024 ( spf == 384 ) ){ //EXTRUDE_VERTEX_NORMALS + PYRAMIDAL_CLIP - vertex normals + don't check for sides, sticking outwards
1025 /* get vertex normals */
1026 for ( j = 0; j < 3; j++ )
1029 dv = &ds->verts[ ds->indexes[ i + j ] ];
1031 VectorCopy( dv->normal, Vnorm[ j ] );
1034 //avg normals for side planes
1035 for ( j = 0; j < 3; j++ )
1037 VectorAdd( Vnorm[ j ], Vnorm[ (j+1)%3 ], Enorm[ j ] );
1038 VectorNormalize( Enorm[ j ], Enorm[ j ] );
1039 //check fuer bad ones
1040 VectorSubtract( points[(j+1)%3], points[ j ], cnt );
1041 CrossProduct( plane, cnt, nrm );
1042 VectorNormalize( nrm, nrm );
1043 //check for negative or outside direction
1044 if ( DotProduct( Enorm[ j ], plane ) > 0.1 ){
1045 if ( ( DotProduct( Enorm[ j ], nrm ) > -0.2 ) || ( spawnFlags & 256 ) ){
1051 //Sys_Printf( "faulty Enormal %i/%i\n", notok, ok );
1053 VectorAdd( plane, nrm, Enorm[ j ] );
1054 VectorNormalize( Enorm[ j ], Enorm[ j ] );
1057 /* make side planes */
1058 for ( j = 0; j < 3; j++ )
1060 VectorSubtract( points[(j+1)%3], points[ j ], nrm );
1061 CrossProduct( Enorm[ j ], nrm, p[ j ] );
1062 VectorNormalize( p[ j ], p[ j ] );
1063 p[j][3] = DotProduct( points[j], p[j] );
1064 //snap nearly axial side planes
1066 for ( k = 0; k < 3; k++ )
1068 if ( fabs(p[j][k]) < 0.00025 && p[j][k] != 0.0 ){
1069 //Sys_Printf( "init plane %6.8f %6.8f %6.8f %6.8f\n", p[j][0], p[j][1], p[j][2], p[j][3]);
1075 VectorNormalize( p[j], p[j] );
1076 //Sys_Printf( "nrm plane %6.8f %6.8f %6.8f %6.8f\n", p[j][0], p[j][1], p[j][2], p[j][3]);
1077 VectorAdd( points[j], points[(j+1)%3], cnt );
1078 VectorScale( cnt, 0.5f, cnt );
1079 p[j][3] = DotProduct( cnt, p[j] );
1080 //Sys_Printf( "dst plane %6.8f %6.8f %6.8f %6.8f\n", p[j][0], p[j][1], p[j][2], p[j][3]);
1084 /* make back plane */
1085 VectorScale( plane, -1.0f, reverse );
1086 reverse[ 3 ] = -plane[ 3 ];
1087 reverse[3] += clipDepth;
1089 /* set up brush sides */
1090 buildBrush->numsides = 5;
1091 buildBrush->sides[ 0 ].shaderInfo = si;
1092 for ( j = 1; j < buildBrush->numsides; j++ ) {
1094 buildBrush->sides[ 0 ].shaderInfo = ShaderInfoForShader( "debugclip2" );
1095 buildBrush->sides[ j ].shaderInfo = ShaderInfoForShader( "debugclip" );
1098 buildBrush->sides[ j ].shaderInfo = NULL; // don't emit these faces as draw surfaces, should make smaller BSPs; hope this works
1101 VectorCopy( points[0], points[3] ); // for cyclic usage
1103 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
1104 buildBrush->sides[ 1 ].planenum = FindFloatPlane( p[0], p[0][ 3 ], 2, &points[ 0 ] ); // p[0] contains points[0] and points[1]
1105 buildBrush->sides[ 2 ].planenum = FindFloatPlane( p[1], p[1][ 3 ], 2, &points[ 1 ] ); // p[1] contains points[1] and points[2]
1106 buildBrush->sides[ 3 ].planenum = FindFloatPlane( p[2], p[2][ 3 ], 2, &points[ 2 ] ); // p[2] contains points[2] and points[0] (copied to points[3]
1107 buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 0, NULL );
1111 else if ( spf == 8 ){ //EXTRUDE_FACE_NORMALS
1113 /* make side planes */
1114 for ( j = 0; j < 3; j++ )
1116 VectorSubtract( points[(j+1)%3], points[ j ], nrm );
1117 CrossProduct( plane, nrm, p[ j ] );
1118 VectorNormalize( p[ j ], p[ j ] );
1119 p[j][3] = DotProduct( points[j], p[j] );
1120 //snap nearly axial side planes
1122 for ( k = 0; k < 3; k++ )
1124 if ( fabs(p[j][k]) < 0.00025 && p[j][k] != 0.0 ){
1125 //Sys_Printf( "init plane %6.8f %6.8f %6.8f %6.8f\n", p[j][0], p[j][1], p[j][2], p[j][3]);
1131 VectorNormalize( p[j], p[j] );
1132 //Sys_Printf( "nrm plane %6.8f %6.8f %6.8f %6.8f\n", p[j][0], p[j][1], p[j][2], p[j][3]);
1133 VectorAdd( points[j], points[(j+1)%3], cnt );
1134 VectorScale( cnt, 0.5f, cnt );
1135 p[j][3] = DotProduct( cnt, p[j] );
1136 //Sys_Printf( "dst plane %6.8f %6.8f %6.8f %6.8f\n", p[j][0], p[j][1], p[j][2], p[j][3]);
1140 /* make back plane */
1141 VectorScale( plane, -1.0f, reverse );
1142 reverse[ 3 ] = -plane[ 3 ];
1143 reverse[3] += clipDepth;
1145 for ( j = 0; j < 3; j++ )
1147 for ( k = 0; k < 3; k++ )
1149 if ( fabs(p[j][k]) < 0.00005 && p[j][k] != 0.0 ){
1150 Sys_Printf( "nonax nrm %6.17f %6.17f %6.17f\n", p[j][0], p[j][1], p[j][2] );
1151 Sys_Printf( "frm src nrm %6.17f %6.17f %6.17f\n", plane[0], plane[1], plane[2]);
1156 /* set up brush sides */
1157 buildBrush->numsides = 5;
1158 buildBrush->sides[ 0 ].shaderInfo = si;
1159 for ( j = 1; j < buildBrush->numsides; j++ ) {
1161 buildBrush->sides[ 0 ].shaderInfo = ShaderInfoForShader( "debugclip2" );
1162 buildBrush->sides[ j ].shaderInfo = ShaderInfoForShader( "debugclip" );
1165 buildBrush->sides[ j ].shaderInfo = NULL; // don't emit these faces as draw surfaces, should make smaller BSPs; hope this works
1168 VectorCopy( points[0], points[3] ); // for cyclic usage
1170 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
1171 buildBrush->sides[ 1 ].planenum = FindFloatPlane( p[0], p[0][ 3 ], 2, &points[ 0 ] ); // p[0] contains points[0] and points[1]
1172 buildBrush->sides[ 2 ].planenum = FindFloatPlane( p[1], p[1][ 3 ], 2, &points[ 1 ] ); // p[1] contains points[1] and points[2]
1173 buildBrush->sides[ 3 ].planenum = FindFloatPlane( p[2], p[2][ 3 ], 2, &points[ 2 ] ); // p[2] contains points[2] and points[0] (copied to points[3]
1174 buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 0, NULL );
1178 else if ( spf == 256 ){ //PYRAMIDAL_CLIP
1180 /* calculate center */
1181 VectorAdd( points[ 0 ], points[ 1 ], cnt );
1182 VectorAdd( cnt, points[ 2 ], cnt );
1183 VectorScale( cnt, 0.3333333333333f, cnt );
1185 /* make back pyramid point */
1186 VectorMA( cnt, -clipDepth, plane, cnt );
1188 /* make 3 more planes */
1189 if( PlaneFromPoints( p[0], points[ 2 ], points[ 1 ], cnt ) &&
1190 PlaneFromPoints( p[1], points[ 1 ], points[ 0 ], cnt ) &&
1191 PlaneFromPoints( p[2], points[ 0 ], points[ 2 ], cnt ) ) {
1193 //check for dangerous planes
1194 while( (( p[0][0] != 0.0 || p[0][1] != 0.0 ) && fabs(p[0][0]) < 0.00025 && fabs(p[0][1]) < 0.00025) ||
1195 (( p[0][0] != 0.0 || p[0][2] != 0.0 ) && fabs(p[0][0]) < 0.00025 && fabs(p[0][2]) < 0.00025) ||
1196 (( p[0][2] != 0.0 || p[0][1] != 0.0 ) && fabs(p[0][2]) < 0.00025 && fabs(p[0][1]) < 0.00025) ||
1197 (( p[1][0] != 0.0 || p[1][1] != 0.0 ) && fabs(p[1][0]) < 0.00025 && fabs(p[1][1]) < 0.00025) ||
1198 (( p[1][0] != 0.0 || p[1][2] != 0.0 ) && fabs(p[1][0]) < 0.00025 && fabs(p[1][2]) < 0.00025) ||
1199 (( p[1][2] != 0.0 || p[1][1] != 0.0 ) && fabs(p[1][2]) < 0.00025 && fabs(p[1][1]) < 0.00025) ||
1200 (( p[2][0] != 0.0 || p[2][1] != 0.0 ) && fabs(p[2][0]) < 0.00025 && fabs(p[2][1]) < 0.00025) ||
1201 (( p[2][0] != 0.0 || p[2][2] != 0.0 ) && fabs(p[2][0]) < 0.00025 && fabs(p[2][2]) < 0.00025) ||
1202 (( p[2][2] != 0.0 || p[2][1] != 0.0 ) && fabs(p[2][2]) < 0.00025 && fabs(p[2][1]) < 0.00025) ) {
1203 VectorMA( cnt, -0.1f, plane, cnt );
1204 // Sys_Printf( "shifting pyramid point\n" );
1205 PlaneFromPoints( p[0], points[ 2 ], points[ 1 ], cnt );
1206 PlaneFromPoints( p[1], points[ 1 ], points[ 0 ], cnt );
1207 PlaneFromPoints( p[2], points[ 0 ], points[ 2 ], cnt );
1210 for ( j = 0; j < 3; j++ )
1212 for ( k = 0; k < 3; k++ )
1214 if ( fabs(p[j][k]) < 0.00005 && p[j][k] != 0.0 ){
1215 Sys_Printf( "nonax nrm %6.17f %6.17f %6.17f\n (%6.8f %6.8f %6.8f)\n (%6.8f %6.8f %6.8f)\n (%6.8f %6.8f %6.8f)\n", p[j][0], p[j][1], p[j][2], points[j][0], points[j][1], points[j][2], points[(j+1)%3][0], points[(j+1)%3][1], points[(j+1)%3][2], cnt[0], cnt[1], cnt[2] );
1220 /* set up brush sides */
1221 buildBrush->numsides = 4;
1222 buildBrush->sides[ 0 ].shaderInfo = si;
1223 for ( j = 1; j < buildBrush->numsides; j++ ) {
1225 buildBrush->sides[ 0 ].shaderInfo = ShaderInfoForShader( "debugclip2" );
1226 buildBrush->sides[ j ].shaderInfo = ShaderInfoForShader( "debugclip" );
1229 buildBrush->sides[ j ].shaderInfo = NULL; // don't emit these faces as draw surfaces, should make smaller BSPs; hope this works
1232 VectorCopy( points[0], points[3] ); // for cyclic usage
1234 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
1235 buildBrush->sides[ 1 ].planenum = FindFloatPlane( p[0], p[0][ 3 ], 2, &points[ 1 ] ); // p[0] contains points[1] and points[2]
1236 buildBrush->sides[ 2 ].planenum = FindFloatPlane( p[1], p[1][ 3 ], 2, &points[ 0 ] ); // p[1] contains points[0] and points[1]
1237 buildBrush->sides[ 3 ].planenum = FindFloatPlane( p[2], p[2][ 3 ], 2, &points[ 2 ] ); // p[2] contains points[2] and points[0] (copied to points[3]
1241 Sys_Printf( "WARNING: triangle (%6.0f %6.0f %6.0f) (%6.0f %6.0f %6.0f) (%6.0f %6.0f %6.0f) of %s was not autoclipped\n", points[0][0], points[0][1], points[0][2], points[1][0], points[1][1], points[1][2], points[2][0], points[2][1], points[2][2], name );
1248 else if ( ( si->clipModel && !( spf ) ) || ( ( spawnFlags & 8090 ) == 2 ) ){ //default CLIPMODEL
1252 VectorCopy( plane, bestNormal );
1253 for ( j = 0; j < 3; j++ ){
1254 if ( fabs(bestNormal[j]) > fabs(bestNormal[(j+1)%3]) ){
1255 bestNormal[(j+1)%3] = 0.0;
1258 bestNormal[j] = 0.0;
1261 VectorNormalize( bestNormal, bestNormal );
1263 /* make side planes */
1264 for ( j = 0; j < 3; j++ )
1266 VectorSubtract( points[(j+1)%3], points[ j ], nrm );
1267 CrossProduct( bestNormal, nrm, p[ j ] );
1268 VectorNormalize( p[ j ], p[ j ] );
1269 p[j][3] = DotProduct( points[j], p[j] );
1272 /* make back plane */
1273 VectorScale( plane, -1.0f, reverse );
1274 reverse[ 3 ] = -plane[ 3 ];
1275 reverse[3] += DotProduct( bestNormal, plane ) * clipDepth;
1277 for ( j = 0; j < 3; j++ )
1279 for ( k = 0; k < 3; k++ )
1281 if ( fabs(p[j][k]) < 0.00025 && p[j][k] != 0.0 ){
1282 Sys_Printf( "nonax nrm %6.17f %6.17f %6.17f\n", p[j][0], p[j][1], p[j][2] );
1287 /* set up brush sides */
1288 buildBrush->numsides = 5;
1289 buildBrush->sides[ 0 ].shaderInfo = si;
1290 for ( j = 1; j < buildBrush->numsides; j++ ) {
1292 buildBrush->sides[ 0 ].shaderInfo = ShaderInfoForShader( "debugclip2" );
1293 buildBrush->sides[ j ].shaderInfo = ShaderInfoForShader( "debugclip" );
1296 buildBrush->sides[ j ].shaderInfo = NULL; // don't emit these faces as draw surfaces, should make smaller BSPs; hope this works
1299 VectorCopy( points[0], points[3] ); // for cyclic usage
1301 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
1302 buildBrush->sides[ 1 ].planenum = FindFloatPlane( p[0], p[0][ 3 ], 2, &points[ 0 ] ); // p[0] contains points[0] and points[1]
1303 buildBrush->sides[ 2 ].planenum = FindFloatPlane( p[1], p[1][ 3 ], 2, &points[ 1 ] ); // p[1] contains points[1] and points[2]
1304 buildBrush->sides[ 3 ].planenum = FindFloatPlane( p[2], p[2][ 3 ], 2, &points[ 2 ] ); // p[2] contains points[2] and points[0] (copied to points[3]
1305 buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 0, NULL );
1310 if ( CreateBrushWindings( buildBrush ) ) {
1312 //% EmitBrushes( buildBrush, NULL, NULL );
1313 buildBrush->next = entities[ mapEntityNum ].brushes;
1314 entities[ mapEntityNum ].brushes = buildBrush;
1315 entities[ mapEntityNum ].numBrushes++;
1318 Sys_Printf( "WARNING: triangle (%6.0f %6.0f %6.0f) (%6.0f %6.0f %6.0f) (%6.0f %6.0f %6.0f) of %s was not autoclipped\n", points[0][0], points[0][1], points[0][2], points[1][0], points[1][1], points[1][2], points[2][0], points[2][1], points[2][2], name );
1323 normalEpsilon = normalEpsilon_save;
1325 else if ( spawnFlags & 8090 ){
1326 Sys_Printf( "WARNING: nonexistent clipping mode selected\n" );
1335 adds misc_model surfaces to the bsp
1338 void AddTriangleModels( entity_t *e ){
1339 int num, frame, skin, castShadows, recvShadows, spawnFlags;
1341 const char *targetName;
1342 const char *target, *model, *value;
1343 char shader[ MAX_QPATH ];
1344 shaderInfo_t *celShader;
1345 float temp, baseLightmapScale, lightmapScale, clipDepth;
1347 int lightmapSampleSize;
1348 vec3_t origin, scale, angles;
1351 remap_t *remap, *remap2;
1356 Sys_FPrintf( SYS_VRB, "--- AddTriangleModels ---\n" );
1359 /* get current brush entity targetname */
1360 if ( e == entities ) {
1365 targetName = ValueForKey( e, "targetname" );
1367 /* misc_model entities target non-worldspawn brush model entities */
1368 if ( targetName[ 0 ] == '\0' ) {
1373 /* get lightmap scale */
1374 /* vortex: added _ls key (short name of lightmapscale) */
1375 baseLightmapScale = 0.0f;
1376 if ( strcmp( "", ValueForKey( e, "lightmapscale" ) ) ||
1377 strcmp( "", ValueForKey( e, "_lightmapscale" ) ) ||
1378 strcmp( "", ValueForKey( e, "_ls" ) ) ) {
1379 baseLightmapScale = FloatForKey( e, "lightmapscale" );
1380 if ( baseLightmapScale <= 0.0f ) {
1381 baseLightmapScale = FloatForKey( e, "_lightmapscale" );
1383 if ( baseLightmapScale <= 0.0f ) {
1384 baseLightmapScale = FloatForKey( e, "_ls" );
1386 if ( baseLightmapScale < 0.0f ) {
1387 baseLightmapScale = 0.0f;
1389 if ( baseLightmapScale > 0.0f ) {
1390 Sys_Printf( "World Entity has lightmap scale of %.4f\n", baseLightmapScale );
1394 /* walk the entity list */
1395 for ( num = 1; num < numEntities; num++ )
1398 e2 = &entities[ num ];
1400 /* convert misc_models into raw geometry */
1401 if ( Q_stricmp( "misc_model", ValueForKey( e2, "classname" ) ) ) {
1405 /* ydnar: added support for md3 models on non-worldspawn models */
1406 target = ValueForKey( e2, "target" );
1407 if ( strcmp( target, targetName ) ) {
1411 /* get model name */
1412 model = ValueForKey( e2, "model" );
1413 if ( model[ 0 ] == '\0' ) {
1414 Sys_FPrintf( SYS_WRN, "WARNING: misc_model at %i %i %i without a model key\n",
1415 (int) origin[ 0 ], (int) origin[ 1 ], (int) origin[ 2 ] );
1419 /* get model frame */
1421 if ( strcmp( "", ValueForKey( e2, "_frame" ) ) ) {
1422 frame = IntForKey( e2, "_frame" );
1424 else if ( strcmp( "", ValueForKey( e2, "frame" ) ) ) {
1425 frame = IntForKey( e2, "frame" );
1428 /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
1429 if ( e == entities ) {
1430 castShadows = WORLDSPAWN_CAST_SHADOWS;
1431 recvShadows = WORLDSPAWN_RECV_SHADOWS;
1434 /* other entities don't cast any shadows, but recv worldspawn shadows */
1437 castShadows = ENTITY_CAST_SHADOWS;
1438 recvShadows = ENTITY_RECV_SHADOWS;
1441 /* get explicit shadow flags */
1442 GetEntityShadowFlags( e2, e, &castShadows, &recvShadows );
1444 /* get spawnflags */
1445 spawnFlags = IntForKey( e2, "spawnflags" );
1448 GetVectorForKey( e2, "origin", origin );
1449 VectorSubtract( origin, e->origin, origin ); /* offset by parent */
1452 scale[ 0 ] = scale[ 1 ] = scale[ 2 ] = 1.0f;
1453 temp = FloatForKey( e2, "modelscale" );
1454 if ( temp != 0.0f ) {
1455 scale[ 0 ] = scale[ 1 ] = scale[ 2 ] = temp;
1457 value = ValueForKey( e2, "modelscale_vec" );
1458 if ( value[ 0 ] != '\0' ) {
1459 sscanf( value, "%f %f %f", &scale[ 0 ], &scale[ 1 ], &scale[ 2 ] );
1462 /* get "angle" (yaw) or "angles" (pitch yaw roll) */
1463 angles[ 0 ] = angles[ 1 ] = angles[ 2 ] = 0.0f;
1464 angles[ 2 ] = FloatForKey( e2, "angle" );
1465 value = ValueForKey( e2, "angles" );
1466 if ( value[ 0 ] != '\0' ) {
1467 sscanf( value, "%f %f %f", &angles[ 1 ], &angles[ 2 ], &angles[ 0 ] );
1470 /* set transform matrix (thanks spog) */
1471 m4x4_identity( transform );
1472 m4x4_pivoted_transform_by_vec3( transform, origin, angles, eXYZ, scale, vec3_origin );
1474 /* get shader remappings */
1476 for ( ep = e2->epairs; ep != NULL; ep = ep->next )
1478 /* look for keys prefixed with "_remap" */
1479 if ( ep->key != NULL && ep->value != NULL &&
1480 ep->key[ 0 ] != '\0' && ep->value[ 0 ] != '\0' &&
1481 !Q_strncasecmp( ep->key, "_remap", 6 ) ) {
1482 /* create new remapping */
1484 remap = safe_malloc( sizeof( *remap ) );
1485 remap->next = remap2;
1486 strcpy( remap->from, ep->value );
1488 /* split the string */
1489 split = strchr( remap->from, ';' );
1490 if ( split == NULL ) {
1491 Sys_FPrintf( SYS_WRN, "WARNING: Shader _remap key found in misc_model without a ; character\n" );
1497 /* store the split */
1499 strcpy( remap->to, ( split + 1 ) );
1502 //% Sys_FPrintf( SYS_VRB, "Remapping %s to %s\n", remap->from, remap->to );
1506 /* ydnar: cel shader support */
1507 value = ValueForKey( e2, "_celshader" );
1508 if ( value[ 0 ] == '\0' ) {
1509 value = ValueForKey( &entities[ 0 ], "_celshader" );
1511 if ( value[ 0 ] != '\0' ) {
1512 sprintf( shader, "textures/%s", value );
1513 celShader = ShaderInfoForShader( shader );
1516 celShader = *globalCelShader ? ShaderInfoForShader( globalCelShader ) : NULL;
1519 /* jal : entity based _samplesize */
1520 lightmapSampleSize = 0;
1521 if ( strcmp( "", ValueForKey( e2, "_lightmapsamplesize" ) ) ) {
1522 lightmapSampleSize = IntForKey( e2, "_lightmapsamplesize" );
1524 else if ( strcmp( "", ValueForKey( e2, "_samplesize" ) ) ) {
1525 lightmapSampleSize = IntForKey( e2, "_samplesize" );
1527 else if ( strcmp( "", ValueForKey( e2, "_ss" ) ) ) {
1528 lightmapSampleSize = IntForKey( e2, "_ss" );
1531 if ( lightmapSampleSize < 0 ) {
1532 lightmapSampleSize = 0;
1535 if ( lightmapSampleSize > 0.0f ) {
1536 Sys_Printf( "misc_model has lightmap sample size of %.d\n", lightmapSampleSize );
1539 /* get lightmap scale */
1540 /* vortex: added _ls key (short name of lightmapscale) */
1541 lightmapScale = 0.0f;
1542 if ( strcmp( "", ValueForKey( e2, "lightmapscale" ) ) ||
1543 strcmp( "", ValueForKey( e2, "_lightmapscale" ) ) ||
1544 strcmp( "", ValueForKey( e2, "_ls" ) ) ) {
1545 lightmapScale = FloatForKey( e2, "lightmapscale" );
1546 if ( lightmapScale <= 0.0f ) {
1547 lightmapScale = FloatForKey( e2, "_lightmapscale" );
1549 if ( lightmapScale <= 0.0f ) {
1550 lightmapScale = FloatForKey( e2, "_ls" );
1552 if ( lightmapScale < 0.0f ) {
1553 lightmapScale = 0.0f;
1555 if ( lightmapScale > 0.0f ) {
1556 Sys_Printf( "misc_model has lightmap scale of %.4f\n", lightmapScale );
1560 /* jal : entity based _shadeangle */
1562 if ( strcmp( "", ValueForKey( e2, "_shadeangle" ) ) ) {
1563 shadeAngle = FloatForKey( e2, "_shadeangle" );
1565 /* vortex' aliases */
1566 else if ( strcmp( "", ValueForKey( e2, "_smoothnormals" ) ) ) {
1567 shadeAngle = FloatForKey( e2, "_smoothnormals" );
1569 else if ( strcmp( "", ValueForKey( e2, "_sn" ) ) ) {
1570 shadeAngle = FloatForKey( e2, "_sn" );
1572 else if ( strcmp( "", ValueForKey( e2, "_sa" ) ) ) {
1573 shadeAngle = FloatForKey( e2, "_sa" );
1575 else if ( strcmp( "", ValueForKey( e2, "_smooth" ) ) ) {
1576 shadeAngle = FloatForKey( e2, "_smooth" );
1579 if ( shadeAngle < 0.0f ) {
1583 if ( shadeAngle > 0.0f ) {
1584 Sys_Printf( "misc_model has shading angle of %.4f\n", shadeAngle );
1588 if ( strcmp( "", ValueForKey( e2, "_skin" ) ) ) {
1589 skin = IntForKey( e2, "_skin" );
1591 else if ( strcmp( "", ValueForKey( e2, "skin" ) ) ) {
1592 skin = IntForKey( e2, "skin" );
1595 clipDepth = clipDepthGlobal;
1596 if ( strcmp( "", ValueForKey( e2, "_clipdepth" ) ) ) {
1597 clipDepth = FloatForKey( e2, "_clipdepth" );
1598 Sys_Printf( "misc_model has autoclip depth of %.3f\n", clipDepth );
1602 /* insert the model */
1603 InsertModel( model, skin, frame, transform, remap, celShader, mapEntityNum, castShadows, recvShadows, spawnFlags, lightmapScale, lightmapSampleSize, shadeAngle, clipDepth );
1605 /* free shader remappings */
1606 while ( remap != NULL )
1608 remap2 = remap->next;