1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2 
3 
4 #include "TerrainBase.h"
5 #include "TerrainTexture.h"
6 #include "Terrain.h"
7 
8 #include "TerrainTextureGLSL.h"
9 #include "Rendering/GL/FBO.h"
10 #include "Rendering/GlobalRendering.h"
11 #include "System/bitops.h"
12 #include "System/Util.h"
13 #include "System/Log/ILog.h"
14 #include "System/Exceptions.h"
15 #include "System/FileSystem/DataDirsAccess.h"
16 #include "System/FileSystem/FileHandler.h"
17 #include "System/FileSystem/FileQueryFlags.h"
18 
19 #include <fstream>
20 #include <list>
21 #include <assert.h>
22 
23 namespace terrain {
24 
ShowInfoLog(GLhandleARB handle)25 static void ShowInfoLog(GLhandleARB handle)
26 {
27 	LOG_L(L_ERROR, "Shader failed to compile, showing info log:");
28 	GLint infoLogLen;
29 	GLsizei actualLength;
30 	glGetObjectParameterivARB(handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infoLogLen);
31 	char* infoLog = new char[infoLogLen];
32 	glGetInfoLogARB(handle, infoLogLen, &actualLength, infoLog);
33 	LOG_L(L_ERROR, "%s", infoLog);
34 	delete[] infoLog;
35 }
36 
37 
38 
39 
40 struct Shader {
41 	std::list<std::string> texts;
42 	GLhandleARB handle;
43 
Shaderterrain::Shader44 	Shader() { handle = 0; }
45 
AddFileterrain::Shader46 	void AddFile(const std::string& file)
47 	{
48 		CFileHandler fh(file);
49 		if (!fh.FileExists())
50 			throw content_error("Can not load shader " + file);
51 
52 		std::string text;
53 		text.resize(fh.FileSize());
54 		fh.Read(&text[0], text.length());
55 
56 		texts.push_back(text);
57 	}
58 
Buildterrain::Shader59 	void Build(GLenum shaderType)
60 	{
61 		handle = glCreateShaderObjectARB(shaderType);
62 
63 		std::vector<GLint> lengths(texts.size());
64 		std::vector<const GLcharARB*> strings(texts.size());
65 		int index = 0;
66 		for (std::list<std::string>::iterator i = texts.begin(); i != texts.end(); ++i, index++) {
67 			lengths[index] = i->length();
68 			strings[index] = i->c_str();
69 		}
70 
71 //		if (shaderType == GL_FRAGMENT_SHADER_ARB)
72 //			DebugOutput(shaderType);
73 
74 		glShaderSourceARB(handle, strings.size(), &strings.front(), &lengths.front());
75 		glCompileShaderARB(handle);
76 
77 		// Check compile status and show info log if failed
78 		GLint isCompiled;
79 		glGetObjectParameterivARB(handle, GL_OBJECT_COMPILE_STATUS_ARB, &isCompiled);
80 		if (!isCompiled)
81 		{
82 			WriteToFile("sm3_failed_shader.glsl");
83 			ShowInfoLog(handle);
84 
85 			std::string errMsg = "Failed to build ";
86 			throw std::runtime_error(errMsg + (shaderType == GL_VERTEX_SHADER_ARB ? "vertex shader" : "fragment shader"));
87 		}
88 	}
DebugOutputterrain::Shader89 	void DebugOutput(GLenum shaderType)
90 	{
91 		char fn[20];
92 		if (shaderType == GL_FRAGMENT_SHADER_ARB) {
93 			static int fpc = 0;
94 			sprintf(fn, "shader%dfp.txt", fpc++);
95 		} else {
96 			static int vpc = 0;
97 			sprintf(fn, "shader%dvp.txt", vpc++);
98 		}
99 		WriteToFile(fn);
100 	}
WriteToFileterrain::Shader101 	void WriteToFile(const char* fn)
102 	{
103 		std::string n = dataDirsAccess.LocateFile(fn, FileQueryFlags::WRITE);
104 
105 		FILE* f = fopen(n.c_str(), "w");
106 
107 		if (f) {
108 			for (std::list<std::string>::iterator i=texts.begin();i!=texts.end();++i)
109 				fputs(i->c_str(), f);
110 			fclose(f);
111 		}
112 	}
113 };
114 
115 
116 
117 
closest_pot(int i)118 static int closest_pot(int i)
119 {
120 	int next = next_power_of_2(i);
121 	return (next - i < i - next/2) ? next : next/2;
122 }
123 
124 // A framebuffer enabled as texture
125 class BufferTexture : public BaseTexture
126 {
127 public:
BufferTexture()128 	BufferTexture()
129 	{
130 	// ATI has GL_EXT_texture_rectangle, but that has no support for GLSL texture2DRect
131 	// nVidia: Use RECT,  ati: use POT
132 		assert(framebuffer.IsValid());
133 
134 		width = globalRendering->viewSizeX;
135 		height = globalRendering->viewSizeY;
136 		if (GLEW_ARB_texture_rectangle)
137 			target = GL_TEXTURE_RECTANGLE_ARB;
138 		else {
139 			target = GL_TEXTURE_2D;
140 			width = closest_pot(width);
141 			height = closest_pot(height);
142 		}
143 
144 		name = "_buffer";
145 
146 		glGenTextures(1, &id);
147 		glBindTexture(target, id);
148 		glTexParameteri(target,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
149 		glTexParameteri(target,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
150 		glTexImage2D(target, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
151 
152 		framebuffer.Bind();
153 		framebuffer.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, GL_DEPTH_COMPONENT24, width, height);
154 		framebuffer.AttachTexture(id, target);
155 		bool status = framebuffer.CheckStatus("sm3");
156 		framebuffer.Unbind();
157 		assert(status);
158 	}
~BufferTexture()159 	~BufferTexture()
160 	{
161 		// texture is deleted by ~BaseTexture
162 	}
IsRect()163 	bool IsRect() {	return target == GL_TEXTURE_RECTANGLE_ARB; }
164 
165 	int width, height;
166 	uint target;
167 	FBO framebuffer;
168 };
169 
170 struct ShaderBuilder
171 {
172 	RenderSetup* renderSetup;
173 	TextureUsage texUsage;
174 	BufferTexture* buffer;
ShadowMappingterrain::ShaderBuilder175 	bool ShadowMapping() const { return renderSetup->shaderDef.useShadowMapping; }
176 	Shader lastFragmentShader, lastVertexShader; // for debugging
177 
178 	ShaderBuilder(RenderSetup* rs);
179 	std::string GenTextureRead(int tu, int tc);
180 	NodeGLSLShader* EndPass(ShaderDef* sd, const std::string &operations, uint passIndex=0);
181 	void BuildFragmentShader(NodeGLSLShader* ns, uint passIndex, const std::string& operations, ShaderDef* sd);
182 	void BuildVertexShader(NodeGLSLShader* ns, uint passIndex, ShaderDef* sd);
183 	bool ProcessStage(std::vector<ShaderDef::Stage>& stages, uint &index, std::string& opstr);
184 	void Build(ShaderDef* shaderDef);
185 	void AddPPDefines(ShaderDef* sd, Shader& shader, uint passIndex);
186 
187 	enum ShadingMethod {
188 		SM_DiffuseSP, // lit diffuse single pass
189 		SM_DiffuseBumpmapSP, // full diffuse + bumpmapping in single pass
190 		SM_DiffuseBumpmapMP, // diffuse pass + bumpmap pass
191 		SM_Impossible  // massive failure
192 	};
193 
194 	ShadingMethod shadingMethod;
195 	ShadingMethod CalculateShadingMethod(ShaderDef* sd) const;
196 
197 	struct TexReq {
TexReqterrain::ShaderBuilder::TexReq198 		TexReq()
199 			: coords(0)
200 			, units(0)
201 		{}
202 
203 		void GetFromGL();
Fitsterrain::ShaderBuilder::TexReq204 		bool Fits(TexReq maxrq) const {
205 			return ((coords <= maxrq.coords) && (units <= maxrq.units));
206 		}
operator +terrain::ShaderBuilder::TexReq207 		TexReq operator + (const TexReq& rq) const {
208 			TexReq r;
209 			r.coords = coords + rq.coords;
210 			r.units = units + rq.units;
211 			return r;
212 		}
213 
214 		GLint coords;
215 		GLint units;
216 	};
217 	// Calculate the texturing requirements for the specified stages
218 	TexReq CalcStagesTexReq(const std::vector<ShaderDef::Stage>& stages, uint startIndex) const;
219 };
220 
221 
222 
223 // Decide how to organise the shading, ie: in how many passes
224 // depending on maximum number of hardware texture units and
225 // coordinates
CalculateShadingMethod(ShaderDef * sd) const226 ShaderBuilder::ShadingMethod  ShaderBuilder::CalculateShadingMethod(ShaderDef* sd) const {
227 	TexReq diffuseRQ = CalcStagesTexReq(sd->stages, 0);
228 	TexReq bumpmapRQ;
229 	TexReq special;
230 
231 	TexReq hwmax;
232 	hwmax.GetFromGL();
233 
234 
235 	if (sd->useShadowMapping) {
236 		// add shadow buffer + shadow texture coord
237 		special.coords++;
238 		special.units++;
239 	}
240 
241 	LOG("[ShaderBuilder::CalculateShadingMethod]");
242 	LOG("\t    hwmax.units=%2d,     hwmax.coords=%2d",     hwmax.units,     hwmax.coords);
243 	LOG("\tdiffuseRQ.units=%2d, diffuseRQ.coords=%2d", diffuseRQ.units, diffuseRQ.coords);
244 	LOG("\tbumpmapRQ.units=%2d, bumpmapRQ.coords=%2d", bumpmapRQ.units, bumpmapRQ.coords);
245 	LOG("\t  special.units=%2d,   special.coords=%2d",   special.units,   special.coords);
246 
247 	if (sd->normalMapStages.empty()) {
248 		if ((diffuseRQ + special).Fits(hwmax)) {
249 			LOG("\tno normal-map stages, SM_DiffuseSP");
250 			return SM_DiffuseSP;
251 		} else {
252 			LOG("\tno normal-map stages, SM_Impossible");
253 			return SM_Impossible;
254 		}
255 	} else {
256 		bumpmapRQ = CalcStagesTexReq(sd->normalMapStages, 0);
257 		// bumpmapping needs two extra indexable TC's for
258 		// lightdir + tsEyeDir or for lightdir + wsEyeDir
259 		special.coords += 2;
260 	}
261 
262 	TexReq total = diffuseRQ + bumpmapRQ + special;
263 
264 	LOG("\t*****************************************");
265 	LOG("\tbumpmapRQ.units=%2d, bumpmapRQ.coords=%2d", bumpmapRQ.units, bumpmapRQ.coords);
266 	LOG("\t  special.units=%2d,   special.coords=%2d",   special.units,   special.coords);
267 	LOG("\t    total.units=%2d,     total.coords=%2d",     total.units,     total.coords);
268 
269 	// diffuse + bumpmap in one pass?
270 	if (total.Fits(hwmax)) {
271 		LOG("\tnormalMapStages.size()=" _STPF_ ", SM_DiffuseBumpmapSP", sd->normalMapStages.size());
272 		return SM_DiffuseBumpmapSP;
273 	}
274 
275 
276 	// for multipass, one extra texture read is required for the diffuse input
277 	special.units++;
278 
279 	LOG("\t*****************************************");
280 	LOG("\t  special.units=%2d,   special.coords=%2d", special.units, special.coords);
281 	LOG("\t    total.units=%2d,     total.coords=%2d",   total.units,   total.coords);
282 
283 	// is multipass possible?
284 	if (diffuseRQ.Fits(hwmax) && (bumpmapRQ + special).Fits(hwmax)) {
285 		LOG("\tnormalMapStages.size()=" _STPF_ ", SM_DiffuseBumpmapMP", sd->normalMapStages.size());
286 		return SM_DiffuseBumpmapMP;
287 	}
288 
289 	// no options left
290 	LOG("\tSM_Impossible");
291 	return SM_Impossible;
292 }
293 
294 
295 
CalcStagesTexReq(const std::vector<ShaderDef::Stage> & stages,uint index) const296 ShaderBuilder::TexReq  ShaderBuilder::CalcStagesTexReq(const std::vector<ShaderDef::Stage>& stages, uint index) const {
297 	TextureUsage usage;
298 
299 	while (index < stages.size()) {
300 		const ShaderDef::Stage& stage = stages[index];
301 		BaseTexture* texture = stage.source;
302 		TextureUsage tmpUsage;
303 
304 		usage.AddTextureRead(-1, texture);
305 		usage.AddTextureCoordRead(-1, texture);
306 
307 		if (stage.operation == ShaderDef::Alpha) {
308 			// next operation is blend (alpha is autoinserted before blend)
309 			assert(index < stages.size()-1 && stages[index+1].operation == ShaderDef::Blend);
310 			const ShaderDef::Stage& blendStage = stages[index+1];
311 
312 			usage.AddTextureRead(-1, blendStage.source);
313 			usage.AddTextureCoordRead(-1, blendStage.source);
314 
315 			index++;
316 		}
317 		index++;
318 	}
319 
320 	TexReq rq;
321 		rq.coords = usage.coordUnits.size();
322 		rq.units = usage.texUnits.size();
323 	return rq;
324 }
325 
GetFromGL()326 void ShaderBuilder::TexReq::GetFromGL() {
327 	glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &units);
328 	glGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, &coords);
329 }
330 
ShaderBuilder(RenderSetup * rs)331 ShaderBuilder::ShaderBuilder(RenderSetup* rs): renderSetup(rs) {
332 	shadingMethod = SM_DiffuseSP;
333 	buffer = 0;
334 }
335 
GenTextureRead(int tu,int tc)336 std::string ShaderBuilder::GenTextureRead(int tu, int tc) {
337 	char tcstr[6];
338 	sprintf(tcstr,"%d", tc);
339 	return "texture2D(" + texUsage.texUnits[tu]->name + ", gl_TexCoord[" + tcstr + "].st)";
340 }
341 
342 
343 
EndPass(ShaderDef * sd,const std::string & operations,uint passIndex)344 NodeGLSLShader* ShaderBuilder::EndPass(ShaderDef* sd, const std::string &operations, uint passIndex)
345 {
346 	NodeGLSLShader* nodeShader = new NodeGLSLShader;
347 
348 	if (shadingMethod == SM_DiffuseSP)
349 		nodeShader->vertBufReq = VRT_Normal;
350 	else
351 		nodeShader->vertBufReq = VRT_TangentSpaceMatrix;
352 	//nodeShader->vertBufReq = VRT_Normal | VRT_TangentSpaceMatrix;
353 
354 	nodeShader->texCoordGen = texUsage.coordUnits;
355 	nodeShader->texUnits = texUsage.texUnits;
356 
357 	BuildVertexShader(nodeShader, passIndex, sd);
358 	BuildFragmentShader(nodeShader, passIndex, operations, sd);
359 
360 	nodeShader->program = glCreateProgramObjectARB();
361 	glAttachObjectARB(nodeShader->program, nodeShader->vertexShader);
362 	glAttachObjectARB(nodeShader->program, nodeShader->fragmentShader);
363 
364 	glLinkProgramARB(nodeShader->program);
365 	GLint isLinked;
366 	glGetObjectParameterivARB(nodeShader->program, GL_OBJECT_LINK_STATUS_ARB, &isLinked);
367 
368 	if (!isLinked) {
369 		LOG_L(L_ERROR, "Failed to link shaders. Showing info log:");
370 		lastFragmentShader.WriteToFile("sm3_fragmentshader.txt");
371 		lastVertexShader.WriteToFile("sm3_vertexshader.txt");
372 		ShowInfoLog(nodeShader->program);
373 		throw std::runtime_error("Failed to link shaders");
374 	}
375 
376 	glUseProgramObjectARB(nodeShader->program);
377 
378 	// set texture image units to texture samplers in the shader
379 	for (size_t a = 0; a < nodeShader->texUnits.size(); a++) {
380 		BaseTexture* tex = nodeShader->texUnits[a];
381 		GLint location = glGetUniformLocationARB(nodeShader->program, tex->name.c_str());
382 		glUniform1iARB(location, (int)a);
383 	}
384 
385 	// have bumpmapping?
386 	if (shadingMethod != SM_DiffuseSP &&
387 		!(shadingMethod == SM_DiffuseBumpmapMP && passIndex == 0))
388 	{
389 		nodeShader->tsmAttrib = glGetAttribLocationARB(nodeShader->program, "TangentSpaceMatrix");
390 		nodeShader->wsLightDirLocation = glGetUniformLocationARB(nodeShader->program, "wsLightDir");
391 		nodeShader->wsEyePosLocation = glGetUniformLocationARB(nodeShader->program, "wsEyePos");
392 	}
393 
394 	if (ShadowMapping()) {
395 		nodeShader->shadowMapLocation = glGetUniformLocationARB(nodeShader->program, "shadowMap");
396 		nodeShader->shadowParamsLocation = glGetUniformLocationARB(nodeShader->program, "shadowParams");
397 		nodeShader->shadowMatrixLocation = glGetUniformLocationARB(nodeShader->program, "shadowMatrix");
398 	}
399 
400 	if (passIndex == 1) {
401 		// set up uniform to read bumpmap
402 		GLint invScreenDim = glGetUniformLocationARB(nodeShader->program, "invScreenDim");
403 		glUniform2fARB(invScreenDim, 1.0f / globalRendering->viewSizeX, 1.0f / globalRendering->viewSizeY);
404 	}
405 
406 	glUseProgramObjectARB(0);
407 
408 	renderSetup->passes.push_back(RenderPass());
409 	RenderPass& rp = renderSetup->passes.back();
410 		rp.shaderSetup = nodeShader;
411 		rp.operation = Pass_Replace;
412 		rp.depthWrite = true;
413 	nodeShader->debugstr = operations;
414 	NodeGLSLShader* ns = nodeShader;
415 	nodeShader = 0;
416 	texUsage = TextureUsage();
417 	return ns;
418 }
419 
420 
AddPPDefines(ShaderDef * sd,Shader & shader,uint passIndex)421 void ShaderBuilder::AddPPDefines(ShaderDef* sd, Shader& shader, uint passIndex)
422 {
423 	bool bumpmapping = (shadingMethod != SM_DiffuseSP &&
424 		!(shadingMethod == SM_DiffuseBumpmapMP && passIndex == 0));
425 
426 	if (bumpmapping) {
427 		shader.texts.push_back("#define UseBumpMapping\n");
428 
429 		if (passIndex == 1) {
430 			shader.texts.push_back("#define DiffuseFromBuffer\n");
431 
432 			if (GLEW_ARB_texture_rectangle)
433 				shader.texts.push_back("#define UseTextureRECT\n");
434 		}
435 	}
436 
437 	if (ShadowMapping())
438 		shader.texts.push_back("#define UseShadowMapping\n");
439 
440 	shader.AddFile("shaders/GLSL/terrainCommon.glsl");
441 	char specularExponentStr[20];
442 	SNPRINTF(specularExponentStr, 20, "%5.3f", sd->specularExponent);
443 	shader.texts.push_back(std::string("const float specularExponent = ") + specularExponentStr + ";\n");
444 }
445 
446 
BuildFragmentShader(NodeGLSLShader * ns,uint passIndex,const std::string & operations,ShaderDef * sd)447 void ShaderBuilder::BuildFragmentShader(NodeGLSLShader* ns, uint passIndex, const std::string& operations, ShaderDef* sd)
448 {
449 	lastFragmentShader = Shader();
450 	Shader& fragmentShader = lastFragmentShader;
451 
452 	// insert texture samplers
453 	std::string textureSamplers;
454 	for (size_t a = 0; a < ns->texUnits.size(); a++) {
455 		BaseTexture* tex = ns->texUnits[a];
456 		if (tex->IsRect())
457 			textureSamplers += "uniform sampler2DRect " + tex->name + ";\n";
458 		else
459 			textureSamplers += "uniform sampler2D " + tex->name + ";\n";
460 	}
461 
462 	AddPPDefines(sd, fragmentShader, passIndex);
463 	fragmentShader.texts.push_back(textureSamplers);
464 
465 	fragmentShader.AddFile("shaders/GLSL/terrainFragmentShader.glsl");
466 
467 	std::string gentxt = "vec4 CalculateColor()  { vec4 color; float curalpha; \n" + operations;
468 
469 	switch (shadingMethod) {
470 		case SM_DiffuseSP:
471 			gentxt += "return Light(color); }\n";
472 			break;
473 		case SM_DiffuseBumpmapSP:
474 			gentxt += "return Light(diffuse, color);}\n";
475 			break;
476 		case SM_DiffuseBumpmapMP:
477 			if (passIndex == 0) {
478 				gentxt += "return color; }\n";
479 			} else { // passIndex=1
480 				// ReadDiffuseColor() is #defined conditionally in
481 				// terrainFragmentShader.glsl if bumpmapping enabled
482 				gentxt += "return Light(ReadDiffuseColor(), color);}\n";
483 			}
484 			break;
485 		case SM_Impossible:
486 			break;
487 	}
488 
489 	fragmentShader.texts.push_back(gentxt);
490 	fragmentShader.Build(GL_FRAGMENT_SHADER_ARB);
491 	ns->fragmentShader = fragmentShader.handle;
492 
493 	LOG("Fragment shader built successfully.");
494 }
495 
BuildVertexShader(NodeGLSLShader * ns,uint passIndex,ShaderDef * sd)496 void ShaderBuilder::BuildVertexShader(NodeGLSLShader* ns, uint passIndex, ShaderDef* sd)
497 {
498 	lastVertexShader = Shader();
499 	Shader& vertexShader = lastVertexShader;
500 
501 	AddPPDefines(sd, vertexShader, passIndex);
502 
503 	// generate texture coords
504 	std::string tcgen = "void CalculateTexCoords() {\n";
505 	static const size_t buf_sizeMax = 160;
506 	for (size_t a = 0; a < ns->texCoordGen.size(); a++) {
507 		char buf[buf_sizeMax];
508 		SNPRINTF(buf, buf_sizeMax, "gl_TexCoord[" _STPF_ "].st = vec2(dot(gl_Vertex, gl_ObjectPlaneS[" _STPF_ "]), dot(gl_Vertex,gl_ObjectPlaneT[" _STPF_ "]));\n", a, a, a);
509 		tcgen += buf;
510 	}
511 	tcgen += "}\n";
512 	vertexShader.texts.push_back(tcgen);
513 
514 	vertexShader.AddFile("shaders/GLSL/terrainVertexShader.glsl");
515 	vertexShader.Build(GL_VERTEX_SHADER_ARB);
516 	LOG("Vertex shader built successfully.");
517 
518 	ns->vertexShader = vertexShader.handle;
519 }
520 
521 
522 
ProcessStage(std::vector<ShaderDef::Stage> & stages,uint & index,std::string & opstr)523 bool ShaderBuilder::ProcessStage(std::vector<ShaderDef::Stage>& stages, uint &index, std::string& opstr)
524 {
525 	ShaderDef::Stage& stage = stages[index];
526 	BaseTexture* texture = stage.source;
527 
528 	TexReq hwmax;
529 	hwmax.GetFromGL();
530 
531 	TextureUsage tmpUsage = texUsage;
532 	int tu = tmpUsage.AddTextureRead(hwmax.units, texture);
533 	int tc = tmpUsage.AddTextureCoordRead(hwmax.coords, texture);
534 
535 	assert(tu >= 0);
536 	assert(tc >= 0);
537 
538 	if (index == 0) {  // replace
539 		texUsage = tmpUsage;
540 		opstr = "color = " + GenTextureRead(tu,tc) + ";\n";
541 	}
542 	else if(stage.operation == ShaderDef::Alpha) {
543 		// next operation is blend (alpha is autoinserted before blend)
544 		assert(index < (stages.size() - 1));
545 		assert(stages[index + 1].operation == ShaderDef::Blend);
546 		ShaderDef::Stage& blendStage = stages[index+1];
547 
548 		int blendTU = tmpUsage.AddTextureRead(hwmax.units, blendStage.source);
549 		int blendTC = tmpUsage.AddTextureCoordRead(hwmax.coords, blendStage.source);
550 
551 		assert(blendTU >= 0);
552 		assert(blendTC >= 0);
553 
554 		index++;
555 
556 		texUsage = tmpUsage;
557 		opstr += "curalpha = " + GenTextureRead(tu, tc) + ".a;\n";
558 		opstr += "color = mix(color, " + GenTextureRead(blendTU, blendTC) + ", curalpha);\n";
559 	}
560 	else if (stage.operation == ShaderDef::Add) {
561 		texUsage = tmpUsage;
562 		opstr += "color += " + GenTextureRead(tu, tc) + ";\n";
563 	} else if (stage.operation == ShaderDef::Mul)  {
564 		texUsage = tmpUsage;
565 		opstr += "color *= " + GenTextureRead(tu, tc) + ";\n";
566 	}
567 	index++;
568 	return true;
569 }
570 
571 
Build(ShaderDef * shaderDef)572 void ShaderBuilder::Build(ShaderDef* shaderDef) {
573 	texUsage = TextureUsage();
574 	shadingMethod = CalculateShadingMethod(shaderDef);
575 
576 	switch (shadingMethod) {
577 		case SM_DiffuseSP: {
578 			std::string opstr;
579 			for (uint stage = 0; stage < shaderDef->stages.size(); )
580 				ProcessStage(shaderDef->stages, stage, opstr);
581 			EndPass(shaderDef, opstr);
582 			break;
583 		}
584 
585 		case SM_DiffuseBumpmapSP: {
586 			std::string diffusecode, bumpmapcode;
587 
588 			for (uint stage = 0; stage < shaderDef->stages.size(); )
589 				ProcessStage(shaderDef->stages, stage, diffusecode);
590 
591 			for (uint stage = 0; stage < shaderDef->normalMapStages.size(); )
592 				ProcessStage(shaderDef->normalMapStages, stage, bumpmapcode);
593 
594 			EndPass(shaderDef, diffusecode + "vec4 diffuse = color;\n" + bumpmapcode);
595 			break;
596 		}
597 
598 		case SM_DiffuseBumpmapMP: {
599 			std::string diffusecode, bumpmapcode;
600 
601 			for (uint stage = 0; stage < shaderDef->stages.size(); )
602 				ProcessStage(shaderDef->stages, stage, diffusecode);
603 
604 
605 			NodeGLSLShader* diffusePass = EndPass(shaderDef, diffusecode, 0);
606 
607 			// multipass: let the diffuse pass render to the buffer
608 			// at this point nodeShader=0 and texUsage is empty
609 			if (!buffer) {
610 				buffer = new BufferTexture;
611 			}
612 			diffusePass->renderBuffer = buffer;
613 			// add texture read operation to second pass
614 			texUsage.AddTextureRead(-1, buffer);
615 
616 
617 			for (uint stage = 0; stage < shaderDef->normalMapStages.size(); )
618 				ProcessStage(shaderDef->normalMapStages, stage, bumpmapcode);
619 
620 			EndPass(shaderDef, bumpmapcode, 1);
621 
622 			break;
623 		}
624 
625 		case SM_Impossible:
626 			throw content_error("Map has too many layers for bumpmapping on this hardware");
627 	}
628 }
629 
630 
NodeGLSLShader()631 NodeGLSLShader::NodeGLSLShader()
632 {
633 	vertexShader = program = fragmentShader = 0;
634 
635 	vertBufReq = 0;
636 	tsmAttrib = -1;
637 	wsLightDirLocation = wsEyePosLocation = -1;
638 
639 	shadowMapLocation = -1;
640 	shadowMatrixLocation = -1;
641 	shadowParamsLocation = -1;
642 
643 	renderBuffer = 0;
644 }
645 
~NodeGLSLShader()646 NodeGLSLShader::~NodeGLSLShader()
647 {
648 	if (program) {
649 		glDetachObjectARB(program,vertexShader);
650 		glDetachObjectARB(program,fragmentShader);
651 		glDeleteObjectARB(program);
652 	}
653 	if (fragmentShader) glDeleteObjectARB(fragmentShader);
654 	if (vertexShader) glDeleteObjectARB(vertexShader);
655 }
656 
657 
658 
BindTSM(Vector3 * buf,uint vertexSize)659 void NodeGLSLShader::BindTSM(Vector3* buf, uint vertexSize)
660 {
661 // according to the GL_ARB_vertex_shader spec:
662 // The VertexAttrib*ARB entry points defined earlier can also be used to
663 // load attributes declared as a 2x2, 3x3 or 4x4 matrix in a vertex shader.
664 // Each column of a matrix takes up one generic 4-component attribute slot
665 // out of the MAX_VERTEX_ATTRIBS_ARB available slots. Matrices are loaded
666 // into these slots in column major order. Matrix columns need to be loaded
667 // in increasing slot numbers.
668 	if (tsmAttrib >= 0) {
669 		for (int a=0;a<3;a++) {
670 			glEnableVertexAttribArrayARB(tsmAttrib+a);
671 			glVertexAttribPointerARB(tsmAttrib+a, 3, GL_FLOAT, 0, vertexSize, buf + a);
672 		}
673 	}
674 }
675 
UnbindTSM()676 void NodeGLSLShader::UnbindTSM()
677 {
678 	if (tsmAttrib >= 0) {
679 		for (int a=0;a<3;a++)
680 			glDisableVertexAttribArrayARB(tsmAttrib+a);
681 	}
682 }
683 
684 
685 
Setup(NodeSetupParams & params)686 void NodeGLSLShader::Setup(NodeSetupParams& params) {
687 	/*
688 	if (renderBuffer) { // use a offscreen rendering buffer
689 		renderBuffer->framebuffer.Bind();
690 		glViewport(0, 0, renderBuffer->width, renderBuffer->height);
691 	}
692 	*/
693 
694 	glUseProgramObjectARB(program);
695 	for (size_t a = 0; a < texUnits.size(); a++) {
696 		glActiveTextureARB(GL_TEXTURE0_ARB + a);
697 
698 		GLenum target;
699 		if (texUnits[a]->IsRect())
700 			target = GL_TEXTURE_RECTANGLE_ARB;
701 		else
702 			target = GL_TEXTURE_2D;
703 
704 		if (texUnits[a]->id)
705 			glBindTexture(target, texUnits[a]->id);
706 		glEnable(target);
707 	}
708 	for (size_t a = 0; a < texCoordGen.size(); a++) {
709 		glActiveTextureARB(GL_TEXTURE0_ARB + a);
710 		texCoordGen[a]->SetupTexGen();
711 	}
712 	glActiveTextureARB(GL_TEXTURE0_ARB);
713 
714 	if (wsLightDirLocation >= 0 && params.wsLightDir)
715 		glUniform3fARB(wsLightDirLocation, params.wsLightDir->x, params.wsLightDir->y, params.wsLightDir->z);
716 	if (wsEyePosLocation >= 0 && params.wsEyePos)
717 		glUniform3fARB(wsEyePosLocation, params.wsEyePos->x, params.wsEyePos->y, params.wsEyePos->z);
718 
719 	if (params.shadowMapParams) {
720 		if (shadowMapLocation >= 0) {
721 			glUniform1i(shadowMapLocation, texUnits.size());
722 			glActiveTextureARB(GL_TEXTURE0_ARB + texUnits.size());
723 			glBindTexture(GL_TEXTURE_2D, params.shadowMapParams->shadowMap);
724 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);
725 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
726 			glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
727 		}
728 
729 		ShadowMapParams& smp = *params.shadowMapParams;
730 		if (shadowMatrixLocation >= 0) glUniformMatrix4fvARB(shadowMatrixLocation, 1, GL_TRUE, smp.shadowMatrix);
731 		if (shadowParamsLocation >= 0) glUniform4fARB(shadowParamsLocation, smp.f_a, smp.f_b, smp.mid[0], smp.mid[1]);
732 	}
733 }
734 
Cleanup()735 void NodeGLSLShader::Cleanup() {
736 	for (size_t a = 0; a < texUnits.size(); a++) {
737 		glActiveTextureARB(GL_TEXTURE0_ARB + a);
738 		glBindTexture(texUnits[a]->IsRect()? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D, 0);
739 		glDisable(texUnits[a]->IsRect()? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D);
740 	}
741 
742 	glActiveTextureARB(GL_TEXTURE0_ARB);
743 	glUseProgramObjectARB(0);
744 }
745 
746 
747 
748 
GetDebugDesc()749 std::string NodeGLSLShader::GetDebugDesc()
750 {
751 	return debugstr;
752 }
753 
GetVertexDataRequirements()754 uint NodeGLSLShader::GetVertexDataRequirements()
755 {
756 	return vertBufReq;
757 }
GetTextureUnits(BaseTexture * tex,int & imageUnit,int & coordUnit)758 void NodeGLSLShader::GetTextureUnits(BaseTexture* tex, int &imageUnit, int& coordUnit)
759 {
760 }
761 
GLSLShaderHandler()762 GLSLShaderHandler::GLSLShaderHandler()
763 {
764 	curShader = 0;
765 	scShader = 0;
766 	buffer = 0;
767 }
768 
~GLSLShaderHandler()769 GLSLShaderHandler::~GLSLShaderHandler()
770 {
771 	delete buffer;
772 	delete scShader;
773 }
774 
775 
776 
EndTexturing()777 void GLSLShaderHandler::EndTexturing() {
778 	glDisable(GL_TEXTURE_2D);
779 	glDisable(GL_TEXTURE_GEN_S);
780 	glDisable(GL_TEXTURE_GEN_T);
781 
782 	if (curShader) {
783 		curShader->Cleanup();
784 		curShader = NULL;
785 	}
786 }
787 
BeginTexturing()788 void GLSLShaderHandler::BeginTexturing() {
789 }
790 
791 
792 
BeginPass(const std::vector<Blendmap * > & blendmaps,const std::vector<TiledTexture * > & textures,int pass)793 void GLSLShaderHandler::BeginPass(const std::vector<Blendmap*>& blendmaps, const std::vector<TiledTexture*>& textures, int pass)
794 {
795 	if (buffer) {
796 		if ((buffer->width != globalRendering->viewSizeX) || (buffer->height != globalRendering->viewSizeY)) {
797 			delete buffer;
798 			buffer = NULL; // to prevent a dead-pointer in case of an out-of-memory exception on the next line
799 			buffer = new BufferTexture;
800 		}
801 	}
802 	if (buffer) {
803 		if (pass == 0) {
804 			buffer->framebuffer.Bind();
805 			glViewport(0, 0, buffer->width, buffer->height);
806 			glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
807 		}
808 		else if (pass == 1) {
809 			buffer->framebuffer.Unbind();
810 			glViewport(globalRendering->viewPosX, globalRendering->viewPosY, globalRendering->viewSizeX, globalRendering->viewSizeY);
811 		}
812 	}
813 }
814 
SetupShader(IShaderSetup * ps,NodeSetupParams & params)815 bool GLSLShaderHandler::SetupShader(IShaderSetup* ps, NodeSetupParams& params)
816 {
817 	if (curShader) {
818 		curShader->Cleanup();
819 		curShader = NULL;
820 	}
821 
822 	GLSLBaseShader* bs = static_cast<GLSLBaseShader*>(ps);
823 	bs->Setup(params);
824 	curShader = bs;
825 	return true;
826 }
827 
828 
BeginBuild()829 void GLSLShaderHandler::BeginBuild()
830 {
831 	if (curShader) {
832 		curShader->Cleanup();
833 		curShader = 0;
834 	}
835 
836 	delete buffer;
837 	delete scShader;
838 
839 	buffer = NULL;
840 	scShader = NULL;
841 
842 	renderSetups.clear();
843 }
844 
845 
EndBuild()846 void GLSLShaderHandler::EndBuild()
847 {
848 	bool multipass = false;
849 	for (size_t a=0;a<renderSetups.size();a++)
850 		if (renderSetups[a]->passes.size()>1) {
851 			multipass = true;
852 			break;
853 		}
854 
855 	if (!multipass)
856 		return;
857 
858 	scShader = new SimpleCopyShader(buffer);
859 
860 	// make sure all rendersetups have 2 passes
861 	for (size_t a = 0; a < renderSetups.size(); a++) {
862 		if (renderSetups[a]->passes.size() == 2)
863 			continue;
864 
865 		// add a simple pass to add
866 		renderSetups[a]->passes.push_back(RenderPass());
867 		RenderPass& pass = renderSetups[a]->passes.back();
868 		pass.depthWrite = true;
869 		pass.operation = Pass_Replace;
870 		pass.shaderSetup = new SimpleCopyNodeShader(scShader);
871 	}
872 }
873 
BuildNodeSetup(ShaderDef * shaderDef,RenderSetup * renderSetup)874 void GLSLShaderHandler::BuildNodeSetup(ShaderDef* shaderDef, RenderSetup* renderSetup)
875 {
876 	ShaderBuilder shaderBuilder(renderSetup);
877 
878 	shaderBuilder.buffer = buffer;
879 	shaderBuilder.Build(shaderDef);
880 
881 	// Build() might have changed buffer
882 	buffer = shaderBuilder.buffer;
883 
884 	renderSetups.push_back(renderSetup);
885 }
886 
887 
888 
MaxTextureUnits()889 int GLSLShaderHandler::MaxTextureUnits() {
890 	GLint n;
891 	glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &n);
892 	return n;
893 }
894 
MaxTextureCoords()895 int GLSLShaderHandler::MaxTextureCoords() {
896 	GLint n;
897 	glGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, &n);
898 	return n;
899 }
900 
901 
902 
SimpleCopyShader(BufferTexture * buf)903 SimpleCopyShader::SimpleCopyShader(BufferTexture* buf)
904 {
905 	Shader fs, vs;
906 
907 	if (buf->IsRect())
908 		fs.texts.push_back("#define UseTextureRECT");
909 	fs.AddFile("shaders/GLSL/terrainSimpleCopyFS.glsl");
910 	fs.Build(GL_FRAGMENT_SHADER_ARB);
911 
912 	vs.AddFile("shaders/GLSL/terrainSimpleCopyVS.glsl");
913 	vs.Build(GL_VERTEX_SHADER_ARB);
914 
915 	vertexShader = vs.handle;
916 	fragmentShader = fs.handle;
917 
918 	program = glCreateProgramObjectARB();
919 	glAttachObjectARB(program, vertexShader);
920 	glAttachObjectARB(program, fragmentShader);
921 
922 	glLinkProgramARB(program);
923 	GLint isLinked;
924 	glGetObjectParameterivARB(program, GL_OBJECT_LINK_STATUS_ARB, &isLinked);
925 	if (!isLinked)
926 	{
927 		LOG_L(L_ERROR, "Failed to link shaders. Showing info log:");
928 		ShowInfoLog(program);
929 		throw std::runtime_error("Failed to link shaders");
930 	}
931 
932 	GLint srcTex = glGetUniformLocationARB(program, "sourceTexture");
933 	glUseProgramObjectARB(program);
934 	glUniform1iARB(srcTex, 0);
935 	if (!buf->IsRect()) {
936 		GLint invScreenDim = glGetUniformLocationARB(program, "invScreenDim");
937 		glUniform2fARB(invScreenDim, 1.0f/globalRendering->viewSizeX, 1.0f/globalRendering->viewSizeY);
938 	}
939 	glUseProgramObjectARB(0);
940 
941 	source = buf;
942 }
943 
~SimpleCopyShader()944 SimpleCopyShader::~SimpleCopyShader()
945 {
946 	glDetachObjectARB(program, vertexShader);
947 	glDetachObjectARB(program, fragmentShader);
948 	glDeleteObjectARB(program);
949 	glDeleteObjectARB(fragmentShader);
950 	glDeleteObjectARB(vertexShader);
951 }
952 
Setup()953 void SimpleCopyShader::Setup()
954 {
955 	GLenum target;
956 	if (source->IsRect())
957 		target = GL_TEXTURE_RECTANGLE_ARB;
958 	else
959 		target = GL_TEXTURE_2D;
960 
961 	glActiveTextureARB(GL_TEXTURE0_ARB);
962 	glBindTexture(target, source->id);
963 	glEnable(target);
964 
965 	glUseProgramObjectARB(program);
966 }
967 
Cleanup()968 void SimpleCopyShader::Cleanup()
969 {
970 	glActiveTextureARB(GL_TEXTURE0_ARB);
971 	if (source->IsRect())
972 		glDisable(GL_TEXTURE_RECTANGLE_ARB);
973 	else
974 		glDisable(GL_TEXTURE_2D);
975 	glUseProgramObjectARB(0);
976 }
977 
978 }
979