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
planet.cpp
Go to the documentation of this file.
1 #include <math.h>
2 #include "vegastrike.h"
3 #include "unit_factory.h"
4 #include "planet.h"
5 #include "gfxlib.h"
6 #include "gfx/sphere.h"
7 #include "collection.h"
8 #include "ai/order.h"
9 #include "gfxlib_struct.h"
10 #include "vs_globals.h"
11 #include "config_xml.h"
12 #include <assert.h>
13 #include "cont_terrain.h"
14 #include "atmosphere.h"
15 #ifdef FIX_TERRAIN
16 #include "gfx/planetary_transform.h"
17 #endif
18 
20 #include "images.h"
21 #include "gfx/halo.h"
22 #include "gfx/animation.h"
23 #include "cmd/script/flightgroup.h"
24 #include "gfx/ring.h"
25 #include "alphacurve.h"
26 #include "gfx/vsimage.h"
27 #include "vsfilesystem.h"
28 #include "gfx/camera.h"
29 
31  GameUnit< Planet > ( 0 )
32 {
33  atmosphere = NULL;
34  terrain = NULL;
35  radius = 0.0;
36  shine = NULL;
37  inside = false;
38  Init();
39  terraintrans = NULL;
40  SetAI( new Order() ); //no behavior
41 }
42 
43 static void SetFogMaterialColor( Mesh *thus, const GFXColor &color, const GFXColor &dcolor )
44 {
45  GFXMaterial m;
46  m.ar = m.ag = m.ab = m.aa = m.sr = m.sg = m.sb = m.sa = 0;
47  m.power = 0;
48  static float emm = XMLSupport::parse_float( vs_config->getVariable( "graphics", "atmosphere_emmissive", "1" ) );
49  static float diff = XMLSupport::parse_float( vs_config->getVariable( "graphics", "atmosphere_diffuse", "1" ) );
50  m.er = emm*color.r;
51  m.eg = emm*color.g;
52  m.eb = emm*color.b;
53  m.ea = emm*color.a;
54  m.dr = diff*dcolor.r;
55  m.dg = diff*dcolor.g;
56  m.db = diff*dcolor.b;
57  m.da = diff*dcolor.a;
58  thus->SetMaterial( m );
59 }
60 Mesh * MakeFogMesh( const AtmosphericFogMesh &f, float radius )
61 {
62  static int count = 0;
63  count++;
64  string nam = f.meshname+XMLSupport::tostring( count )+".png";
65  if (f.min_alpha != 0 || f.max_alpha != 255 || f.concavity != 0 || f.focus != .5 || f.tail_mode_start != -1
66  || f.tail_mode_end != -1) {
67  static int rez = XMLSupport::parse_int( vs_config->getVariable( "graphics", "atmosphere_texture_resolution", "512" ) );
68  unsigned char *tex = (unsigned char*) malloc( sizeof (char)*rez*4 );
69  for (int i = 0; i < rez; ++i) {
70  tex[i*4] = 255;
71  tex[i*4+1] = 255;
72  tex[i*4+2] = 255;
73  tex[i*4+3] = get_alpha( i, rez, f.min_alpha, f.max_alpha, f.focus, f.concavity, f.tail_mode_start, f.tail_mode_end );
74  }
75  //Writing in the homedir texture directory
76  ::VSImage image;
78  image.WriteImage( (char*) nam.c_str(), &tex[0], PngImage, rez, 1, true, 8, TextureFile );
79  }
80  vector< string >override;
81  override.push_back( nam );
82  Mesh *ret = Mesh::LoadMesh( f.meshname.c_str(), Vector( f.scale*radius, f.scale*radius, f.scale*radius ), 0, NULL, override );
83  ret->setConvex( true );
84  SetFogMaterialColor( ret, GFXColor( f.er, f.eg, f.eb, f.ea ), GFXColor( f.dr, f.dg, f.db, f.da ) );
85  return ret;
86 }
87 
88 class AtmosphereHalo : public GameUnit< Unit >
89 {
90 public:
91  float planetRadius;
92  AtmosphereHalo( float radiusOfPlanet, vector< Mesh* > &meshes, int faction ) :
93  GameUnit< Unit > ( meshes, true, faction )
94  {
95  planetRadius = radiusOfPlanet;
96  }
97  virtual void Draw( const Transformation &quat = identity_transformation, const Matrix &m = identity_matrix )
98  {
99  QVector dirtocam = _Universe->AccessCamera()->GetPosition()-m.p;
100  Transformation qua = quat;
101  Matrix mat = m;
102  float distance = dirtocam.Magnitude();
103 
104  float MyDistanceRadiusFactor = planetRadius/distance;
105  float HorizonHeight = sqrt( 1-MyDistanceRadiusFactor*MyDistanceRadiusFactor )*planetRadius;
106 
107  float zscale;
108  float xyscale = zscale = HorizonHeight/planetRadius;
109  zscale = 0;
110  dirtocam.Normalize();
111  mat.p += sqrt( planetRadius*planetRadius-HorizonHeight*HorizonHeight )*dirtocam;
112  ScaleMatrix( mat, Vector( xyscale, xyscale, zscale ) );
113  qua.position = mat.p;
114  GameUnit< Unit >::Draw( qua, mat );
115  }
116 };
117 void GamePlanet::AddFog( const std::vector< AtmosphericFogMesh > &v, bool opticalillusion )
118 {
119  if ( meshdata.empty() ) meshdata.push_back( NULL );
120 #ifdef MESHONLY
121  Mesh *shield = meshdata.back();
122  meshdata.pop_back();
123 #endif
124  std::vector< Mesh* >fogs;
125  for (unsigned int i = 0; i < v.size(); ++i) {
126  Mesh *fog = MakeFogMesh( v[i], rSize() );
127  fogs.push_back( fog );
128  }
129  Unit *fawg;
130  if (opticalillusion)
131  fawg = new AtmosphereHalo( this->rSize(), fogs, 0 );
132  else
133  fawg = UnitFactory::createUnit( fogs, true, 0 );
134  fawg->setFaceCamera();
135  getSubUnits().preinsert( fawg );
136  fawg->hull /= fawg->GetHullPercent();
137 #ifdef MESHONLY
138  meshdata.push_back( shield );
139 #endif
140 }
141 void GamePlanet::AddCity( const std::string &texture,
142  float radius,
143  int numwrapx,
144  int numwrapy,
145  BLENDFUNC blendSrc,
146  BLENDFUNC blendDst,
147  bool inside_out,
148  bool reverse_normals )
149 {
150  if ( meshdata.empty() )
151  meshdata.push_back( NULL );
152  Mesh *shield = meshdata.back();
153  meshdata.pop_back();
154  GFXMaterial m;
155  m.ar = m.ag = m.ab = m.aa = 0.0;
156  static float materialweight = XMLSupport::parse_float( vs_config->getVariable( "graphics", "city_light_strength", "10" ) );
157  static float daymaterialweight =
158  XMLSupport::parse_float( vs_config->getVariable( "graphics", "day_city_light_strength", "0" ) );
159  m.dr = m.dg = m.db = m.da = materialweight;
160  m.sr = m.sg = m.sb = m.sa = 0.0;
161  m.er = m.eg = m.eb = m.ea = daymaterialweight;
162  m.power = 0.0;
163  static int stacks = XMLSupport::parse_int( vs_config->getVariable( "graphics", "planet_detail", "24" ) );
164  meshdata.push_back( new CityLights( radius, stacks, stacks, texture.c_str(), numwrapx, numwrapy, inside_out, ONE, ONE,
165  false, 0, M_PI, 0.0, 2*M_PI, reverse_normals ) );
166  meshdata.back()->setEnvMap( GFXFALSE );
167  meshdata.back()->SetMaterial( m );
168 
169  meshdata.push_back( shield );
170 }
171 
172 Vector GamePlanet::AddSpaceElevator( const std::string &name, const std::string &faction, char direction )
173 {
174  //direction is udrlfb//up down right left front ack
175  return Planet::AddSpaceElevator( name, faction, direction );
176 }
177 void GamePlanet::AddAtmosphere( const std::string &texture,
178  float radius,
179  BLENDFUNC blendSrc,
180  BLENDFUNC blendDst,
181  bool inside_out )
182 {
183  if ( meshdata.empty() )
184  meshdata.push_back( NULL );
185  Mesh *shield = meshdata.back();
186  meshdata.pop_back();
187  static int stacks = XMLSupport::parse_int( vs_config->getVariable( "graphics", "planet_detail", "24" ) );
188  meshdata.push_back( new SphereMesh( radius, stacks, stacks, texture.c_str(), string(), NULL, inside_out, blendSrc, blendDst ) );
189  if ( meshdata.back() ) {
190  //By klauss - this needs to be done for most atmospheres
191  GFXMaterial a = {
192  0, 0, 0, 0,
193  1, 1, 1, 1,
194  0, 0, 0, 0,
195  0, 0, 0, 0,
196  0
197  };
198  meshdata.back()->SetMaterial( a );
199  }
200  meshdata.push_back( shield );
201 }
202 void GamePlanet::AddRing( const std::string &texture,
203  float iradius,
204  float oradius,
205  const QVector &R,
206  const QVector &S,
207  int slices,
208  int wrapx,
209  int wrapy,
210  BLENDFUNC blendSrc,
211  BLENDFUNC blendDst )
212 {
213  if ( meshdata.empty() )
214  meshdata.push_back( NULL );
215  Mesh *shield = meshdata.back();
216  meshdata.pop_back();
217  static int stacks = XMLSupport::parse_int( vs_config->getVariable( "graphics", "planet_detail", "24" ) );
218  if (slices > 0) {
219  stacks = stacks;
220  if (stacks < 3)
221  stacks = 3;
222  for (int i = 0; i < slices; i++)
223  meshdata.push_back( new RingMesh( iradius, oradius, stacks, texture.c_str(), R, S, wrapx, wrapy, blendSrc, blendDst,
224  false, i*(2*M_PI)/( (float) slices ), (i+1)*(2*M_PI)/( (float) slices ) ) );
225  }
226  meshdata.push_back( shield );
227 }
228 
229 extern const vector< string >& ParseDestinations( const string &value );
231  QVector y,
232  float vely,
233  const Vector &rotvel,
234  float pos,
235  float gravity,
236  float radius,
237  const string &textname,
238  const string &technique,
239  const string &unitname,
240  BLENDFUNC blendSrc,
241  BLENDFUNC blendDst,
242  const vector< string > &dest,
243  const QVector &orbitcent,
244  Unit *parent,
245  const GFXMaterial &ourmat,
246  const std::vector< GFXLightLocal > &ligh,
247  int faction,
248  string fgid,
249  bool inside_out ) :
250  GameUnit< Planet > ( 0 )
251 {
252  atmosphere = NULL;
253  terrain = NULL;
254 
255  shine = NULL;
256  unsigned int nlights = 0;
257  if ( !ligh.empty() )
258  nlights = ligh.size();
259  for (unsigned int i = 0; i < nlights; i++) {
260  int l;
261  GFXCreateLight( l, ligh[i].ligh, !ligh[i].islocal );
262  lights.push_back( l );
263  }
264  bool wormhole = dest.size() != 0;
265  if (wormhole) {
266  static std::string wormhole_unit = vs_config->getVariable( "graphics", "wormhole", "wormhole" );
267  string stab( ".stable" );
268  if (rand() > RAND_MAX*.99)
269  stab = ".unstable";
270  string wormholename = wormhole_unit+stab;
271  string wormholeneutralname = wormhole_unit+".neutral"+stab;
272  Unit *jum = UnitFactory::createUnit( wormholename.c_str(), true, faction );
273  int neutralfaction = FactionUtil::GetNeutralFaction();
274  faction = neutralfaction;
275 
276  Unit *neujum = UnitFactory::createUnit( wormholeneutralname.c_str(), true, neutralfaction );
277  Unit *jump = jum;
278  bool anytrue = false;
279  while (jump != NULL) {
280  if (jump->name != "LOAD_FAILED") {
281  anytrue = true;
282  radius = jump->rSize();
283  Mesh *shield = jump->meshdata.size() ? jump->meshdata.back() : NULL;
284  if ( jump->meshdata.size() ) jump->meshdata.pop_back();
285  while ( jump->meshdata.size() ) {
286  this->meshdata.push_back( jump->meshdata.back() );
287  jump->meshdata.pop_back();
288  }
289  jump->meshdata.push_back( shield );
290  Unit *su;
291  for (un_kiter i = jump->viewSubUnits(); (su = *i) != NULL; ++i)
292  SubUnits.prepend( su );
293  jump->SubUnits.clear();
294  }
295  jump->Kill();
296  if (jump != neujum)
297  jump = neujum;
298  else
299  jump = NULL;
300  }
301  if (anytrue)
302  meshdata.push_back( NULL ); //shield mesh...otherwise is a standard planet
303  wormhole = anytrue;
304  }
305  if (!wormhole) {
306  static int stacks = XMLSupport::parse_int( vs_config->getVariable( "graphics", "planet_detail", "24" ) );
307  atmospheric = !(blendSrc == ONE && blendDst == ZERO);
308  meshdata.push_back( new SphereMesh( radius, stacks, stacks, textname.c_str(), technique, NULL, inside_out, blendSrc, blendDst ) );
309  meshdata.back()->setEnvMap( GFXFALSE );
310  meshdata.back()->SetMaterial( ourmat );
311  meshdata.push_back( NULL );
312  }
313  calculate_extent( false );
314  if (wormhole) {
315  static float radscale = XMLSupport::parse_float( vs_config->getVariable( "physics", "jump_mesh_radius_scale", ".5" ) );
316  radius *= radscale;
317  corner_min.i = corner_min.j = corner_min.k = -radius;
318  corner_max.i = corner_max.j = corner_max.k = radius;
319  radial_size = radius;
320  if ( !meshdata.empty() )
321  meshdata[0]->setVirtualBoundingBox( corner_min, corner_max, radius );
322  }
323  if (ligh.size() > 0) {
324  static float bodyradius = XMLSupport::parse_float( vs_config->getVariable( "graphics", "star_body_radius", ".33" ) );
325  static bool drawglow = XMLSupport::parse_bool( vs_config->getVariable( "graphics", "draw_star_glow", "true" ) );
326 
327  static bool drawstar = XMLSupport::parse_bool( vs_config->getVariable( "graphics", "draw_star_body", "true" ) );
328  static float glowradius =
329  XMLSupport::parse_float( vs_config->getVariable( "graphics", "star_glow_radius", "1.33" ) )/bodyradius;
330  if (drawglow) {
331  GFXColor c( ourmat.er, ourmat.eg, ourmat.eb, ourmat.ea );
332  static bool spec = XMLSupport::parse_bool( vs_config->getVariable( "graphics", "glow_ambient_star_light", "false" ) );
333  static bool diff = XMLSupport::parse_bool( vs_config->getVariable( "graphics", "glow_diffuse_star_light", "false" ) );
334  if (diff)
335  c = ligh[0].ligh.GetProperties( DIFFUSE );
336  if (spec)
337  c = ligh[0].ligh.GetProperties( AMBIENT );
338  static vector< string >shines = ParseDestinations( vs_config->getVariable( "graphics", "star_shine", "shine.ani" ) );
339  if ( shines.empty() )
340  shines.push_back( "shine.ani" );
341  shine = new Animation( shines[rand()%shines.size()].c_str(), true, .1, BILINEAR, false, true, c ); //GFXColor(ourmat.er,ourmat.eg,ourmat.eb,ourmat.ea));
342  shine->SetDimensions( glowradius*radius, glowradius*radius );
343  if (!drawstar) {
344  delete meshdata[0];
345  meshdata.clear();
346  meshdata.push_back( NULL );
347  }
348  }
349  }
350  this->InitPlanet( x, y, vely, rotvel,
351  pos,
352  gravity, radius,
353  textname, technique, unitname,
354  dest,
355  orbitcent, parent,
356  faction, fgid,
357  inside_out,
358  nlights );
359 }
360 
361 vector< UnitContainer* >PlanetTerrainDrawQueue;
362 void GamePlanet::Draw( const Transformation &quat, const Matrix &m )
363 {
364  //Do lighting fx
365  //if cam inside don't draw?
366  //if(!inside) {
367  GameUnit< Planet >::Draw( quat, m );
368  //}
369  QVector t( _Universe->AccessCamera()->GetPosition()-Position() );
370  static int counter = 0;
371  if (counter++ > 100) {
372  if (t.Magnitude() < corner_max.i) {
373  inside = true;
374  } else {
375  inside = false;
377  if (terrain) {
378 #ifdef PLANETARYTRANSFORM
379  terrain->DisableUpdate();
380 #endif
381  }
382  }
383  }
385  for (unsigned int i = 0; i < lights.size(); i++)
386  GFXSetLight( lights[i], POSITION, GFXColor( cumulative_transformation.position.Cast() ) );
387  if (inside && terrain)
388  PlanetTerrainDrawQueue.push_back( new UnitContainer( this ) );
389  if (shine) {
390  Vector p, q, r;
391  QVector c;
392  MatrixToVectors( cumulative_transformation_matrix, p, r, q, c );
393  shine->SetOrientation( p, q, r );
394  shine->SetPosition( c );
395  static int num_shine_drawing =
396  XMLSupport::parse_int( vs_config->getVariable( "graphics", "num_times_to_draw_shine", "2" ) );
397  for (int i = 0; i < num_shine_drawing; ++i)
398  shine->Draw();
399  }
400 }
402 {
403  while ( !PlanetTerrainDrawQueue.empty() ) {
404  Planet *pl = (Planet*) PlanetTerrainDrawQueue.back()->GetUnit();
405  pl->DrawTerrain();
406  PlanetTerrainDrawQueue.back()->SetUnit( NULL );
407  delete PlanetTerrainDrawQueue.back();
408  PlanetTerrainDrawQueue.pop_back();
409  }
410 }
411 
413 {
414  inside = true;
415  if (terrain)
416  terrain->EnableUpdate();
417 #ifdef PLANETARYTRANSFORM
418  TerrainUp = t;
419  Normalize( TerrainUp );
420  TerrainH = TerrainUp.Cross( Vector( -TerrainUp.i+.25, TerrainUp.j-.24, -TerrainUp.k+.24 ) );
421  Normalize( TerrainH );
422 #endif
423 
425  if (inside && terrain) {
427  terrain->SetTransformation( *_Universe->AccessCamera()->GetPlanetGFX() );
428  terrain->AdjustTerrain( _Universe->activeStarSystem() );
429  terrain->Draw();
430 #ifdef PLANETARYTRANSFORM
431  terraintrans->GrabPerpendicularOrigin( _Universe->AccessCamera()->GetPosition(), tmp );
432  terrain->SetTransformation( tmp );
433  terrain->AdjustTerrain( _Universe->activeStarSystem() );
434  terrain->Draw();
435  if (atmosphere) {
436  Vector tup( tmp[4], tmp[5], tmp[6] );
438  Vector blah = p-Vector( tmp[12], tmp[13], tmp[14] );
439  blah = p-( blah.Dot( tup ) )*tup;
440  tmp[12] = blah.i;
441  tmp[13] = blah.j;
442  tmp[14] = blah.k;
443  atmosphere->SetMatricesAndDraw( _Universe->AccessCamera()->GetPosition(), tmp );
444  }
445 #endif
446  }
447 }
448 
449 extern bool CrashForceDock( Unit *thus, Unit *dockingUn, bool force );
450 extern void abletodock( int dock );
452  const QVector &biglocation,
453  const Vector &bignormal,
454  const QVector &smalllocation,
455  const Vector &smallnormal,
456  float dist )
457 {
458 #ifdef JUMP_DEBUG
459  VSFileSystem::vs_fprintf( stderr, "%s reacting to collision with %s drive %d", name.c_str(),
460  un->name.c_str(), un->GetJumpStatus().drive );
461 #endif
462 #ifdef FIX_TERRAIN
463  if (terrain && un->isUnit() != PLANETPTR) {
464  un->SetPlanetOrbitData( terraintrans );
465  Matrix top;
466  Identity( top );
467  /*
468  * Vector posRelToTerrain = terraintrans->InvTransform(un->LocalPosition());
469  * top[12]=un->Position().i- posRelToTerrain.i;
470  * top[13]=un->Position().j- posRelToTerrain.j;
471  * top[14]=un->Position().k- posRelToTerrain.k;
472  */
473  Vector P, Q, R;
474  un->GetOrientation( P, Q, R );
475  terraintrans->InvTransformBasis( top, P, Q, R, un->Position() );
476  Matrix inv, t;
477 
478  InvertMatrix( inv, top );
479  VectorAndPositionToMatrix( t, P, Q, R, un->Position() );
480  MultMatrix( top, t, inv );
481 #ifdef PLANETARYTRANSFORM
482  terraintrans->GrabPerpendicularOrigin( un->Position(), top );
483  static int tmp = 0;
484 #endif
485  terrain->Collide( un, top );
486  }
487 #endif
488  jumpReactToCollision( un );
489  //screws with earth having an atmosphere... blahrgh
490  if (!terrain && GetDestinations().empty() && !atmospheric) {
491  //no place to go and acts like a ship
492  GameUnit< Planet >::reactToCollision( un, biglocation, bignormal, smalllocation, smallnormal, dist );
493  static bool planet_crash_docks =
494  XMLSupport::parse_bool( vs_config->getVariable( "physics", "planet_collision_docks", "true" ) );
495  if (_Universe->isPlayerStarship( un ) && planet_crash_docks)
496  CrashForceDock( this, un, true );
497  }
498  //nothing happens...you fail to do anythign :-)
499  //maybe air reisstance here? or swithc dynamics to atmos mode
500 }
502 {
503  for (unsigned int i = 0; i < lights.size(); i++)
504  GFXEnableLight( lights[i] );
505 }
507 {
508  for (unsigned int i = 0; i < lights.size(); i++)
510 }
512 {
513  if (shine)
514  delete shine;
515  if (terrain)
516  delete terrain;
517  if (atmosphere)
518  delete atmosphere;
519 #ifdef FIX_TERRAIN
520  if (terraintrans) {
521  Matrix *tmp = new Matrix();
522  *tmp = cumulative_transformation_matrix;
523  terraintrans->SetTransformation( tmp );
524  //FIXME
525  //We're losing memory here...but alas alas... planets don't die that often
526  }
527 #endif
528 }
529 
530 PlanetaryTransform* GamePlanet::setTerrain( ContinuousTerrain *t, float ratiox, int numwraps, float scaleatmos )
531 {
532  terrain = t;
533  terrain->DisableDraw();
534  float x, z;
535  t->GetTotalSize( x, z );
536 #ifdef FIX_TERRAIN
537  terraintrans = new PlanetaryTransform( .8*corner_max.i, x*ratiox, z, numwraps, scaleatmos );
538  terraintrans->SetTransformation( &cumulative_transformation_matrix );
539 
540  return terraintrans;
541 #endif
542  return NULL;
543 }
544 
546 {
547  atmosphere = t;
548 }
549 
550 void GamePlanet::Kill( bool erasefromsave )
551 {
552  Unit *tmp;
553  for (un_iter iter = satellites.createIterator(); (tmp=*iter)!=NULL; ++iter)
554  tmp->SetAI( new Order );
555  /* probably not FIXME...right now doesn't work on paged out systems... not a big deal */
556  for (unsigned int i = 0; i < this->lights.size(); i++)
557  GFXDeleteLight( lights[i] );
558  /* */
559  satellites.clear();
560  insiders.clear();
561  GameUnit< Planet >::Kill( erasefromsave );
562 }