1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2 
3 #include "Rendering/GL/myGL.h"
4 
5 #include "Rendering/Shaders/ShaderHandler.h"
6 #include "Rendering/GlobalRendering.h"
7 #include "System/Log/ILog.h"
8 #include "System/Util.h"
9 
10 #include <cassert>
11 
12 
GetInstance()13 CShaderHandler* CShaderHandler::GetInstance() {
14 	static CShaderHandler shaHandler;
15 	return &shaHandler;
16 }
17 
18 
ReloadAll()19 void CShaderHandler::ReloadAll() {
20 	for (std::map<std::string, ProgramObjMap>::iterator it = programObjects.begin(); it != programObjects.end(); ++it) {
21 		for (ProgramObjMapIt jt = it->second.begin(); jt != it->second.end(); ++jt) {
22 			(jt->second)->Reload(true);
23 		}
24 	}
25 }
26 
27 
ReleaseProgramObjects(const std::string & poClass)28 void CShaderHandler::ReleaseProgramObjects(const std::string& poClass) {
29 	if (programObjects.find(poClass) == programObjects.end()) {
30 		return;
31 	}
32 
33 	for (ProgramObjMapIt it = programObjects[poClass].begin(); it != programObjects[poClass].end(); ++it) {
34 		// free the program object and its attachments
35 		if (it->second != Shader::nullProgramObject) {
36 			(it->second)->Release(); delete (it->second);
37 		}
38 	}
39 
40 	programObjects[poClass].clear();
41 	programObjects.erase(poClass);
42 }
43 
44 
GetProgramObject(const std::string & poClass,const std::string & poName)45 Shader::IProgramObject* CShaderHandler::GetProgramObject(const std::string& poClass, const std::string& poName) {
46 	if (programObjects.find(poClass) != programObjects.end()) {
47 		if (programObjects[poClass].find(poName) != programObjects[poClass].end()) {
48 			return (programObjects[poClass][poName]);
49 		}
50 	}
51 	return NULL;
52 }
53 
54 
CreateProgramObject(const std::string & poClass,const std::string & poName,bool arbProgram)55 Shader::IProgramObject* CShaderHandler::CreateProgramObject(const std::string& poClass, const std::string& poName, bool arbProgram) {
56 	Shader::IProgramObject* po = Shader::nullProgramObject;
57 
58 	if (programObjects.find(poClass) != programObjects.end()) {
59 		if (programObjects[poClass].find(poName) != programObjects[poClass].end()) {
60 			LOG_L(L_WARNING, "[%s] There is already a shader program named \"%s\"!",
61 					__FUNCTION__, poName.c_str());
62 			return (programObjects[poClass][poName]);
63 		}
64 	} else {
65 		programObjects[poClass] = ProgramObjMap();
66 	}
67 
68 	if (arbProgram) {
69 		if (globalRendering->haveARB) {
70 			po = new Shader::ARBProgramObject(poName);
71 		}
72 	} else {
73 		if (globalRendering->haveGLSL) {
74 			po = new Shader::GLSLProgramObject(poName);
75 		}
76 	}
77 
78 	if (po == Shader::nullProgramObject) {
79 		LOG_L(L_ERROR, "[%s] Tried to create \"%s\" a %s shader program on hardware w/o support for it!",
80 				__FUNCTION__, poName.c_str(), arbProgram ? "ARB" : "GLSL");
81 	}
82 
83 	programObjects[poClass][poName] = po;
84 	return po;
85 }
86 
87 
88 
CreateShaderObject(const std::string & soName,const std::string & soDefs,int soType)89 Shader::IShaderObject* CShaderHandler::CreateShaderObject(const std::string& soName, const std::string& soDefs, int soType) {
90 	assert(!soName.empty());
91 
92 	const std::string lowerSoName = StringToLower(soName);
93 
94 	const bool arbShader = (lowerSoName.find("arb") != std::string::npos);
95 /*
96 	const bool arbShader =
97 		lowerSoName.find(".glsl") == std::string::npos &&
98 		lowerSoName.find(".vert") == std::string::npos &&
99 		lowerSoName.find(".frag") == std::string::npos;
100 */
101 	Shader::IShaderObject* so = Shader::nullShaderObject;
102 
103 	switch (soType) {
104 		case GL_VERTEX_PROGRAM_ARB:
105 		case GL_FRAGMENT_PROGRAM_ARB: {
106 			assert(arbShader);
107 
108 			if (globalRendering->haveARB) {
109 				so = new Shader::ARBShaderObject(soType, soName);
110 			}
111 		} break;
112 
113 		default: {
114 			// assume GLSL shaders by default
115 			assert(!arbShader);
116 
117 			if (globalRendering->haveGLSL) {
118 				so = new Shader::GLSLShaderObject(soType, soName, soDefs);
119 			}
120 		} break;
121 	}
122 
123 	if (so == Shader::nullShaderObject) {
124 		LOG_L(L_ERROR, "[%s] Tried to create a %s shader (\"%s\") on hardware that does not support them!",
125 			__FUNCTION__, arbShader? "ARB": "GLSL", soName.c_str());
126 		return so;
127 	}
128 
129 	so->Compile(true);
130 	return so;
131 }
132