File: AmbientLightVisitor.cpp

package info (click to toggle)
pinball 0.3.20201218-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 8,452 kB
  • sloc: cpp: 15,230; makefile: 840; sh: 381; xml: 24
file content (256 lines) | stat: -rw-r--r-- 10,388 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/***************************************************************************
                          AmbientLightVisitor.cpp  -  description
                             -------------------
    begin                : Wed Jan 26 2000
    copyright            : (C) 2000 by Henrik Enqvist 
    email                : henqvist@excite.com
***************************************************************************/

#include "Private.h"
#include "AmbientLightVisitor.h"
#include "Group.h"
#include "Shape3D.h"
#include "Polygon.h"
#include "Config.h"
#include "Light.h"

AmbientLightVisitor * AmbientLightVisitor::p_AmbientLightVisitor = NULL;

AmbientLightVisitor::AmbientLightVisitor(int size) {
  m_fStrength = (float)0.1;
  m_fBackground = (float)0.0;
  m_vLight.reserve(size);
}

AmbientLightVisitor::~AmbientLightVisitor() {
  p_AmbientLightVisitor = NULL;
}

AmbientLightVisitor * AmbientLightVisitor::getInstance() {
  if (p_AmbientLightVisitor == NULL) {
    p_AmbientLightVisitor = new AmbientLightVisitor();
  }
  return p_AmbientLightVisitor;
}

void AmbientLightVisitor::add(Light* l) {
  if (l == NULL) return;
  m_vLight.push_back(l);
}

void AmbientLightVisitor::clear() {
  m_vLight.clear();
}

void AmbientLightVisitor::setLightning(float s, float bg) {
  m_fStrength = s;
  m_fBackground = bg;
#if OPENGL_LIGHTS
  GLfloat amb[] = {bg, bg, bg, 1};
  glLightModelfv(GL_LIGHT_MODEL_AMBIENT,amb);

  glEnable(GL_LIGHT0);
	
  // create light
  GLfloat pos[] = {0.0f, 10000.0f, 0.0f, 0.0f};
  GLfloat light[] = {s, s, s, 1.0f};
  glLightfv(GL_LIGHT0, GL_POSITION, pos);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, light);
  glLightfv(GL_LIGHT0, GL_SPECULAR, light);
#endif
}

void AmbientLightVisitor::visit(Group * g) {
  // Check properties before applying light
  if (g->m_iProperties & EM_GROUP_NO_LIGHT) return;

  if (g->m_iProperties & EM_GROUP_LIGHT_ONCE) {
    g->unsetProperty(EM_GROUP_LIGHT_ONCE);
    g->setProperty(EM_GROUP_NO_LIGHT);
  } 

  vector<Shape3D*>::iterator iter = g->m_vShape3D.begin();
  vector<Shape3D*>::iterator end = g->m_vShape3D.end();
  for ( ; iter != end; iter++) {
    if ((*iter)->m_iProperties & (EM_SHAPE3D_HIDDEN | EM_SHAPE3D_ALWAYSLIT)) continue;
    //if ((*iter)->m_iProperties & EM_SHAPE3D_TRANS) continue;
    //if ((*iter)->m_iProperties & EM_SHAPE3D_HIDDEN) continue;
    this->visitAmbient((*iter));
    this->visitPoint((*iter));
  }
}

