2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
39 The ambientCache is on the stack, so we don't want to leave a reference
40 to it that would try to be freed later. Create the ambientCache immediately.
43 static void R_FinishDeform( drawSurf_t *drawSurf, srfTriangles_t *newTri, idDrawVert *ac ) {
48 // generate current normals, tangents, and bitangents
49 // We might want to support the possibility of deform functions generating
50 // explicit normals, and we might also want to allow the cached deformInfo
51 // optimization for these.
52 // FIXME: this doesn't work, because the deformed surface is just the
53 // ambient one, and there isn't an opportunity to generate light interactions
54 if ( drawSurf->material->ReceivesLighting() ) {
56 R_DeriveTangents( newTri, false );
60 newTri->ambientCache = vertexCache.AllocFrameTemp( ac, newTri->numVerts * sizeof( idDrawVert ) );
61 // if we are out of vertex cache, leave it the way it is
62 if ( newTri->ambientCache ) {
63 drawSurf->geo = newTri;
71 Assuming all the triangles for this shader are independant
72 quads, rebuild them as forward facing sprites
75 static void R_AutospriteDeform( drawSurf_t *surf ) {
81 idVec3 leftDir, upDir;
82 const srfTriangles_t *tri;
83 srfTriangles_t *newTri;
87 if ( tri->numVerts & 3 ) {
88 common->Warning( "R_AutospriteDeform: shader had odd vertex count" );
91 if ( tri->numIndexes != ( tri->numVerts >> 2 ) * 6 ) {
92 common->Warning( "R_AutospriteDeform: autosprite had odd index count" );
96 R_GlobalVectorToLocal( surf->space->modelMatrix, tr.viewDef->renderView.viewaxis[1], leftDir );
97 R_GlobalVectorToLocal( surf->space->modelMatrix, tr.viewDef->renderView.viewaxis[2], upDir );
99 if ( tr.viewDef->isMirror ) {
100 leftDir = vec3_origin - leftDir;
103 // this srfTriangles_t and all its indexes and caches are in frame
104 // memory, and will be automatically disposed of
105 newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
106 newTri->numVerts = tri->numVerts;
107 newTri->numIndexes = tri->numIndexes;
108 newTri->indexes = (glIndex_t *)R_FrameAlloc( newTri->numIndexes * sizeof( newTri->indexes[0] ) );
110 idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
112 for ( i = 0 ; i < tri->numVerts ; i+=4 ) {
116 mid[0] = 0.25 * (v->xyz[0] + (v+1)->xyz[0] + (v+2)->xyz[0] + (v+3)->xyz[0]);
117 mid[1] = 0.25 * (v->xyz[1] + (v+1)->xyz[1] + (v+2)->xyz[1] + (v+3)->xyz[1]);
118 mid[2] = 0.25 * (v->xyz[2] + (v+1)->xyz[2] + (v+2)->xyz[2] + (v+3)->xyz[2]);
120 delta = v->xyz - mid;
121 radius = delta.Length() * 0.707; // / sqrt(2)
123 left = leftDir * radius;
126 ac[i+0].xyz = mid + left + up;
129 ac[i+1].xyz = mid - left + up;
132 ac[i+2].xyz = mid - left - up;
135 ac[i+3].xyz = mid + left - up;
139 newTri->indexes[6*(i>>2)+0] = i;
140 newTri->indexes[6*(i>>2)+1] = i+1;
141 newTri->indexes[6*(i>>2)+2] = i+2;
143 newTri->indexes[6*(i>>2)+3] = i;
144 newTri->indexes[6*(i>>2)+4] = i+2;
145 newTri->indexes[6*(i>>2)+5] = i+3;
148 R_FinishDeform( surf, newTri, ac );
152 =====================
155 will pivot a rectangular quad along the center of its long axis
157 Note that a geometric tube with even quite a few sides tube will almost certainly render much faster
158 than this, so this should only be for faked volumetric tubes.
159 Make sure this is used with twosided translucent shaders, because the exact side
160 order may not be correct.
161 =====================
163 static void R_TubeDeform( drawSurf_t *surf ) {
166 const srfTriangles_t *tri;
167 static int edgeVerts[6][2] = {
178 if ( tri->numVerts & 3 ) {
179 common->Error( "R_AutospriteDeform: shader had odd vertex count" );
181 if ( tri->numIndexes != ( tri->numVerts >> 2 ) * 6 ) {
182 common->Error( "R_AutospriteDeform: autosprite had odd index count" );
185 // we need the view direction to project the minor axis of the tube
186 // as the view changes
188 R_GlobalPointToLocal( surf->space->modelMatrix, tr.viewDef->renderView.vieworg, localView );
190 // this srfTriangles_t and all its indexes and caches are in frame
191 // memory, and will be automatically disposed of
192 srfTriangles_t *newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
193 newTri->numVerts = tri->numVerts;
194 newTri->numIndexes = tri->numIndexes;
195 newTri->indexes = (glIndex_t *)R_FrameAlloc( newTri->numIndexes * sizeof( newTri->indexes[0] ) );
196 memcpy( newTri->indexes, tri->indexes, newTri->numIndexes * sizeof( newTri->indexes[0] ) );
198 idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
199 memset( ac, 0, sizeof( idDrawVert ) * newTri->numVerts );
201 // this is a lot of work for two triangles...
202 // we could precalculate a lot if it is an issue, but it would mess up
203 // the shader abstraction
204 for ( i = 0, indexes = 0 ; i < tri->numVerts ; i+=4, indexes+=6 ) {
209 const idDrawVert *v1, *v2;
211 // identify the two shortest edges out of the six defined by the indexes
212 nums[0] = nums[1] = 0;
213 lengths[0] = lengths[1] = 999999;
215 for ( j = 0 ; j < 6 ; j++ ) {
218 v1 = &tri->verts[tri->indexes[i+edgeVerts[j][0]]];
219 v2 = &tri->verts[tri->indexes[i+edgeVerts[j][1]]];
221 l = ( v1->xyz - v2->xyz ).Length();
222 if ( l < lengths[0] ) {
224 lengths[1] = lengths[0];
227 } else if ( l < lengths[1] ) {
233 // find the midpoints of the two short edges, which
234 // will give us the major axis in object coordinates
235 for ( j = 0 ; j < 2 ; j++ ) {
236 v1 = &tri->verts[tri->indexes[i+edgeVerts[nums[j]][0]]];
237 v2 = &tri->verts[tri->indexes[i+edgeVerts[nums[j]][1]]];
239 mid[j][0] = 0.5 * (v1->xyz[0] + v2->xyz[0]);
240 mid[j][1] = 0.5 * (v1->xyz[1] + v2->xyz[1]);
241 mid[j][2] = 0.5 * (v1->xyz[2] + v2->xyz[2]);
244 // find the vector of the major axis
245 major = mid[1] - mid[0];
247 // re-project the points
248 for ( j = 0 ; j < 2 ; j++ ) {
250 int i1 = tri->indexes[i+edgeVerts[nums[j]][0]];
251 int i2 = tri->indexes[i+edgeVerts[nums[j]][1]];
253 idDrawVert *av1 = &ac[i1];
254 idDrawVert *av2 = &ac[i2];
256 *av1 = *(idDrawVert *)&tri->verts[i1];
257 *av2 = *(idDrawVert *)&tri->verts[i2];
259 l = 0.5 * lengths[j];
261 // cross this with the view direction to get minor axis
262 idVec3 dir = mid[j] - localView;
263 minor.Cross( major, dir );
267 av1->xyz = mid[j] - l * minor;
268 av2->xyz = mid[j] + l * minor;
270 av1->xyz = mid[j] + l * minor;
271 av2->xyz = mid[j] - l * minor;
276 R_FinishDeform( surf, newTri, ac );
280 =====================
281 R_WindingFromTriangles
283 =====================
285 #define MAX_TRI_WINDING_INDEXES 16
286 int R_WindingFromTriangles( const srfTriangles_t *tri, glIndex_t indexes[MAX_TRI_WINDING_INDEXES] ) {
289 indexes[0] = tri->indexes[0];
291 int numTris = tri->numIndexes / 3;
294 // find an edge that goes from the current index to another
295 // index that isn't already used, and isn't an internal edge
296 for ( i = 0 ; i < numTris ; i++ ) {
297 for ( j = 0 ; j < 3 ; j++ ) {
298 if ( tri->indexes[i*3+j] != indexes[numIndexes-1] ) {
301 int next = tri->indexes[i*3+(j+1)%3];
303 // make sure it isn't already used
304 if ( numIndexes == 1 ) {
305 if ( next == indexes[0] ) {
309 for ( k = 1 ; k < numIndexes ; k++ ) {
310 if ( indexes[k] == next ) {
314 if ( k != numIndexes ) {
319 // make sure it isn't an interior edge
320 for ( k = 0 ; k < numTris ; k++ ) {
324 for ( l = 0 ; l < 3 ; l++ ) {
327 a = tri->indexes[k*3+l];
331 b = tri->indexes[k*3+(l+1)%3];
332 if ( b != indexes[numIndexes-1] ) {
336 // this is an interior edge
343 if ( k != numTris ) {
347 // add this to the list
348 indexes[numIndexes] = next;
356 if ( numIndexes == tri->numVerts ) {
359 } while ( i != numTris );
365 =====================
368 =====================
371 static void R_FlareDeform( drawSurf_t *surf ) {
372 const srfTriangles_t *tri;
373 srfTriangles_t *newTri;
381 if ( tri->numVerts != 4 || tri->numIndexes != 6 ) {
382 //FIXME: temp hack for flares on tripleted models
383 common->Warning( "R_FlareDeform: not a single quad" );
387 // this srfTriangles_t and all its indexes and caches are in frame
388 // memory, and will be automatically disposed of
389 newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
390 newTri->numVerts = 4;
391 newTri->numIndexes = 2*3;
392 newTri->indexes = (glIndex_t *)R_FrameAlloc( newTri->numIndexes * sizeof( newTri->indexes[0] ) );
394 idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
397 plane.FromPoints( tri->verts[tri->indexes[0]].xyz, tri->verts[tri->indexes[1]].xyz, tri->verts[tri->indexes[2]].xyz );
399 // if viewer is behind the plane, draw nothing
400 R_GlobalPointToLocal( surf->space->modelMatrix, tr.viewDef->renderView.vieworg, localViewer );
401 float distFromPlane = localViewer * plane.Normal() + plane[3];
402 if ( distFromPlane <= 0 ) {
403 newTri->numIndexes = 0;
409 center = tri->verts[0].xyz;
410 for ( j = 1 ; j < tri->numVerts ; j++ ) {
411 center += tri->verts[j].xyz;
413 center *= 1.0/tri->numVerts;
415 idVec3 dir = localViewer - center;
418 dot = dir * plane.Normal();
420 // set vertex colors based on plane angle
421 int color = (int)(dot * 8 * 256);
425 for ( j = 0 ; j < newTri->numVerts ; j++ ) {
428 ac[j].color[2] = color;
429 ac[j].color[3] = 255;
432 float spread = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ] * r_flareSize.GetFloat();
433 idVec3 edgeDir[4][3];
434 glIndex_t indexes[MAX_TRI_WINDING_INDEXES];
435 int numIndexes = R_WindingFromTriangles( tri, indexes );
437 surf->material = declManager->FindMaterial( "textures/smf/anamorphicFlare" );
439 // only deal with quads
440 if ( numIndexes != 4 ) {
445 idVec3 centroid, toeye, forward, up, left;
446 centroid.Set( 0, 0, 0 );
447 for ( int i = 0; i < 4; i++ ) {
448 centroid += tri->verts[ indexes[i] ].xyz;
452 // compute basis vectors
455 toeye = centroid - localViewer;
457 left = toeye.Cross( up );
458 up = left.Cross( toeye );
460 left = left * 40 * 6;
469 static flare_t flares[] = {
474 for ( int i = 0; i < 4; i++ ) {
475 memset( ac + i, 0, sizeof( ac[i] ) );
478 ac[0].xyz = centroid - left;
479 ac[0].st[0] = 0; ac[0].st[1] = 0;
481 ac[1].xyz = centroid + up;
482 ac[1].st[0] = 1; ac[1].st[1] = 0;
484 ac[2].xyz = centroid + left;
485 ac[2].st[0] = 1; ac[2].st[1] = 1;
487 ac[3].xyz = centroid - up;
488 ac[3].st[0] = 0; ac[3].st[1] = 1;
491 for ( j = 0 ; j < newTri->numVerts ; j++ ) {
494 ac[j].color[2] = 255;
495 ac[j].color[3] = 255;
499 static glIndex_t triIndexes[2*3] = {
503 memcpy( newTri->indexes, triIndexes, sizeof( triIndexes ) );
505 R_FinishDeform( surf, newTri, ac );
509 static void R_FlareDeform( drawSurf_t *surf ) {
510 const srfTriangles_t *tri;
511 srfTriangles_t *newTri;
519 if ( tri->numVerts != 4 || tri->numIndexes != 6 ) {
520 //FIXME: temp hack for flares on tripleted models
521 common->Warning( "R_FlareDeform: not a single quad" );
525 // this srfTriangles_t and all its indexes and caches are in frame
526 // memory, and will be automatically disposed of
527 newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
528 newTri->numVerts = 16;
529 newTri->numIndexes = 18*3;
530 newTri->indexes = (glIndex_t *)R_FrameAlloc( newTri->numIndexes * sizeof( newTri->indexes[0] ) );
532 idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
535 plane.FromPoints( tri->verts[tri->indexes[0]].xyz, tri->verts[tri->indexes[1]].xyz, tri->verts[tri->indexes[2]].xyz );
537 // if viewer is behind the plane, draw nothing
538 R_GlobalPointToLocal( surf->space->modelMatrix, tr.viewDef->renderView.vieworg, localViewer );
539 float distFromPlane = localViewer * plane.Normal() + plane[3];
540 if ( distFromPlane <= 0 ) {
541 newTri->numIndexes = 0;
547 center = tri->verts[0].xyz;
548 for ( j = 1 ; j < tri->numVerts ; j++ ) {
549 center += tri->verts[j].xyz;
551 center *= 1.0/tri->numVerts;
553 idVec3 dir = localViewer - center;
556 dot = dir * plane.Normal();
558 // set vertex colors based on plane angle
559 int color = (int)(dot * 8 * 256);
563 for ( j = 0 ; j < newTri->numVerts ; j++ ) {
566 ac[j].color[2] = color;
567 ac[j].color[3] = 255;
570 float spread = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ] * r_flareSize.GetFloat();
571 idVec3 edgeDir[4][3];
572 glIndex_t indexes[MAX_TRI_WINDING_INDEXES];
573 int numIndexes = R_WindingFromTriangles( tri, indexes );
576 // only deal with quads
577 if ( numIndexes != 4 ) {
581 // calculate vector directions
582 for ( i = 0 ; i < 4 ; i++ ) {
583 ac[i].xyz = tri->verts[ indexes[i] ].xyz;
587 idVec3 toEye = tri->verts[ indexes[i] ].xyz - localViewer;
590 idVec3 d1 = tri->verts[ indexes[(i+1)%4] ].xyz - localViewer;
592 edgeDir[i][1].Cross( toEye, d1 );
593 edgeDir[i][1].Normalize();
594 edgeDir[i][1] = vec3_origin - edgeDir[i][1];
596 idVec3 d2 = tri->verts[ indexes[(i+3)%4] ].xyz - localViewer;
598 edgeDir[i][0].Cross( toEye, d2 );
599 edgeDir[i][0].Normalize();
601 edgeDir[i][2] = edgeDir[i][0] + edgeDir[i][1];
602 edgeDir[i][2].Normalize();
605 // build all the points
606 ac[4].xyz = tri->verts[ indexes[0] ].xyz + spread * edgeDir[0][0];
610 ac[5].xyz = tri->verts[ indexes[0] ].xyz + spread * edgeDir[0][2];
614 ac[6].xyz = tri->verts[ indexes[0] ].xyz + spread * edgeDir[0][1];
619 ac[7].xyz = tri->verts[ indexes[1] ].xyz + spread * edgeDir[1][0];
623 ac[8].xyz = tri->verts[ indexes[1] ].xyz + spread * edgeDir[1][2];
627 ac[9].xyz = tri->verts[ indexes[1] ].xyz + spread * edgeDir[1][1];
632 ac[10].xyz = tri->verts[ indexes[2] ].xyz + spread * edgeDir[2][0];
636 ac[11].xyz = tri->verts[ indexes[2] ].xyz + spread * edgeDir[2][2];
640 ac[12].xyz = tri->verts[ indexes[2] ].xyz + spread * edgeDir[2][1];
645 ac[13].xyz = tri->verts[ indexes[3] ].xyz + spread * edgeDir[3][0];
649 ac[14].xyz = tri->verts[ indexes[3] ].xyz + spread * edgeDir[3][2];
653 ac[15].xyz = tri->verts[ indexes[3] ].xyz + spread * edgeDir[3][1];
657 for ( i = 4 ; i < 16 ; i++ ) {
658 idVec3 dir = ac[i].xyz - localViewer;
659 float len = dir.Normalize();
661 float ang = dir * plane.Normal();
663 // ac[i].xyz -= dir * spread * 2;
664 float newLen = -( distFromPlane / ang );
666 if ( newLen > 0 && newLen < len ) {
667 ac[i].xyz = localViewer + dir * newLen;
675 static glIndex_t triIndexes[18*3] = {
676 0,4,5, 0,5,6, 0,6,7, 0,7,1, 1,7,8, 1,8,9,
677 15,4,0, 15,0,3, 3,0,1, 3,1,2, 2,1,9, 2,9,10,
678 14,15,3, 14,3,13, 13,3,2, 13,2,12, 12,2,11, 11,2,10
681 newTri->numIndexes = 12;
682 static glIndex_t triIndexes[4*3] = {
683 0,1,2, 0,2,3, 0,4,5,0,5,6
687 memcpy( newTri->indexes, triIndexes, sizeof( triIndexes ) );
689 R_FinishDeform( surf, newTri, ac );
695 =====================
698 Expands the surface along it's normals by a shader amount
699 =====================
701 static void R_ExpandDeform( drawSurf_t *surf ) {
703 const srfTriangles_t *tri;
704 srfTriangles_t *newTri;
708 // this srfTriangles_t and all its indexes and caches are in frame
709 // memory, and will be automatically disposed of
710 newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
711 newTri->numVerts = tri->numVerts;
712 newTri->numIndexes = tri->numIndexes;
713 newTri->indexes = tri->indexes;
715 idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
717 float dist = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ];
718 for ( i = 0 ; i < tri->numVerts ; i++ ) {
719 ac[i] = *(idDrawVert *)&tri->verts[i];
720 ac[i].xyz = tri->verts[i].xyz + tri->verts[i].normal * dist;
723 R_FinishDeform( surf, newTri, ac );
727 =====================
730 Moves the surface along the X axis, mostly just for demoing the deforms
731 =====================
733 static void R_MoveDeform( drawSurf_t *surf ) {
735 const srfTriangles_t *tri;
736 srfTriangles_t *newTri;
740 // this srfTriangles_t and all its indexes and caches are in frame
741 // memory, and will be automatically disposed of
742 newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
743 newTri->numVerts = tri->numVerts;
744 newTri->numIndexes = tri->numIndexes;
745 newTri->indexes = tri->indexes;
747 idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
749 float dist = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ];
750 for ( i = 0 ; i < tri->numVerts ; i++ ) {
751 ac[i] = *(idDrawVert *)&tri->verts[i];
752 ac[i].xyz[0] += dist;
755 R_FinishDeform( surf, newTri, ac );
758 //=====================================================================================
761 =====================
764 Turbulently deforms the XYZ, S, and T values
765 =====================
767 static void R_TurbulentDeform( drawSurf_t *surf ) {
769 const srfTriangles_t *tri;
770 srfTriangles_t *newTri;
774 // this srfTriangles_t and all its indexes and caches are in frame
775 // memory, and will be automatically disposed of
776 newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
777 newTri->numVerts = tri->numVerts;
778 newTri->numIndexes = tri->numIndexes;
779 newTri->indexes = tri->indexes;
781 idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
783 idDeclTable *table = (idDeclTable *)surf->material->GetDeformDecl();
784 float range = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ];
785 float timeOfs = surf->shaderRegisters[ surf->material->GetDeformRegister(1) ];
786 float domain = surf->shaderRegisters[ surf->material->GetDeformRegister(2) ];
789 for ( i = 0 ; i < tri->numVerts ; i++ ) {
790 float f = tri->verts[i].xyz[0] * 0.003 + tri->verts[i].xyz[1] * 0.007 + tri->verts[i].xyz[2] * 0.011;
792 f = timeOfs + domain * f;
795 ac[i] = *(idDrawVert *)&tri->verts[i];
797 ac[i].st[0] += range * table->TableLookup( f );
798 ac[i].st[1] += range * table->TableLookup( f + tOfs );
801 R_FinishDeform( surf, newTri, ac );
804 //=====================================================================================
807 =====================
808 AddTriangleToIsland_r
810 =====================
812 #define MAX_EYEBALL_TRIS 10
813 #define MAX_EYEBALL_ISLANDS 6
816 int tris[MAX_EYEBALL_TRIS];
822 static void AddTriangleToIsland_r( const srfTriangles_t *tri, int triangleNum, bool *usedList, eyeIsland_t *island ) {
825 usedList[triangleNum] = true;
827 // add to the current island
828 if ( island->numTris == MAX_EYEBALL_TRIS ) {
829 common->Error( "MAX_EYEBALL_TRIS" );
831 island->tris[island->numTris] = triangleNum;
834 // recurse into all neighbors
835 a = tri->indexes[triangleNum*3];
836 b = tri->indexes[triangleNum*3+1];
837 c = tri->indexes[triangleNum*3+2];
839 island->bounds.AddPoint( tri->verts[a].xyz );
840 island->bounds.AddPoint( tri->verts[b].xyz );
841 island->bounds.AddPoint( tri->verts[c].xyz );
843 int numTri = tri->numIndexes / 3;
844 for ( int i = 0 ; i < numTri ; i++ ) {
848 if ( tri->indexes[i*3+0] == a
849 || tri->indexes[i*3+1] == a
850 || tri->indexes[i*3+2] == a
851 || tri->indexes[i*3+0] == b
852 || tri->indexes[i*3+1] == b
853 || tri->indexes[i*3+2] == b
854 || tri->indexes[i*3+0] == c
855 || tri->indexes[i*3+1] == c
856 || tri->indexes[i*3+2] == c ) {
857 AddTriangleToIsland_r( tri, i, usedList, island );
863 =====================
866 Each eyeball surface should have an separate upright triangle behind it, long end
867 pointing out the eye, and another single triangle in front of the eye for the focus point.
868 =====================
870 static void R_EyeballDeform( drawSurf_t *surf ) {
872 const srfTriangles_t *tri;
873 srfTriangles_t *newTri;
874 eyeIsland_t islands[MAX_EYEBALL_ISLANDS];
876 bool triUsed[MAX_EYEBALL_ISLANDS*MAX_EYEBALL_TRIS];
880 // separate all the triangles into islands
881 int numTri = tri->numIndexes / 3;
882 if ( numTri > MAX_EYEBALL_ISLANDS*MAX_EYEBALL_TRIS ) {
883 common->Printf( "R_EyeballDeform: too many triangles in surface" );
886 memset( triUsed, 0, sizeof( triUsed ) );
888 for ( numIslands = 0 ; numIslands < MAX_EYEBALL_ISLANDS ; numIslands++ ) {
889 islands[numIslands].numTris = 0;
890 islands[numIslands].bounds.Clear();
891 for ( i = 0 ; i < numTri ; i++ ) {
893 AddTriangleToIsland_r( tri, i, triUsed, &islands[numIslands] );
902 // assume we always have two eyes, two origins, and two targets
903 if ( numIslands != 3 ) {
904 common->Printf( "R_EyeballDeform: %i triangle islands\n", numIslands );
908 // this srfTriangles_t and all its indexes and caches are in frame
909 // memory, and will be automatically disposed of
911 // the surface cannot have more indexes or verts than the original
912 newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) );
913 memset( newTri, 0, sizeof( *newTri ) );
914 newTri->numVerts = tri->numVerts;
915 newTri->numIndexes = tri->numIndexes;
916 newTri->indexes = (glIndex_t *)R_FrameAlloc( tri->numIndexes * sizeof( newTri->indexes[0] ) );
917 idDrawVert *ac = (idDrawVert *)_alloca16( tri->numVerts * sizeof( idDrawVert ) );
919 newTri->numIndexes = 0;
921 // decide which islands are the eyes and points
922 for ( i = 0 ; i < numIslands ; i++ ) {
923 islands[i].mid = islands[i].bounds.GetCenter();
926 for ( i = 0 ; i < numIslands ; i++ ) {
927 eyeIsland_t *island = &islands[i];
929 if ( island->numTris == 1 ) {
933 // the closest single triangle point will be the eye origin
934 // and the next-to-farthest will be the focal point
935 idVec3 origin, focus;
936 int originIsland = 0;
937 float dist[MAX_EYEBALL_ISLANDS];
938 int sortOrder[MAX_EYEBALL_ISLANDS];
940 for ( j = 0 ; j < numIslands ; j++ ) {
941 idVec3 dir = islands[j].mid - island->mid;
942 dist[j] = dir.Length();
944 for ( k = j-1 ; k >= 0 ; k-- ) {
945 if ( dist[k] > dist[k+1] ) {
946 int temp = sortOrder[k];
947 sortOrder[k] = sortOrder[k+1];
948 sortOrder[k+1] = temp;
949 float ftemp = dist[k];
956 originIsland = sortOrder[1];
957 origin = islands[originIsland].mid;
959 focus = islands[sortOrder[2]].mid;
961 // determine the projection directions based on the origin island triangle
962 idVec3 dir = focus - origin;
965 const idVec3 &p1 = tri->verts[tri->indexes[islands[originIsland].tris[0]+0]].xyz;
966 const idVec3 &p2 = tri->verts[tri->indexes[islands[originIsland].tris[0]+1]].xyz;
967 const idVec3 &p3 = tri->verts[tri->indexes[islands[originIsland].tris[0]+2]].xyz;
974 // texVec[0] will be the normal to the origin triangle
977 texVec[0].Cross( v1, v2 );
979 texVec[1].Cross( texVec[0], dir );
981 for ( j = 0 ; j < 2 ; j++ ) {
982 texVec[j] -= dir * ( texVec[j] * dir );
983 texVec[j].Normalize();
986 // emit these triangles, generating the projected texcoords
988 for ( j = 0 ; j < islands[i].numTris ; j++ ) {
989 for ( k = 0 ; k < 3 ; k++ ) {
990 int index = islands[i].tris[j] * 3;
992 index = tri->indexes[index+k];
993 newTri->indexes[newTri->numIndexes++] = index;
995 ac[index].xyz = tri->verts[index].xyz;
997 idVec3 local = tri->verts[index].xyz - origin;
999 ac[index].st[0] = 0.5 + local * texVec[0];
1000 ac[index].st[1] = 0.5 + local * texVec[1];
1005 R_FinishDeform( surf, newTri, ac );
1008 //==========================================================================================
1012 =====================
1015 Emit particles from the surface instead of drawing it
1016 =====================
1018 static void R_ParticleDeform( drawSurf_t *surf, bool useArea ) {
1019 const struct renderEntity_s *renderEntity = &surf->space->entityDef->parms;
1020 const struct viewDef_s *viewDef = tr.viewDef;
1021 const idDeclParticle *particleSystem = (idDeclParticle *)surf->material->GetDeformDecl();
1023 if ( r_skipParticles.GetBool() ) {
1028 if ( renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] &&
1029 viewDef->renderView.time*0.001 >= renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] ) {
1030 // the entire system has faded out
1036 // calculate the area of all the triangles
1038 int numSourceTris = surf->geo->numIndexes / 3;
1039 float totalArea = 0;
1040 float *sourceTriAreas = NULL;
1041 const srfTriangles_t *srcTri = surf->geo;
1044 sourceTriAreas = (float *)_alloca( sizeof( *sourceTriAreas ) * numSourceTris );
1046 for ( int i = 0 ; i < srcTri->numIndexes ; i += 3, triNum++ ) {
1048 area = idWinding::TriangleArea( srcTri->verts[srcTri->indexes[i]].xyz, srcTri->verts[srcTri->indexes[i+1]].xyz, srcTri->verts[srcTri->indexes[i+2]].xyz );
1049 sourceTriAreas[triNum] = totalArea;
1055 // create the particles almost exactly the way idRenderModelPrt does
1059 g.renderEnt = renderEntity;
1060 g.renderView = &viewDef->renderView;
1062 g.axis = mat3_identity;
1064 for ( int currentTri = 0; currentTri < ( ( useArea ) ? 1 : numSourceTris ); currentTri++ ) {
1066 for ( int stageNum = 0 ; stageNum < particleSystem->stages.Num() ; stageNum++ ) {
1067 idParticleStage *stage = particleSystem->stages[stageNum];
1069 if ( !stage->material ) {
1072 if ( !stage->cycleMsec ) {
1075 if ( stage->hidden ) { // just for gui particle editor use
1079 // we interpret stage->totalParticles as "particles per map square area"
1080 // so the systems look the same on different size surfaces
1081 int totalParticles = ( useArea ) ? stage->totalParticles * totalArea / 4096.0 : ( stage->totalParticles );
1083 int count = totalParticles * stage->NumQuadsPerParticle();
1085 // allocate a srfTriangles in temp memory that can hold all the particles
1086 srfTriangles_t *tri;
1088 tri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *tri ) );
1089 tri->numVerts = 4 * count;
1090 tri->numIndexes = 6 * count;
1091 tri->verts = (idDrawVert *)R_FrameAlloc( tri->numVerts * sizeof( tri->verts[0] ) );
1092 tri->indexes = (glIndex_t *)R_FrameAlloc( tri->numIndexes * sizeof( tri->indexes[0] ) );
1094 // just always draw the particles
1095 tri->bounds = stage->bounds;
1099 idRandom steppingRandom, steppingRandom2;
1101 int stageAge = g.renderView->time + renderEntity->shaderParms[SHADERPARM_TIMEOFFSET] * 1000 - stage->timeOffset * 1000;
1102 int stageCycle = stageAge / stage->cycleMsec;
1103 int inCycleTime = stageAge - stageCycle * stage->cycleMsec;
1105 // some particles will be in this cycle, some will be in the previous cycle
1106 steppingRandom.SetSeed( (( stageCycle << 10 ) & idRandom::MAX_RAND) ^ (int)( renderEntity->shaderParms[SHADERPARM_DIVERSITY] * idRandom::MAX_RAND ) );
1107 steppingRandom2.SetSeed( (( (stageCycle-1) << 10 ) & idRandom::MAX_RAND) ^ (int)( renderEntity->shaderParms[SHADERPARM_DIVERSITY] * idRandom::MAX_RAND ) );
1109 for ( int index = 0 ; index < totalParticles ; index++ ) {
1113 steppingRandom.RandomInt();
1114 steppingRandom2.RandomInt();
1116 // calculate local age for this index
1117 int bunchOffset = stage->particleLife * 1000 * stage->spawnBunching * index / totalParticles;
1119 int particleAge = stageAge - bunchOffset;
1120 int particleCycle = particleAge / stage->cycleMsec;
1121 if ( particleCycle < 0 ) {
1122 // before the particleSystem spawned
1125 if ( stage->cycles && particleCycle >= stage->cycles ) {
1126 // cycled systems will only run cycle times
1130 if ( particleCycle == stageCycle ) {
1131 g.random = steppingRandom;
1133 g.random = steppingRandom2;
1136 int inCycleTime = particleAge - particleCycle * stage->cycleMsec;
1138 if ( renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] &&
1139 g.renderView->time - inCycleTime >= renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME]*1000 ) {
1140 // don't fire any more particles
1144 // supress particles before or after the age clamp
1145 g.frac = (float)inCycleTime / ( stage->particleLife * 1000 );
1147 // yet to be spawned
1150 if ( g.frac > 1.0 ) {
1151 // this particle is in the deadTime band
1156 // locate the particle origin and axis somewhere on the surface
1159 int pointTri = currentTri;
1162 // select a triangle based on an even area distribution
1163 pointTri = idBinSearch_LessEqual<float>( sourceTriAreas, numSourceTris, g.random.RandomFloat() * totalArea );
1166 // now pick a random point inside pointTri
1167 const idDrawVert *v1 = &srcTri->verts[ srcTri->indexes[ pointTri * 3 + 0 ] ];
1168 const idDrawVert *v2 = &srcTri->verts[ srcTri->indexes[ pointTri * 3 + 1 ] ];
1169 const idDrawVert *v3 = &srcTri->verts[ srcTri->indexes[ pointTri * 3 + 2 ] ];
1171 float f1 = g.random.RandomFloat();
1172 float f2 = g.random.RandomFloat();
1173 float f3 = g.random.RandomFloat();
1175 float ft = 1.0f / ( f1 + f2 + f3 + 0.0001f );
1181 g.origin = v1->xyz * f1 + v2->xyz * f2 + v3->xyz * f3;
1182 g.axis[0] = v1->tangents[0] * f1 + v2->tangents[0] * f2 + v3->tangents[0] * f3;
1183 g.axis[1] = v1->tangents[1] * f1 + v2->tangents[1] * f2 + v3->tangents[1] * f3;
1184 g.axis[2] = v1->normal * f1 + v2->normal * f2 + v3->normal * f3;
1186 //-----------------------
1188 // this is needed so aimed particles can calculate origins at different times
1189 g.originalRandom = g.random;
1191 g.age = g.frac * stage->particleLife;
1193 // if the particle doesn't get drawn because it is faded out or beyond a kill region,
1194 // don't increment the verts
1195 tri->numVerts += stage->CreateParticle( &g, tri->verts + tri->numVerts );
1198 if ( tri->numVerts > 0 ) {
1199 // build the index list
1201 for ( int i = 0 ; i < tri->numVerts ; i += 4 ) {
1202 tri->indexes[indexes+0] = i;
1203 tri->indexes[indexes+1] = i+2;
1204 tri->indexes[indexes+2] = i+3;
1205 tri->indexes[indexes+3] = i;
1206 tri->indexes[indexes+4] = i+3;
1207 tri->indexes[indexes+5] = i+1;
1210 tri->numIndexes = indexes;
1211 tri->ambientCache = vertexCache.AllocFrameTemp( tri->verts, tri->numVerts * sizeof( idDrawVert ) );
1212 if ( tri->ambientCache ) {
1214 R_AddDrawSurf( tri, surf->space, renderEntity, stage->material, surf->scissorRect );
1221 //========================================================================================
1228 void R_DeformDrawSurf( drawSurf_t *drawSurf ) {
1229 if ( !drawSurf->material ) {
1233 if ( r_skipDeforms.GetBool() ) {
1236 switch ( drawSurf->material->Deform() ) {
1240 R_AutospriteDeform( drawSurf );
1243 R_TubeDeform( drawSurf );
1246 R_FlareDeform( drawSurf );
1249 R_ExpandDeform( drawSurf );
1252 R_MoveDeform( drawSurf );
1255 R_TurbulentDeform( drawSurf );
1258 R_EyeballDeform( drawSurf );
1261 R_ParticleDeform( drawSurf, true );
1263 case DFRM_PARTICLE2:
1264 R_ParticleDeform( drawSurf, false );