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