void AmbientLightVisitor::visitAmbient(Shape3D* s) {
  EM_COUT("AmbientLightVisitor::visit()" << endl, 0);
  //TODO Flat polygons - who cares about flat polygons anyway
  EM_COUT_D("AmbientLightVisitor::visit() shape lights " << 
	    (*shapeIter)->m_vLight.size() << " normal " << 
	    (*shapeIter)->m_vNmlTrans.size() << endl, 0);
  // Count light for all vertices.
  vector<Color>::iterator diffuseIter = s->m_vLight.begin();
  vector<Color>::iterator diffuseEnd = s->m_vLight.end();
  vector<Color>::iterator specularIter = s->m_vSpecular.begin();
  vector<Vertex3D>::iterator nmlTransIter = s->m_vNmlTrans.begin();
  vector<Vertex3D>::iterator nmlAlignIter = s->m_vNmlAlign.begin();
  //vector<Color>::iterator specularEnd = s->m_vSpecular.end();
  //vector<Vertex3D>::iterator nmlTransEnd = s->m_vNmlTrans.end();
  //vector<Vertex3D>::iterator nmlAlignEnd = s->m_vNmlAlign.end();
  
  for ( ; diffuseIter != diffuseEnd; 
	++diffuseIter, ++nmlTransIter, ++nmlAlignIter, ++specularIter) {
    // Count angle between normal and y-axis.
    float fAngle = (*nmlTransIter).y;
    float fLight = fAngle/2 + 0.5;
    //			float fLight = 0.5;
    (*diffuseIter).r = fLight * m_fStrength + m_fBackground;
    (*diffuseIter).r = EM_MIN(1.0, (*diffuseIter).r);
    (*diffuseIter).g = (*diffuseIter).b = (*diffuseIter).r;
    EM_COUT_D("Light " << (*diffuseIter).r << " "	<< (*diffuseIter).g << " " << 
	      (*diffuseIter).b << endl, 0);
    // TODO: Move if-specular outside for loop
    // specular light
#if EM_USE_GLOBAL_SPECULAR
    if (s->m_iProperties & EM_SHAPE3D_SPECULAR) {
      Vertex3D vtxRef = {0,0,-1};
      Vertex3D vtxDir = {0,-1,0};
      EMath::reflection(vtxDir, (*nmlAlignIter), vtxRef, false);
      EMath::normalizeVector(vtxRef); // TODO: optimize - remove normalize
      //float view = EMath::dotProduct((*nmlAlignIter), vtxView); // TODO: optimize
      float spe = EM_MAX(0.0f, vtxRef.z);
      float spe2 = spe * spe;
      float spe4 = spe2 * spe2;
      (*specularIter).r = (*specularIter).g = (*specularIter).b = spe4 * spe4 * 0.5;
    } else {
      (*specularIter).r = (*specularIter).g = (*specularIter).b = 0;
    }
#else
    (*specularIter).r = (*specularIter).g = (*specularIter).b = 0;
#endif
  }
}

