Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mesh_gfx.cpp
Go to the documentation of this file.
1 #include <algorithm>
2 #include "mesh.h"
3 #include "aux_texture.h"
4 #include "aux_logo.h"
5 #include "lin_time.h"
6 #include "configxml.h"
7 #include "vs_globals.h"
8 #include "cmd/nebula_generic.h"
9 #include "gfx/camera.h"
10 #include "gfx/animation.h"
11 #include "gfx/technique.h"
12 #include "mesh_xml.h"
13 #include "gldrv/gl_globals.h"
14 #include "gldrv/gl_light.h"
15 #if defined (CG_SUPPORT)
16 #include "cg_global.h"
17 #endif
18 #include "universe_util.h"
19 #include <utility>
20 #include <unistd.h>
21 #include <signal.h>
22 #include <sys/types.h>
23 
24 extern vector< Logo* > undrawn_logos;
25 
26 #include <exception>
27 
28 #ifdef _MSC_VER
29 //Undefine those nasty min/max macros
30 //MS must hate the STL
31 #undef min
32 #undef max
33 #endif
34 
35 class Exception : public std::exception
36 {
37 private:
38  std::string _message;
39 
40 public: Exception() {}
41  Exception( const Exception &other ) : _message( other._message ) {}
42  explicit Exception( const std::string &message ) : _message( message ) {}
43  virtual ~Exception() throw () {}
44  virtual const char * what() const throw ()
45  {
46  return _message.c_str();
47  }
48 };
49 
50 class MissingTexture : public Exception
51 {
52 public:
53  explicit MissingTexture( const string &msg ) : Exception( msg ) {}
55 };
56 
58 {
59 public:
60  float d;
62  int program;
63 
64  unsigned int transparent : 1;
65  unsigned int zsort : 1;
66  unsigned int passno : 14;
67  int sequence : 16;
68 
70  {
71  orig = NULL;
72  }
74  {
75  assert( passno < orig->technique->getNumPasses() );
76 
77  const Technique::Pass &pass = orig->technique->getPass( passno );
78  this->orig = orig;
79  this->d = -d;
80  this->passno = passno;
81  this->sequence = pass.sequence;
82  this->program = pass.getCompiledProgram();
83  this->transparent =
84  ( (pass.blendMode == Technique::Pass::Decal)
85  || ( (pass.blendMode == Technique::Pass::Default)
86  && (orig->blendDst == ZERO)
87  && (orig->blendSrc != DESTCOLOR) )
88  ) ? 0 : 1;
89  this->zsort = ( transparent && ( (pass.blendMode != Technique::Pass::Default) || (orig->blendDst != ONE) || (orig->blendSrc != ONE) ) ) ? 1 : 0;
90 
91  assert( this->passno == passno );
92  assert( this->sequence == pass.sequence );
93  }
94 
95  #define SLESSX( a, b ) \
96  do {if ( !( (a) == (b) ) ) return ( (a) < (b) ); \
97  } \
98  while (0)
99 
100  #define PLESSX( a, b ) \
101  do {SLESSX( bool(a), bool(b) ); if ( bool(a) ) SLESSX( *a, *b ); \
102  } \
103  while (0)
104 
105  #define SLESS( f ) SLESSX( f, b.f )
106 
107  #define PLESS( f ) PLESSX( f, b.f )
108 
109  bool operator<( const OrigMeshContainer &b ) const
110  {
111  SLESS( sequence ); //explicit sequence takes precedence
112  SLESS( transparent ); //then render opaques first
113  SLESS( zsort ); //And the ones that need z-sort last
114  if (zsort)
115  SLESS( d );
116  SLESS( passno ); //Make sure lesser passes render first
117  SLESS( program ); //group same program together (with fixed-fn at the beginning)
118  //Fixed-fn passes have program == 0
119  if (program == 0) {
120  //Fixed-fn passes sort by texture
121  SLESS( orig->Decal.size() );
122  if (orig->Decal.size() > 0)
123  PLESS( orig->Decal[0] );
124  } else {
125  //Shader passes sort by effective texture
126  const Technique::Pass &apass = orig->technique->getPass( passno );
127  const Technique::Pass &bpass = b.orig->technique->getPass( b.passno );
128 
129  SLESSX( apass.getNumTextureUnits(), bpass.getNumTextureUnits() );
130  for (size_t i = 0, n = apass.getNumTextureUnits(); i < n; ++i) {
131  const Technique::Pass::TextureUnit atu = apass.getTextureUnit( i );
132  const Technique::Pass::TextureUnit btu = bpass.getTextureUnit( i );
133  if (atu.sourceType == btu.sourceType) {
135  //Compare preloaded textures
136  SLESSX( *atu.texture, *btu.texture );
138  //Compare decal textures
139  const Texture *ta = ( atu.sourceIndex < static_cast<int>(orig->Decal.size()) ) ? orig->Decal[atu.sourceIndex] : NULL;
140  const Texture *tb = ( btu.sourceIndex < static_cast<int>(b.orig->Decal.size()) ) ? b.orig->Decal[btu.sourceIndex] : NULL;
141  PLESSX( ta, tb );
142  }
143  } else {
144  //Render file-type ones first
146  }
147  }
148  }
149  //They're equivalent!
150  return false;
151  }
152 
153  #undef PLESS
154  #undef SLESS
155  #undef PLESSX
156  #undef SLESSX
157 
158  bool operator==( const OrigMeshContainer &b ) const
159  {
160  //TODO: Specialize operator==
161  return !(*this < b) && !(b < *this);
162  }
163 };
164 
166 {
167  bool operator()( const OrigMeshContainer &a, const OrigMeshContainer &b ) const
168  {
169  return a.d > b.d;
170  }
171 };
172 
174 {
176  const std::vector< MeshDrawContext > &queue;
177 
178  MeshDrawContextPainterSort( const Vector &center, const std::vector< MeshDrawContext > &q ) : ctr( center )
179  , queue( q ) {}
180 
181  bool operator()( int a, int b ) const
182  {
183  return (queue[a].mat.p-ctr).MagnitudeSquared() > (queue[b].mat.p-ctr).MagnitudeSquared();
184  }
185 };
186 
187 typedef std::vector< OrigMeshContainer >OrigMeshVector;
188 
189 #define NUM_PASSES (4)
190 #define BASE_PASS (0)
191 #define ENVSPEC_PASS (1)
192 #define DAMAGE_PASS (2)
193 #define GLOW_PASS (3)
194 #define BASE_TEX (0)
195 #define ENVSPEC_TEX (1)
196 #define DAMAGE_TEX (2)
197 #define GLOW_TEX (3)
198 #define NORMAL_TEX (4)
199 #define NUM_TEX (5)
200 
202 
204 
205 Texture* Mesh::TempGetTexture( MeshXML *xml, std::string filename, std::string factionname, GFXBOOL detail ) const
206 {
207  static FILTER fil =
208  XMLSupport::parse_bool( vs_config->getVariable( "graphics", "detail_texture_trilinear", "true" ) ) ? TRILINEAR : MIPMAP;
209  static bool factionalize_textures =
210  XMLSupport::parse_bool( vs_config->getVariable( "graphics", "faction_dependant_textures", "true" ) );
211  string faction_prefix = ( factionalize_textures ? (factionname+"_") : string() );
212  Texture *ret = NULL;
213  string facplus = faction_prefix+filename;
214  if (filename.find( ".ani" ) != string::npos) {
215  ret = new AnimatedTexture( facplus.c_str(), 1, fil, detail );
216  if ( !ret->LoadSuccess() ) {
217  delete ret;
218  ret = new AnimatedTexture( filename.c_str(), 1, fil, detail );
219  if ( !ret->LoadSuccess() ) {
220  delete ret;
221  ret = NULL;
222  } else {
223  return ret;
224  }
225  } else {
226  return ret;
227  }
228  }
229  ret = new Texture( facplus.c_str(), 1, fil, TEXTURE2D, TEXTURE_2D, GFXFALSE, 65536, detail );
230  if ( !ret->LoadSuccess() ) {
231  delete ret;
232  ret = new Texture( filename.c_str(), 1, fil, TEXTURE2D, TEXTURE_2D, GFXFALSE, 65536, detail );
233  }
234  return ret;
235 }
236 
238 {
239  if ( Decal.size() )
240  if (Decal[0])
241  return Decal[0]->numFrames();
242  return 1;
243 }
244 
246 {
247  if ( Decal.size() )
248  if (Decal[0])
249  return Decal[0]->curTime();
250  return 0;
251 }
252 
254 {
255  if ( Decal.size() )
256  if (Decal[0])
257  return Decal[0]->framesPerSecond();
258  return 0;
259 }
260 
262 {
263  for (unsigned int i = 0; i < Decal.size(); ++i)
264  if (Decal[i])
265  Decal[i]->setTime( d );
266 }
267 
268 Texture* Mesh::TempGetTexture( MeshXML *xml, int index, std::string factionname ) const
269 {
270  static bool factionalize_textures =
271  XMLSupport::parse_bool( vs_config->getVariable( "graphics", "faction_dependant_textures", "true" ) );
272  string faction_prefix = ( factionalize_textures ? (factionname+"_") : string() );
273  Texture *tex = NULL;
274  assert( index < (int) xml->decals.size() );
275  MeshXML::ZeTexture *zt = &(xml->decals[index]);
276  if ( zt->animated_name.length() ) {
277  string tempani = faction_prefix+zt->animated_name;
278  tex = new AnimatedTexture( tempani.c_str(), 0, BILINEAR );
279  if ( !tex->LoadSuccess() ) {
280  delete tex;
281  tex = new AnimatedTexture( zt->animated_name.c_str(), 0, BILINEAR );
282  }
283  } else if (zt->decal_name.length() == 0) {
284  tex = NULL;
285  } else {
286  if (zt->alpha_name.length() == 0) {
287  string temptex = faction_prefix+zt->decal_name;
288  tex =
289  new Texture(
290  temptex.c_str(), 0, MIPMAP, TEXTURE2D, TEXTURE_2D,
292  if ( !tex->LoadSuccess() ) {
293  delete tex;
294  tex =
295  new Texture(
296  zt->decal_name.c_str(), 0, MIPMAP, TEXTURE2D, TEXTURE_2D,
298  }
299  } else {
300  string temptex = faction_prefix+zt->decal_name;
301  string tempalp = faction_prefix+zt->alpha_name;
302  tex =
303  new Texture( temptex.c_str(), tempalp.c_str(), 0, MIPMAP, TEXTURE2D, TEXTURE_2D, 1, 0,
305  if ( !tex->LoadSuccess() ) {
306  delete tex;
307  tex =
308  new Texture( zt->decal_name.c_str(), zt->alpha_name.c_str(), 0, MIPMAP, TEXTURE2D, TEXTURE_2D, 1, 0,
310  }
311  }
312  }
313  return tex;
314 }
315 
316 Texture * createTexture( const char *filename,
317  int stage = 0,
318  enum FILTER f1 = MIPMAP,
319  enum TEXTURE_TARGET t0 = TEXTURE2D,
321  unsigned char c = GFXFALSE,
322  int i = 65536 )
323 {
324  return new Texture( filename, stage, f1, t0, t, c, i );
325 }
326 
327 Logo * createLogo( int numberlogos,
328  Vector *center,
329  Vector *normal,
330  float *sizes,
331  float *rotations,
332  float offset,
333  Texture *Dec,
334  Vector *Ref )
335 {
336  return new Logo( numberlogos, center, normal, sizes, rotations, offset, Dec, Ref );
337 }
338 
339 Texture * createTexture( char const *ccc,
340  char const *cc,
341  int k = 0,
342  enum FILTER f1 = MIPMAP,
343  enum TEXTURE_TARGET t0 = TEXTURE2D,
345  float f = 1,
346  int j = 0,
347  unsigned char c = GFXFALSE,
348  int i = 65536 )
349 {
350  return new Texture( ccc, cc, k, f1, t0, t, f, j, c, i );
351 }
352 
353 AnimatedTexture * createAnimatedTexture( char const *c, int i, enum FILTER f )
354 {
355  return new AnimatedTexture( c, i, f );
356 }
357 
360 {
361  if (!orig || orig == this) {
362  for (int j = 0; j < NUM_MESH_SEQUENCE; j++)
363  for (OrigMeshVector::iterator it = undrawn_meshes[j].begin(); it != undrawn_meshes[j].end(); ++it)
364  if (it->orig == this) {
365  undrawn_meshes[j].erase( it-- );
366  VSFileSystem::vs_fprintf( stderr, "stale mesh found in draw queue--removed!\n" );
367  }
368  delete vlist;
369  for (unsigned int i = 0; i < Decal.size(); i++)
370  if (Decal[i] != NULL) {
371  delete Decal[i];
372  Decal[i] = NULL;
373  }
374  if (squadlogos != NULL) {
375  delete squadlogos;
376  squadlogos = NULL;
377  }
378  if (forcelogos != NULL) {
379  delete forcelogos;
380  forcelogos = NULL;
381  }
382  if (meshHashTable.Get( hash_name ) == this)
384  vector< Mesh* > *hashers = bfxmHashTable.Get( hash_name );
385  vector< Mesh* >::iterator finder;
386  if (hashers) {
387  for (int i = hashers->size()-1; i >= 0; --i)
388  if ( (*hashers)[i] == this ) {
389  hashers->erase( hashers->begin()+i );
390  if ( hashers->empty() ) {
391  bfxmHashTable.Delete( hash_name );
392  delete hashers;
393  }
394  }
395  }
396  if (draw_queue != NULL)
397  delete[] draw_queue;
398  } else {
399  orig->refcount--;
400  //printf ("orig refcount: %d",refcount);
401  if (orig->refcount == 0)
402  delete[] orig;
403  }
404 }
405 
406 void Mesh::Draw( float lod, const Matrix &m, float toofar, int cloak, float nebdist, unsigned char hulldamage, bool renormalize, const MeshFX*mfx ) //short fix
407 {
408  Mesh *origmesh = getLOD( lod );
409  if (origmesh->rSize() > 0) {
410  //Vector pos (local_pos.Transform(m));
411  MeshDrawContext c( m );
412  if (mfx) {
413  c.xtraFX=*mfx;
414  c.useXtraFX=true;
415  }
417  c.SpecialFX = &LocalFX;
418  c.damage = hulldamage;
419 
420  c.mesh_seq = ( ( toofar+rSize() ) > g_game.zfar ) ? NUM_ZBUF_SEQ : draw_sequence;
422  if (nebdist < 0)
424  if (renormalize)
426  if (cloak >= 0) {
428  if ( (cloak&0x1) ) {
430  c.mesh_seq = MESH_SPECIAL_FX_ONLY; //draw near the end with lights
431  } else {
432  c.mesh_seq = 2;
433  }
434  if (cloak <= 2147483647/2)
436  float tmp = ( (float) cloak )/2147483647;
437  c.CloakFX.r = (c.cloaked&MeshDrawContext::GLASSCLOAK) ? tmp : 1;
438  c.CloakFX.g = (c.cloaked&MeshDrawContext::GLASSCLOAK) ? tmp : 1;
439  c.CloakFX.b = (c.cloaked&MeshDrawContext::GLASSCLOAK) ? tmp : 1;
440  c.CloakFX.a = tmp;
441  /*
442  * c.CloakNebFX.ambient[0]=((float)cloak)/2147483647;
443  * c.CloakNebFX.ag=((float)cloak)/2147483647;
444  * c.CloakNebFX.ab=((float)cloak)/2147483647;
445  * c.CloakNebFX.aa=((float)cloak)/2147483647;
446  */
448  }
449  //c.mat[12]=pos.i;
450  //c.mat[13]=pos.j;
451  //c.mat[14]=pos.k;//to translate to local_pos which is now obsolete!
452 
453  origmesh->draw_queue[static_cast<size_t>(c.mesh_seq)].push_back( c );
454  if ( !( origmesh->will_be_drawn&(1<<c.mesh_seq) ) ) {
455  origmesh->will_be_drawn |= (1<<c.mesh_seq);
456  for (int passno = 0, npasses = origmesh->technique->getNumPasses(); passno < npasses; ++passno)
457  undrawn_meshes[static_cast<size_t>(c.mesh_seq)].push_back( OrigMeshContainer( origmesh, toofar-rSize(), passno ) );
458  }
459  will_be_drawn |= (1<<c.mesh_seq);
460  }
461 }
462 
463 void Mesh::DrawNow( float lod, bool centered, const Matrix &m, int cloak, float nebdist )
464 {
465  //short fix
466  Mesh *o = getLOD( lod );
467  //fixme: cloaking not delt with.... not needed for backgroudn anyway
468  if (nebdist < 0) {
470  if (t)
471  t->SetFogState();
472  } else {
473  GFXFogMode( FOG_OFF );
474  }
475  if (centered) {
476  //Matrix m1 (m);
477  //Vector pos(_Universe->AccessCamera()->GetPosition().Transform(m1));
478  //m1[12]=pos.i;
479  //m1[13]=pos.j;
480  //m1[14]=pos.k;
481  GFXCenterCamera( true );
482  GFXLoadMatrixModel( m );
483  } else {
486  GFXPickLights( Vector( m.p.i, m.p.j, m.p.k ), rSize() );
487  }
488  GFXLoadMatrixModel( m );
489  }
490  //Making it static avoids frequent reallocations - although may be troublesome for thread safety
491  //but... WTH... nothing is thread safe in VS.
492  //Also: Be careful with reentrancy... right now, this section is not reentrant.
493  static vector< int >specialfxlight;
494 
495  unsigned int i;
496  for (i = 0; i < LocalFX.size(); i++) {
497  int ligh;
498  GFXCreateLight( ligh, (LocalFX)[i], true );
499  specialfxlight.push_back( ligh );
500  }
502  if (blendSrc != SRCALPHA && blendDst != ZERO)
505  if (o->Decal.size() && o->Decal[0])
506  o->Decal[0]->MakeActive();
507  GFXTextureEnv( 0, GFXMODULATETEXTURE ); //Default diffuse mode
508  GFXTextureEnv( 1, GFXADDTEXTURE ); //Default envmap mode
509  GFXToggleTexture( bool(o->Decal.size() && o->Decal[0]), 0 );
510  o->vlist->DrawOnce();
511  if (centered)
512  GFXCenterCamera( false );
513  for (i = 0; i < specialfxlight.size(); i++)
514  GFXDeleteLight( specialfxlight[i] );
515  if (cloak >= 0 && cloak < 2147483647)
516  GFXEnable( TEXTURE1 );
517 }
518 
519 void Mesh::ProcessZFarMeshes( bool nocamerasetup )
520 {
521  int a = NUM_ZBUF_SEQ;
522 
523  //clear Z buffer
525 
526  static float far_margin = XMLSupport::parse_float( vs_config->getVariable( "graphics", "mesh_far_percent", ".8" ) );
528 
529  std::sort( undrawn_meshes[a].begin(), undrawn_meshes[a].end() );
530  for (OrigMeshVector::iterator it = undrawn_meshes[a].begin(); it < undrawn_meshes[a].end(); ++it) {
531  Mesh *m = it->orig;
532  m->ProcessDrawQueue( it->passno, a, it->zsort, _Universe->AccessCamera()->GetPosition() );
533  m->will_be_drawn &= ( ~(1<<a) ); //not accurate any more
534  }
535  for (OrigMeshVector::iterator it = undrawn_meshes[a].begin(); it < undrawn_meshes[a].end(); ++it) {
536  Mesh *m = it->orig;
537  m->draw_queue[a].clear();
538  }
539  undrawn_meshes[a].clear();
540 
543  glDisable( GL_FRAMEBUFFER_SRGB_EXT );
544 
545  Animation::ProcessFarDrawQueue( -FLT_MAX );
546 }
547 
549 {
550  return GFXGetMaterial( myMatNum );
551 }
552 
553 template < typename T >
554 inline bool rangesOverlap( T min1, T max1, T min2, T max2 )
555 {
556  return !( ( (min1 < min2) == (max1 < min2) )
557  && ( (min1 < max2) == (max1 < max2) )
558  && ( (min1 < min2) == (min1 < max2) ) );
559 }
560 
561 void Mesh::ProcessUndrawnMeshes( bool pushSpecialEffects, bool nocamerasetup )
562 {
563  //clear Z buffer
565 
566  for (int a = 0; a < NUM_ZBUF_SEQ; a++) {
567  if (a == MESH_SPECIAL_FX_ONLY) {
570  } else {
572  }
573  std::sort( undrawn_meshes[a].begin(), undrawn_meshes[a].end() );
574  for (OrigMeshVector::iterator it = undrawn_meshes[a].begin(); it < undrawn_meshes[a].end(); ++it) {
575  Mesh *m = it->orig;
576  m->ProcessDrawQueue( it->passno, a, it->zsort, _Universe->AccessCamera()->GetPosition() );
577  m->will_be_drawn &= ( ~(1<<a) ); //not accurate any more
578  }
579  for (OrigMeshVector::iterator it = undrawn_meshes[a].begin(); it < undrawn_meshes[a].end(); ++it) {
580  Mesh *m = it->orig;
581  m->draw_queue[a].clear();
582  }
583  undrawn_meshes[a].clear();
584  if (a == MESH_SPECIAL_FX_ONLY) {
585  if (!pushSpecialEffects)
588  }
589  for (vector< Logo* >::iterator it = undrawn_logos.begin(); it < undrawn_logos.end(); it++) {
590  Logo *l = *it;
591  l->ProcessDrawQueue();
592  l->will_be_drawn = false;
593  }
594  undrawn_logos.clear();
595  }
596 
597  // Restore state
600  glDisable( GL_FRAMEBUFFER_SRGB_EXT );
601 }
602 
603 void Mesh::RestoreCullFace( int whichdrawqueue )
604 {
605  if ( blendDst != ZERO || getCullFaceForcedOff() )
606  if (blendSrc != SRCALPHA)
607  GFXEnable( CULLFACE );
608 }
609 
610 void Mesh::SelectCullFace( int whichdrawqueue )
611 {
612  if ( getCullFaceForcedOn() )
613  GFXEnable( CULLFACE );
614  else if ( getCullFaceForcedOff() )
615  GFXDisable( CULLFACE );
616  if (blendDst != ZERO)
617  if ( blendSrc != SRCALPHA || getCullFaceForcedOff() )
618  GFXDisable( CULLFACE );
619 }
620 
621 void SetupCloakState( char cloaked,
622  const GFXColor &CloakFX,
623  vector< int > &specialfxlight,
624  unsigned char hulldamage,
625  unsigned int matnum )
626 {
627  if (cloaked&MeshDrawContext::CLOAK) {
629  GFXDisable( CULLFACE );
630 
631  GFXEnable( LIGHTING );
632  GFXEnable( TEXTURE0 );
633  GFXEnable( TEXTURE1 );
634 
635  if (cloaked&MeshDrawContext::GLASSCLOAK) {
636  GFXDisable( TEXTURE1 );
637  int ligh;
638  GFXCreateLight( ligh,
639  GFXLight( true,
640  GFXColor( 0, 0, 0,
641  1 ), GFXColor( 0, 0, 0, 1 ), GFXColor( 0, 0, 0, 1 ), CloakFX, GFXColor( 1,
642  0,
643  0 ) ),
644  true );
645  specialfxlight.push_back( ligh );
646  GFXBlendMode( ONE, ONE );
648  GFXColor( 1, 1, 1, 1 ),
649  GFXColor( 1, 1, 1, 1 ),
650  GFXColor( 1, 1, 1, 1 ),
651  CloakFX );
652  } else {
653  GFXEnable( TEXTURE1 );
654  if (cloaked&MeshDrawContext::NEARINVIS) {
655  //NOT sure I like teh jump this produces GFXDisable (TEXTURE1);
656  }
659  if (hulldamage)
660  GFXColor4f( CloakFX.r, CloakFX.g, CloakFX.b, CloakFX.a*hulldamage/255 );
661  else
662  GFXColorf( CloakFX );
663  }
664  } else if (hulldamage) {
665  //ok now we go in and do the dirtying
667  GFXColor4f( 1, 1, 1, hulldamage/255. );
668  }
669 }
670 
671 static void RestoreCloakState( char cloaked, bool envMap, unsigned char damage )
672 {
673  if (cloaked&MeshDrawContext::CLOAK) {
674  GFXColorMaterial( 0 );
675  if (envMap)
676  GFXEnable( TEXTURE1 );
677  GFXPopBlendMode();
678 #if defined (CG_SUPPORT)
679  cgGLDisableProfile( cloak_cg->vertexProfile );
680 #endif
681  }
682  if (damage)
683  GFXColorMaterial( 0 );
684 }
685 
686 static void SetupFogState( char cloaked )
687 {
688  if (cloaked&MeshDrawContext::FOG) {
690  if (t)
691  t->SetFogState();
692  } else {
693  GFXFogMode( FOG_OFF );
694  }
695 }
696 
698  size_t decalSize,
699  unsigned int mat,
700  bool envMap,
701  float polygon_offset,
702  Texture *detailTexture,
703  const vector< Vector > &detailPlanes,
704  bool &skip_glowpass,
705  bool nomultienv )
706 {
708 
709  static bool separatespec =
710  XMLSupport::parse_bool( vs_config->getVariable( "graphics", "separatespecularcolor", "false" ) ) ? GFXTRUE : GFXFALSE;
711  GFXSetSeparateSpecularColor( separatespec );
712 
713  static bool multitex_glowpass = XMLSupport::parse_bool( vs_config->getVariable( "graphics", "multitexture_glowmaps", "true" ) );
714  if (polygon_offset) {
715  float a, b;
716  GFXGetPolygonOffset( &a, &b );
717  GFXPolygonOffset( a, b-polygon_offset );
718  }
719  if (nomultienv) {
721  GFXColor( 1, 1, 1, 1 ),
722  GFXColor( 1, 1, 1, 1 ),
723  GFXColor( 0, 0, 0, 0 ),
724  GFXColor( 0, 0, 0, 0 ) );
725  GFXBlendMode( ONE, ONE );
726  GFXDepthFunc( LEQUAL );
727  }
728  bool retval = false;
729  skip_glowpass = false;
730  size_t detailoffset = 2;
731  if ( !nomultienv && (decalSize > 1) && (decal[1]) ) {
732  detailoffset = 1;
734  GFXColor( 1, 1, 1, 1 ),
735  GFXColor( 1, 1, 1, 1 ),
736  GFXColor( 0, 0, 0, 0 ),
737  GFXColor( 0, 0, 0, 0 ) );
738  retval = true;
739  if (envMap && detailTexture == NULL) {
740  if ( (decalSize > GLOW_PASS) && decal[GLOW_PASS] && gl_options.Multitexture && multitex_glowpass ) {
741  decal[GLOW_PASS]->MakeActive( 1 );
743  GFXToggleTexture( true, 1 );
744  GFXTextureCoordGenMode( 1, NO_GEN, NULL, NULL );
745  skip_glowpass = true;
746  } else {GFXDisable( TEXTURE1 ); }
747  }
748  if (decal[0]) {
749  decal[0]->MakeActive( 0 );
750  GFXToggleTexture( true, 0 );
751  } else {
752  GFXToggleTexture( false, 0 );
753  }
754  } else if (decalSize && decal[0]) {
755  GFXToggleTexture( true, 0 );
756  decal[0]->MakeActive( 0 );
757  } else {
758  GFXToggleTexture( false, 0 );
759  }
760  if ( detailTexture && (gl_options.Multitexture > detailoffset) ) {
761  for (unsigned int i = 1; i < detailPlanes.size(); i += 2) {
762  int stage = (i/2)+detailoffset;
763  const float params[4] = {detailPlanes[i-1].i, detailPlanes[i-1].j, detailPlanes[i-1].k, 0};
764  const float paramt[4] = {detailPlanes[i].i, detailPlanes[i].j, detailPlanes[i].k, 0};
765  GFXTextureCoordGenMode( stage, OBJECT_LINEAR_GEN, params, paramt );
766  detailTexture->MakeActive( stage );
768  GFXToggleTexture( true, stage );
769  }
770  }
771  return retval;
772 }
773 
774 void RestoreFirstPassState( Texture *detailTexture,
775  const vector< Vector > &detailPlanes,
776  bool skipped_glowpass,
777  bool nomultienv )
778 {
779  GFXPopBlendMode();
780  if (!nomultienv) GFXDepthFunc( LEQUAL );
781  if (detailTexture || skipped_glowpass) {
782  static float tempo[4] = {1, 0, 0, 0};
784  }
785  if (detailTexture) {
786  unsigned int sizeplus1 = detailPlanes.size()/2+1;
787  for (unsigned int i = 1; i < sizeplus1; i++)
788  GFXToggleTexture( false, i+1 ); //turn off high detial tex
789  }
790 }
791 
792 void SetupEnvmapPass( Texture *decal, unsigned int mat, int passno )
793 {
794  assert( passno >= 0 && passno <= 2 );
795 
796  //This is only used when there's no multitexturing... so don't use multitexturing
799  GFXColor( 0, 0, 0, 0 ),
800  GFXColor( 0, 0, 0, 0 ),
801  (passno == 2) ? GFXColor( 1, 1, 1, 1 ) : GFXColor( 0, 0, 0, 0 ),
802  (passno == 2) ? GFXColor( 0, 0, 0, 0 ) : GFXColor( 1, 1, 1, 1 ) );
803  if (passno == 2)
805  if (passno != 2)
806  GFXDisable( LIGHTING );
807  if (decal)
808  GFXBlendMode( (passno != 1) ? ONE : ZERO, (passno == 1) ? SRCCOLOR : (passno ? ONE : ZERO) );
809 
810  else
811  GFXBlendMode( ONE, ONE );
812  if ( decal && ( (passno == 0) || (passno == 2) ) ) {
813  decal->MakeActive( 0 );
814  GFXToggleTexture( true, 0 );
815  } else if (passno == 1) {
817  } else {
818  GFXToggleTexture( false, 0 );
819  }
820  GFXTextureEnv( 0, ( (passno != 2) ? GFXREPLACETEXTURE : GFXMODULATETEXTURE ) );
821  GFXDepthFunc( LEQUAL );
822 }
823 
825 {
826  float dummy[4];
827  static bool separatespec =
828  XMLSupport::parse_bool( vs_config->getVariable( "graphics", "separatespecularcolor", "false" ) ) ? GFXTRUE : GFXFALSE;
829  GFXSetSeparateSpecularColor( separatespec );
830  GFXEnable( LIGHTING );
831  GFXTextureCoordGenMode( 0, NO_GEN, dummy, dummy );
833  GFXDepthFunc( LEQUAL );
834  GFXPopBlendMode();
835  GFXToggleTexture( false, 0 );
836 }
837 
839  unsigned int mat,
840  BLENDFUNC blendsrc,
841  bool envMap,
842  const GFXColor &cloakFX,
843  float polygon_offset )
844 {
847  GFXColor( 0, 0, 0, 0 ),
848  GFXColor( 0, 0, 0, 0 ),
849  cloakFX,
850  ( envMap ? GFXColor( 1, 1, 1, 1 ) : GFXColor( 0, 0, 0, 0 ) ) );
851  GFXBlendMode( ONE, ONE );
852  if (!envMap || gl_options.Multitexture)
853  if (decal) decal->MakeActive();
854  //float a,b;
855  //GFXGetPolygonOffset(&a,&b);
856  //GFXPolygonOffset (a, b-1-polygon_offset); //Not needed, since we use GL_EQUAL and appeal to invariance
857  GFXDepthFunc( LEQUAL ); //By Klauss - this, with invariance, assures correct rendering (and avoids z-buffer artifacts at low res)
859  if (envMap) {
860  int stage = gl_options.Multitexture ? 1 : 0;
863  GFXEnable( TEXTURE0 );
864  GFXActiveTexture( stage );
867  GFXEnable( TEXTURE1 );
868  } else {
871  GFXEnable( TEXTURE0 );
872  GFXActiveTexture( 1 );
873  GFXDisable( TEXTURE1 );
874  }
875 }
876 
878  unsigned int mat,
879  BLENDFUNC blendsrc,
880  const GFXColor &cloakFX,
881  float polygon_offset )
882 {
885  GFXColor( 0, 0, 0, 0 ),
886  GFXColor( 0, 0, 0, 0 ),
887  GFXColor( 0, 0, 0, 0 ),
888  cloakFX );
889  GFXBlendMode( ONE, ONE );
890  if (decal) decal->MakeActive();
891  //float a,b;
892  //GFXGetPolygonOffset(&a,&b);
893  //GFXPolygonOffset (a, b-2-polygon_offset);
894  GFXDepthFunc( LEQUAL ); //By Klauss - this, with invariance, assures correct rendering (and avoids z-buffer artifacts at low res)
896  GFXDisable( TEXTURE1 );
897 }
898 
899 void SetupDamageMapThirdPass( Texture *decal, unsigned int mat, float polygon_offset )
900 {
903  if (decal) decal->MakeActive();
904  //float a,b;
905  //GFXGetPolygonOffset(&a,&b);
906  //GFXPolygonOffset (a, b-DAMAGE_PASS-polygon_offset);
907  GFXDepthFunc( LEQUAL ); //By Klauss - this, with invariance, assures correct rendering (and avoids z-buffer artifacts at low res)
909  GFXDisable( TEXTURE1 );
910 }
911 
912 void RestoreGlowMapState( bool write_to_depthmap, float polygonoffset, float NOT_USED_BUT_BY_HELPER = 3 )
913 {
914  float a, b;
915  //GFXGetPolygonOffset(&a,&b);
916  //GFXPolygonOffset (a, b+polygonoffset+NOT_USED_BUT_BY_HELPER);
917  GFXDepthFunc( LEQUAL ); //By Klauss - restore original depth function
918  static bool force_write_to_depthmap =
919  XMLSupport::parse_bool( vs_config->getVariable( "graphics", "force_glowmap_restore_write_to_depthmap", "true" ) );
920  if (force_write_to_depthmap || write_to_depthmap)
922  GFXEnable( TEXTURE1 );
923  GFXPopBlendMode();
924 }
925 
926 void RestoreDamageMapState( bool write_to_depthmap, float polygonoffset )
927 {
928  RestoreGlowMapState( write_to_depthmap, polygonoffset, DAMAGE_PASS );
929 }
930 
931 void RestoreSpecMapState( bool envMap, bool write_to_depthmap, float polygonoffset )
932 {
933  //float a,b;
934  //GFXGetPolygonOffset(&a,&b);
935  //GFXPolygonOffset (a, b+1+polygonoffset); //Not needed anymore, since InitSpecMapSecondPass() no longer messes with polygon offsets
936  GFXDepthFunc( LEQUAL ); //By Klauss - restore original depth function
937  if (envMap) {
938  if (gl_options.Multitexture) {
939  GFXActiveTexture( 1 );
940  GFXTextureEnv( 1, GFXADDTEXTURE ); //restore modulate
941  } else {
942  float dummy[4];
943  GFXTextureCoordGenMode( 0, NO_GEN, dummy, dummy );
944  }
945  } else {
946  static bool separatespec =
947  XMLSupport::parse_bool( vs_config->getVariable( "graphics", "separatespecularcolor",
948  "false" ) ) ? GFXTRUE : GFXFALSE;
949  GFXSetSeparateSpecularColor( separatespec );
950  }
951  if (write_to_depthmap)
953  GFXEnable( TEXTURE0 );
954  GFXPopBlendMode();
955 }
956 
957 void Mesh::ProcessDrawQueue( size_t whichpass, int whichdrawqueue, bool zsort, const QVector &sortctr )
958 {
959  //Process the pass for all queued instances
960  const Technique::Pass &pass = technique->getPass( whichpass );
961  if (pass.type == Technique::Pass::ShaderPass)
962  ProcessShaderDrawQueue( whichpass, whichdrawqueue, zsort, sortctr );
963  else
964  ProcessFixedDrawQueue( whichpass, whichdrawqueue, zsort, sortctr );
965  //Restore texture units
966  for (unsigned int i = 0; i < gl_options.Multitexture; ++i)
967  GFXToggleTexture( i < 2, i );
968 }
969 
970 void Mesh::activateTextureUnit( const Technique::Pass::TextureUnit &tu, bool deflt )
971 {
972  //I'm leaving target and source index as int's because I tried to change technique.h's target and source to size_t's
973  //and had problems. So I'll just add static casts to int to the unsigned/size_t other sides in comparisons --chuck_starchaser
974  int targetIndex = tu.targetIndex;
975  int sourceIndex = deflt ? tu.defaultIndex : tu.sourceIndex;
977  switch (sourceType)
978  {
980  //Direct file sources go in tu.texture
981  switch (tu.texKind)
982  {
987  tu.texture->MakeActive( targetIndex );
988  break;
990  default: throw Exception( "Texture Unit for technique of unhandled kind" );
991  }
992  switch (tu.texKind)
993  {
996  GFXToggleTexture( true, targetIndex, TEXTURE2D );
997  break;
999  GFXToggleTexture( true, targetIndex, TEXTURE3D );
1000  break;
1003  GFXToggleTexture( true, targetIndex, CUBEMAP );
1004  break;
1005  default: throw Exception( "Texture Unit for technique of unhandled kind" );
1006  }
1007  break;
1009  _Universe->activateLightMap( targetIndex );
1010  #ifdef NV_CUBE_MAP
1014  "Environment Texture Unit for technique must be a cube map" );
1015  GFXToggleTexture( true, targetIndex, CUBEMAP );
1016  #else
1019  "Environment Texture Unit for technique must be a 2D spheremap" );
1020  GFXToggleTexture( true, targetIndex, TEXTURE2D );
1021  #endif
1022  break;
1026  "Detail Texture Unit for technique must be 2D" );
1027  if (detailTexture)
1028  detailTexture->MakeActive( targetIndex );
1029  else if (!deflt)
1030  activateTextureUnit( tu, true );
1031  else throw MissingTexture(
1032  "Texture Unit for technique requested a missing texture (detail default given that cannot be found)" );
1033  break;
1035  if ( ( sourceIndex < static_cast<int>(Decal.size()) ) && Decal[sourceIndex] )
1036  //Mesh has the referenced decal
1037  Decal[sourceIndex]->MakeActive( targetIndex );
1038  else if (!deflt)
1039  activateTextureUnit( tu, true );
1040  else throw MissingTexture(
1041  "Texture Unit for technique requested a missing texture (decal default given that cannot be found)" );
1042  switch (tu.texKind)
1043  {
1046  GFXToggleTexture( true, targetIndex, TEXTURE2D );
1047  break;
1049  GFXToggleTexture( true, targetIndex, TEXTURE3D );
1050  break;
1053  GFXToggleTexture( true, targetIndex, CUBEMAP );
1054  break;
1055  default: throw Exception( "Texture Unit for technique of unhandled kind" );
1056  }
1057  break;
1058  case Technique::Pass::TextureUnit::None: //chuck_starchaser
1059  default:
1060  break;
1061  }
1062 }
1063 
1064 static void setupGLState(const Technique::Pass &pass, bool zwrite, BLENDFUNC blendSrc, BLENDFUNC blendDst, int material, unsigned char alphatest, int whichdrawqueue)
1065 {
1066  //Setup color/z writes, culling, etc...
1067  if (pass.colorWrite)
1068  GFXEnable( COLORWRITE );
1069  else
1071  {
1072  DEPTHFUNC func;
1073  switch (pass.depthFunction)
1074  {
1076  func = ALWAYS;
1077  break;
1079  func = NEVER;
1080  break;
1081  case Technique::Pass::Less:
1082  func = LESS;
1083  break;
1085  func = GREATER;
1086  break;
1088  func = GEQUAL;
1089  break;
1091  func = EQUAL;
1092  break;
1093  default:
1095  func = LEQUAL;
1096  break;
1097  }
1098  GFXDepthFunc( func );
1099  }
1100  {
1101  POLYMODE mode;
1102  switch (pass.polyMode)
1103  {
1105  mode = GFXPOINTMODE;
1106  break;
1107  case Technique::Pass::Line:
1108  mode = GFXLINEMODE;
1109  break;
1110  default:
1111  case Technique::Pass::Fill:
1112  mode = GFXFILLMODE;
1113  break;
1114  }
1115  GFXPolygonMode( mode );
1116  }
1117  if (pass.polyMode == Technique::Pass::Line)
1118  GFXLineWidth( pass.lineWidth );
1119  if (pass.cullMode == Technique::Pass::None) {
1120  GFXDisable( CULLFACE );
1121  } else if (pass.cullMode == Technique::Pass::DefaultFace) {
1122  //Not handled by this helper function, since it depends on mesh data
1123  //SelectCullFace( whichdrawqueue );
1124  } else {
1125  POLYFACE face;
1126  GFXEnable( CULLFACE );
1127  switch (pass.cullMode)
1128  {
1130  face = GFXFRONT;
1131  break;
1133  face = GFXFRONTANDBACK;
1134  break;
1135  default:
1136  case Technique::Pass::Back:
1137  face = GFXBACK;
1138  break;
1139  }
1140  GFXCullFace( face );
1141  }
1143 
1144  if (zwrite)
1145  GFXEnable( DEPTHWRITE );
1146  else
1148 
1149  //Setup blend mode
1150  switch (pass.blendMode)
1151  {
1152  case Technique::Pass::Add:
1153  GFXBlendMode( ONE, ONE );
1154  break;
1158  break;
1160  GFXBlendMode( ONE, ZERO );
1161  break;
1164  break;
1167  break;
1169  default:
1170  GFXBlendMode( blendSrc, blendDst );
1171  break;
1172  }
1173 
1174  GFXEnable( LIGHTING );
1175  GFXSelectMaterial( material );
1176 
1177  //If we're doing zwrite, alpha test is more or less mandatory for correct results
1178  if (alphatest)
1179  GFXAlphaTest( GEQUAL, alphatest/255.0 );
1180  else if (zwrite)
1181  GFXAlphaTest( GREATER, 0 );
1182 
1184  if (pass.sRGBAware)
1185  glEnable( GL_FRAMEBUFFER_SRGB_EXT );
1186  else
1187  glDisable( GL_FRAMEBUFFER_SRGB_EXT );
1188  }
1189 }
1190 
1191 void Mesh::ProcessShaderDrawQueue( size_t whichpass, int whichdrawqueue, bool zsort, const QVector &sortctr )
1192 {
1193  if (!technique->isCompiled(GFXGetProgramVersion())) {
1194  try {
1195  technique->compile();
1196  }
1197  catch (Exception &e) {
1198  VSFileSystem::vs_dprintf(1, "Technique recompilation failed: %s\n", e.what());
1199  }
1200  }
1201 
1202  const Technique::Pass &pass = technique->getPass( whichpass );
1203 
1204  //First of all, decide zwrite, so we can skip the pass if !zwrite && !cwrite
1205  bool zwrite;
1206  if (whichdrawqueue == MESH_SPECIAL_FX_ONLY) {
1207  //Special effects pass - no zwrites... no zwrites...
1208  zwrite = false;
1209  } else {
1210  //Near draw queue - write to z-buffer if in auto mode and not translucent
1211  zwrite = (blendDst == ZERO);
1212  switch (pass.zWrite)
1213  {
1214  case Technique::Pass::Auto:
1215  break;
1216  case Technique::Pass::True:
1217  zwrite = true;
1218  break;
1220  zwrite = false;
1221  break;
1222  }
1223  }
1224  //If we're not writing anything... why go on?
1225  if (!pass.colorWrite && !zwrite)
1226  return;
1227  float zero[4] = {0, 0, 0, 0};
1228  float envmaprgba[4] = {1, 1, 1, 0};
1229  float noenvmaprgba[4] = {0.5, 0.5, 0.5, 1.0};
1230 
1231  vector< MeshDrawContext > &cur_draw_queue = draw_queue[whichdrawqueue];
1232 
1233  GFXPushBlendMode();
1234  setupGLState(pass, zwrite, blendSrc, blendDst, myMatNum, alphatest, whichdrawqueue);
1236  SelectCullFace( whichdrawqueue ); // Default not handled by setupGLState, it depends on mesh data
1237 
1238  //Activate shader
1240 
1241  //Set shader parameters (instance-independent only)
1242  int activeLightsArrayParam = -1;
1243  int apparentLightSizeArrayParam = -1;
1244  int numLightsParam = -1;
1245  for (size_t spi = 0; spi < pass.getNumShaderParams(); ++spi) {
1246  const Technique::Pass::ShaderParam &sp = pass.getShaderParam( spi );
1247  if (sp.id >= 0) {
1248  switch (sp.semantic)
1249  {
1251  GFXShaderConstant( sp.id, sp.value );
1252  break;
1254  GFXShaderConstant( sp.id, getEnvMap() ? envmaprgba : noenvmaprgba );
1255  break;
1257  GFXShaderConstant( sp.id, detailPlanes[0] );
1258  break;
1260  GFXShaderConstant( sp.id, detailPlanes[1] );
1261  break;
1264  break;
1266  numLightsParam = sp.id;
1267  break;
1269  activeLightsArrayParam = sp.id;
1270  break;
1272  apparentLightSizeArrayParam = sp.id;
1273  break;
1274  case Technique::Pass::ShaderParam::CloakingPhase: //chuck_starchaser
1275  default:
1276  break;
1277  }
1278  }
1279  }
1280  //Activate texture units
1281  size_t tui;
1282  size_t tuimask = 0;
1283  for (tui = 0; tui < pass.getNumTextureUnits(); ++tui) {
1284  const Technique::Pass::TextureUnit &tu = pass.getTextureUnit( tui );
1285  if (tu.targetIndex < 0)
1286  continue;
1287  if (tu.targetParamId >= 0)
1289 
1290  else
1291  continue;
1292  try {
1293  activateTextureUnit( tu );
1294  tuimask |= (1<<tu.targetIndex);
1295  }
1296  catch (MissingTexture e) {
1298  //Global default for decal 0 is white, this allows textureless objects
1299  //that would otherwise not be possible
1300  static Texture *white = new Texture( "white.png" );
1301  white->MakeActive( tu.targetIndex );
1302  tuimask |= (1<<tu.targetIndex);
1303  } else {
1304  //Ok, this is an error - die horribly
1305  throw e;
1306  }
1307  }
1308  }
1309  for (tui = 0; tui < gl_options.Multitexture; ++tui)
1310  GFXToggleTexture( ( ( tuimask&(1<<tui) ) != 0 ), tui, TEXTURE2D );
1311  //Render all instances, no specific order if not necessary
1312  //TODO: right now only meshes of same kind get drawn in correct order - should fix this.
1313  static std::vector< int >indices;
1314  if (zsort) {
1315  indices.resize( cur_draw_queue.size() );
1316  for (int i = 0, n = cur_draw_queue.size(); i < n; ++i)
1317  indices[i] = i;
1318  std::sort( indices.begin(), indices.end(),
1319  MeshDrawContextPainterSort( sortctr, cur_draw_queue ) );
1320  }
1321  vlist->BeginDrawState();
1322  for (int i = 0, n = cur_draw_queue.size(); i < n; ++i) {
1323  //Making it static avoids frequent reallocations - although may be troublesome for thread safety
1324  //but... WTH... nothing is thread safe in VS.
1325  //Also: Be careful with reentrancy... right now, this section is not reentrant.
1326  static vector< int >lights;
1327  int numGlobalLights = _GLLightsEnabled;
1328  MeshDrawContext &c = cur_draw_queue[zsort ? indices[i] : i];
1329  if (c.mesh_seq == whichdrawqueue) {
1330  lights.clear();
1331  //Dynamic lights
1332  if (whichdrawqueue != MESH_SPECIAL_FX_ONLY) {
1333  int maxPerPass = pass.perLightIteration ? pass.perLightIteration : 1;
1334  int maxPassCount = pass.perLightIteration ? (pass.maxIterations ? pass.maxIterations : 32) : 1;
1335  GFXPickLights( Vector( c.mat.p.i, c.mat.p.j, c.mat.p.k ), rSize(), lights, maxPerPass*maxPassCount, true );
1336  }
1337  //FX lights
1338  size_t fxLightsBase = lights.size();
1339  for (size_t i = 0; i < c.SpecialFX->size(); i++) {
1340  int light;
1341  GFXLoadMatrixModel( c.mat );
1342  GFXCreateLight( light, (*c.SpecialFX)[i], true );
1343  lights.push_back( light );
1344  }
1345  if (c.useXtraFX) {
1346  int light;
1347  GFXLoadMatrixModel( c.mat );
1348  GFXCreateLight( light, c.xtraFX, true );
1349  lights.push_back( light );
1350  }
1351  //Fog
1352  SetupFogState( c.cloaked );
1353 
1354  //Render, iterating per light if/as requested
1355  bool popGlobals = false;
1356  size_t maxiter = 1;
1357  int maxlights = lights.size();
1358  size_t nlights = 0;
1359  if (pass.perLightIteration) {
1360  maxlights = pass.perLightIteration;
1361  maxiter = pass.maxIterations;
1362  }
1363 
1364  int npasslights = 0;
1365  for (size_t iter = 0, lightnum = 0, nlights = lights.size();
1366  (iter < maxiter) && ( (pass.perLightIteration == 0 && lightnum == 0) || (lightnum < nlights) );
1367  ++iter, lightnum += npasslights)
1368  {
1369  //Setup transform and lights
1370  npasslights = std::max( 0, std::min( int(nlights) - int(lightnum), int(maxlights) ) );
1371 
1372  //MultiAlphaBlend stuff
1373  if (iter > 0) {
1374  switch (pass.blendMode) {
1377  break;
1380  break;
1381  default:
1382  break;
1383  }
1384  }
1385 
1386  GFXLoadMatrixModel( c.mat );
1387  if (lightnum == 0) {
1389  popGlobals = true;
1390  }
1391 
1392  //Set shader parameters (instance-specific only)
1393  // NOTE: keep after GFXLoadMatrixModel
1395  numLightsParam,
1396  activeLightsArrayParam,
1397  apparentLightSizeArrayParam,
1398  true,
1399  lights.begin() + lightnum,
1400  lights.begin() + lightnum + npasslights );
1401 
1402  for (unsigned int spi = 0; spi < pass.getNumShaderParams(); ++spi) {
1403  const Technique::Pass::ShaderParam &sp = pass.getShaderParam( spi );
1404  if (sp.id >= 0) {
1405  switch (sp.semantic)
1406  {
1408  GFXShaderConstant( sp.id,
1409  c.CloakFX.r,
1410  c.CloakFX.a,
1411  ( (c.cloaked&MeshDrawContext::CLOAK) ? 1.f : 0.f ),
1412  ( (c.cloaked&MeshDrawContext::GLASSCLOAK) ? 1.f : 0.f ) );
1413  break;
1415  GFXShaderConstant( sp.id, c.damage/255.f );
1416  break;
1418  GFXShaderConstant( sp.id,
1419  c.damage/255.f,
1420  c.damage/255.f,
1421  c.damage/255.f,
1422  c.damage/255.f );
1423  break;
1424  case Technique::Pass::ShaderParam::EnvColor: //chuck_starchaser
1431  default:
1432  break;
1433  }
1434  }
1435  }
1436  vlist->Draw();
1437  }
1438  if (popGlobals)
1440  for (; fxLightsBase < lights.size(); ++fxLightsBase)
1441  GFXDeleteLight( lights[fxLightsBase] );
1442  size_t lastPass = technique->getNumPasses();
1443  if ( 0 != forcelogos && whichpass == lastPass && !(c.cloaked&MeshDrawContext::NEARINVIS) )
1444  forcelogos->Draw( c.mat );
1445  if ( 0 != squadlogos && whichpass == lastPass && !(c.cloaked&MeshDrawContext::NEARINVIS) )
1446  squadlogos->Draw( c.mat );
1447  }
1448  }
1449  vlist->EndDrawState();
1450 
1451  //Restore state
1452  GFXEnable( CULLFACE );
1453  GFXEnable( COLORWRITE );
1454  GFXEnable( DEPTHWRITE );
1455  GFXCullFace( GFXBACK );
1457  GFXPolygonOffset( 0, 0 );
1458  GFXDepthFunc( LEQUAL );
1459  if (pass.polyMode == Technique::Pass::Line)
1460  GFXLineWidth( 1 );
1461  //Restore blend mode
1462  GFXPopBlendMode();
1463 }
1464 
1465 #define GETDECAL( pass ) ( (Decal[pass]) )
1466 #define HASDECAL( pass ) ( ( (NUM_PASSES > pass) && Decal[pass] ) )
1467 #define SAFEDECAL( pass ) ( (HASDECAL( pass ) ? Decal[pass] : black) )
1468 
1469 void Mesh::ProcessFixedDrawQueue( size_t techpass, int whichdrawqueue, bool zsort, const QVector &sortctr )
1470 {
1471  const Technique::Pass &pass = technique->getPass( techpass );
1472 
1473  //First of all, decide zwrite, so we can skip the pass if !zwrite && !cwrite
1474  bool zwrite;
1475  if (whichdrawqueue == MESH_SPECIAL_FX_ONLY) {
1476  //Special effects pass - no zwrites... no zwrites...
1477  zwrite = false;
1478  } else {
1479  //Near draw queue - write to z-buffer if in auto mode and not translucent
1480  zwrite = (blendDst == ZERO);
1481  switch (pass.zWrite)
1482  {
1483  case Technique::Pass::Auto:
1484  break;
1485  case Technique::Pass::True:
1486  zwrite = true;
1487  break;
1489  zwrite = false;
1490  break;
1491  }
1492  }
1493  //If we're not writing anything... why go on?
1494  if (!pass.colorWrite && !zwrite)
1495  return;
1496 
1497  //Map texture units
1499  memset( Decal, 0, sizeof (Decal) );
1500  for (unsigned int tui = 0; tui < pass.getNumTextureUnits(); ++tui) {
1501  const Technique::Pass::TextureUnit &tu = pass.getTextureUnit( tui );
1502  switch (tu.sourceType)
1503  {
1505  //Direct file sources go in tu.texture
1506  Decal[tu.targetIndex] = tu.texture.get();
1507  break;
1509  if ( ( tu.sourceIndex < static_cast<int>(this->Decal.size()) ) && this->Decal[tu.sourceIndex] ) {
1510  //Mesh has the referenced decal
1511  Decal[tu.targetIndex] = this->Decal[tu.sourceIndex];
1512  } else {
1513  //Mesh does not have the referenced decal, activate the default
1514  switch (tu.defaultType)
1515  {
1517  //Direct file defaults go in tu.texture (direct file sources preclude defaults)
1518  Decal[tu.targetIndex] = tu.texture.get();
1519  break;
1521  //Decal reference as default - risky, but may be cool
1522  if ( ( tu.defaultIndex < static_cast<int>(this->Decal.size()) ) && this->Decal[tu.defaultIndex] )
1523  //Valid reference, activate
1524  Decal[tu.targetIndex] = this->Decal[tu.defaultIndex];
1525  else
1526  //Invalid reference, activate global default (null)
1527  Decal[tu.targetIndex] = NULL;
1528  break;
1529  case Technique::Pass::TextureUnit::None: //chuck_starchaser
1532  default:
1533  break;
1534  }
1535  }
1536  break;
1537  case Technique::Pass::TextureUnit::None: //chuck_starchaser
1540  default:
1541  break;
1542  }
1543  }
1544  std::vector< MeshDrawContext > &cur_draw_queue = draw_queue[whichdrawqueue];
1545  if ( cur_draw_queue.empty() ) {
1546  static bool thiserrdone = false; //Avoid filling up stderr.txt with this thing (it would be output at least once per frame)
1547  if (!thiserrdone) {
1548  VSFileSystem::vs_fprintf( stderr, "cloaking queues issue! Report to hellcatv@hotmail.com\nn%d\n%s",
1549  whichdrawqueue,
1550  hash_name.c_str() );
1551  }
1552  thiserrdone = true;
1553  return;
1554  }
1556 
1557  size_t DecalSize = NUM_PASSES;
1558  while ( (DecalSize > 0) && HASDECAL( DecalSize-1 ) )
1559  --DecalSize;
1560 
1561  //Restore texture units
1562  for (unsigned int i = 2; i < gl_options.Multitexture; ++i)
1563  GFXToggleTexture( false, i );
1564  bool last_pass = !DecalSize;
1565 
1566  // Set up GL state from technique-specified values
1567  setupGLState(pass, zwrite, blendSrc, blendDst, myMatNum, alphatest, whichdrawqueue);
1569  SelectCullFace( whichdrawqueue ); // Default not handled by setupGLState, it depends on mesh data
1570  if ( !getLighting() ) {
1571  GFXDisable( LIGHTING );
1572  GFXColor4f( 1, 1, 1, 1 );
1573  }
1574 
1575  GFXEnable( TEXTURE0 );
1576  if (alphatest)
1577  GFXAlphaTest( GEQUAL, alphatest/255.0 );
1578  static Texture *white = new Texture( "white.png" );
1579  static Texture *black = new Texture( "blackclear.png" );
1580  if ( HASDECAL( BASE_TEX ) )
1581  GETDECAL( BASE_TEX )->MakeActive();
1582  GFXTextureEnv( 0, GFXMODULATETEXTURE ); //Default diffuse mode
1583  GFXTextureEnv( 1, GFXADDTEXTURE ); //Default envmap mode
1584 
1585  GFXToggleTexture( (DecalSize > 0), 0 );
1586  if ( getEnvMap() ) {
1587  GFXEnable( TEXTURE1 );
1589  } else {
1590  GFXDisable( TEXTURE1 );
1591  }
1592  const GFXMaterial &mat = GFXGetMaterial( myMatNum );
1593  static bool wantsplitpass1 = XMLSupport::parse_bool( vs_config->getVariable( "graphics", "specmap_with_reflection", "false" ) );
1594  bool splitpass1 =
1595  ( wantsplitpass1 && getEnvMap()
1596  && ( (mat.sr != 0) || (mat.sg != 0)
1597  || (mat.sb != 0) ) )
1598  || ( getEnvMap() && !gl_options.Multitexture && (ENVSPEC_PASS < DecalSize) && ( !HASDECAL( ENVSPEC_TEX ) ) ); //For now, no PPL reflections with no multitexturing - There is a way, however, doing it before the diffuse texture (odd, I know). If you see this, remind me to do it (Klauss).
1599  bool skipglowpass = false;
1600  bool nomultienv = false;
1601  int nomultienv_passno = 0;
1602 
1603  size_t whichpass = BASE_PASS;
1604 
1605  if ( !gl_options.Multitexture && getEnvMap() ) {
1606  if ( HASDECAL( ENVSPEC_TEX ) ) {
1607  whichpass = ENVSPEC_PASS;
1608  nomultienv_passno = 0;
1609  } else {
1610  nomultienv_passno = 1;
1611  }
1612  nomultienv = true;
1613  }
1614  while ( ( nomultienv && (whichpass == ENVSPEC_PASS) ) || !whichpass || (whichpass < DecalSize) ) {
1615  if ( !(nomultienv_passno >= 0 && nomultienv_passno <= 2) ) {
1616  static int errcount = 0;
1617  errcount++;
1618  if (errcount < 100)
1619  fprintf( stderr, "Nomultienvpassno failure %s!\n", hash_name.c_str() );
1620  return;
1621  }
1622  if ( (whichpass == GLOW_PASS) && skipglowpass ) {
1623  whichpass++;
1624  continue;
1625  }
1626  if ( (nomultienv && whichpass == ENVSPEC_PASS) || !whichpass || HASDECAL( whichpass ) ) {
1627  switch (whichpass)
1628  {
1629  case BASE_PASS:
1630  SetupSpecMapFirstPass( Decal, DecalSize, myMatNum,
1631  getEnvMap(), polygon_offset, detailTexture, detailPlanes, skipglowpass, nomultienv
1632  && HASDECAL( ENVSPEC_TEX ) );
1633  break;
1634  case ENVSPEC_PASS:
1635  if (!nomultienv)
1636  SetupSpecMapSecondPass( SAFEDECAL( ENVSPEC_TEX ), myMatNum, blendSrc, ( splitpass1 ? false : getEnvMap() ),
1637  ( splitpass1 ? GFXColor( 1, 1, 1, 1 ) : GFXColor( 0, 0, 0, 0 ) ), polygon_offset );
1638 
1639  else
1640  SetupEnvmapPass( SAFEDECAL( ENVSPEC_TEX ), myMatNum, nomultienv_passno );
1641  break;
1642  case DAMAGE_PASS:
1644  break;
1645  case GLOW_PASS:
1647  break;
1648  }
1649  //Render all instances, no specific order if not necessary
1650  //TODO: right now only meshes of same kind get drawn in correct order - should fix this.
1651  static std::vector< int >indices;
1652  if (zsort) {
1653  indices.resize( cur_draw_queue.size() );
1654  for (int i = 0, n = cur_draw_queue.size(); i < n; ++i)
1655  indices[i] = i;
1656  std::sort( indices.begin(), indices.end(),
1657  MeshDrawContextPainterSort( sortctr, cur_draw_queue ) );
1658  }
1659  vlist->BeginDrawState();
1660  for (int i = 0, n = cur_draw_queue.size(); i < n; ++i) {
1661  //Making it static avoids frequent reallocations - although may be troublesome for thread safety
1662  //but... WTH... nothing is thread safe in VS.
1663  //Also: Be careful with reentrancy... right now, this section is not reentrant.
1664  static vector< int >specialfxlight;
1665 
1666  MeshDrawContext &c = cur_draw_queue[zsort ? indices[i] : i];
1667  if (c.mesh_seq != whichdrawqueue)
1668  continue;
1669  if (c.damage == 0 && whichpass == DAMAGE_PASS)
1670  continue; //No damage, so why draw it...
1671  if ( (c.cloaked&MeshDrawContext::CLOAK) && whichpass != 0 )
1672  continue; //Cloaking, there are no multiple passes...
1673  if (whichdrawqueue != MESH_SPECIAL_FX_ONLY) {
1675  GFXPickLights( Vector( c.mat.p.i, c.mat.p.j, c.mat.p.k ), rSize() );
1676  }
1677  specialfxlight.clear();
1678  GFXLoadMatrixModel( c.mat );
1679  unsigned char damaged = ( (whichpass == DAMAGE_PASS) ? c.damage : 0 );
1680  SetupCloakState( c.cloaked, c.CloakFX, specialfxlight, damaged, myMatNum );
1681  for (unsigned int j = 0; j < c.SpecialFX->size(); j++) {
1682  int ligh;
1683  GFXCreateLight( ligh, (*c.SpecialFX)[j], true );
1684  specialfxlight.push_back( ligh );
1685  }
1686  if (c.useXtraFX) {
1687  int ligh;
1688  GFXCreateLight( ligh, c.xtraFX, true );
1689  specialfxlight.push_back( ligh );
1690  }
1691  SetupFogState( c.cloaked );
1693  glEnable( GL_NORMALIZE );
1694  vlist->Draw();
1696  glDisable( GL_NORMALIZE );
1697  for (unsigned int j = 0; j < specialfxlight.size(); j++)
1698  GFXDeleteLight( specialfxlight[j] );
1699  RestoreCloakState( c.cloaked, getEnvMap(), damaged );
1700  if ( 0 != forcelogos && whichpass == BASE_PASS && !(c.cloaked&MeshDrawContext::NEARINVIS) )
1701  forcelogos->Draw( c.mat );
1702  if ( 0 != squadlogos && whichpass == BASE_PASS && !(c.cloaked&MeshDrawContext::NEARINVIS) )
1703  squadlogos->Draw( c.mat );
1704  }
1705  vlist->EndDrawState();
1706  switch (whichpass)
1707  {
1708  case BASE_PASS:
1709  RestoreFirstPassState( detailTexture, detailPlanes, skipglowpass, nomultienv );
1710  break;
1711  case ENVSPEC_PASS:
1712  if (!nomultienv)
1713  RestoreSpecMapState( ( splitpass1 ? false : getEnvMap() ), zwrite, polygon_offset );
1714 
1715  else
1717  break;
1718  case DAMAGE_PASS:
1719  RestoreDamageMapState( zwrite, polygon_offset ); //nothin
1720  break;
1721  case GLOW_PASS:
1723  break;
1724  }
1725  }
1726  switch (whichpass)
1727  {
1728  case BASE_PASS:
1729  if ( DecalSize > ( whichpass = ( ( nomultienv && HASDECAL( ENVSPEC_TEX ) ) ? DAMAGE_PASS : ENVSPEC_PASS ) ) )
1730  {
1731  if ( (nomultienv && whichpass == ENVSPEC_PASS) || HASDECAL( whichpass ) )
1732  break;
1733  }
1734  break; //FIXME Nothing is done here! --chuck_starchaser
1735  case ENVSPEC_PASS:
1736  if (whichpass == ENVSPEC_PASS) {
1737  //Might come from BASE_PASS and want to go to DAMAGE_PASS
1738  if (!nomultienv) {
1739  if (splitpass1) {
1740  splitpass1 = false;
1741  break;
1742  } else if ( DecalSize > (whichpass = DAMAGE_PASS) ) {
1743  if ( HASDECAL( whichpass ) ) break;
1744  } else {break; }
1745  } else {
1746  nomultienv_passno++;
1747  if ( nomultienv_passno > ( 2-( ( splitpass1 || !HASDECAL( ENVSPEC_TEX ) ) ? 0 : 1 ) ) )
1748  whichpass = HASDECAL( ENVSPEC_TEX ) ? BASE_PASS : GLOW_PASS;
1749  break;
1750  }
1751  }
1752  case DAMAGE_PASS:
1753  if ( DecalSize > (whichpass = GLOW_PASS) )
1754  {
1755  if ( HASDECAL( whichpass ) )
1756  break;
1757  }
1758  break; //FIXME Nothing is done here! --chuck_starchaser
1759  default:
1760  whichpass++; //always increment pass number, otherwise infinite loop espresso
1761  }
1762  }
1763  if (alphatest) GFXAlphaTest( ALWAYS, 0 ); //Are you sure it was supposed to be after vlist->EndDrawState()? It makes more sense to put it here...
1764  if ( !getLighting() ) GFXEnable( LIGHTING );
1765  if (!zwrite) GFXEnable( DEPTHWRITE ); //risky--for instance logos might be fubar!
1766  RestoreCullFace( whichdrawqueue );
1767 }
1768 
1769 #undef SAFEDECAL
1770 #undef GETDECAL
1771 #undef HASDECAL
1772 
1773 void Mesh::CreateLogos( MeshXML *xml, int faction, Flightgroup *fg )
1774 {
1775  numforcelogo = numsquadlogo = 0;
1776  unsigned int index;
1777  for (index = 0; index < xml->logos.size(); index++) {
1778  if (xml->logos[index].type == 0)
1779  numforcelogo++;
1780  if (xml->logos[index].type == 1)
1781  numsquadlogo++;
1782  }
1783  unsigned int nfl = numforcelogo;
1784  Logo **tmplogo = NULL;
1785  Texture *Dec = NULL;
1786  for ( index = 0, nfl = numforcelogo, tmplogo = &forcelogos, Dec = FactionUtil::getForceLogo( faction );
1787  index < 2;
1788  index++, nfl = numsquadlogo, tmplogo = &squadlogos, Dec =
1789  (fg == NULL ? FactionUtil::getSquadLogo( faction ) : fg->squadLogo) ) {
1790  if (Dec == NULL)
1791  Dec = FactionUtil::getSquadLogo( faction );
1792  if (nfl == 0)
1793  continue;
1794  Vector *PolyNormal = new Vector[nfl];
1795  Vector *center = new Vector[nfl];
1796  float *sizes = new float[nfl];
1797  float *rotations = new float[nfl];
1798  float *offset = new float[nfl];
1799  Vector *Ref = new Vector[nfl];
1800  Vector norm1, norm2, norm;
1801  int ri = 0;
1802  float totoffset = 0;
1803  for (unsigned int ind = 0; ind < xml->logos.size(); ind++)
1804  if (xml->logos[ind].type == index) {
1805  float weight = 0;
1806  norm1.Set( 0, 1, 0 );
1807  norm2.Set( 1, 0, 0 );
1808  if (xml->logos[ind].refpnt.size() > 2) {
1809  if ( xml->logos[ind].refpnt[0] < static_cast<int>(xml->vertices.size())
1810  && xml->logos[ind].refpnt[0] >= 0
1811  && xml->logos[ind].refpnt[1] < static_cast<int>(xml->vertices.size())
1812  && xml->logos[ind].refpnt[1] >= 0
1813  && xml->logos[ind].refpnt[2] < static_cast<int>(xml->vertices.size())
1814  && xml->logos[ind].refpnt[2] >= 0) {
1815  norm2 = Vector( xml->vertices[xml->logos[ind].refpnt[1]].x
1816  -xml->vertices[xml->logos[ind].refpnt[0]].x,
1817  xml->vertices[xml->logos[ind].refpnt[1]].y
1818  -xml->vertices[xml->logos[ind].refpnt[0]].y,
1819  xml->vertices[xml->logos[ind].refpnt[1]].z
1820  -xml->vertices[xml->logos[ind].refpnt[0]].z );
1821  norm1 = Vector( xml->vertices[xml->logos[ind].refpnt[2]].x
1822  -xml->vertices[xml->logos[ind].refpnt[0]].x,
1823  xml->vertices[xml->logos[ind].refpnt[2]].y
1824  -xml->vertices[xml->logos[ind].refpnt[0]].y,
1825  xml->vertices[xml->logos[ind].refpnt[2]].z
1826  -xml->vertices[xml->logos[ind].refpnt[0]].z );
1827  }
1828  }
1829  CrossProduct( norm2, norm1, norm );
1830 
1831  Normalize( norm ); //norm is our normal vect, norm1 is our reference vect
1832  Vector Cent( 0, 0, 0 );
1833  for (unsigned int rj = 0; rj < xml->logos[ind].refpnt.size(); rj++) {
1834  weight += xml->logos[ind].refweight[rj];
1835  Cent += Vector( xml->vertices[xml->logos[ind].refpnt[rj]].x*xml->logos[ind].refweight[rj],
1836  xml->vertices[xml->logos[ind].refpnt[rj]].y*xml->logos[ind].refweight[rj],
1837  xml->vertices[xml->logos[ind].refpnt[rj]].z*xml->logos[ind].refweight[rj] );
1838  }
1839  if (weight != 0) {
1840  Cent.i /= weight;
1841  Cent.j /= weight;
1842  Cent.k /= weight;
1843  }
1844  //Cent.i-=x_center;
1845  //Cent.j-=y_center;
1846  //Cent.k-=z_center;
1847  Ref[ri] = norm2;
1848  PolyNormal[ri] = norm;
1849  center[ri] = Cent;
1850  sizes[ri] = xml->logos[ind].size*xml->scale.k;
1851  rotations[ri] = xml->logos[ind].rotate;
1852  offset[ri] = xml->logos[ind].offset;
1853  totoffset += offset[ri];
1854  ri++;
1855  }
1856  totoffset /= nfl;
1857  *tmplogo = new Logo( nfl, center, PolyNormal, sizes, rotations, totoffset, Dec, Ref );
1858  delete[] Ref;
1859  delete[] PolyNormal;
1860  delete[] center;
1861  delete[] sizes;
1862  delete[] rotations;
1863  delete[] offset;
1864  }
1865 }
1866 
1867 void Mesh::initTechnique( const std::string &xmltechnique )
1868 {
1869  if ( xmltechnique.empty() ) {
1870  //Load default technique, which depends:
1871  string effective;
1872  if ( Decal.size() > 1 || getEnvMap() ) {
1873  //Use shader-ified technique for multitexture or environment-mapped meshes
1874 #ifdef __APPLE__
1875  static string shader_technique = vs_config->getVariable( "graphics", "default_full_technique", "mac" );
1876 #else
1877  static string shader_technique = vs_config->getVariable( "graphics", "default_full_technique", "default" );
1878 #endif
1879  effective = shader_technique;
1880  } else {
1881  static string fixed_technique = vs_config->getVariable( "graphics", "default_simple_technique", "fixed_simple" );
1882  effective = fixed_technique;
1883  }
1884  technique = Technique::getTechnique( effective );
1885  } else {
1886  technique = Technique::getTechnique( xmltechnique );
1887  }
1888 }
1889