LightEnv::LightEnv( const std::string& envFilename ) : m_fLightAttenuation(40.0f) { std::ifstream fileStream(envFilename.c_str()); if(!fileStream.is_open()) throw std::runtime_error("Could not find the mesh file."); TiXmlDocument theDoc; fileStream >> theDoc; fileStream.close(); if(theDoc.Error()) throw std::runtime_error(theDoc.ErrorDesc()); TiXmlHandle docHandle(&theDoc); const TiXmlElement *pRootNode = docHandle.FirstChild("lightenv").ToElement(); if(!pRootNode) throw std::runtime_error("The root node must be a 'lightenv' element."); pRootNode->QueryFloatAttribute("atten", &m_fLightAttenuation); m_fLightAttenuation = 1.0f / (m_fLightAttenuation * m_fLightAttenuation); const TiXmlElement *pSunNode = docHandle.FirstChild("lightenv").FirstChild("sun").ToElement(); if(!pSunNode) throw std::runtime_error("There must be a 'lightenv' element that has a 'sun' element as a child."); float timerTime = 0; if(pSunNode->QueryFloatAttribute("time", &timerTime) != TIXML_SUCCESS) throw std::runtime_error("'sun' elements must have a 'time' attribute that is a float."); m_sunTimer = Framework::Timer(Framework::Timer::TT_LOOP, timerTime); LightVector ambient; LightVector light; LightVector background; MaxIntensityVector maxIntensity; for(const TiXmlElement *pKeyElem = pSunNode->FirstChildElement("key"); pKeyElem; pKeyElem = pKeyElem->NextSiblingElement("key")) { float keyTime = 0; if(pKeyElem->QueryFloatAttribute("time", &keyTime) != TIXML_SUCCESS) throw std::runtime_error("'key' elements must have a 'time' attribute that is a float."); //Convert from hours to normalized time. keyTime = keyTime / 24.0f; std::string strVec4; if(pKeyElem->QueryStringAttribute("ambient", &strVec4) != TIXML_SUCCESS) throw std::runtime_error("'key' elements must have an 'ambient' attribute."); ambient.push_back(LightData(ParseVec4(strVec4), keyTime)); if(pKeyElem->QueryStringAttribute("intensity", &strVec4) != TIXML_SUCCESS) throw std::runtime_error("'key' elements must have a 'intensity' attribute."); light.push_back(LightData(ParseVec4(strVec4), keyTime)); if(pKeyElem->QueryStringAttribute("background", &strVec4) != TIXML_SUCCESS) throw std::runtime_error("'key' elements must have a 'background' attribute."); background.push_back(LightData(ParseVec4(strVec4), keyTime)); maxIntensity.push_back(MaxIntensityData(0.0f, keyTime)); if(pKeyElem->QueryFloatAttribute("max-intensity", &maxIntensity.back().first) != TIXML_SUCCESS) throw std::runtime_error("'key' elements must have a 'max-intensity' attribute that is a float."); } if(ambient.empty()) throw std::runtime_error("'sun' element must have at least one 'key' element child."); m_ambientInterpolator.SetValues(ambient); m_sunlightInterpolator.SetValues(light); m_backgroundInterpolator.SetValues(background); m_maxIntensityInterpolator.SetValues(maxIntensity); const TiXmlElement *pLightNode = docHandle.FirstChild("lightenv").FirstChild("light").ToElement(); for(; pLightNode; pLightNode = pLightNode->NextSiblingElement("light")) { if(m_lightPos.size() + 1 == MAX_NUMBER_OF_LIGHTS) throw std::runtime_error("Too many lights specified."); float lightTime = 0; if(pLightNode->QueryFloatAttribute("time", &lightTime) != TIXML_SUCCESS) throw std::runtime_error("'light' elements must have a 'time' attribute that is a float."); m_lightTimers.push_back(Framework::Timer(Framework::Timer::TT_LOOP, lightTime)); std::string strVec4; if(pLightNode->QueryStringAttribute("intensity", &strVec4) != TIXML_SUCCESS) throw std::runtime_error("'light' elements must have an 'intensity' attribute."); m_lightIntensity.push_back(ParseVec4(strVec4)); std::vector<glm::vec3> posValues; for(const TiXmlElement *pKeyElem = pLightNode->FirstChildElement("key"); pKeyElem; pKeyElem = pKeyElem->NextSiblingElement("key")) { posValues.push_back(ParseVec3(pKeyElem->GetText())); } if(posValues.empty()) throw std::runtime_error("'light' elements must have at least one 'key' element child."); m_lightPos.push_back(LightInterpolator()); m_lightPos.back().SetValues(posValues); } }
LightEnv::LightEnv( const std::string& envFilename ) : m_fLightAttenuation(40.0f) { std::ifstream fileStream(envFilename.c_str()); if(!fileStream.is_open()) throw std::runtime_error("Could not find the mesh file."); std::vector<char> fileData; fileData.reserve(2000); fileData.insert(fileData.end(), std::istreambuf_iterator<char>(fileStream), std::istreambuf_iterator<char>()); fileData.push_back('\0'); xml_document<> doc; try { doc.parse<0>(&fileData[0]); } catch(rapidxml::parse_error &e) { std::cout << envFilename << ": Parse error in light environment file." << std::endl; std::cout << e.what() << std::endl << e.where<char>() << std::endl; throw; } xml_node<> *pRootNode = doc.first_node("lightenv"); PARSE_THROW(pRootNode, ("lightenv node not found in light environment file: " + envFilename)); m_fLightAttenuation = rapidxml::get_attrib_float(*pRootNode, "atten", m_fLightAttenuation); m_fLightAttenuation = 1.0f / (m_fLightAttenuation * m_fLightAttenuation); xml_node<> *pSunNode = pRootNode->first_node("sun"); PARSE_THROW(pSunNode, "lightenv node must have a first child that is called `sun`."); m_sunTimer = Framework::Timer(Framework::Timer::TT_LOOP, rapidxml::get_attrib_float(*pSunNode, "time", ThrowAttrib)); LightVector ambient; LightVector light; LightVector background; MaxIntensityVector maxIntensity; for(const xml_node<> *pKeyNode = pSunNode->first_node("key"); pKeyNode; pKeyNode = pKeyNode->next_sibling("key")) { float keyTime = rapidxml::get_attrib_float(*pKeyNode, "time", ThrowAttrib); //Convert from hours to normalized time. keyTime = keyTime / 24.0f; ambient.push_back(LightData( rapidxml::get_attrib_vec4(*pKeyNode, "ambient", ThrowAttrib), keyTime)); light.push_back(LightData( rapidxml::get_attrib_vec4(*pKeyNode, "intensity", ThrowAttrib), keyTime)); background.push_back(LightData( rapidxml::get_attrib_vec4(*pKeyNode, "background", ThrowAttrib), keyTime)); maxIntensity.push_back(MaxIntensityData( rapidxml::get_attrib_float(*pKeyNode, "max-intensity", ThrowAttrib), keyTime)); } if(ambient.empty()) throw std::runtime_error("'sun' element must have at least one 'key' element child."); m_ambientInterpolator.SetValues(ambient); m_sunlightInterpolator.SetValues(light); m_backgroundInterpolator.SetValues(background); m_maxIntensityInterpolator.SetValues(maxIntensity); for(xml_node<> *pLightNode = pRootNode->first_node("light"); pLightNode; pLightNode = pLightNode->next_sibling("light")) { if(m_lightPos.size() + 1 == MAX_NUMBER_OF_LIGHTS) throw std::runtime_error("Too many lights specified."); m_lightTimers.push_back(Framework::Timer( Framework::Timer::TT_LOOP, rapidxml::get_attrib_float(*pLightNode, "time", ThrowAttrib))); m_lightIntensity.push_back(rapidxml::get_attrib_vec4( *pLightNode, "intensity", ThrowAttrib)); std::vector<glm::vec3> posValues; for(xml_node<> *pKeyNode = pLightNode->first_node("key"); pKeyNode; pKeyNode = pKeyNode->next_sibling("key")) { posValues.push_back(ParseVec3(make_string(*pKeyNode))); } if(posValues.empty()) throw std::runtime_error("'light' elements must have at least one 'key' element child."); m_lightPos.push_back(LightInterpolator()); m_lightPos.back().SetValues(posValues); } }