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.cpp
Go to the documentation of this file.
1 /*
2  * Vega Strike
3  * Copyright (C) 2001-2002 Daniel Horn
4  *
5  * http://vegastrike.sourceforge.net/
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 #include <memory.h>
22 #include "animation.h"
23 #include "aux_logo.h"
24 #include "mesh.h"
25 #include "matrix.h"
26 #include "camera.h"
27 //#include "bounding_box.h"
28 //#include "bsp.h"
29 #include <assert.h>
30 #include <math.h>
31 #include "cmd/nebula_generic.h"
32 #include <list>
33 #include <string>
34 #include <fstream>
35 #include "vsfilesystem.h"
36 #include "lin_time.h"
37 #include "gfxlib.h"
38 #include "vs_globals.h"
39 #include "configxml.h"
40 #include "hashtable.h"
41 #include "vegastrike.h"
42 #include "sphere.h"
43 #include "lin_time.h"
44 #include "mesh_xml.h"
45 #include "gfx/technique.h"
46 #include <float.h>
47 #include <algorithm>
48 
49 #define LOD_HYSTHERESIS_DIVIDER (20)
50 #define LOD_HYSTHERESIS_MAXENLARGEMENT_FACTOR (1.1)
51 
52 using std::list;
56 
57 int Mesh::getNumAnimationFrames( const string &which ) const
58 {
59  if ( which.empty() ) {
60  vector< int > *animSeq = animationSequences.Get( hash_name );
61  if (animSeq) return animSeq->size();
62  } else {
63  vector< int > *animSeq = animationSequences.Get( hash_name+"*"+which );
64  if (animSeq) return animSeq->size();
65  }
66  return 0;
67 }
68 
70 {
71  convex = false;
72  polygon_offset = 0;
73  framespersecond = 0;
74  numlods = 1;
75  alphatest = 0;
76  lodsize = FLT_MAX;
77  forcelogos = NULL;
78  squadlogos = NULL;
79  local_pos = Vector( 0, 0, 0 );
80  blendSrc = ONE;
81  blendDst = ZERO;
82  vlist = NULL;
83  mn = Vector( 0, 0, 0 );
84  mx = Vector( 0, 0, 0 );
85  radialSize = 0;
86  GFXVertex *alphalist;
87  if ( Decal.empty() )
88  Decal.push_back( NULL );
89  alphalist = NULL;
90 
91  //texturename[0] = -1;
93  myMatNum = 0; //default material!
94  //scale = Vector(1.0,1.0,1.0);
95  refcount = 1; //FIXME VEGASTRIKE THIS _WAS_ zero...NOW ONE
96  orig = NULL;
97 
98  envMapAndLit = 0x3;
99  setEnvMap( GFXTRUE );
100  setLighting( GFXTRUE );
101  detailTexture = NULL;
102  draw_queue = NULL;
104  draw_sequence = 0;
105 
106  initTechnique( "fixed" );
107 }
108 
110 {
111  InitUnit();
112 }
113 
114 bool Mesh::LoadExistant( Mesh *oldmesh )
115 {
116  *this = *oldmesh;
117  oldmesh->refcount++;
118  orig = oldmesh;
119  return true;
120 }
121 
122 bool Mesh::LoadExistant( const string filehash, const Vector &scale, int faction )
123 {
124  Mesh *oldmesh;
125 
126  hash_name = VSFileSystem::GetHashName( filehash, scale, faction );
127  oldmesh = meshHashTable.Get( hash_name );
128  if (oldmesh == 0) {
129  hash_name = VSFileSystem::GetSharedMeshHashName( filehash, scale, faction );
130  oldmesh = meshHashTable.Get( hash_name );
131  }
132  if (0 != oldmesh)
133  return LoadExistant( oldmesh );
134  //VSFileSystem::Fprintf (stderr,"cannot cache %s",GetSharedMeshHashName(filehash,scale,faction).c_str());
135  return false;
136 }
137 
139 Mesh::Mesh( const Mesh &m )
140 {
141  fprintf( stderr, "UNTESTED MESH COPY CONSTRUCTOR" );
142  this->orig = NULL;
143  this->hash_name = m.hash_name;
144  InitUnit();
145  Mesh *oldmesh = meshHashTable.Get( hash_name );
146  if (0 == oldmesh) {
147  vector< Mesh* > *vec = bfxmHashTable.Get( hash_name );
148  for (unsigned int i = 0; i < vec->size(); ++i) {
149  Mesh *mush = (*vec)[i]->orig ? (*vec)[i]->orig : (*vec)[i];
150  if (mush == m.orig || mush == &m)
151  oldmesh = (*vec)[i];
152  }
153  if (0 == oldmesh) {
154  if (vec->size() > 1) fprintf( stderr, "Copy constructor %s used in ambiguous Situation", hash_name.c_str() );
155  if ( vec->size() )
156  oldmesh = (*vec)[0];
157  }
158  }
159  if ( LoadExistant( oldmesh->orig != NULL ? oldmesh->orig : oldmesh ) )
160  return;
161 }
162 
163 void Mesh::setConvex( bool b )
164 {
165  this->convex = b;
166  if (orig && orig != this)
167  orig->setConvex( b );
168 }
169 
170 using namespace VSFileSystem;
172 
173 Mesh::Mesh( std::string filename, const Vector &scale, int faction, Flightgroup *fg, bool orig ) : hash_name( filename )
174 {
175  this->convex = false;
176  Mesh *cpy = LoadMesh( filename.c_str(), scale, faction, fg, vector< std::string > () );
177  if (cpy->orig) {
178  LoadExistant( cpy->orig );
179  delete cpy; //wasteful, but hey
180  if (orig != false) {
181  orig = false;
182  std::vector< Mesh* > *tmp = bfxmHashTable.Get( this->orig->hash_name );
183  if (tmp && tmp->size() && (*tmp)[0] == this->orig) {
184  if (this->orig->refcount == 1) {
185  bfxmHashTable.Delete( this->orig->hash_name );
186  delete tmp;
187  orig = true;
188  }
189  }
190  if (meshHashTable.Get( this->orig->hash_name ) == this->orig) {
191  if (this->orig->refcount == 1) {
192  meshHashTable.Delete( this->orig->hash_name );
193  orig = true;
194  }
195  }
196  if (orig) {
197  Mesh *tmp = this->orig;
198  tmp->orig = this;
199  this->orig = NULL;
200  refcount = 2;
201  delete[] tmp;
202  }
203  }
204  } else {
205  delete cpy;
206  fprintf( stderr, "fallback, %s unable to be loaded as bfxm\n", filename.c_str() );
207  }
208 }
209 
210 Mesh::Mesh( const char *filename,
211  const Vector &scale,
212  int faction,
213  Flightgroup *fg,
214  bool orig,
215  const vector< string > &textureOverride ) : hash_name( filename )
216 {
217  this->convex = false;
218  this->orig = NULL;
219  InitUnit();
220  Mesh *oldmesh;
221  if ( LoadExistant( filename, scale, faction ) )
222  return;
223  bool shared = false;
224  VSFile f;
225  VSError err = Unspecified;
226  err = f.OpenReadOnly( filename, MeshFile );
227  if (err > Ok) {
228  VSFileSystem::vs_fprintf( stderr, "Cannot Open Mesh File %s\n", filename );
229 //cleanexit=1;
230 //winsys_exit(1);
231  return;
232  }
233  shared = (err == Shared);
234 
235  bool xml = true;
236  if (xml) {
237  //LoadXML(filename,scale,faction,fg,orig);
238  LoadXML( f, scale, faction, fg, orig, textureOverride );
239  oldmesh = this->orig;
240  } else {
241  //This must be changed someday
242  LoadBinary( shared ? ( VSFileSystem::sharedmeshes+"/"+(filename) ).c_str() : filename, faction );
243  oldmesh = new Mesh[1];
244  }
245  if (err <= Ok)
246  f.Close();
247  draw_queue = new vector< MeshDrawContext >[NUM_ZBUF_SEQ+1];
248  if (!orig) {
249  hash_name = shared ? VSFileSystem::GetSharedMeshHashName( filename, scale, faction ) : VSFileSystem::GetHashName(
250  filename,
251  scale,
252  faction );
253  meshHashTable.Put( hash_name, oldmesh );
254  //oldmesh[0]=*this;
255  *oldmesh = *this;
256  oldmesh->orig = NULL;
257  oldmesh->refcount++;
258  } else {
259  this->orig = NULL;
260  }
261 }
262 
263 float const ooPI = 1.00F/3.1415926535F;
264 //#include "d3d_internal.h"
265 void Mesh::SetMaterial( const GFXMaterial &mat )
266 {
267  GFXSetMaterial( myMatNum, mat );
268  if (orig)
269  for (int i = 0; i < numlods; i++)
270  orig[i].myMatNum = myMatNum;
271 }
272 
273 int Mesh::getNumLOD() const
274 {
275  return numlods;
276 }
277 
278 void Mesh::setCurrentFrame( float which )
279 {
280  framespersecond = which;
281 }
282 
284 {
285  return framespersecond;
286 }
287 
289 {
290  return vlist;
291 }
292 
294 {
295  vlist = _vlist;
296 }
297 
299 {
300  return orig ? orig->framespersecond : framespersecond;
301 }
302 
303 Mesh* Mesh::getLOD( float lod, bool bBypassDamping )
304 {
305  if (!orig)
306  return this;
307  Mesh *retval = &orig[0];
308  vector< int > *animFrames = 0;
309  if ( getFramesPerSecond() > .0000001 && ( animFrames = animationSequences.Get( hash_name ) ) ) {
310  //return &orig[(int)floor(fmod (getNewTime()*getFramesPerSecond(),numlods))];
311  unsigned int which = (int) float_to_int( floor( fmod( getCurrentFrame(),
312  animFrames->size() ) ) );
313  float adv = GetElapsedTime()*getFramesPerSecond();
314  static float max_frames_skipped =
315  XMLSupport::parse_float( vs_config->getVariable( "graphics", "mesh_animation_max_frames_skipped", "3" ) );
316  if (adv > max_frames_skipped)
317  adv = max_frames_skipped;
319  return &orig[(*animFrames)[which%animFrames->size()]%getNumLOD()];
320  } else {
321  float maxlodsize = retval ? retval->lodsize : 0.0f;
322  for (int i = 1; i < numlods; i++) {
323  float lodoffs = 0;
324  if (!bBypassDamping) {
325  if (lod < orig[i].lodsize)
326  lodoffs = ( (i < numlods-1) ? (orig[i+1].lodsize-orig[i].lodsize)/LOD_HYSTHERESIS_DIVIDER : 0.0f );
327  else
328  lodoffs = ( (i > 0) ? (orig[i-1].lodsize-orig[i].lodsize)/LOD_HYSTHERESIS_DIVIDER : 0.0f );
329  float maxenlargement = ( (orig[i].lodsize*LOD_HYSTHERESIS_MAXENLARGEMENT_FACTOR)-orig[i].lodsize );
330  if ( (lodoffs > 0) && (lodoffs > maxenlargement) ) lodoffs = maxenlargement; //Avoid excessive enlargement of low-detail LOD levels, when LOD levels are far apart.
331  }
332  if ( ( lod < (orig[i].lodsize+lodoffs) ) && (lod < maxlodsize) ) {
333  maxlodsize = orig[i].lodsize;
334  retval = &orig[i];
335  }
336  }
337  }
338  return retval;
339 }
340 
341 void Mesh::SetBlendMode( BLENDFUNC src, BLENDFUNC dst, bool lodcascade )
342 {
343  blendSrc = src;
344  blendDst = dst;
345  draw_sequence = 0;
346  if (blendDst != ZERO) {
347  draw_sequence++;
348  if (blendDst != ONE)
349  draw_sequence++;
350  }
351  if (orig) {
352  orig->draw_sequence = draw_sequence;
353  orig->blendSrc = src;
354  orig->blendDst = dst;
355  if (lodcascade) {
356  for (int i = 1; i < numlods; i++) {
357  orig[i].draw_sequence = draw_sequence;
358  orig[i].blendSrc = src;
359  orig[i].blendDst = dst;
360  }
361  }
362  }
363 }
364 
366 inline bool OpenWithin( const QVector &query,
367  const Vector &mn,
368  const Vector &mx,
369  const float err,
370  enum EX_EXCLUSION excludeWhich )
371 {
372  switch (excludeWhich)
373  {
374  case EX_X:
375  return (query.j >= mn.j-err) && (query.k >= mn.k-err) && (query.j <= mx.j+err) && (query.k <= mx.k+err);
376 
377  case EX_Y:
378  return (query.i >= mn.i-err) && (query.k >= mn.k-err) && (query.i <= mx.i+err) && (query.k <= mx.k+err);
379 
380  case EX_Z:
381  default:
382  return (query.j >= mn.j-err) && (query.i >= mn.i-err) && (query.j <= mx.j+err) && (query.i <= mx.i+err);
383  }
384 }
385 /*
386 bool Mesh::queryBoundingBox( const QVector &eye, const QVector &end, const float err ) const
387 {
388  QVector slope( end-eye );
389  QVector IntersectXYZ;
390  double k = ( (mn.i-eye.i)/slope.i );
391  IntersectXYZ = eye+k*slope; //(Normal dot (mn-eye)/div)*slope
392  if ( OpenWithin( IntersectXYZ, mn, mx, err, EX_X ) )
393  return true;
394  k = ( (mx.i-eye.i)/slope.i );
395  if (k >= 0) {
396  IntersectXYZ = eye+k*slope;
397  if ( OpenWithin( IntersectXYZ, mn, mx, err, EX_X ) )
398  return true;
399  }
400  k = ( (mn.j-eye.j)/slope.j );
401  if (k >= 0) {
402  IntersectXYZ = eye+k*slope;
403  if ( OpenWithin( IntersectXYZ, mn, mx, err, EX_Y ) )
404  return true;
405  }
406  k = ( (mx.j-eye.j)/slope.j );
407  if (k >= 0) {
408  IntersectXYZ = eye+k*slope;
409  if ( OpenWithin( IntersectXYZ, mn, mx, err, EX_Y ) )
410  return true;
411  }
412  k = ( (mn.k-eye.k)/slope.k );
413  if (k >= 0) {
414  IntersectXYZ = eye+k*slope;
415  if ( OpenWithin( IntersectXYZ, mn, mx, err, EX_Z ) )
416  return true;
417  }
418  k = ( (mx.k-eye.k)/slope.k );
419  if (k >= 0) {
420  IntersectXYZ = eye+k*slope;
421  if ( OpenWithin( IntersectXYZ, mn, mx, err, EX_Z ) )
422  return true;
423  }
424  return false;
425 }
426 
427 bool Mesh::queryBoundingBox( const QVector &start, const float err ) const
428 {
429  return start.i >= mn.i-err && start.j >= mn.j-err && start.k >= mn.k-err
430  && start.i <= mx.i+err && start.j <= mx.j+err && start.k <= mx.k+err;
431 }
432 
433 BoundingBox* Mesh::getBoundingBox()
434 {
435  BoundingBox *tbox = new BoundingBox( QVector( mn.i, 0, 0 ), QVector( mx.i, 0, 0 ),
436  QVector( 0, mn.j, 0 ), QVector( 0, mx.j, 0 ),
437  QVector( 0, 0, mn.k ), QVector( 0, 0, mx.k ) );
438  return tbox;
439 }
440 */