CShaderLibrary::CShaderLibrary() { s_pShaderLibrary = this; m_bCompiled = false; m_iSamples = -1; FILE* f = tfopen("shaders/functions.si", "r"); if (f) { tstring sLine; while (fgetts(sLine, f)) m_sFunctions += sLine; fclose(f); } f = tfopen("shaders/header.si", "r"); if (f) { tstring sLine; while (fgetts(sLine, f)) m_sHeader += sLine; fclose(f); } }
// Silo ascii void CModelConverter::ReadSIA(const tstring& sFilename) { if (m_pWorkListener) m_pWorkListener->BeginProgress(); CConversionSceneNode* pScene = m_pScene->GetScene(m_pScene->AddScene(GetFilename(sFilename).append(_T(".sia")))); if (m_pWorkListener) m_pWorkListener->SetAction(_T("Reading file into memory..."), 0); FILE* fp = tfopen(sFilename, _T("r")); if (!fp) { printf("No input file. Sorry!\n"); return; } fseek(fp, 0L, SEEK_END); long iOBJSize = ftell(fp); fseek(fp, 0L, SEEK_SET); // Make sure we allocate more than we need just in case. size_t iFileSize = (iOBJSize+1) * (sizeof(tchar)+1); tchar* pszEntireFile = (tchar*)malloc(iFileSize); tchar* pszCurrent = pszEntireFile; // Read the entire file into an array first for faster processing. tstring sLine; while (fgetts(sLine, fp)) { tstrncpy(pszCurrent, iFileSize-(pszCurrent-pszEntireFile), sLine.c_str(), sLine.length()); size_t iLength = sLine.length(); if (pszCurrent[iLength-1] == _T('\n')) { pszCurrent[iLength-1] = _T('\0'); iLength--; } pszCurrent += iLength; pszCurrent++; if (m_pWorkListener) m_pWorkListener->WorkProgress(0); } pszCurrent[0] = _T('\0'); fclose(fp); const tchar* pszLine = pszEntireFile; const tchar* pszNextLine = NULL; while (pszLine < pszCurrent) { if (pszNextLine) pszLine = pszNextLine; pszNextLine = pszLine + tstrlen(pszLine) + 1; // This code used to call StripWhitespace() but that's too slow for very large files w/ millions of lines. // Instead we'll just cut the whitespace off the front and deal with whitespace on the end when we come to it. while (*pszLine && IsWhitespace(*pszLine)) pszLine++; if (tstrlen(pszLine) == 0) continue; eastl::vector<tstring> aTokens; tstrtok(pszLine, aTokens, _T(" ")); const tchar* pszToken = aTokens[0].c_str(); if (tstrncmp(pszToken, _T("-Version"), 8) == 0) { // Warning if version is later than 1.0, we may not support it int iMajor, iMinor; eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" .")); if (asTokens.size() >= 3) { iMajor = stoi(asTokens[1]); iMinor = stoi(asTokens[2]); if (iMajor != 1 && iMinor != 0) printf("WARNING: I was programmed for version 1.0, this file is version %d.%d, so this might not work exactly right!\n", iMajor, iMinor); } } else if (tstrncmp(pszToken, _T("-Mat"), 4) == 0) { pszNextLine = ReadSIAMat(pszNextLine, pszCurrent, pScene, sFilename); } else if (tstrncmp(pszToken, _T("-Shape"), 6) == 0) { pszNextLine = ReadSIAShape(pszNextLine, pszCurrent, pScene); } else if (tstrncmp(pszToken, _T("-Texshape"), 9) == 0) { // This is the 3d UV space of the object, but we only care about its 2d UV space which is contained in rhw -Shape section, so meh. pszNextLine = ReadSIAShape(pszNextLine, pszCurrent, pScene, false); } } free(pszEntireFile); m_pScene->SetWorkListener(m_pWorkListener); for (size_t i = 0; i < m_pScene->GetNumMeshes(); i++) { m_pScene->GetMesh(i)->CalculateEdgeData(); m_pScene->GetMesh(i)->CalculateVertexNormals(); m_pScene->GetMesh(i)->CalculateVertexTangents(); } m_pScene->CalculateExtends(); if (m_pWorkListener) m_pWorkListener->EndProgress(); }
void CModelConverter::ReadOBJ(const tstring& sFilename) { if (m_pWorkListener) m_pWorkListener->BeginProgress(); FILE* fp = tfopen(sFilename, _T("r")); if (!fp) { printf("No input file. Sorry!\n"); return; } CConversionSceneNode* pScene = m_pScene->GetScene(m_pScene->AddScene(GetFilename(sFilename).append(_T(".obj")))); CConversionMesh* pMesh = m_pScene->GetMesh(m_pScene->AddMesh(GetFilename(sFilename))); // Make sure it exists. CConversionSceneNode* pMeshNode = m_pScene->GetDefaultSceneMeshInstance(pScene, pMesh); size_t iCurrentMaterial = ~0; size_t iSmoothingGroup = ~0; bool bSmoothingGroups = false; tstring sLastTask; int iTotalVertices = 0; int iTotalFaces = 0; int iVerticesComplete = 0; int iFacesComplete = 0; if (m_pWorkListener) m_pWorkListener->SetAction(_T("Reading file into memory..."), 0); fseek(fp, 0L, SEEK_END); long iOBJSize = ftell(fp); fseek(fp, 0L, SEEK_SET); // Make sure we allocate more than we need just in case. size_t iFileSize = (iOBJSize+1) * (sizeof(tchar)+1); tchar* pszEntireFile = (tchar*)malloc(iFileSize); tchar* pszCurrent = pszEntireFile; pszCurrent[0] = _T('\0'); // Read the entire file into an array first for faster processing. tstring sLine; while (fgetts(sLine, fp)) { tstrncpy(pszCurrent, iFileSize-(pszCurrent-pszEntireFile), sLine.c_str(), sLine.length()); size_t iLength = sLine.length(); tchar cLastChar = pszCurrent[iLength-1]; while (cLastChar == _T('\n') || cLastChar == _T('\r')) { pszCurrent[iLength-1] = _T('\0'); iLength--; cLastChar = pszCurrent[iLength-1]; } pszCurrent += iLength; pszCurrent++; if (m_pWorkListener) m_pWorkListener->WorkProgress(0); } pszCurrent[0] = _T('\0'); fclose(fp); const tchar* pszLine = pszEntireFile; const tchar* pszNextLine = NULL; while (pszLine < pszCurrent) { if (pszNextLine) pszLine = pszNextLine; pszNextLine = pszLine + tstrlen(pszLine) + 1; // This code used to call StripWhitespace() but that's too slow for very large files w/ millions of lines. // Instead we'll just cut the whitespace off the front and deal with whitespace on the end when we come to it. while (*pszLine && IsWhitespace(*pszLine)) pszLine++; if (tstrlen(pszLine) == 0) continue; if (pszLine[0] == '#') { // ZBrush is kind enough to notate exactly how many vertices and faces we have in the comments at the top of the file. if (tstrncmp(pszLine, _T("#Vertex Count"), 13) == 0) { iTotalVertices = stoi(pszLine+13); pMesh->SetTotalVertices(iTotalVertices); } if (tstrncmp(pszLine, _T("#Face Count"), 11) == 0) { iTotalFaces = stoi(pszLine+11); pMesh->SetTotalFaces(iTotalFaces); // Don't kill the video card while we're loading the faces. if (iTotalFaces > 10000) pMeshNode->GetMeshInstance(0)->SetVisible(false); } continue; } tchar szToken[1024]; tstrncpy(szToken, 1024, pszLine, 1024); tchar* pszState = NULL; tchar* pszToken = strtok<tchar>(szToken, " ", &pszState); if (tstrncmp(pszToken, _T("mtllib"), 6) == 0) { tstring sDirectory = GetDirectory(sFilename); tstring sMaterial = sprintf(tstring("%s/%s"), sDirectory.c_str(), pszLine + 7); ReadMTL(sMaterial); } else if (tstrncmp(pszToken, _T("o"), 1) == 0) { // Dunno what this does. } else if (tstrncmp(pszToken, _T("v"), 2) == 0) { if (m_pWorkListener) { if (tstrncmp(sLastTask.c_str(), pszToken, sLastTask.length()) == 0) m_pWorkListener->WorkProgress(iVerticesComplete++); else { m_pWorkListener->SetAction(_T("Reading vertex data"), iTotalVertices); sLastTask = tstring(pszToken); } } // A vertex. float v[3]; // scanf is pretty slow even for such a short string due to lots of mallocs. const tchar* pszToken = pszLine+1; int iDimension = 0; while (*pszToken) { while (pszToken[0] == _T(' ')) pszToken++; v[iDimension++] = (float)stof(pszToken); if (iDimension >= 3) break; while (pszToken[0] != _T(' ')) pszToken++; } pMesh->AddVertex(v[0], v[1], v[2]); } else if (tstrncmp(pszToken, _T("vn"), 3) == 0) { if (m_pWorkListener) { if (tstrncmp(sLastTask.c_str(), pszToken, sLastTask.length()) == 0) m_pWorkListener->WorkProgress(0); else m_pWorkListener->SetAction(_T("Reading vertex normal data"), 0); } sLastTask = tstring(pszToken); // A vertex normal. float x, y, z; eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" ")); if (asTokens.size() == 4) { x = stof(asTokens[1]); y = stof(asTokens[2]); z = stof(asTokens[3]); pMesh->AddNormal(x, y, z); } } else if (tstrncmp(pszToken, _T("vt"), 3) == 0) { if (m_pWorkListener) { if (tstrncmp(sLastTask.c_str(), pszToken, sLastTask.length()) == 0) m_pWorkListener->WorkProgress(0); else m_pWorkListener->SetAction(_T("Reading texture coordinate data"), 0); } sLastTask = tstring(pszToken); // A UV coordinate for a vertex. float u, v; eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" ")); if (asTokens.size() == 3) { u = stof(asTokens[1]); v = stof(asTokens[2]); pMesh->AddUV(u, v); } } else if (tstrncmp(pszToken, _T("g"), 1) == 0) { // A group of faces. pMesh->AddBone(pszLine+2); } else if (tstrncmp(pszToken, _T("usemtl"), 6) == 0) { // All following faces should use this material. tstring sMaterial = tstring(pszLine+7); size_t iMaterial = pMesh->FindMaterialStub(sMaterial); if (iMaterial == ((size_t)~0)) { size_t iSceneMaterial = m_pScene->FindMaterial(sMaterial); if (iSceneMaterial == ((size_t)~0)) iCurrentMaterial = m_pScene->AddDefaultSceneMaterial(pScene, pMesh, sMaterial); else { size_t iMaterialStub = pMesh->AddMaterialStub(sMaterial); m_pScene->GetDefaultSceneMeshInstance(pScene, pMesh)->GetMeshInstance(0)->AddMappedMaterial(iMaterialStub, iSceneMaterial); iCurrentMaterial = iMaterialStub; } } else iCurrentMaterial = iMaterial; } else if (tstrncmp(pszToken, _T("s"), 1) == 0) { if (tstrncmp(pszLine, _T("s off"), 5) == 0) { iSmoothingGroup = ~0; } else { bSmoothingGroups = true; eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" ")); if (asTokens.size() == 2) iSmoothingGroup = stoi(asTokens[1]); } } else if (tstrncmp(pszToken, _T("f"), 1) == 0) { if (m_pWorkListener) { if (tstrncmp(sLastTask.c_str(), pszToken, sLastTask.length()) == 0) m_pWorkListener->WorkProgress(iFacesComplete++); else { m_pWorkListener->SetAction(_T("Reading polygon data"), iTotalFaces); sLastTask = tstring(pszToken); } } if (iCurrentMaterial == ~0) iCurrentMaterial = m_pScene->AddDefaultSceneMaterial(pScene, pMesh, pMesh->GetName()); // A face. size_t iFace = pMesh->AddFace(iCurrentMaterial); // If we get to 10k faces force the mesh off so it doesn't kill the video card. if (iFace == 10000) pMeshNode->GetMeshInstance(0)->SetVisible(false); pMesh->GetFace(iFace)->m_iSmoothingGroup = iSmoothingGroup; while (pszToken = strtok<tchar>(NULL, _T(" "), &pszState)) { if (tstrlen(pszToken) == 0) continue; // We don't use size_t because SOME EXPORTS put out negative numbers. long f[3]; bool bValues[3]; bValues[0] = false; bValues[1] = false; bValues[2] = false; // scanf is pretty slow even for such a short string due to lots of mallocs. const tchar* pszValues = pszToken; int iValue = 0; do { if (!pszValues) break; if (!bValues[0] || pszValues[0] == _T('/')) { if (pszValues[0] == _T('/')) pszValues++; bValues[iValue] = true; f[iValue++] = (long)stoi(pszValues); if (iValue >= 3) break; } // Don't advance if we're on a slash, because that means empty slashes. ie, 11//12 <-- the 12 would get skipped. if (pszValues[0] != _T('/')) pszValues++; } while (*pszValues); if (bValues[0]) { if (f[0] < 0) f[0] = (long)pMesh->GetNumVertices()+f[0]+1; TAssert ( f[0] >= 1 && f[0] < (long)pMesh->GetNumVertices()+1 ); } if (bValues[1] && pMesh->GetNumUVs()) { if (f[1] < 0) f[1] = (long)pMesh->GetNumUVs()+f[1]+1; TAssert ( f[1] >= 1 && f[1] < (long)pMesh->GetNumUVs()+1 ); } if (bValues[2] && pMesh->GetNumNormals()) { if (f[2] < 0) f[2] = (long)pMesh->GetNumNormals()+f[2]+1; TAssert ( f[2] >= 1 && f[2] < (long)pMesh->GetNumNormals()+1 ); } // OBJ uses 1-based indexing. // Convert to 0-based indexing. f[0]--; f[1]--; f[2]--; if (!pMesh->GetNumUVs()) f[1] = ~0; if (bValues[2] == false || !pMesh->GetNumNormals()) f[2] = ~0; pMesh->AddVertexToFace(iFace, f[0], f[1], f[2]); } } } free(pszEntireFile); m_pScene->SetWorkListener(m_pWorkListener); m_pScene->CalculateExtends(); for (size_t i = 0; i < m_pScene->GetNumMeshes(); i++) { m_pScene->GetMesh(i)->CalculateEdgeData(); if (bSmoothingGroups || m_pScene->GetMesh(i)->GetNumNormals() == 0) m_pScene->GetMesh(i)->CalculateVertexNormals(); m_pScene->GetMesh(i)->CalculateVertexTangents(); } if (m_pWorkListener) m_pWorkListener->EndProgress(); }
void CModelConverter::ReadMTL(const tstring& sFilename) { FILE* fp = tfopen(sFilename, _T("r")); if (!fp) return; if (m_pWorkListener) m_pWorkListener->SetAction(_T("Reading materials"), 0); size_t iCurrentMaterial = ~0; tstring sLine; while (fgetts(sLine, fp)) { sLine = StripWhitespace(sLine); if (sLine.length() == 0) continue; if (sLine[0] == '#') continue; eastl::vector<tstring> asTokens; tstrtok(sLine, asTokens, _T(" ")); const tchar* pszToken = NULL; pszToken = asTokens[0].c_str(); CConversionMaterial* pMaterial = NULL; if (iCurrentMaterial != ~0) pMaterial = m_pScene->GetMaterial(iCurrentMaterial); if (tstrncmp(pszToken, _T("newmtl"), 6) == 0) { pszToken = asTokens[1].c_str(); CConversionMaterial oMaterial(pszToken, Vector(0.2f,0.2f,0.2f), Vector(0.8f,0.8f,0.8f), Vector(1,1,1), Vector(0,0,0), 1.0, 0); iCurrentMaterial = m_pScene->AddMaterial(oMaterial); } else if (tstrncmp(pszToken, _T("Ka"), 2) == 0) { eastl::vector<tstring> asTokens; tstrtok(sLine, asTokens, _T(" ")); if (asTokens.size() == 4) { pMaterial->m_vecAmbient.x = stof(asTokens[1]); pMaterial->m_vecAmbient.y = stof(asTokens[2]); pMaterial->m_vecAmbient.z = stof(asTokens[3]); } } else if (tstrncmp(pszToken, _T("Kd"), 2) == 0) { eastl::vector<tstring> asTokens; tstrtok(sLine, asTokens, _T(" ")); if (asTokens.size() == 4) { pMaterial->m_vecDiffuse.x = stof(asTokens[1]); pMaterial->m_vecDiffuse.y = stof(asTokens[2]); pMaterial->m_vecDiffuse.z = stof(asTokens[3]); } } else if (tstrncmp(pszToken, _T("Ks"), 2) == 0) { eastl::vector<tstring> asTokens; tstrtok(sLine, asTokens, _T(" ")); if (asTokens.size() == 4) { pMaterial->m_vecSpecular.x = stof(asTokens[1]); pMaterial->m_vecSpecular.y = stof(asTokens[2]); pMaterial->m_vecSpecular.z = stof(asTokens[3]); } } else if (tstrncmp(pszToken, _T("d"), 1) == 0 || tstrncmp(pszToken, _T("Tr"), 2) == 0) { pMaterial->m_flTransparency = (float)stof(asTokens[1]); } else if (tstrncmp(pszToken, _T("Ns"), 2) == 0) { pMaterial->m_flShininess = (float)stof(asTokens[1])*128/1000; } else if (tstrncmp(pszToken, _T("illum"), 5) == 0) { pMaterial->m_eIllumType = (IllumType_t)stoi(asTokens[1]); } else if (tstrncmp(pszToken, _T("map_Kd"), 6) == 0) { pszToken = asTokens[1].c_str(); FILE* fpTest = tfopen(pszToken, _T("r")); if (fpTest) { fclose(fpTest); pMaterial->m_sDiffuseTexture = tstring(pszToken); } else { tstring sDirectory = GetDirectory(sFilename); pMaterial->m_sDiffuseTexture = sprintf(tstring("%s/%s"), sDirectory.c_str(), pszToken); } } } fclose(fp); }
bool CShader::Compile() { tstring sShaderHeader = CShaderLibrary::GetShaderHeader(); if (CShaderLibrary::Get()->m_iSamples) sShaderHeader += "#define USE_MULTISAMPLE_TEXTURES 1\n"; sShaderHeader += CShaderLibrary::GetShaderFunctions(); FILE* f = tfopen("shaders/" + m_sVertexFile + ".vs", "r"); TAssert(f); if (!f) return false; tstring sVertexShader = sShaderHeader; sVertexShader += "uniform mat4x4 mProjection;\n"; sVertexShader += "uniform mat4x4 mView;\n"; sVertexShader += "uniform mat4x4 mGlobal;\n"; tstring sLine; while (fgetts(sLine, f)) sVertexShader += sLine; fclose(f); f = tfopen("shaders/" + m_sFragmentFile + ".fs", "r"); TAssert(f); if (!f) return false; tstring sFragmentShader = sShaderHeader; sFragmentShader += "out vec4 vecOutputColor;\n"; while (fgetts(sLine, f)) sFragmentShader += sLine; fclose(f); size_t iVShader = glCreateShader(GL_VERTEX_SHADER); const char* pszStr = sVertexShader.c_str(); glShaderSource((GLuint)iVShader, 1, &pszStr, NULL); glCompileShader((GLuint)iVShader); int iVertexCompiled; glGetShaderiv((GLuint)iVShader, GL_COMPILE_STATUS, &iVertexCompiled); if (iVertexCompiled != GL_TRUE || Application()->HasCommandLineSwitch("--debug-gl")) { int iLogLength = 0; char szLog[1024]; glGetShaderInfoLog((GLuint)iVShader, 1024, &iLogLength, szLog); CShaderLibrary::Get()->WriteLog(m_sVertexFile + ".vs", szLog, pszStr); } size_t iFShader = glCreateShader(GL_FRAGMENT_SHADER); pszStr = sFragmentShader.c_str(); glShaderSource((GLuint)iFShader, 1, &pszStr, NULL); glCompileShader((GLuint)iFShader); int iFragmentCompiled; glGetShaderiv((GLuint)iFShader, GL_COMPILE_STATUS, &iFragmentCompiled); if (iFragmentCompiled != GL_TRUE || Application()->HasCommandLineSwitch("--debug-gl")) { int iLogLength = 0; char szLog[1024]; glGetShaderInfoLog((GLuint)iFShader, 1024, &iLogLength, szLog); CShaderLibrary::Get()->WriteLog(m_sFragmentFile + ".fs", szLog, pszStr); } size_t iProgram = glCreateProgram(); glBindAttribLocation(iProgram, 0, "vecPosition"); // Force position at location 0. ATI cards won't work without this. glAttachShader((GLuint)iProgram, (GLuint)iVShader); glAttachShader((GLuint)iProgram, (GLuint)iFShader); glLinkProgram((GLuint)iProgram); int iProgramLinked; glGetProgramiv((GLuint)iProgram, GL_LINK_STATUS, &iProgramLinked); if (iProgramLinked != GL_TRUE || Application()->HasCommandLineSwitch("--debug-gl")) { int iLogLength = 0; char szLog[1024]; glGetProgramInfoLog((GLuint)iProgram, 1024, &iLogLength, szLog); CShaderLibrary::Get()->WriteLog("link", szLog, "link"); } if (iVertexCompiled != GL_TRUE || iFragmentCompiled != GL_TRUE || iProgramLinked != GL_TRUE) { TError("Shader compilation failed for shader " + m_sName + ". Check shaders.txt\n"); Destroy(); return false; } m_iProgram = iProgram; m_iVShader = iVShader; m_iFShader = iFShader; m_iPositionAttribute = glGetAttribLocation(m_iProgram, "vecPosition"); m_iNormalAttribute = glGetAttribLocation(m_iProgram, "vecNormal"); m_iTangentAttribute = glGetAttribLocation(m_iProgram, "vecTangent"); m_iBitangentAttribute = glGetAttribLocation(m_iProgram, "vecBitangent"); for (size_t i = 0; i < MAX_TEXTURE_CHANNELS; i++) m_aiTexCoordAttributes[i] = glGetAttribLocation(m_iProgram, sprintf("vecTexCoord%d", i).c_str()); m_iColorAttribute = glGetAttribLocation(m_iProgram, "vecVertexColor"); glBindFragDataLocation(m_iProgram, 0, "vecOutputColor"); TAssert(m_iPositionAttribute != ~0); int iNumUniforms; glGetProgramiv(m_iProgram, GL_ACTIVE_UNIFORMS, &iNumUniforms); char szUniformName[256]; GLsizei iLength; GLint iSize; GLenum iType; for (int i = 0; i < iNumUniforms; i++) { glGetActiveUniform(m_iProgram, i, sizeof(szUniformName), &iLength, &iSize, &iType, szUniformName); tstring sUniformName = szUniformName; if (sUniformName == "mProjection") continue; if (sUniformName == "mView") continue; if (sUniformName == "mGlobal") continue; CShader::CUniform& oUniform = m_asUniforms[sUniformName]; oUniform.m_pDefault = nullptr; switch (iType) { case GL_FLOAT: oUniform.m_sUniformType = "float"; break; case GL_FLOAT_VEC2: oUniform.m_sUniformType = "vec2"; break; case GL_FLOAT_VEC3: oUniform.m_sUniformType = "vec3"; break; case GL_FLOAT_VEC4: oUniform.m_sUniformType = "vec4"; break; case GL_INT: oUniform.m_sUniformType = "int"; break; case GL_BOOL: oUniform.m_sUniformType = "bool"; break; case GL_FLOAT_MAT4: oUniform.m_sUniformType = "mat4"; break; case GL_SAMPLER_2D: oUniform.m_sUniformType = "sampler2D"; break; default: TUnimplemented(); } } for (auto it = m_aParameters.begin(); it != m_aParameters.end(); it++) { for (size_t j = 0; j < it->second.m_aActions.size(); j++) { auto it2 = m_asUniforms.find(it->second.m_aActions[j].m_sName); TAssert(it2 != m_asUniforms.end()); if (it2 == m_asUniforms.end()) { TError("Shader '" + m_sName + "' specifies a uniform '" + it->second.m_aActions[j].m_sName + "' that is not in the linked program.\n"); continue; } CShader::CUniform& oUniform = it2->second; // This is almost cheating CData d; d.SetValue(it->second.m_aActions[j].m_sValue); if (oUniform.m_sUniformType == "float") it->second.m_aActions[j].m_flValue = d.GetValueFloat(); else if (oUniform.m_sUniformType == "vec2") it->second.m_aActions[j].m_vec2Value = d.GetValueVector2D(); else if (oUniform.m_sUniformType == "vec3") it->second.m_aActions[j].m_vecValue = d.GetValueVector(); else if (oUniform.m_sUniformType == "vec4") it->second.m_aActions[j].m_vec4Value = d.GetValueVector4D(); else if (oUniform.m_sUniformType == "int") it->second.m_aActions[j].m_iValue = d.GetValueInt(); else if (oUniform.m_sUniformType == "bool") it->second.m_aActions[j].m_bValue = d.GetValueBool(); else if (oUniform.m_sUniformType == "mat4") { TUnimplemented(); } else if (oUniform.m_sUniformType == "sampler2D") { // No op. } else TUnimplemented(); } } for (auto it = m_aDefaults.begin(); it != m_aDefaults.end(); it++) { auto it2 = m_asUniforms.find(it->first); TAssert(it2 != m_asUniforms.end()); if (it2 == m_asUniforms.end()) { TError("Shader '" + m_sName + "' specifies a default for uniform '" + it->second.m_sName + "' that is not in the linked program.\n"); continue; } CShader::CUniform& oUniform = it2->second; oUniform.m_pDefault = &it->second; // Again with the cheating. CData d; d.SetValue(it->second.m_sValue); if (oUniform.m_sUniformType == "float") it->second.m_flValue = d.GetValueFloat(); else if (oUniform.m_sUniformType == "vec2") it->second.m_vec2Value = d.GetValueVector2D(); else if (oUniform.m_sUniformType == "vec3") it->second.m_vecValue = d.GetValueVector(); else if (oUniform.m_sUniformType == "vec4") it->second.m_vec4Value = d.GetValueVector4D(); else if (oUniform.m_sUniformType == "int") it->second.m_iValue = d.GetValueInt(); else if (oUniform.m_sUniformType == "bool") it->second.m_bValue = d.GetValueBool(); else if (oUniform.m_sUniformType == "mat4") { TUnimplemented(); } else if (oUniform.m_sUniformType == "sampler2D") { TUnimplemented(); // Can't set a default texture... yet. } else TUnimplemented(); } return true; }