]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/renderer/tr_deform.cpp
hello world
[icculus/iodoom3.git] / neo / renderer / tr_deform.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
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.
13
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.
18
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/>.
21
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.
23
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.
25
26 ===========================================================================
27 */
28
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "tr_local.h"
33
34
35 /*
36 =================
37 R_FinishDeform
38
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.
41 =================
42 */
43 static void R_FinishDeform( drawSurf_t *drawSurf, srfTriangles_t *newTri, idDrawVert *ac ) {
44         if ( !newTri ) {
45                 return;
46         }
47
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() ) {
55                 newTri->verts = ac;
56                 R_DeriveTangents( newTri, false );
57                 newTri->verts = NULL;
58         }
59
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;
64         }
65 }
66
67 /*
68 =====================
69 R_AutospriteDeform
70
71 Assuming all the triangles for this shader are independant
72 quads, rebuild them as forward facing sprites
73 =====================
74 */
75 static void R_AutospriteDeform( drawSurf_t *surf ) {
76         int             i;
77         const idDrawVert        *v;
78         idVec3  mid, delta;
79         float   radius;
80         idVec3  left, up;
81         idVec3  leftDir, upDir;
82         const srfTriangles_t    *tri;
83         srfTriangles_t  *newTri;
84
85         tri = surf->geo;
86
87         if ( tri->numVerts & 3 ) {
88                 common->Warning( "R_AutospriteDeform: shader had odd vertex count" );
89                 return;
90         }
91         if ( tri->numIndexes != ( tri->numVerts >> 2 ) * 6 ) {
92                 common->Warning( "R_AutospriteDeform: autosprite had odd index count" );
93                 return;
94         }
95
96         R_GlobalVectorToLocal( surf->space->modelMatrix, tr.viewDef->renderView.viewaxis[1], leftDir );
97         R_GlobalVectorToLocal( surf->space->modelMatrix, tr.viewDef->renderView.viewaxis[2], upDir );
98
99         if ( tr.viewDef->isMirror ) {
100                 leftDir = vec3_origin - leftDir;
101         }
102
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] ) );
109
110         idDrawVert      *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
111
112         for ( i = 0 ; i < tri->numVerts ; i+=4 ) {
113                 // find the midpoint
114                 v = &tri->verts[i];
115
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]);
119
120                 delta = v->xyz - mid;
121                 radius = delta.Length() * 0.707;                // / sqrt(2)
122
123                 left = leftDir * radius;
124                 up = upDir * radius;
125
126                 ac[i+0].xyz = mid + left + up;
127                 ac[i+0].st[0] = 0;
128                 ac[i+0].st[1] = 0;
129                 ac[i+1].xyz = mid - left + up;
130                 ac[i+1].st[0] = 1;
131                 ac[i+1].st[1] = 0;
132                 ac[i+2].xyz = mid - left - up;
133                 ac[i+2].st[0] = 1;
134                 ac[i+2].st[1] = 1;
135                 ac[i+3].xyz = mid + left - up;
136                 ac[i+3].st[0] = 0;
137                 ac[i+3].st[1] = 1;
138
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;
142
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;
146         }
147
148         R_FinishDeform( surf, newTri, ac );
149 }
150
151 /*
152 =====================
153 R_TubeDeform
154
155 will pivot a rectangular quad along the center of its long axis
156
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 =====================
162 */
163 static void R_TubeDeform( drawSurf_t *surf ) {
164         int             i, j;
165         int             indexes;
166         const srfTriangles_t *tri;
167 static int edgeVerts[6][2] = {
168         { 0, 1 },
169         { 1, 2 },
170         { 2, 0 },
171         { 3, 4 },
172         { 4, 5 },
173         { 5, 3 }
174 };
175
176         tri = surf->geo;
177
178         if ( tri->numVerts & 3 ) {
179                 common->Error( "R_AutospriteDeform: shader had odd vertex count" );
180         }
181         if ( tri->numIndexes != ( tri->numVerts >> 2 ) * 6 ) {
182                 common->Error( "R_AutospriteDeform: autosprite had odd index count" );
183         }
184
185         // we need the view direction to project the minor axis of the tube
186         // as the view changes
187         idVec3  localView;
188         R_GlobalPointToLocal( surf->space->modelMatrix, tr.viewDef->renderView.vieworg, localView ); 
189
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] ) );
197
198         idDrawVert      *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
199         memset( ac, 0, sizeof( idDrawVert ) * newTri->numVerts );
200
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 ) {
205                 float   lengths[2];
206                 int             nums[2];
207                 idVec3  mid[2];
208                 idVec3  major, minor;
209                 const idDrawVert *v1, *v2;
210
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;
214
215                 for ( j = 0 ; j < 6 ; j++ ) {
216                         float   l;
217
218                         v1 = &tri->verts[tri->indexes[i+edgeVerts[j][0]]];
219                         v2 = &tri->verts[tri->indexes[i+edgeVerts[j][1]]];
220
221                         l = ( v1->xyz - v2->xyz ).Length();
222                         if ( l < lengths[0] ) {
223                                 nums[1] = nums[0];
224                                 lengths[1] = lengths[0];
225                                 nums[0] = j;
226                                 lengths[0] = l;
227                         } else if ( l < lengths[1] ) {
228                                 nums[1] = j;
229                                 lengths[1] = l;
230                         }
231                 }
232
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]]];
238
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]);
242                 }
243
244                 // find the vector of the major axis
245                 major = mid[1] - mid[0];
246
247                 // re-project the points
248                 for ( j = 0 ; j < 2 ; j++ ) {
249                         float   l;
250                         int     i1 = tri->indexes[i+edgeVerts[nums[j]][0]];
251                         int     i2 = tri->indexes[i+edgeVerts[nums[j]][1]];
252
253                         idDrawVert *av1 = &ac[i1];
254                         idDrawVert *av2 = &ac[i2];
255
256                         *av1 = *(idDrawVert *)&tri->verts[i1];
257                         *av2 = *(idDrawVert *)&tri->verts[i2];
258
259                         l = 0.5 * lengths[j];
260                         
261                         // cross this with the view direction to get minor axis
262                         idVec3  dir = mid[j] - localView;
263                         minor.Cross( major, dir );
264                         minor.Normalize();
265
266                         if ( j ) {
267                                 av1->xyz = mid[j] - l * minor;
268                                 av2->xyz = mid[j] + l * minor;
269                         } else {
270                                 av1->xyz = mid[j] + l * minor;
271                                 av2->xyz = mid[j] - l * minor;
272                         }
273                 }
274         }
275
276         R_FinishDeform( surf, newTri, ac );
277 }
278
279 /*
280 =====================
281 R_WindingFromTriangles
282
283 =====================
284 */
285 #define MAX_TRI_WINDING_INDEXES         16
286 int     R_WindingFromTriangles( const srfTriangles_t *tri, glIndex_t indexes[MAX_TRI_WINDING_INDEXES] ) {
287         int                     i, j, k, l;
288
289         indexes[0] = tri->indexes[0];
290         int numIndexes = 1;
291         int     numTris = tri->numIndexes / 3;
292
293         do {
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] ) {
299                                         continue;
300                                 }
301                                 int             next = tri->indexes[i*3+(j+1)%3];
302
303                                 // make sure it isn't already used
304                                 if ( numIndexes == 1 ) {
305                                         if ( next == indexes[0] ) {
306                                                 continue;
307                                         }
308                                 } else {
309                                         for ( k = 1 ; k < numIndexes ; k++ ) {
310                                                 if ( indexes[k] == next ) {
311                                                         break;
312                                                 }
313                                         }
314                                         if ( k != numIndexes ) {
315                                                 continue;
316                                         }
317                                 }
318
319                                 // make sure it isn't an interior edge
320                                 for ( k = 0 ; k < numTris ; k++ ) {
321                                         if ( k == i ) {
322                                                 continue;
323                                         }
324                                         for ( l = 0 ; l < 3 ; l++ ) {
325                                                 int     a, b;
326
327                                                 a = tri->indexes[k*3+l];
328                                                 if ( a != next ) {
329                                                         continue;
330                                                 }
331                                                 b = tri->indexes[k*3+(l+1)%3];
332                                                 if ( b != indexes[numIndexes-1] ) {
333                                                         continue;
334                                                 }
335
336                                                 // this is an interior edge
337                                                 break;
338                                         }
339                                         if ( l != 3 ) {
340                                                 break;
341                                         }
342                                 }
343                                 if ( k != numTris ) {
344                                         continue;
345                                 }
346
347                                 // add this to the list
348                                 indexes[numIndexes] = next;
349                                 numIndexes++;
350                                 break;
351                         }
352                         if ( j != 3 ) {
353                                 break;
354                         }
355                 }
356                 if ( numIndexes == tri->numVerts ) {
357                         break;
358                 }
359         } while ( i != numTris );
360
361         return numIndexes;
362 }
363
364 /*
365 =====================
366 R_FlareDeform
367
368 =====================
369 */
370 /*
371 static void R_FlareDeform( drawSurf_t *surf ) {
372         const srfTriangles_t *tri;
373         srfTriangles_t          *newTri;
374         idPlane plane;
375         float   dot;
376         idVec3  localViewer;
377         int             j;
378
379         tri = surf->geo;
380
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" );
384                 return;
385         }
386
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] ) );
393         
394         idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
395
396         // find the plane
397         plane.FromPoints( tri->verts[tri->indexes[0]].xyz, tri->verts[tri->indexes[1]].xyz, tri->verts[tri->indexes[2]].xyz );
398
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;
404                 surf->geo = newTri;
405                 return;
406         }
407
408         idVec3  center;
409         center = tri->verts[0].xyz;
410         for ( j = 1 ; j < tri->numVerts ; j++ ) {
411                 center += tri->verts[j].xyz;
412         }
413         center *= 1.0/tri->numVerts;
414
415         idVec3  dir = localViewer - center;
416         dir.Normalize();
417
418         dot = dir * plane.Normal();
419
420         // set vertex colors based on plane angle
421         int     color = (int)(dot * 8 * 256);
422         if ( color > 255 ) {
423                 color = 255;
424         }
425         for ( j = 0 ; j < newTri->numVerts ; j++ ) {
426                 ac[j].color[0] =
427                 ac[j].color[1] =
428                 ac[j].color[2] = color;
429                 ac[j].color[3] = 255;
430         }
431
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 );
436
437         surf->material = declManager->FindMaterial( "textures/smf/anamorphicFlare" );
438
439         // only deal with quads
440         if ( numIndexes != 4 ) {
441                 return;
442         }
443
444         // compute centroid
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;
449         }
450         centroid /= 4;
451
452         // compute basis vectors
453         up.Set( 0, 0, 1 );
454
455         toeye = centroid - localViewer;
456         toeye.Normalize();
457         left = toeye.Cross( up );
458         up = left.Cross( toeye );
459
460         left = left * 40 * 6;
461         up = up * 40;
462
463         // compute flares
464         struct flare_t {
465                 float   angle;
466                 float   length;
467         };
468
469         static flare_t flares[] = {
470                 { 0, 100 },
471                 { 90, 100 }
472         };
473
474         for ( int i = 0; i < 4; i++ ) {
475                 memset( ac + i, 0, sizeof( ac[i] ) );
476         }
477
478         ac[0].xyz = centroid - left;
479         ac[0].st[0] = 0; ac[0].st[1] = 0;
480
481         ac[1].xyz = centroid + up;
482         ac[1].st[0] = 1; ac[1].st[1] = 0;
483
484         ac[2].xyz = centroid + left;
485         ac[2].st[0] = 1; ac[2].st[1] = 1;
486
487         ac[3].xyz = centroid - up;
488         ac[3].st[0] = 0; ac[3].st[1] = 1;
489
490         // setup colors
491         for ( j = 0 ; j < newTri->numVerts ; j++ ) {
492                 ac[j].color[0] =
493                 ac[j].color[1] =
494                 ac[j].color[2] = 255;
495                 ac[j].color[3] = 255;
496         }
497
498         // setup indexes
499         static glIndex_t        triIndexes[2*3] = {
500                 0,1,2,  0,2,3
501         };
502
503         memcpy( newTri->indexes, triIndexes, sizeof( triIndexes ) );
504
505         R_FinishDeform( surf, newTri, ac );
506 }
507 */
508
509 static void R_FlareDeform( drawSurf_t *surf ) {
510         const srfTriangles_t *tri;
511         srfTriangles_t          *newTri;
512         idPlane plane;
513         float   dot;
514         idVec3  localViewer;
515         int             j;
516
517         tri = surf->geo;
518
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" );
522                 return;
523         }
524
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] ) );
531         
532         idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
533
534         // find the plane
535         plane.FromPoints( tri->verts[tri->indexes[0]].xyz, tri->verts[tri->indexes[1]].xyz, tri->verts[tri->indexes[2]].xyz );
536
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;
542                 surf->geo = newTri;
543                 return;
544         }
545
546         idVec3  center;
547         center = tri->verts[0].xyz;
548         for ( j = 1 ; j < tri->numVerts ; j++ ) {
549                 center += tri->verts[j].xyz;
550         }
551         center *= 1.0/tri->numVerts;
552
553         idVec3  dir = localViewer - center;
554         dir.Normalize();
555
556         dot = dir * plane.Normal();
557
558         // set vertex colors based on plane angle
559         int     color = (int)(dot * 8 * 256);
560         if ( color > 255 ) {
561                 color = 255;
562         }
563         for ( j = 0 ; j < newTri->numVerts ; j++ ) {
564                 ac[j].color[0] =
565                 ac[j].color[1] =
566                 ac[j].color[2] = color;
567                 ac[j].color[3] = 255;
568         }
569
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 );
574
575
576         // only deal with quads
577         if ( numIndexes != 4 ) {
578                 return;
579         }
580         int i;
581         // calculate vector directions
582         for ( i = 0 ; i < 4 ; i++ ) {
583                 ac[i].xyz = tri->verts[ indexes[i] ].xyz;
584                 ac[i].st[0] =
585                 ac[i].st[1] = 0.5;
586
587                 idVec3  toEye = tri->verts[ indexes[i] ].xyz - localViewer;
588                 toEye.Normalize();
589
590                 idVec3  d1 = tri->verts[ indexes[(i+1)%4] ].xyz - localViewer; 
591                 d1.Normalize();
592                 edgeDir[i][1].Cross( toEye, d1 );
593                 edgeDir[i][1].Normalize();
594                 edgeDir[i][1] = vec3_origin - edgeDir[i][1];
595
596                 idVec3  d2 = tri->verts[ indexes[(i+3)%4] ].xyz - localViewer; 
597                 d2.Normalize();
598                 edgeDir[i][0].Cross( toEye, d2 );
599                 edgeDir[i][0].Normalize();
600
601                 edgeDir[i][2] = edgeDir[i][0] + edgeDir[i][1];
602                 edgeDir[i][2].Normalize();
603         }
604
605         // build all the points
606         ac[4].xyz = tri->verts[ indexes[0] ].xyz + spread * edgeDir[0][0];
607         ac[4].st[0] = 0;
608         ac[4].st[1] = 0.5;
609
610         ac[5].xyz = tri->verts[ indexes[0] ].xyz + spread * edgeDir[0][2];
611         ac[5].st[0] = 0;
612         ac[5].st[1] = 0;
613
614         ac[6].xyz = tri->verts[ indexes[0] ].xyz + spread * edgeDir[0][1];
615         ac[6].st[0] = 0.5;
616         ac[6].st[1] = 0;
617
618
619         ac[7].xyz = tri->verts[ indexes[1] ].xyz + spread * edgeDir[1][0];
620         ac[7].st[0] = 0.5;
621         ac[7].st[1] = 0;
622
623         ac[8].xyz = tri->verts[ indexes[1] ].xyz + spread * edgeDir[1][2];
624         ac[8].st[0] = 1;
625         ac[8].st[1] = 0;
626
627         ac[9].xyz = tri->verts[ indexes[1] ].xyz + spread * edgeDir[1][1];
628         ac[9].st[0] = 1;
629         ac[9].st[1] = 0.5;
630
631
632         ac[10].xyz = tri->verts[ indexes[2] ].xyz + spread * edgeDir[2][0];
633         ac[10].st[0] = 1;
634         ac[10].st[1] = 0.5;
635
636         ac[11].xyz = tri->verts[ indexes[2] ].xyz + spread * edgeDir[2][2];
637         ac[11].st[0] = 1;
638         ac[11].st[1] = 1;
639
640         ac[12].xyz = tri->verts[ indexes[2] ].xyz + spread * edgeDir[2][1];
641         ac[12].st[0] = 0.5;
642         ac[12].st[1] = 1;
643
644
645         ac[13].xyz = tri->verts[ indexes[3] ].xyz + spread * edgeDir[3][0];
646         ac[13].st[0] = 0.5;
647         ac[13].st[1] = 1;
648
649         ac[14].xyz = tri->verts[ indexes[3] ].xyz + spread * edgeDir[3][2];
650         ac[14].st[0] = 0;
651         ac[14].st[1] = 1;
652
653         ac[15].xyz = tri->verts[ indexes[3] ].xyz + spread * edgeDir[3][1];
654         ac[15].st[0] = 0;
655         ac[15].st[1] = 0.5;
656
657         for ( i = 4 ; i < 16 ; i++ ) {
658                 idVec3  dir = ac[i].xyz - localViewer;
659                 float len = dir.Normalize();
660
661                 float ang = dir * plane.Normal();
662
663 //              ac[i].xyz -= dir * spread * 2;
664                 float newLen = -( distFromPlane / ang );
665
666                 if ( newLen > 0 && newLen < len ) {
667                         ac[i].xyz = localViewer + dir * newLen;
668                 }
669
670                 ac[i].st[0] = 0;
671                 ac[i].st[1] = 0.5;
672         }
673
674 #if 1
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
679         };
680 #else
681         newTri->numIndexes = 12;
682         static glIndex_t triIndexes[4*3] = {
683                 0,1,2, 0,2,3, 0,4,5,0,5,6
684         };
685 #endif
686
687         memcpy( newTri->indexes, triIndexes, sizeof( triIndexes ) );
688
689         R_FinishDeform( surf, newTri, ac );
690 }
691
692
693
694 /*
695 =====================
696 R_ExpandDeform
697
698 Expands the surface along it's normals by a shader amount
699 =====================
700 */
701 static void R_ExpandDeform( drawSurf_t *surf ) {
702         int             i;
703         const srfTriangles_t    *tri;
704         srfTriangles_t  *newTri;
705
706         tri = surf->geo;
707
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;
714
715         idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
716
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;
721         }
722
723         R_FinishDeform( surf, newTri, ac );
724 }
725
726 /*
727 =====================
728 R_MoveDeform
729
730 Moves the surface along the X axis, mostly just for demoing the deforms
731 =====================
732 */
733 static void  R_MoveDeform( drawSurf_t *surf ) {
734         int             i;
735         const srfTriangles_t    *tri;
736         srfTriangles_t  *newTri;
737
738         tri = surf->geo;
739
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;
746
747         idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
748
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;
753         }
754
755         R_FinishDeform( surf, newTri, ac );
756 }
757
758 //=====================================================================================
759
760 /*
761 =====================
762 R_TurbulentDeform
763
764 Turbulently deforms the XYZ, S, and T values
765 =====================
766 */
767 static void  R_TurbulentDeform( drawSurf_t *surf ) {
768         int             i;
769         const srfTriangles_t    *tri;
770         srfTriangles_t  *newTri;
771
772         tri = surf->geo;
773
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;
780
781         idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) );
782
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) ];
787         float tOfs = 0.5;
788
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;
791
792                 f = timeOfs + domain * f;
793                 f += timeOfs;
794
795                 ac[i] = *(idDrawVert *)&tri->verts[i];
796
797                 ac[i].st[0] += range * table->TableLookup( f );
798                 ac[i].st[1] += range * table->TableLookup( f + tOfs );
799         }
800
801         R_FinishDeform( surf, newTri, ac );
802 }
803
804 //=====================================================================================
805
806 /*
807 =====================
808 AddTriangleToIsland_r
809
810 =====================
811 */
812 #define MAX_EYEBALL_TRIS        10
813 #define MAX_EYEBALL_ISLANDS     6
814
815 typedef struct {
816         int             tris[MAX_EYEBALL_TRIS];
817         int             numTris;
818         idBounds        bounds;
819         idVec3          mid;
820 } eyeIsland_t;
821
822 static void AddTriangleToIsland_r( const srfTriangles_t *tri, int triangleNum, bool *usedList, eyeIsland_t *island ) {
823         int             a, b, c;
824
825         usedList[triangleNum] = true;
826
827         // add to the current island
828         if ( island->numTris == MAX_EYEBALL_TRIS ) {
829                 common->Error( "MAX_EYEBALL_TRIS" );
830         }
831         island->tris[island->numTris] = triangleNum;
832         island->numTris++;
833
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];
838
839         island->bounds.AddPoint( tri->verts[a].xyz );
840         island->bounds.AddPoint( tri->verts[b].xyz );
841         island->bounds.AddPoint( tri->verts[c].xyz );
842
843         int     numTri = tri->numIndexes / 3;
844         for ( int i = 0 ; i < numTri ; i++ ) {
845                 if ( usedList[i] ) {
846                         continue;
847                 }
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 );
858                 }
859         }
860 }
861
862 /*
863 =====================
864 R_EyeballDeform
865
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 =====================
869 */
870 static void R_EyeballDeform( drawSurf_t *surf ) {
871         int             i, j, k;
872         const srfTriangles_t    *tri;
873         srfTriangles_t  *newTri;
874         eyeIsland_t     islands[MAX_EYEBALL_ISLANDS];
875         int                     numIslands;
876         bool            triUsed[MAX_EYEBALL_ISLANDS*MAX_EYEBALL_TRIS];
877
878         tri = surf->geo;
879
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" );
884                 return;
885         }
886         memset( triUsed, 0, sizeof( triUsed ) );
887
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++ ) {
892                         if ( !triUsed[i] ) {
893                                 AddTriangleToIsland_r( tri, i, triUsed, &islands[numIslands] );
894                                 break;
895                         }
896                 }
897                 if ( i == numTri ) {
898                         break;
899                 }
900         }
901
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 );
905                 return;
906         }
907
908         // this srfTriangles_t and all its indexes and caches are in frame
909         // memory, and will be automatically disposed of
910
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 ) );
918
919         newTri->numIndexes = 0;
920
921         // decide which islands are the eyes and points
922         for ( i = 0 ; i < numIslands ; i++ ) {
923                 islands[i].mid = islands[i].bounds.GetCenter();
924         }
925
926         for ( i = 0 ; i < numIslands ; i++ ) {
927                 eyeIsland_t             *island = &islands[i];
928
929                 if ( island->numTris == 1 ) {
930                         continue;
931                 }
932
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];
939
940                 for ( j = 0 ; j < numIslands ; j++ ) {
941                         idVec3  dir = islands[j].mid - island->mid;
942                         dist[j] = dir.Length();
943                         sortOrder[j] = j;
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];
950                                         dist[k] = dist[k+1];
951                                         dist[k+1] = ftemp;
952                                 }
953                         }
954                 }
955
956                 originIsland = sortOrder[1];
957                 origin = islands[originIsland].mid;
958
959                 focus = islands[sortOrder[2]].mid;
960
961                 // determine the projection directions based on the origin island triangle
962                 idVec3  dir = focus - origin;
963                 dir.Normalize();
964
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;
968
969                 idVec3  v1 = p2 - p1;
970                 v1.Normalize();
971                 idVec3  v2 = p3 - p1;
972                 v2.Normalize();
973
974                 // texVec[0] will be the normal to the origin triangle
975                 idVec3  texVec[2];
976
977                 texVec[0].Cross( v1, v2 );
978
979                 texVec[1].Cross( texVec[0], dir );
980
981                 for ( j = 0 ; j < 2 ; j++ ) {
982                         texVec[j] -= dir * ( texVec[j] * dir );
983                         texVec[j].Normalize();
984                 }
985
986                 // emit these triangles, generating the projected texcoords
987
988                 for ( j = 0 ; j < islands[i].numTris ; j++ ) {
989                         for ( k = 0 ; k < 3 ; k++ ) {
990                                 int     index = islands[i].tris[j] * 3;
991
992                                 index = tri->indexes[index+k];
993                                 newTri->indexes[newTri->numIndexes++] = index;
994
995                                 ac[index].xyz = tri->verts[index].xyz;
996
997                                 idVec3  local = tri->verts[index].xyz - origin;
998
999                                 ac[index].st[0] = 0.5 + local * texVec[0];
1000                                 ac[index].st[1] = 0.5 + local * texVec[1];
1001                         }
1002                 }
1003         }
1004
1005         R_FinishDeform( surf, newTri, ac );
1006 }
1007
1008 //==========================================================================================
1009
1010
1011 /*
1012 =====================
1013 R_ParticleDeform
1014
1015 Emit particles from the surface instead of drawing it
1016 =====================
1017 */
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();
1022
1023         if ( r_skipParticles.GetBool() ) {
1024                 return;
1025         }
1026
1027 #if 0
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
1031                 return NULL;
1032         }
1033 #endif
1034
1035         //
1036         // calculate the area of all the triangles
1037         //
1038         int             numSourceTris = surf->geo->numIndexes / 3;
1039         float   totalArea = 0;
1040         float   *sourceTriAreas = NULL;
1041         const srfTriangles_t    *srcTri = surf->geo;
1042
1043         if ( useArea ) {
1044                 sourceTriAreas = (float *)_alloca( sizeof( *sourceTriAreas ) * numSourceTris );
1045                 int     triNum = 0;
1046                 for ( int i = 0 ; i < srcTri->numIndexes ; i += 3, triNum++ ) {
1047                         float   area;
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;
1050                         totalArea += area;
1051                 }
1052         }
1053
1054         //
1055         // create the particles almost exactly the way idRenderModelPrt does
1056         //
1057         particleGen_t g;
1058
1059         g.renderEnt = renderEntity;
1060         g.renderView = &viewDef->renderView;
1061         g.origin.Zero();
1062         g.axis = mat3_identity;
1063
1064         for ( int currentTri = 0; currentTri < ( ( useArea ) ? 1 : numSourceTris ); currentTri++ ) {
1065
1066                 for ( int stageNum = 0 ; stageNum < particleSystem->stages.Num() ; stageNum++ ) {
1067                         idParticleStage *stage = particleSystem->stages[stageNum];
1068
1069                         if ( !stage->material ) {
1070                                 continue;
1071                         }
1072                         if ( !stage->cycleMsec ) {
1073                                 continue;
1074                         }
1075                         if ( stage->hidden ) {          // just for gui particle editor use
1076                                 continue;
1077                         }
1078
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 );
1082
1083                         int     count = totalParticles * stage->NumQuadsPerParticle();
1084
1085                         // allocate a srfTriangles in temp memory that can hold all the particles
1086                         srfTriangles_t  *tri;
1087
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] ) );
1093
1094                         // just always draw the particles
1095                         tri->bounds = stage->bounds;
1096
1097                         tri->numVerts = 0;
1098
1099                         idRandom        steppingRandom, steppingRandom2;
1100
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;
1104
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 )  );
1108
1109                         for ( int index = 0 ; index < totalParticles ; index++ ) {
1110                                 g.index = index;
1111
1112                                 // bump the random
1113                                 steppingRandom.RandomInt();
1114                                 steppingRandom2.RandomInt();
1115
1116                                 // calculate local age for this index 
1117                                 int     bunchOffset = stage->particleLife * 1000 * stage->spawnBunching * index / totalParticles;
1118
1119                                 int particleAge = stageAge - bunchOffset;
1120                                 int     particleCycle = particleAge / stage->cycleMsec;
1121                                 if ( particleCycle < 0 ) {
1122                                         // before the particleSystem spawned
1123                                         continue;
1124                                 }
1125                                 if ( stage->cycles && particleCycle >= stage->cycles ) {
1126                                         // cycled systems will only run cycle times
1127                                         continue;
1128                                 }
1129
1130                                 if ( particleCycle == stageCycle ) {
1131                                         g.random = steppingRandom;
1132                                 } else {
1133                                         g.random = steppingRandom2;
1134                                 }
1135
1136                                 int     inCycleTime = particleAge - particleCycle * stage->cycleMsec;
1137
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
1141                                         continue;
1142                                 }
1143
1144                                 // supress particles before or after the age clamp
1145                                 g.frac = (float)inCycleTime / ( stage->particleLife * 1000 );
1146                                 if ( g.frac < 0 ) {
1147                                         // yet to be spawned
1148                                         continue;
1149                                 }
1150                                 if ( g.frac > 1.0 ) {
1151                                         // this particle is in the deadTime band
1152                                         continue;
1153                                 }
1154
1155                                 //---------------
1156                                 // locate the particle origin and axis somewhere on the surface
1157                                 //---------------
1158
1159                                 int pointTri = currentTri;
1160
1161                                 if ( useArea ) {
1162                                         // select a triangle based on an even area distribution
1163                                         pointTri = idBinSearch_LessEqual<float>( sourceTriAreas, numSourceTris, g.random.RandomFloat() * totalArea );
1164                                 }
1165
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 ] ];
1170
1171                                 float   f1 = g.random.RandomFloat();
1172                                 float   f2 = g.random.RandomFloat();
1173                                 float   f3 = g.random.RandomFloat();
1174
1175                                 float   ft = 1.0f / ( f1 + f2 + f3 + 0.0001f );
1176
1177                                 f1 *= ft;
1178                                 f2 *= ft;
1179                                 f3 *= ft;
1180
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;
1185
1186                                 //-----------------------
1187
1188                                 // this is needed so aimed particles can calculate origins at different times
1189                                 g.originalRandom = g.random;
1190
1191                                 g.age = g.frac * stage->particleLife;
1192
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 );
1196                         }
1197         
1198                         if ( tri->numVerts > 0 ) {
1199                                 // build the index list
1200                                 int     indexes = 0;
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;
1208                                         indexes += 6;
1209                                 }
1210                                 tri->numIndexes = indexes;
1211                                 tri->ambientCache = vertexCache.AllocFrameTemp( tri->verts, tri->numVerts * sizeof( idDrawVert ) );
1212                                 if ( tri->ambientCache ) {
1213                                         // add the drawsurf
1214                                         R_AddDrawSurf( tri, surf->space, renderEntity, stage->material, surf->scissorRect );
1215                                 }
1216                         }
1217                 }
1218         }
1219 }
1220
1221 //========================================================================================
1222
1223 /*
1224 =================
1225 R_DeformDrawSurf
1226 =================
1227 */
1228 void R_DeformDrawSurf( drawSurf_t *drawSurf ) {
1229         if ( !drawSurf->material ) {
1230                 return;
1231         }
1232
1233         if ( r_skipDeforms.GetBool() ) {
1234                 return;
1235         }
1236         switch ( drawSurf->material->Deform() ) {
1237         case DFRM_NONE:
1238                 return;
1239         case DFRM_SPRITE:
1240                 R_AutospriteDeform( drawSurf );
1241                 break;
1242         case DFRM_TUBE:
1243                 R_TubeDeform( drawSurf );
1244                 break;
1245         case DFRM_FLARE:
1246                 R_FlareDeform( drawSurf );
1247                 break;
1248         case DFRM_EXPAND:
1249                 R_ExpandDeform( drawSurf );
1250                 break;
1251         case DFRM_MOVE:
1252                 R_MoveDeform( drawSurf );
1253                 break;
1254         case DFRM_TURB:
1255                 R_TurbulentDeform( drawSurf );
1256                 break;
1257         case DFRM_EYEBALL:
1258                 R_EyeballDeform( drawSurf );
1259                 break;
1260         case DFRM_PARTICLE:
1261                 R_ParticleDeform( drawSurf, true );
1262                 break;
1263         case DFRM_PARTICLE2:
1264                 R_ParticleDeform( drawSurf, false );
1265                 break;
1266         }
1267 }