void AmbientLightVisitor::visitPoint(Shape3D * s) {
  if (Config::getInstance()->useLights()) {
    vector<Light*>::iterator lightIter = m_vLight.begin();
    vector<Light*>::iterator lightEnd = m_vLight.end();
    EM_COUT("PointLightVisitor::visit() lights " << m_vLight.size(), 0);
    for ( ; lightIter != lightEnd; ++lightIter) {
      if (!(*lightIter)->m_bOn) continue;
      // TODO check bounds with collision bounds so that we don't
      // need to check every vertex.
      // TODO ugly optimization: if statements moved outside for loop		
      vector<Vertex3D>::iterator vtxTransIter = s->m_vVtxTrans.begin();
      vector<Vertex3D>::iterator vtxTransEnd = s->m_vVtxTrans.end();
      vector<Vertex3D>::iterator vtxAlignIter = s->m_vVtxAlign.begin();
      vector<Vertex3D>::iterator nmlTransIter = s->m_vNmlTrans.begin();
      vector<Vertex3D>::iterator nmlAlignIter = s->m_vNmlAlign.begin();
      vector<Color>::iterator diffuseIter = s->m_vLight.begin();
      vector<Color>::iterator specularIter = s->m_vSpecular.begin();
      //vector<Vertex3D>::iterator vtxAlignEnd = s->m_vVtxAlign.end();
      //vector<Vertex3D>::iterator nmlTransEnd = s->m_vNmlTrans.end();
      //vector<Vertex3D>::iterator nmlAlignEnd = s->m_vNmlAlign.end();
      //vector<Color>::iterator diffuseEnd = s->m_vLight.end();
      //vector<Color>::iterator specularEnd = s->m_vSpecular.end();
      
      for ( ; vtxTransIter != vtxTransEnd; 
	    ++vtxTransIter, ++vtxAlignIter, ++nmlTransIter, 
	      ++nmlAlignIter, ++diffuseIter, ++specularIter) {
	if ((*lightIter)->m_iProperties & EM_USE_DIFFUSE) {
	  Vertex3D vtxLight;
	  // Get length from vertex to light
	  vtxLight.x = (*lightIter)->m_vtxTrans.x - (*vtxTransIter).x;
	  vtxLight.y = (*lightIter)->m_vtxTrans.y - (*vtxTransIter).y;
	  vtxLight.z = (*lightIter)->m_vtxTrans.z - (*vtxTransIter).z;
	  float lengthsqr = EMath::vectorLengthSqr(vtxLight);
	  // Check bounds
	  if (((*lightIter)->m_iProperties & EM_USE_BOUNDS) && 
	      lengthsqr > ((*lightIter)->m_fBounds*(*lightIter)->m_fBounds)) {
	    continue;
	  }
	  // TODO Move if statement outside for loop for performance
	  // Calculate angle between normal and light
	  float light;
	  if ((*lightIter)->m_iProperties & EM_IGNORE_ANGLE_FULL) {
	    light = 1;
	  } else if ((*lightIter)->m_iProperties & EM_IGNORE_ANGLE_HALF) {
	    EMath::normalizeVector(vtxLight);
	    float angle = EMath::dotProduct((*nmlTransIter), vtxLight);
	    light = angle; // 1.0f - EMath::emAcos(angle)/EM_PI_DIV_2; // ??
	    if (light > 0.0f) light = 1.0f;
	  } else {
	    EMath::normalizeVector(vtxLight);
	    float angle = EMath::dotProduct((*nmlTransIter), vtxLight);
	    light = angle;// 1.0f - EMath::emAcos(angle)/EM_PI_DIV_2;
	    light = EM_MAX(0.0f, light);
	  }
	  // Calculate distance
	  float k;
	  if ((*lightIter)->m_iProperties & EM_IGNORE_DISTANCE) {
	    k = light;
	  } else {
	    k = light / ((*lightIter)->m_fConstant + 
			 (*lightIter)->m_fLinear * EMath::emSqrt(lengthsqr) + 
			 (*lightIter)->m_fQuadratic * lengthsqr);
	  }
	  (*diffuseIter).r += k * (*lightIter)->m_fR;
	  (*diffuseIter).g += k * (*lightIter)->m_fG;
	  (*diffuseIter).b += k * (*lightIter)->m_fB;
	}
	// specular light
#if EM_USE_SOURCE_SPECULAR
	if ((s->m_iProperties & EM_SHAPE3D_SPECULAR) && 
	    ((*lightIter)->m_iProperties & EM_USE_SPECULAR)) {
	  float specular;
	  Vertex3D vtxRef = {0.0f ,0.0f , -1.0f};
	  Vertex3D vtxDir;
	  vtxDir.x = (*vtxAlignIter).x - (*lightIter)->m_vtxAlign.x;
	  vtxDir.y = (*vtxAlignIter).y - (*lightIter)->m_vtxAlign.y;
	  vtxDir.z = (*vtxAlignIter).z - (*lightIter)->m_vtxAlign.z;
	  EMath::reflection(vtxDir, (*nmlAlignIter), vtxRef, false);
	  EMath::normalizeVector(vtxRef); // TODO: optimize - remove normalize
	  //float view = EMath::dotProduct((*nmlAlignIter), vtxView); // TODO: optimize
	  float spe = EM_MAX(0.0f, vtxRef.z);
	  float spe2 = spe * spe;
	  float spe4 = spe2 * spe2;
	  specular = spe4 * spe4;
	  
	  (*specularIter).r += specular * (*lightIter)->m_fR;
	  (*specularIter).g += specular * (*lightIter)->m_fG;
	  (*specularIter).b += specular * (*lightIter)->m_fB;
	} 
#endif
	EM_COUT_D("PointLightVisitor::visit() factor " << k, 0);
	EM_COUT_D("PointLightVisitor::visit() specular " << specular, 0);
      }
    }
  } // if config->useLights
  // apply the lights to the color
  // TODO textured polygons don't need color if filter != -1
  vector<Color>::iterator diffuseIter = s->m_vLight.begin();
  vector<Color>::iterator diffuseEnd = s->m_vLight.end();
  vector<Color>::iterator specularIter = s->m_vSpecular.begin();
  vector<Color>::iterator colorIter = s->m_vColor.begin();
  vector<Color>::iterator litColorIter = s->m_vLitColor.begin();
  // move if statement outside loop for performance
  //if (s->m_iProperties & EM_SHAPE3D_SPECULAR) {
  for (; diffuseIter != diffuseEnd;
       ++diffuseIter, ++specularIter, ++colorIter, ++litColorIter) {
    (*litColorIter).r = (*colorIter).r * (*diffuseIter).r + (*specularIter).r;
    (*litColorIter).g = (*colorIter).g * (*diffuseIter).g + (*specularIter).g;
    (*litColorIter).b = (*colorIter).b * (*diffuseIter).b + (*specularIter).b;
    (*litColorIter).a = (*colorIter).a;
  }
  //   } else {
  //     for (; diffuseIter != diffuseEnd;
  // 	 ++diffuseIter, ++specularIter, ++colorIter, ++litColorIter) {
  //       (*litColorIter).r = (*colorIter).r * (*diffuseIter).r;
  //       (*litColorIter).g = (*colorIter).g * (*diffuseIter).g;
  //       (*litColorIter).b = (*colorIter).b * (*diffuseIter).b;
  //       (*litColorIter).a = (*colorIter).a;
  //     }
  /*
    (*litColorIter).r = EM_MAX((*litColorIter).r, 1.0f);
    (*litColorIter).g = EM_MAX((*litColorIter).g, 1.0f);
    (*litColorIter).b = EM_MAX((*litColorIter).b, 1.0f);
  */
}