/*************************************************************************** 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::iterator iter = g->m_vShape3D.begin(); vector::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::iterator diffuseIter = s->m_vLight.begin(); vector::iterator diffuseEnd = s->m_vLight.end(); vector::iterator specularIter = s->m_vSpecular.begin(); vector::iterator nmlTransIter = s->m_vNmlTrans.begin(); vector::iterator nmlAlignIter = s->m_vNmlAlign.begin(); //vector::iterator specularEnd = s->m_vSpecular.end(); //vector::iterator nmlTransEnd = s->m_vNmlTrans.end(); //vector::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::iterator lightIter = m_vLight.begin(); vector::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::iterator vtxTransIter = s->m_vVtxTrans.begin(); vector::iterator vtxTransEnd = s->m_vVtxTrans.end(); vector::iterator vtxAlignIter = s->m_vVtxAlign.begin(); vector::iterator nmlTransIter = s->m_vNmlTrans.begin(); vector::iterator nmlAlignIter = s->m_vNmlAlign.begin(); vector::iterator diffuseIter = s->m_vLight.begin(); vector::iterator specularIter = s->m_vSpecular.begin(); //vector::iterator vtxAlignEnd = s->m_vVtxAlign.end(); //vector::iterator nmlTransEnd = s->m_vNmlTrans.end(); //vector::iterator nmlAlignEnd = s->m_vNmlAlign.end(); //vector::iterator diffuseEnd = s->m_vLight.end(); //vector::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::iterator diffuseIter = s->m_vLight.begin(); vector::iterator diffuseEnd = s->m_vLight.end(); vector::iterator specularIter = s->m_vSpecular.begin(); vector::iterator colorIter = s->m_vColor.begin(); vector::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); */ }