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"
37 idGuiModel::idGuiModel
40 idGuiModel::idGuiModel() {
41 indexes.SetGranularity( 1000 );
42 verts.SetGranularity( 1000 );
49 Begins collecting draw commands into surfaces
52 void idGuiModel::Clear() {
53 surfaces.SetNum( 0, false );
54 indexes.SetNum( 0, false );
55 verts.SetNum( 0, false );
61 idGuiModel::WriteToDemo
64 void idGuiModel::WriteToDemo( idDemoFile *demo ) {
69 for ( j = 0; j < i; j++ )
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] );
84 for ( j = 0; j < i; j++ ) {
85 demo->WriteInt(indexes[j] );
90 for ( j = 0 ; j < i ; j++ ) {
91 guiModelSurface_t *surf = &surfaces[j];
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() );
108 idGuiModel::ReadFromDemo
111 void idGuiModel::ReadFromDemo( idDemoFile *demo ) {
116 verts.SetNum( i, false );
117 for ( j = 0; j < i; j++ )
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] );
132 indexes.SetNum( i, false );
133 for ( j = 0; j < i; j++ ) {
134 demo->ReadInt(indexes[j] );
139 surfaces.SetNum( i, false );
140 for ( j = 0 ; j < i ; j++ ) {
141 guiModelSurface_t *surf = &surfaces[j];
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() );
161 void idGuiModel::EmitSurface( guiModelSurface_t *surf, float modelMatrix[16], float modelViewMatrix[16], bool depthHack ) {
164 if ( surf->numVerts == 0 ) {
165 return; // nothing in the surface
168 // copy verts and indexes
169 tri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *tri ) );
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] ) );
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] ) );
182 // move the verts to the vertex cache
183 tri->ambientCache = vertexCache.AllocFrameTemp( tri->verts, tri->numVerts * sizeof( tri->verts[0] ) );
185 // if we are out of vertex cache, don't create the surface
186 if ( !tri->ambientCache ) {
190 renderEntity_t renderEntity;
191 memset( &renderEntity, 0, sizeof( renderEntity ) );
192 memcpy( renderEntity.shaderParms, surf->color, sizeof( surf->color ) );
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;
199 // add the surface, which might recursively create another gui
200 R_AddDrawSurf( tri, guiSpace, &renderEntity, surf->material, tr.viewDef->scissor );
208 void idGuiModel::EmitToCurrentView( float modelMatrix[16], bool depthHack ) {
209 float modelViewMatrix[16];
211 myGlMultMatrix( modelMatrix, tr.viewDef->worldSpace.modelViewMatrix,
214 for ( int i = 0 ; i < surfaces.Num() ; i++ ) {
215 EmitSurface( &surfaces[i], modelMatrix, modelViewMatrix, depthHack );
221 idGuiModel::EmitFullScreen
223 Creates a view that covers the screen and emit the surfaces
226 void idGuiModel::EmitFullScreen( void ) {
229 if ( surfaces[0].numVerts == 0 ) {
233 viewDef = (viewDef_t *)R_ClearedFrameAlloc( sizeof( *viewDef ) );
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;
242 tr.RenderViewToViewport( &viewDef->renderView, &viewDef->viewport );
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;
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;
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;
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;
265 viewDef->floatTime = tr.frameShaderTime;
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;
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;
281 viewDef->maxDrawSurfs = surfaces.Num();
282 viewDef->drawSurfs = (drawSurf_t **)R_FrameAlloc( viewDef->maxDrawSurfs * sizeof( viewDef->drawSurfs[0] ) );
283 viewDef->numDrawSurfs = 0;
285 viewDef_t *oldViewDef = tr.viewDef;
286 tr.viewDef = viewDef;
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 );
293 tr.viewDef = oldViewDef;
295 // add the command to draw this view
296 R_AddDrawViewCmd( viewDef );
304 void idGuiModel::AdvanceSurf() {
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;
318 s.material = tr.defaultMaterial;
321 s.firstIndex = indexes.Num();
323 s.firstVert = verts.Num();
325 surfaces.Append( s );
326 surf = &surfaces[ surfaces.Num() - 1 ];
334 void idGuiModel::SetColor( float r, float g, float b, float a ) {
335 if ( !glConfig.isInitialized ) {
338 if ( r == surf->color[0] && g == surf->color[1]
339 && b == surf->color[2] && a == surf->color[3] ) {
343 if ( surf->numVerts ) {
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 ) {
364 if ( !( dverts && dindexes && vertCount && indexCount && hShader ) ) {
368 // break the current surface if we are changing to a new material
369 if ( hShader != surf->material ) {
370 if ( surf->numVerts ) {
373 const_cast<idMaterial *>(hShader)->EnsureNotPurged(); // in case it was a gui item started before a level change
374 surf->material = hShader;
377 // add the verts and indexes to the current surface
382 // FIXME: this is grim stuff, and should be rewritten if we have any significant
383 // number of guis asking for clipping
385 for ( i = 0; i < indexCount; i += 3 ) {
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));
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 ) {
399 p.Normal().y = p.Normal().z = 0.0f; p.Normal().x = 1.0f; p.SetDist( min_x );
401 p.Normal().y = p.Normal().z = 0.0f; p.Normal().x = -1.0f; p.SetDist( -max_x );
403 p.Normal().x = p.Normal().z = 0.0f; p.Normal().y = 1.0f; p.SetDist( min_y );
405 p.Normal().x = p.Normal().z = 0.0f; p.Normal().y = -1.0f; p.SetDist( -max_y );
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];
419 dv->normal.Set(0, 0, 1);
420 dv->tangents[0].Set(1, 0, 0);
421 dv->tangents[1].Set(0, 1, 0);
423 surf->numVerts += w.GetNumPoints();
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;
435 int numVerts = verts.Num();
436 int numIndexes = indexes.Num();
438 verts.AssureSize( numVerts + vertCount );
439 indexes.AssureSize( numIndexes + indexCount );
441 surf->numVerts += vertCount;
442 surf->numIndexes += indexCount;
444 for ( int i = 0; i < indexCount; i++ ) {
445 indexes[numIndexes + i] = numVerts + dindexes[i] - surf->firstVert;
448 memcpy( &verts[numVerts], dverts, vertCount * sizeof( verts[0] ) );
456 x/y/w/h are in the 0,0 to 640,480 range
459 void idGuiModel::DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial *hShader ) {
461 glIndex_t indexes[6];
463 if ( !glConfig.isInitialized ) {
470 // clip to edges, because the pic may be going into a guiShader
471 // instead of full screen
473 s1 += ( s2 - s1 ) * -x / w;
478 t1 += ( t2 - t1 ) * -y / h;
483 s2 -= ( s2 - s1 ) * ( x + w - 640 ) / w;
487 t2 -= ( t2 - t1 ) * ( y + h - 480 ) / h;
491 if ( w <= 0 || h <= 0 ) {
492 return; // completely clipped away
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;
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;
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;
544 verts[3].xyz[1] = y + h;
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;
558 DrawStretchPic( &verts[0], &indexes[0], 4, 6, hShader, false, 0.0f, 0.0f, 640.0f, 480.0f );
565 x/y/w/h are in the 0,0 to 640,480 range
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];
574 if ( !glConfig.isInitialized ) {
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;
627 // break the current surface if we are changing to a new material
628 if ( material != surf->material ) {
629 if ( surf->numVerts ) {
632 const_cast<idMaterial *>(material)->EnsureNotPurged(); // in case it was a gui item started before a level change
633 surf->material = material;
637 int numVerts = verts.Num();
638 int numIndexes = indexes.Num();
640 verts.AssureSize( numVerts + vertCount );
641 indexes.AssureSize( numIndexes + indexCount );
643 surf->numVerts += vertCount;
644 surf->numIndexes += indexCount;
646 for ( int i = 0; i < indexCount; i++ ) {
647 indexes[numIndexes + i] = numVerts + tempIndexes[i] - surf->firstVert;
650 memcpy( &verts[numVerts], tempVerts, vertCount * sizeof( verts[0] ) );