IqmTypeMap getShader(XMLElement*elShade, ShaderPtr& sPtr, uint32_t nMat, uint32_t nLights){ // this will store all vertex attributes IqmTypeMap ret; // Check to see if all variables described in XML are present string v(check("Vertex", elShade)->Attribute("src")); string f(check("Fragment", elShade)->Attribute("src")); ifstream vIn("../Resources/Shaders/" + v), fIn("../Resources/Shaders/" + f); string vSrc((istreambuf_iterator<char>(vIn)), istreambuf_iterator<char>()); string fSrc((istreambuf_iterator<char>(fIn)), istreambuf_iterator<char>()); // Set the light and geom (material) count in the shaders auto setNum = [nMat, nLights](string& shdrSrc){ auto pos = shdrSrc.find("\n"); shdrSrc.insert(pos + 1, "#define NUM_MATS " + std::to_string(nMat) + "\n"); shdrSrc.insert(pos + 1, "#define NUM_LIGHTS " + std::to_string(nLights) + "\n"); }; setNum(vSrc); setNum(fSrc); sPtr = Shader::FromSource(vSrc, fSrc); auto sBind = sPtr->Bind(); // Declared vertex attributes XMLElement * attrs = check("Attributes", elShade); // Make sure those variables exist in the shader for (auto el = attrs->FirstChildElement(); el; el = el->NextSiblingElement()){ string type(el->Value()); string var(el->GetText()); GLint handle = sPtr->getHandle(var); // Should I have the shader ensure it's an attribute? // A negative handle means the query was unsuccessful if (handle < 0){ cout << "Invalid variable queried in shader " << var << endl; continue; //exit(6); } // Populate returned map if (type.compare("Position") == 0) ret[IqmFile::IQM_T::POSITION] = handle; else if (type.compare("TexCoord") == 0) ret[IqmFile::IQM_T::TEXCOORD] = handle; else if (type.compare("Normal") == 0) ret[IqmFile::IQM_T::NORMAL] = handle; else if (type.compare("Tangent") == 0) ret[IqmFile::IQM_T::TANGENT] = handle; } return ret; }
void setupMiscUniforms(const ShaderPtr& sPtr){ // Uniform Handles (really shouldn't be hard coded like this) Camera::SetProjHandle(sPtr->getHandle("PV")); // Projection Matrix Camera::SetPosHandle(sPtr->getHandle("u_wCameraPos")); // World Space cam pos //Camera::SetCHandle(shader["C"]); // Camera Matrix Geometry::setMHandle(sPtr->getHandle("M")); // World transform Matrix Geometry::setNHandle(sPtr->getHandle("N")); // Normal Matrix Geometry::setMatIdxHandle(sPtr->getHandle("mIdx")); // If these end up negative, so be it Material::SetTexMapHandle(sPtr->getHandle("u_TextureMap")); // Texture Map Sampler Material::SetNrmMapHandle(sPtr->getHandle("u_NormalMap")); // Normal Map Sample; // This causes GL_TEXTUREi to be associated with an int // Make a manager for this inside Textures namespace glUniform1i(sPtr->getHandle("u_TextureMap"), COLOR_TEX_UNIT); glUniform1i(sPtr->getHandle("u_NormalMap"), NORMAL_TEX_UNIT); glUniform1i(sPtr->getHandle("u_EnvMap"), CUBE_TEX_UNIT); }
Scene::Scene(string XmlSrc, ShaderPtr& sPtr, Camera& cam){ XMLDocument doc; doc.LoadFile(XmlSrc.c_str()); // Get the root (Scene) element XMLElement * elScene = doc.FirstChildElement("Scene"); if (!elScene){ cout << "XML Root not found. " << endl; exit(5); } // Get and verify that important things are there XMLElement * elCam = check("Camera", elScene); XMLElement * elShade = check("Shader", elScene); XMLElement * elGeom = check("Geom", elScene); XMLElement * elLight = check("Light", elScene); // First create host assets // Init Camera Camera::Type camType = getCamera(*elCam, cam); if (camType == Camera::Type::NIL){ cout << "Error creating Camera" << endl; exit(7); } // Init Geometry for (XMLElement * el = elGeom->FirstChildElement(); el; el = el->NextSiblingElement()) m_vGeometry.push_back(getGeom(el)); // Set up the lights, arbitrarily assigning pre-existing geometry as its representation for (auto el = elLight->FirstChildElement(); el; el = el->NextSiblingElement()) m_vLights.push_back(getLight(el)); // Init shader // The material count == #geom + # of point lights int nMaterials = m_vGeometry.size() + std::count_if( m_vLights.begin(), m_vLights.end(), [](const Light& l){ return l.getType() == Light::Type::POINT; }); IqmTypeMap iqmTypes = getShader(elShade, sPtr, nMaterials, m_vLights.size()); // Sort so overlapping geometry is adjacent std::sort(m_vGeometry.begin(), m_vGeometry.end()); // Create all GPU assets, starting by binding the shader auto sBind = sPtr->ScopeBind(); // Create Geometry for (auto it = m_vGeometry.begin(); it != m_vGeometry.end();){ // For the first instance, create the assets createGPUAssets(iqmTypes, *it); // For all remaining instances, just copy VAO and nIdx int count = std::count(m_vGeometry.begin(), m_vGeometry.end(), *it); auto cloneIt = it; for (int i = 1; i < count; i++){ (it + i)->setNumIndices(it->getNumIdx()); (it + i)->setVAO(it->getVAO()); } it += count; } // Set up material shader access Shader * s = sPtr.get(); auto fixMaterial = [s](Geometry& G, int i){ string m = "MatArr[i]."; m[m.length() - 3] = '0' + i; Material M = G.getMaterial(); // Material handles aren't static M.SetReflectHandle(s->getHandle(m + "Reflectivity")); M.setShinyHandle(s->getHandle(m + "Shininess")); M.setDiffHandle(s->getHandle(m + "Diffuse")); M.setSpecHandle(s->getHandle(m + "Specular")); createGPUAssets(M); G.setMaterial(M); }; // Upload all geometry materials for (int i = 0; i < m_vGeometry.size(); i++) fixMaterial(m_vGeometry[i], i); // Create lights for (int i = 0; i < m_vLights.size(); i++){ // Upload to shader (Must be accessed like "TheLights[i].Type, GL3) string s = "LightArr[i]."; s[s.length() - 3] = '0' + i; // Store handles per light, since they could move m_vLights[i].SetTypeHandle(sPtr->getHandle(s + "Type")); m_vLights[i].SetPosOrHalfHandle(sPtr->getHandle(s + "PosOrHalf")); m_vLights[i].SetDirOrAttenHandle(sPtr->getHandle(s + "DirOrAtten")); m_vLights[i].SetIntensityHandle(sPtr->getHandle(s + "Intensity")); // Put light data on GPU createGPUAssets(m_vLights[i]); // Give point lights some geometry if (m_vLights[i].getType() == Light::Type::POINT){ Geometry lightGeom = m_vGeometry[0]; lightGeom.identity(); // Maybe scale it somehow? mat4 light_T = glm::translate(m_vLights[i].getPos()); lightGeom.leftMultM(light_T); Material lightMat(10.f, 0.f, vec4(glm::linearRand(vec3(0), vec3(1)), 0.5f), vec4(1)); lightGeom.setMaterial(lightMat); fixMaterial(lightGeom, i + m_vGeometry.size() ); m_vLights[i].SetGeometry(lightGeom); } //// Set up point light materials //if (m_vLights[i].getType() == Light::Type::POINT){ // Geometry g = m_vLights[i].GetGeometry(); // I wish we didn't have to go back and forth like this // fixMaterial(g, i + m_vGeometry.size() - 1); // but returning a reference seems like overkill // m_vLights[i].SetGeometry(g); //} } setupMiscUniforms(sPtr); Scene::s_EnvMapHandle = sPtr->getHandle("u_EnvMap"); //// Find a better place for this, do XML std::string cubeFaces[6] = { "posX.png", "negX.png", "posY.png", "negY.png", "posZ.png", "negZ.png" }; m_EnvMap = Textures::CubeMap(cubeFaces); }