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
gl_light_pick.cpp
Go to the documentation of this file.
1 #include "gl_light.h"
2 #include "options.h"
3 #include <queue>
4 #include <list>
5 #include "vsfilesystem.h"
6 
7 #include <vector>
8 #include <algorithm>
9 using std::priority_queue;
10 #include "hashtable_3d.h"
11 //using std::list;
12 using std::vector;
13 //optimization globals
14 float intensity_cutoff = 0.06; //something that would normally round down
15 float optintense = 0.2;
16 float optsat = 0.95;
17 
18 struct light_key
19 {
20  int number;
23  {
24  intensity_key = number = 0;
25  }
26  light_key( int num, float inte )
27  {
28  number = num;
29  intensity_key = inte;
30  }
31 };
32 static bool operator<( light_key tmp1, light_key tmp2 )
33 {
34  return tmp1.intensity_key < tmp2.intensity_key;
35 }
36 
37 static priority_queue< light_key >lightQ;
38 
39 //pickedlights was a list, but lists imply heavy reallocation, which is bad in critical sections
40 //( and pickedlights is used in the most critical section: just before GFXVertexList::Draw() )
41 static vector< int > pickedlights[2];
42 static vector< int > *newpicked = &pickedlights[0];
43 static vector< int > *oldpicked = &pickedlights[1];
45  std::vector<int>::iterator where;
46  for (int i=0;i<2;++i) {
47  while ((where=std::find(pickedlights[i].begin(),pickedlights[i].end(),index))!=pickedlights[i].end()) {
48  pickedlights[i].erase(where);
49  }
50  }
51 }
52 
53 inline int getIndex( const LineCollide &t )
54 {
55  return t.object.i;
56 }
57 static void swappicked()
58 {
59  if (newpicked == &pickedlights[0]) {
60  newpicked = &pickedlights[1];
61  oldpicked = &pickedlights[0];
62  } else {
63  newpicked = &pickedlights[0];
64  oldpicked = &pickedlights[1];
65  }
66  newpicked->clear();
67 }
68 
70 {
71  for (std::vector< int >::iterator i = newpicked->begin(); i != newpicked->end(); i++) {
72  if (*i>=(int)_llights->size()) {
73  VSFileSystem::vs_fprintf (stderr,"GFXLIGHT FAILURE %d is beyond array of size %d",(int)*i,(int)_llights->size());
74  }
75  if (GLLights[(*_llights)[*i].Target()].index != *i) {
76  VSFileSystem::vs_fprintf (stderr,"GFXLIGHT uh oh");
77  (*_llights)[*i].Target() = -1;
78  continue; //a lengthy operation... Since picked lights may have been smashed
79  }
80  int targ = (*_llights)[*i].Target();
81  if (GLLights[targ].options&OpenGLL::GL_ENABLED) {
82  glDisable( GL_LIGHT0+targ );
84  GLLights[targ].index = -1;
85  (*_llights)[*i].Target() = -1; //unref
86  }
87  }
88  newpicked->clear();
89  oldpicked->clear();
90 }
91 
92 static float attenuatedIntensity( const gfx_light &light, const Vector &center, const float rad )
93 {
94  float intensity = (1.0/3.0)*(
95  light.diffuse[0]+light.specular[0]
96  +light.diffuse[1]+light.specular[1]
97  +light.diffuse[2]+light.specular[2]);
98  float distance = float( (Vector( light.vect[0], light.vect[1], light.vect[2] )-center).Magnitude() )-rad;
99  float cf = light.attenuate[0]; //constant factor
100  float lf = light.attenuate[1]; //linear factor
101  float qf = light.attenuate[2]; //quadratic factor
102  float att = (cf+lf*distance+qf*distance*distance);
103  if ( (distance <= 0) || (att <= 0) )
104  return 1.f;
105 
106  else
107  return (intensity/att) >= light.cutoff;
108 }
109 
110 static bool picklight( const LineCollide &lightcollide,
111  const Vector &center,
112  const float rad,
113  const int lightsenabled,
114  const int lightindex )
115 {
116  const gfx_light &light = (*_llights)[lightindex];
117  return !light.attenuated()
118  || (attenuatedIntensity( light, center, rad ) >= light.cutoff);
119 }
120 
121 struct lightsort
122 {
124  float rad;
125 
126  lightsort( const Vector &_center, const float _rad ) : center( _center )
127  , rad( _rad ) {}
128 
129  bool operator()( const int a, const int b ) const
130  {
131  const gfx_light &lighta = (*_llights)[a];
132  const gfx_light &lightb = (*_llights)[b];
133  return attenuatedIntensity( lighta, center, rad ) > attenuatedIntensity( lightb, center, rad );
134  }
135 };
136 
137 typedef vector< LineCollideStar >veclinecol;
138 
139 void GFXPickLights( const Vector &center, const float radius, vector< int > &lights, const int maxlights, const bool pickglobals )
140 {
141  QVector tmp;
142  //Beware if re-using rndvar !! Because rand returns an int and on 64 bits archs sizeof( void*) != sizeof( int) !!!
143  //void * rndvar = (void *)rand();
144  int lightsenabled = _GLLightsEnabled;
145  tmp = QVector( radius, radius, radius );
146 
147  if (lightsenabled && pickglobals) {
148  // Push global lights into the picked set
149  for (int i = 0; i < GFX_MAX_LIGHTS; ++i) {
151  // It's global and enabled
152  lights.push_back(GLLights[i].index);
153  }
154  }
155  }
156 
157  veclinecol *tmppickt[2];
158  lighttable.Get( center.Cast(), tmppickt );
159 
160  for (int j = 0; j < 2; j++) {
161  veclinecol::iterator i;
162 
163  for (i = tmppickt[j]->begin(); i != tmppickt[j]->end(); i++) {
164  if ( picklight( *i->lc, center, radius, lightsenabled, i->GetIndex() ) ) {
165  lights.push_back( i->GetIndex() );
166  lightsenabled++;
167  }
168  }
169  }
170  std::sort( lights.begin(), lights.end(), lightsort( center, radius ) );
171 }
172 
173 void GFXPickLights( const Vector &center, const float radius )
174 {
175  swappicked();
176  GFXPickLights( center, radius, *newpicked, 8, false );
178 }
179 
180 void GFXPickLights( vector< int >::const_iterator begin, vector< int >::const_iterator end )
181 {
182  swappicked();
183  newpicked->insert( newpicked->end(), begin, end );
185 }
186 
188 {
189  //sort it to find minimum num lights changed from last time.
190  sort( newpicked->begin(), newpicked->end() );
191  //newpicked->sort();
192  std::vector< int >::iterator traverse = newpicked->begin();
193  std::vector< int >::iterator oldtrav;
194  while ( traverse != newpicked->end() && ( !oldpicked->empty() ) ) {
195  oldtrav = oldpicked->begin();
196  while (oldtrav != oldpicked->end() && *oldtrav < *traverse)
197  oldtrav++;
198  if ( ( (*traverse) == (*oldtrav) ) && ( (*_llights)[*oldtrav].target >= 0 ) )
199  //BOGUS ASSERT... just like this light wasn't on if it was somehow clobberedassert (GLLights[(*_llights)[oldpicked->front()].target].index == oldpicked->front());
200  oldpicked->erase( oldtrav ); //already taken care of. main screen turn on ;-)
201  traverse++;
202  }
203  oldtrav = oldpicked->begin();
204  while ( oldtrav != oldpicked->end() ) {
205  if ( GLLights[(*_llights)[(*oldtrav)].target].index != (*oldtrav) ) {
206  oldtrav++;
207  continue; //don't clobber what's not yours
208  }
209  GLLights[(*_llights)[(*oldtrav)].target].index = -1;
210  GLLights[(*_llights)[(*oldtrav)].target].options &= (OpenGLL::GL_ENABLED&OpenGLL::GLL_LOCAL); //set it to be desirable to kill
211  oldtrav++;
212  }
213  traverse = newpicked->begin();
214  while ( traverse != newpicked->end() ) {
215  if (*traverse>=(int)_llights->size()) {
216  VSFileSystem::vs_fprintf (stderr,"GFXLIGHT FAILURE %d is beyond array of size %d",(int)*traverse,(int)_llights->size());
217  traverse++;
218  continue;
219  }
220  if ( (*_llights)[*traverse].target == -1 ) {
221  int gltarg = findLocalClobberable();
222  if (gltarg == -1) {
223  newpicked->erase( traverse, newpicked->end() ); //erase everything on the picked list. Nothing can fit;
224  break;
225  }
226  (*_llights)[(*traverse)].ClobberGLLight( gltarg );
227  }
228  traverse++;
229  }
230  /*while (!oldpicked->empty()) {
231  * int glind=(*_llights)[oldpicked->front()].target;
232  * if ((GLLights[glind].options&OpenGLL::GL_ENABLED)&&GLLights[glind].index==-1) {//if hasn't been duly clobbered
233  * glDisable (GL_LIGHT0+glind);
234  * GLLights[glind].options &= (~OpenGLL::GL_ENABLED);
235  * }
236  * (*_llights)[oldpicked->front()].target=-1;//make sure it doesn't think it owns any gl lights!
237  * oldpicked->pop_front();
238  * }*/
239  for (oldtrav = oldpicked->begin(); oldtrav != oldpicked->end(); oldtrav++) {
240  if (*oldtrav>=(int)_llights->size()) {
241  VSFileSystem::vs_fprintf (stderr,"GFXLIGHT FAILURE %d is beyond array of size %d",(int)*oldtrav,(int)_llights->size());
242  continue;
243  }
244 
245  int glind = (*_llights)[*oldtrav].target;
246  if ( (GLLights[glind].options&OpenGLL::GL_ENABLED) && GLLights[glind].index == -1 ) {
247  //if hasn't been duly clobbered
248  glDisable( GL_LIGHT0+glind );
249  GLLights[glind].options &= (~OpenGLL::GL_ENABLED);
250  }
251  (*_llights)[*oldtrav].target = -1; //make sure it doesn't think it owns any gl lights!
252  }
253  oldpicked->clear();
254 }
255 
256 #ifdef MIRACLESAVESDAY
257 
258 void /*GFXDRVAPI*/ GFXPickLights( const float *transform )
259 {
260  //picks 1-5 lights to use
261  //glMatrixMode(GL_MODELVIEW);
262  //glPushMatrix();
263  //float tm [16]={1,0,0,1000,0,1,0,1000,0,0,1,1000,0,0,0,1};
264  //glLoadIdentity();
265  //GFXLoadIdentity(MODEL);
266  if (!GFXLIGHTING) return;
267  Vector loc( transform[12], transform[13], transform[14] );
268  SetLocalCompare( loc );
269  newQsize = 0;
270  unsigned int i;
271  light_key tmpvar;
272  unsigned int lightQsize = lightQ.size();
273  for (i = 0; i < lightQsize; i++) {
274  tmpvar = lightQ.top();
275  if (i < GFX_MAX_LIGHTS) {
276  //do more stuff with intensity before hacking it to hell
277  if (i > GFX_OPTIMAL_LIGHTS) {
280  break; //no new lights
281  } else {
282  if (i == GFX_OPTIMAL_LIGHTS-2 && tmpvar.intensity_key < .25*optintense)
283  break; //no new lights
284  if (i == GFX_OPTIMAL_LIGHTS-1 && tmpvar.intensity_key < .5*optintense)
285  break; //no new lights
286  if (i == GFX_OPTIMAL_LIGHTS && tmpvar.intensity_key < optintense)
287  break;
288  }
289  newQsize++;
290 #ifdef PER_MESH_ATTENUATE
291  if ( (*_llights)[i].vect[3] ) {
292  //intensity now has become the attenuation factor
293  newQ[i] = tmpvar.number;
294  AttenuateQ[i] = tmpvar.intensity_key/(*_llights)[i].intensity;
295  } else {
296 #endif
297  newQ[i] = tmpvar.number;
298 #ifdef PER_MESH_ATTENUATE
299  AttenuateQ[i] = 0;
300  }
301 #endif
302  } else
303  break;
304  lightQ.pop();
305  }
306  unsigned int light;
307  for (i = 0; i < newQsize; i++) {
308  light = newQ[i];
309  if ( (*_llights)[light].target >= 0 ) {
310 #ifdef PER_MESH_ATTENUATE
311  if (AttenuateQ[i])
312  EnableExistingAttenuated( light, AttenuateQ[i] );
313  else
314 #endif
315  EnableExisting( newQ[i] );
316  /***daniel 081901
317  * AttTmp[0]=(*_llights)[light].vect[0]-loc.i;
318  * AttTmp[1]=(*_llights)[light].vect[1]-loc.j;
319  * AttTmp[2]=(*_llights)[light].vect[2]-loc.k;
320  * VecT[3]=0;
321  * VecT[0]=AttTmp[0]*transform[0]+AttTmp[1]*transform[1]+AttTmp[2]*transform[2];
322  * VecT[1]=AttTmp[0]*transform[4]+AttTmp[1]*transform[5]+AttTmp[2]*transform[6];
323  * VecT[2]=AttTmp[0]*transform[8]+AttTmp[1]*transform[9]+AttTmp[2]*transform[10];
324  *
325  * glLightfv (GL_LIGHT0+(*_llights)[light].target, GL_POSITION, VecT);
326  ****/
327  }
328  }
329  for (i = 0; i < GFX_MAX_LIGHTS; i++)
330  DisableExisting( i );
331  //go through newQ and tag all existing lights for enablement
332  //disable rest of lights
333  //ForceActivate the rest.
334  unsigned int tmp = 0; //where to start looking for disabled lights
335  unsigned int newtarg = 0;
336  for (i = 0; i < newQsize; i++) {
337  light = newQ[i];
338  if ( (*_llights)[light].target == -1 ) {
339  if (AttenuateQ[i])
340  ForceEnableAttenuated( light, AttenuateQ[i], tmp, newtarg );
341  else
342  ForceEnable( light, tmp, newtarg );
343  AttTmp[0] = (*_llights)[light].vect[0]-loc.i;
344  AttTmp[1] = (*_llights)[light].vect[1]-loc.j;
345  AttTmp[2] = (*_llights)[light].vect[2]-loc.k;
346  AttTmp[3] = 0;
347  VecT[0] = AttTmp[0]*transform[0]+AttTmp[1]*transform[1]+AttTmp[2]*transform[2];
348  VecT[1] = AttTmp[0]*transform[4]+AttTmp[1]*transform[5]+AttTmp[2]*transform[6];
349  VecT[2] = AttTmp[0]*transform[8]+AttTmp[1]*transform[9]+AttTmp[2]*transform[10];
350  glLightfv( GL_LIGHT0+(*_llights)[light].target, GL_POSITION, VecT );
351 
352  //glLightfv (GL_LIGHT0+(*llight_dat)[newQ[i]].target, GL_POSITION, /*wrong*/(*_llights)[light].vect);
353  }
354  }
355  //glPopMatrix();
356 }
357 
358 /*
359  * curlightloc.intensity=(curlight.specular[0]+curlight.specular[1]+curlight.specular[2]+curlight.diffuse[0]+curlight.diffuse[1]+curlight.diffuse[2]+curlight.ambient[0]+curlight.ambient[1]+curlight.ambient[2])*.333333333333333333333333;//calculate new cuttof val for light 'caching'
360  */
361 #endif
362