]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/renderer/GuiModel.cpp
hello world
[icculus/iodoom3.git] / neo / renderer / GuiModel.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 idGuiModel::idGuiModel
38 ================
39 */
40 idGuiModel::idGuiModel() {
41         indexes.SetGranularity( 1000 );
42         verts.SetGranularity( 1000 );
43 }
44
45 /*
46 ================
47 idGuiModel::Clear
48
49 Begins collecting draw commands into surfaces
50 ================
51 */
52 void idGuiModel::Clear() {
53         surfaces.SetNum( 0, false );
54         indexes.SetNum( 0, false );
55         verts.SetNum( 0, false );
56         AdvanceSurf();
57 }
58
59 /*
60 ================
61 idGuiModel::WriteToDemo
62 ================
63 */
64 void idGuiModel::WriteToDemo( idDemoFile *demo ) {
65         int             i, j;
66
67         i = verts.Num();
68         demo->WriteInt( i );
69         for ( j = 0; j < i; j++ )
70         {
71                 demo->WriteVec3( verts[j].xyz );
72                 demo->WriteVec2( verts[j].st );
73                 demo->WriteVec3( verts[j].normal );
74                 demo->WriteVec3( verts[j].tangents[0] );
75                 demo->WriteVec3( verts[j].tangents[1] );
76                 demo->WriteUnsignedChar( verts[j].color[0] );
77                 demo->WriteUnsignedChar( verts[j].color[1] );
78                 demo->WriteUnsignedChar( verts[j].color[2] );
79                 demo->WriteUnsignedChar( verts[j].color[3] );
80         }
81         
82         i = indexes.Num();
83         demo->WriteInt( i );
84         for ( j = 0; j < i; j++ ) {
85                 demo->WriteInt(indexes[j] );
86         }
87         
88         i = surfaces.Num();
89         demo->WriteInt( i );
90         for ( j = 0 ; j < i ; j++ ) {
91                 guiModelSurface_t       *surf = &surfaces[j];
92                 
93                 demo->WriteInt( (int&)surf->material );
94                 demo->WriteFloat( surf->color[0] );
95                 demo->WriteFloat( surf->color[1] );
96                 demo->WriteFloat( surf->color[2] );
97                 demo->WriteFloat( surf->color[3] );
98                 demo->WriteInt( surf->firstVert );
99                 demo->WriteInt( surf->numVerts );
100                 demo->WriteInt( surf->firstIndex );
101                 demo->WriteInt( surf->numIndexes );
102                 demo->WriteHashString( surf->material->GetName() );
103         }
104 }
105
106 /*
107 ================
108 idGuiModel::ReadFromDemo
109 ================
110 */
111 void idGuiModel::ReadFromDemo( idDemoFile *demo ) {
112         int             i, j;
113
114         i = verts.Num();
115         demo->ReadInt( i );
116         verts.SetNum( i, false );
117         for ( j = 0; j < i; j++ )
118         {
119                 demo->ReadVec3( verts[j].xyz );
120                 demo->ReadVec2( verts[j].st );
121                 demo->ReadVec3( verts[j].normal );
122                 demo->ReadVec3( verts[j].tangents[0] );
123                 demo->ReadVec3( verts[j].tangents[1] );
124                 demo->ReadUnsignedChar( verts[j].color[0] );
125                 demo->ReadUnsignedChar( verts[j].color[1] );
126                 demo->ReadUnsignedChar( verts[j].color[2] );
127                 demo->ReadUnsignedChar( verts[j].color[3] );
128         }
129         
130         i = indexes.Num();
131         demo->ReadInt( i );
132         indexes.SetNum( i, false );
133         for ( j = 0; j < i; j++ ) {
134                 demo->ReadInt(indexes[j] );
135         }
136         
137         i = surfaces.Num();
138         demo->ReadInt( i );
139         surfaces.SetNum( i, false );
140         for ( j = 0 ; j < i ; j++ ) {
141                 guiModelSurface_t       *surf = &surfaces[j];
142                 
143                 demo->ReadInt( (int&)surf->material );
144                 demo->ReadFloat( surf->color[0] );
145                 demo->ReadFloat( surf->color[1] );
146                 demo->ReadFloat( surf->color[2] );
147                 demo->ReadFloat( surf->color[3] );
148                 demo->ReadInt( surf->firstVert );
149                 demo->ReadInt( surf->numVerts );
150                 demo->ReadInt( surf->firstIndex );
151                 demo->ReadInt( surf->numIndexes );
152                 surf->material = declManager->FindMaterial( demo->ReadHashString() );
153         }
154 }
155
156 /*
157 ================
158 EmitSurface
159 ================
160 */
161 void idGuiModel::EmitSurface( guiModelSurface_t *surf, float modelMatrix[16], float modelViewMatrix[16], bool depthHack ) {
162         srfTriangles_t  *tri;
163
164         if ( surf->numVerts == 0 ) {
165                 return;         // nothing in the surface
166         }
167
168         // copy verts and indexes
169         tri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *tri ) );
170
171         tri->numIndexes = surf->numIndexes;
172         tri->numVerts = surf->numVerts;
173         tri->indexes = (glIndex_t *)R_FrameAlloc( tri->numIndexes * sizeof( tri->indexes[0] ) );
174         memcpy( tri->indexes, &indexes[surf->firstIndex], tri->numIndexes * sizeof( tri->indexes[0] ) );
175
176         // we might be able to avoid copying these and just let them reference the list vars
177         // but some things, like deforms and recursive
178         // guis, need to access the verts in cpu space, not just through the vertex range
179         tri->verts = (idDrawVert *)R_FrameAlloc( tri->numVerts * sizeof( tri->verts[0] ) );
180         memcpy( tri->verts, &verts[surf->firstVert], tri->numVerts * sizeof( tri->verts[0] ) );
181
182         // move the verts to the vertex cache
183         tri->ambientCache = vertexCache.AllocFrameTemp( tri->verts, tri->numVerts * sizeof( tri->verts[0] ) );
184
185         // if we are out of vertex cache, don't create the surface
186         if ( !tri->ambientCache ) {
187                 return;
188         }
189
190         renderEntity_t renderEntity;
191         memset( &renderEntity, 0, sizeof( renderEntity ) );
192         memcpy( renderEntity.shaderParms, surf->color, sizeof( surf->color ) );
193
194         viewEntity_t *guiSpace = (viewEntity_t *)R_ClearedFrameAlloc( sizeof( *guiSpace ) );
195         memcpy( guiSpace->modelMatrix, modelMatrix, sizeof( guiSpace->modelMatrix ) );
196         memcpy( guiSpace->modelViewMatrix, modelViewMatrix, sizeof( guiSpace->modelViewMatrix ) );
197         guiSpace->weaponDepthHack = depthHack;
198
199         // add the surface, which might recursively create another gui
200         R_AddDrawSurf( tri, guiSpace, &renderEntity, surf->material, tr.viewDef->scissor );
201 }
202
203 /*
204 ====================
205 EmitToCurrentView
206 ====================
207 */
208 void idGuiModel::EmitToCurrentView( float modelMatrix[16], bool depthHack ) {
209         float   modelViewMatrix[16];
210
211         myGlMultMatrix( modelMatrix, tr.viewDef->worldSpace.modelViewMatrix, 
212                         modelViewMatrix );
213
214         for ( int i = 0 ; i < surfaces.Num() ; i++ ) {
215                 EmitSurface( &surfaces[i], modelMatrix, modelViewMatrix, depthHack );
216         }
217 }
218
219 /*
220 ================
221 idGuiModel::EmitFullScreen
222
223 Creates a view that covers the screen and emit the surfaces
224 ================
225 */
226 void idGuiModel::EmitFullScreen( void ) {
227         viewDef_t       *viewDef;
228
229         if ( surfaces[0].numVerts == 0 ) {
230                 return;
231         }
232
233         viewDef = (viewDef_t *)R_ClearedFrameAlloc( sizeof( *viewDef ) );
234
235         // for gui editor
236         if ( !tr.viewDef || !tr.viewDef->isEditor ) {
237                 viewDef->renderView.x = 0;
238                 viewDef->renderView.y = 0;
239                 viewDef->renderView.width = SCREEN_WIDTH;
240                 viewDef->renderView.height = SCREEN_HEIGHT;
241
242                 tr.RenderViewToViewport( &viewDef->renderView, &viewDef->viewport );
243
244                 viewDef->scissor.x1 = 0;
245                 viewDef->scissor.y1 = 0;
246                 viewDef->scissor.x2 = viewDef->viewport.x2 - viewDef->viewport.x1;
247                 viewDef->scissor.y2 = viewDef->viewport.y2 - viewDef->viewport.y1;
248         } else {
249                 viewDef->renderView.x = tr.viewDef->renderView.x;
250                 viewDef->renderView.y = tr.viewDef->renderView.y;
251                 viewDef->renderView.width = tr.viewDef->renderView.width;
252                 viewDef->renderView.height = tr.viewDef->renderView.height;
253                 
254                 viewDef->viewport.x1 = tr.viewDef->renderView.x;
255                 viewDef->viewport.x2 = tr.viewDef->renderView.x + tr.viewDef->renderView.width;
256                 viewDef->viewport.y1 = tr.viewDef->renderView.y;
257                 viewDef->viewport.y2 = tr.viewDef->renderView.y + tr.viewDef->renderView.height;
258
259                 viewDef->scissor.x1 = tr.viewDef->scissor.x1;
260                 viewDef->scissor.y1 = tr.viewDef->scissor.y1;
261                 viewDef->scissor.x2 = tr.viewDef->scissor.x2;
262                 viewDef->scissor.y2 = tr.viewDef->scissor.y2;
263         }
264
265         viewDef->floatTime = tr.frameShaderTime;
266
267         // qglOrtho( 0, 640, 480, 0, 0, 1 );            // always assume 640x480 virtual coordinates
268         viewDef->projectionMatrix[0] = 2.0f / 640.0f;
269         viewDef->projectionMatrix[5] = -2.0f / 480.0f;
270         viewDef->projectionMatrix[10] = -2.0f / 1.0f;
271         viewDef->projectionMatrix[12] = -1.0f;
272         viewDef->projectionMatrix[13] = 1.0f;
273         viewDef->projectionMatrix[14] = -1.0f;
274         viewDef->projectionMatrix[15] = 1.0f;
275
276         viewDef->worldSpace.modelViewMatrix[0] = 1.0f;
277         viewDef->worldSpace.modelViewMatrix[5] = 1.0f;
278         viewDef->worldSpace.modelViewMatrix[10] = 1.0f;
279         viewDef->worldSpace.modelViewMatrix[15] = 1.0f;
280
281         viewDef->maxDrawSurfs = surfaces.Num();
282         viewDef->drawSurfs = (drawSurf_t **)R_FrameAlloc( viewDef->maxDrawSurfs * sizeof( viewDef->drawSurfs[0] ) );
283         viewDef->numDrawSurfs = 0;
284
285         viewDef_t       *oldViewDef = tr.viewDef;
286         tr.viewDef = viewDef;
287
288         // add the surfaces to this view
289         for ( int i = 0 ; i < surfaces.Num() ; i++ ) {
290                 EmitSurface( &surfaces[i], viewDef->worldSpace.modelMatrix, viewDef->worldSpace.modelViewMatrix, false );
291         }
292
293         tr.viewDef = oldViewDef;
294
295         // add the command to draw this view
296         R_AddDrawViewCmd( viewDef );
297 }
298
299 /*
300 =============
301 AdvanceSurf
302 =============
303 */
304 void idGuiModel::AdvanceSurf() {
305         guiModelSurface_t       s;
306
307         if ( surfaces.Num() ) {
308                 s.color[0] = surf->color[0];
309                 s.color[1] = surf->color[1];
310                 s.color[2] = surf->color[2];
311                 s.color[3] = surf->color[3];
312                 s.material = surf->material;
313         } else {
314                 s.color[0] = 1;
315                 s.color[1] = 1;
316                 s.color[2] = 1;
317                 s.color[3] = 1;
318                 s.material = tr.defaultMaterial;
319         }
320         s.numIndexes = 0;
321         s.firstIndex = indexes.Num();
322         s.numVerts = 0;
323         s.firstVert = verts.Num();
324
325         surfaces.Append( s );
326         surf = &surfaces[ surfaces.Num() - 1 ];
327 }
328
329 /*
330 =============
331 SetColor
332 =============
333 */
334 void idGuiModel::SetColor( float r, float g, float b, float a ) {
335         if ( !glConfig.isInitialized ) {
336                 return;
337         }
338         if ( r == surf->color[0] && g == surf->color[1]
339                 && b == surf->color[2] && a == surf->color[3] ) {
340                 return; // no change
341         }
342
343         if ( surf->numVerts ) {
344                 AdvanceSurf();
345         }
346
347         // change the parms
348         surf->color[0] = r;
349         surf->color[1] = g;
350         surf->color[2] = b;
351         surf->color[3] = a;
352 }
353
354 /*
355 =============
356 DrawStretchPic
357 =============
358 */
359 void idGuiModel::DrawStretchPic( const idDrawVert *dverts, const glIndex_t *dindexes, int vertCount, int indexCount, const idMaterial *hShader, 
360                                                                            bool clip, float min_x, float min_y, float max_x, float max_y ) {
361         if ( !glConfig.isInitialized ) {
362                 return;
363         }
364         if ( !( dverts && dindexes && vertCount && indexCount && hShader ) ) {
365                 return;
366         }
367
368         // break the current surface if we are changing to a new material
369         if ( hShader != surf->material ) {
370                 if ( surf->numVerts ) {
371                         AdvanceSurf();
372                 }
373                 const_cast<idMaterial *>(hShader)->EnsureNotPurged();   // in case it was a gui item started before a level change
374                 surf->material = hShader;
375         }
376
377         // add the verts and indexes to the current surface
378
379         if ( clip ) {
380                 int i, j;
381
382                 // FIXME:       this is grim stuff, and should be rewritten if we have any significant
383                 //                      number of guis asking for clipping
384                 idFixedWinding w;
385                 for ( i = 0; i < indexCount; i += 3 ) {
386                         w.Clear();
387                         w.AddPoint(idVec5(dverts[dindexes[i]].xyz.x, dverts[dindexes[i]].xyz.y, dverts[dindexes[i]].xyz.z, dverts[dindexes[i]].st.x, dverts[dindexes[i]].st.y));
388                         w.AddPoint(idVec5(dverts[dindexes[i+1]].xyz.x, dverts[dindexes[i+1]].xyz.y, dverts[dindexes[i+1]].xyz.z, dverts[dindexes[i+1]].st.x, dverts[dindexes[i+1]].st.y));
389                         w.AddPoint(idVec5(dverts[dindexes[i+2]].xyz.x, dverts[dindexes[i+2]].xyz.y, dverts[dindexes[i+2]].xyz.z, dverts[dindexes[i+2]].st.x, dverts[dindexes[i+2]].st.y));
390
391                         for ( j = 0; j < 3; j++ ) {
392                                 if ( w[j].x < min_x || w[j].x > max_x ||
393                                         w[j].y < min_y || w[j].y > max_y ) {
394                                         break;
395                                 }
396                         }
397                         if ( j < 3 ) {
398                                 idPlane p;
399                                 p.Normal().y = p.Normal().z = 0.0f; p.Normal().x = 1.0f; p.SetDist( min_x );
400                                 w.ClipInPlace( p );
401                                 p.Normal().y = p.Normal().z = 0.0f; p.Normal().x = -1.0f; p.SetDist( -max_x );
402                                 w.ClipInPlace( p );
403                                 p.Normal().x = p.Normal().z = 0.0f; p.Normal().y = 1.0f; p.SetDist( min_y );
404                                 w.ClipInPlace( p );
405                                 p.Normal().x = p.Normal().z = 0.0f; p.Normal().y = -1.0f; p.SetDist( -max_y );
406                                 w.ClipInPlace( p );
407                         }
408
409                         int     numVerts = verts.Num();
410                         verts.SetNum( numVerts + w.GetNumPoints(), false );
411                         for ( j = 0 ; j < w.GetNumPoints() ; j++ ) {
412                                 idDrawVert *dv = &verts[numVerts+j];
413
414                                 dv->xyz.x = w[j].x;
415                                 dv->xyz.y = w[j].y;
416                                 dv->xyz.z = w[j].z;
417                                 dv->st.x = w[j].s;
418                                 dv->st.y = w[j].t;
419                                 dv->normal.Set(0, 0, 1);
420                                 dv->tangents[0].Set(1, 0, 0);
421                                 dv->tangents[1].Set(0, 1, 0);
422                         }
423                         surf->numVerts += w.GetNumPoints();
424
425                         for ( j = 2; j < w.GetNumPoints(); j++ ) {
426                                 indexes.Append( numVerts - surf->firstVert );
427                                 indexes.Append( numVerts + j - 1 - surf->firstVert );
428                                 indexes.Append( numVerts + j - surf->firstVert );
429                                 surf->numIndexes += 3;
430                         }
431                 }
432
433         } else {
434
435                 int numVerts = verts.Num();
436                 int numIndexes = indexes.Num();
437
438                 verts.AssureSize( numVerts + vertCount );
439                 indexes.AssureSize( numIndexes + indexCount );
440
441                 surf->numVerts += vertCount;
442                 surf->numIndexes += indexCount;
443
444                 for ( int i = 0; i < indexCount; i++ ) {
445                         indexes[numIndexes + i] = numVerts + dindexes[i] - surf->firstVert;
446                 }
447
448                 memcpy( &verts[numVerts], dverts, vertCount * sizeof( verts[0] ) );
449         }
450 }
451
452 /*
453 =============
454 DrawStretchPic
455
456 x/y/w/h are in the 0,0 to 640,480 range
457 =============
458 */
459 void idGuiModel::DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial *hShader ) {
460         idDrawVert verts[4];
461         glIndex_t indexes[6];
462
463         if ( !glConfig.isInitialized ) {
464                 return;
465         }
466         if ( !hShader ) {
467                 return;
468         }
469
470         // clip to edges, because the pic may be going into a guiShader
471         // instead of full screen
472         if ( x < 0 ) {
473                 s1 += ( s2 - s1 ) * -x / w;
474                 w += x;
475                 x = 0;
476         }
477         if ( y < 0 ) {
478                 t1 += ( t2 - t1 ) * -y / h;
479                 h += y;
480                 y = 0;
481         }
482         if ( x + w > 640 ) {
483                 s2 -= ( s2 - s1 ) * ( x + w - 640 ) / w;
484                 w = 640 - x;
485         }
486         if ( y + h > 480 ) {
487                 t2 -= ( t2 - t1 ) * ( y + h - 480 ) / h;
488                 h = 480 - y;
489         }
490         
491         if ( w <= 0 || h <= 0 ) {
492                 return;         // completely clipped away
493         }
494
495         indexes[0] = 3;
496         indexes[1] = 0;
497         indexes[2] = 2;
498         indexes[3] = 2;
499         indexes[4] = 0;
500         indexes[5] = 1;
501         verts[0].xyz[0] = x;
502         verts[0].xyz[1] = y;
503         verts[0].xyz[2] = 0;
504         verts[0].st[0] = s1;
505         verts[0].st[1] = t1;
506         verts[0].normal[0] = 0;
507         verts[0].normal[1] = 0;
508         verts[0].normal[2] = 1;
509         verts[0].tangents[0][0] = 1;
510         verts[0].tangents[0][1] = 0;
511         verts[0].tangents[0][2] = 0;
512         verts[0].tangents[1][0] = 0;
513         verts[0].tangents[1][1] = 1;
514         verts[0].tangents[1][2] = 0;
515         verts[1].xyz[0] = x + w;
516         verts[1].xyz[1] = y;
517         verts[1].xyz[2] = 0;
518         verts[1].st[0] = s2;
519         verts[1].st[1] = t1;
520         verts[1].normal[0] = 0;
521         verts[1].normal[1] = 0;
522         verts[1].normal[2] = 1;
523         verts[1].tangents[0][0] = 1;
524         verts[1].tangents[0][1] = 0;
525         verts[1].tangents[0][2] = 0;
526         verts[1].tangents[1][0] = 0;
527         verts[1].tangents[1][1] = 1;
528         verts[1].tangents[1][2] = 0;
529         verts[2].xyz[0] = x + w;
530         verts[2].xyz[1] = y + h;
531         verts[2].xyz[2] = 0;
532         verts[2].st[0] = s2;
533         verts[2].st[1] = t2;
534         verts[2].normal[0] = 0;
535         verts[2].normal[1] = 0;
536         verts[2].normal[2] = 1;
537         verts[2].tangents[0][0] = 1;
538         verts[2].tangents[0][1] = 0;
539         verts[2].tangents[0][2] = 0;
540         verts[2].tangents[1][0] = 0;
541         verts[2].tangents[1][1] = 1;
542         verts[2].tangents[1][2] = 0;
543         verts[3].xyz[0] = x;
544         verts[3].xyz[1] = y + h;
545         verts[3].xyz[2] = 0;
546         verts[3].st[0] = s1;
547         verts[3].st[1] = t2;
548         verts[3].normal[0] = 0;
549         verts[3].normal[1] = 0;
550         verts[3].normal[2] = 1;
551         verts[3].tangents[0][0] = 1;
552         verts[3].tangents[0][1] = 0;
553         verts[3].tangents[0][2] = 0;
554         verts[3].tangents[1][0] = 0;
555         verts[3].tangents[1][1] = 1;
556         verts[3].tangents[1][2] = 0;
557
558         DrawStretchPic( &verts[0], &indexes[0], 4, 6, hShader, false, 0.0f, 0.0f, 640.0f, 480.0f );
559 }
560
561 /*
562 =============
563 DrawStretchTri
564
565 x/y/w/h are in the 0,0 to 640,480 range
566 =============
567 */
568 void idGuiModel::DrawStretchTri( idVec2 p1, idVec2 p2, idVec2 p3, idVec2 t1, idVec2 t2, idVec2 t3, const idMaterial *material ) {
569         idDrawVert tempVerts[3];
570         glIndex_t tempIndexes[3];
571         int vertCount = 3;
572         int indexCount = 3;
573
574         if ( !glConfig.isInitialized ) {
575                 return;
576         }
577         if ( !material ) {
578                 return;
579         }
580
581         tempIndexes[0] = 1;
582         tempIndexes[1] = 0;
583         tempIndexes[2] = 2;
584         tempVerts[0].xyz[0] = p1.x;
585         tempVerts[0].xyz[1] = p1.y;
586         tempVerts[0].xyz[2] = 0;
587         tempVerts[0].st[0] = t1.x;
588         tempVerts[0].st[1] = t1.y;
589         tempVerts[0].normal[0] = 0;
590         tempVerts[0].normal[1] = 0;
591         tempVerts[0].normal[2] = 1;
592         tempVerts[0].tangents[0][0] = 1;
593         tempVerts[0].tangents[0][1] = 0;
594         tempVerts[0].tangents[0][2] = 0;
595         tempVerts[0].tangents[1][0] = 0;
596         tempVerts[0].tangents[1][1] = 1;
597         tempVerts[0].tangents[1][2] = 0;
598         tempVerts[1].xyz[0] = p2.x;
599         tempVerts[1].xyz[1] = p2.y;
600         tempVerts[1].xyz[2] = 0;
601         tempVerts[1].st[0] = t2.x;
602         tempVerts[1].st[1] = t2.y;
603         tempVerts[1].normal[0] = 0;
604         tempVerts[1].normal[1] = 0;
605         tempVerts[1].normal[2] = 1;
606         tempVerts[1].tangents[0][0] = 1;
607         tempVerts[1].tangents[0][1] = 0;
608         tempVerts[1].tangents[0][2] = 0;
609         tempVerts[1].tangents[1][0] = 0;
610         tempVerts[1].tangents[1][1] = 1;
611         tempVerts[1].tangents[1][2] = 0;
612         tempVerts[2].xyz[0] = p3.x;
613         tempVerts[2].xyz[1] = p3.y;
614         tempVerts[2].xyz[2] = 0;
615         tempVerts[2].st[0] = t3.x;
616         tempVerts[2].st[1] = t3.y;
617         tempVerts[2].normal[0] = 0;
618         tempVerts[2].normal[1] = 0;
619         tempVerts[2].normal[2] = 1;
620         tempVerts[2].tangents[0][0] = 1;
621         tempVerts[2].tangents[0][1] = 0;
622         tempVerts[2].tangents[0][2] = 0;
623         tempVerts[2].tangents[1][0] = 0;
624         tempVerts[2].tangents[1][1] = 1;
625         tempVerts[2].tangents[1][2] = 0;
626
627         // break the current surface if we are changing to a new material
628         if ( material != surf->material ) {
629                 if ( surf->numVerts ) {
630                         AdvanceSurf();
631                 }
632                 const_cast<idMaterial *>(material)->EnsureNotPurged();  // in case it was a gui item started before a level change
633                 surf->material = material;
634         }
635
636
637         int numVerts = verts.Num();
638         int numIndexes = indexes.Num();
639
640         verts.AssureSize( numVerts + vertCount );
641         indexes.AssureSize( numIndexes + indexCount );
642
643         surf->numVerts += vertCount;
644         surf->numIndexes += indexCount;
645
646         for ( int i = 0; i < indexCount; i++ ) {
647                 indexes[numIndexes + i] = numVerts + tempIndexes[i] - surf->firstVert;
648         }
649
650         memcpy( &verts[numVerts], tempVerts, vertCount * sizeof( verts[0] ) );
651 }
652