temp commit
[SARndbox.git] / SurfaceRenderer.cpp
blobfcd37c4121887512a1a71db7f1faeb7e8611ece4
1 /***********************************************************************
2 SurfaceRenderer - Class to render a surface defined by a regular grid in
3 depth image space.
4 Copyright (c) 2012-2018 Oliver Kreylos
6 This file is part of the Augmented Reality Sandbox (SARndbox).
8 The Augmented Reality Sandbox is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
13 The Augmented Reality Sandbox is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License along
19 with the Augmented Reality Sandbox; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 ***********************************************************************/
23 #include "SurfaceRenderer.h"
25 #include <string>
26 #include <vector>
27 #include <Misc/PrintInteger.h>
28 #include <Misc/ThrowStdErr.h>
29 #include <Misc/MessageLogger.h>
30 #include <GL/gl.h>
31 #include <GL/GLVertexArrayParts.h>
32 #include <GL/Extensions/GLARBFragmentShader.h>
33 #include <GL/Extensions/GLARBMultitexture.h>
34 #include <GL/Extensions/GLARBShaderObjects.h>
35 #include <GL/Extensions/GLARBTextureFloat.h>
36 #include <GL/Extensions/GLARBTextureRectangle.h>
37 #include <GL/Extensions/GLARBTextureRg.h>
38 #include <GL/Extensions/GLARBVertexShader.h>
39 #include <GL/Extensions/GLEXTFramebufferObject.h>
40 #include <GL/GLLightTracker.h>
41 #include <GL/GLContextData.h>
42 #include <GL/GLTransformationWrappers.h>
43 #include <GL/GLGeometryVertex.h>
45 #include "DepthImageRenderer.h"
46 #include "ElevationColorMap.h"
47 #include "DEM.h"
48 #include "WaterTable2.h"
49 #include "ShaderHelper.h"
50 #include "Config.h"
52 /******************************************
53 Methods of class SurfaceRenderer::DataItem:
54 ******************************************/
56 SurfaceRenderer::DataItem::DataItem(void)
57 : contourLineFramebufferObject(0), contourLineDepthBufferObject(0),
58 contourLineColorTextureObject(0), contourLineVersion(0),
59 heightMapShader(0), surfaceSettingsVersion(0), lightTrackerVersion(0),
60 globalAmbientHeightMapShader(0), shadowedIlluminatedHeightMapShader(0) {
61 /* Initialize all required extensions: */
62 GLARBFragmentShader::initExtension();
63 GLARBMultitexture::initExtension();
64 GLARBShaderObjects::initExtension();
65 GLARBTextureFloat::initExtension();
66 GLARBTextureRectangle::initExtension();
67 GLARBTextureRg::initExtension();
68 GLARBVertexShader::initExtension();
69 GLEXTFramebufferObject::initExtension();
72 SurfaceRenderer::DataItem::~DataItem(void) {
73 /* Release all allocated buffers, textures, and shaders: */
74 glDeleteFramebuffersEXT(1, &contourLineFramebufferObject);
75 glDeleteRenderbuffersEXT(1, &contourLineDepthBufferObject);
76 glDeleteTextures(1, &contourLineColorTextureObject);
77 glDeleteObjectARB(heightMapShader);
78 glDeleteObjectARB(globalAmbientHeightMapShader);
79 glDeleteObjectARB(shadowedIlluminatedHeightMapShader);
82 /********************************
83 Methods of class SurfaceRenderer:
84 ********************************/
86 void SurfaceRenderer::shaderSourceFileChanged(const IO::FileMonitor::Event& event) {
87 /* Invalidate the single-pass surface shader: */
88 ++surfaceSettingsVersion;
91 GLhandleARB SurfaceRenderer::createSinglePassSurfaceShader(const GLLightTracker& lt,
92 GLint* uniformLocations) const {
93 GLhandleARB result = 0;
95 std::vector<GLhandleARB> shaders;
96 try {
97 /*********************************************************************
98 Assemble and compile the surface rendering vertex shader:
99 *********************************************************************/
101 /* Assemble the function and declaration strings: */
102 std::string vertexFunctions = "\
103 #extension GL_ARB_texture_rectangle : enable\n";
105 std::string vertexUniforms = "\
106 uniform sampler2DRect depthSampler; // Sampler for the depth image-space elevation texture\n\
107 uniform mat4 depthProjection; // Transformation from depth image space to camera space\n\
108 uniform mat4 projectionModelviewDepthProjection; // Transformation from depth image space to clip space\n";
110 std::string vertexVaryings;
112 /* Assemble the vertex shader's main function: */
113 std::string vertexMain = "\
114 void main()\n\
115 {\n\
116 /* Get the vertex' depth image-space z coordinate from the texture: */\n\
117 vec4 vertexDic=gl_Vertex;\n\
118 vertexDic.z=texture2DRect(depthSampler,gl_Vertex.xy).r;\n\
120 /* Transform the vertex from depth image space to camera space and normalize it: */\n\
121 vec4 vertexCc=depthProjection*vertexDic;\n\
122 vertexCc/=vertexCc.w;\n\
123 \n";
125 if(dem != 0) {
126 /* Add declarations for DEM matching: */
127 vertexUniforms += "\
128 uniform mat4 demTransform; // Transformation from camera space to DEM space\n\
129 uniform sampler2DRect demSampler; // Sampler for the DEM texture\n\
130 uniform float demDistScale; // Distance from surface to DEM at which the color map saturates\n";
132 vertexVaryings += "\
133 varying float demDist; // Scaled signed distance from surface to DEM\n";
135 /* Add DEM matching code to vertex shader's main function: */
136 vertexMain += "\
137 /* Transform the camera-space vertex to scaled DEM space: */\n\
138 vec4 vertexDem=demTransform*vertexCc;\n\
140 /* Calculate scaled DEM-surface distance: */\n\
141 demDist=(vertexDem.z-texture2DRect(demSampler,vertexDem.xy).r)*demDistScale;\n\
142 \n";
143 } else {
144 if(elevationColorMap != 0) {
145 /* Add declarations for height mapping: */
146 vertexUniforms += "\
147 uniform vec4 heightColorMapPlaneEq; // Plane equation of the base plane in camera space, scaled for height map textures\n";
149 vertexVaryings += "\
150 varying float heightColorMapTexCoord; // Texture coordinate for the height color map\n";
152 /* Add height mapping code to vertex shader's main function: */
153 vertexMain += "\
154 /* Plug camera-space vertex into the scaled and offset base plane equation: */\n\
155 heightColorMapTexCoord=dot(heightColorMapPlaneEq,vertexCc);\n\
156 \n";
159 if(drawDippingBed) {
160 /* Add declarations for dipping bed rendering: */
161 if(dippingBedFolded) {
162 vertexUniforms += "\
163 uniform float dbc[5]; // Dipping bed coefficients\n";
164 } else {
165 vertexUniforms += "\
166 uniform vec4 dippingBedPlaneEq; // Plane equation of the dipping bed\n";
169 vertexVaryings += "\
170 varying float dippingBedDistance; // Vertex distance to dipping bed\n";
172 /* Add dipping bed code to vertex shader's main function: */
173 if(dippingBedFolded) {
174 vertexMain += "\
175 /* Calculate distance from camera-space vertex to dipping bed equation: */\n\
176 dippingBedDistance=vertexCc.z-(((1.0-dbc[3])+cos(dbc[0]*vertexCc.x)*dbc[3])*sin(dbc[1]*vertexCc.y)*dbc[2]+dbc[4]);\n\
177 \n";
178 } else {
179 vertexMain += "\
180 /* Plug camera-space vertex into the dipping bed equation: */\n\
181 dippingBedDistance=dot(dippingBedPlaneEq,vertexCc);\n\
182 \n";
187 if(illuminate) {
188 /* Add declarations for illumination: */
189 vertexUniforms += "\
190 uniform mat4 modelview; // Transformation from camera space to eye space\n\
191 uniform mat4 tangentModelviewDepthProjection; // Transformation from depth image space to eye space for tangent planes\n";
193 vertexVaryings += "\
194 varying vec4 diffColor,specColor; // Diffuse and specular colors, interpolated separately for correct highlights\n";
196 /* Add illumination code to vertex shader's main function: */
197 vertexMain += "\
198 /* Calculate the vertex' tangent plane equation in depth image space: */\n\
199 vec4 tangentDic;\n\
200 tangentDic.x=texture2DRect(depthSampler,vec2(vertexDic.x-1.0,vertexDic.y)).r-texture2DRect(depthSampler,vec2(vertexDic.x+1.0,vertexDic.y)).r;\n\
201 tangentDic.y=texture2DRect(depthSampler,vec2(vertexDic.x,vertexDic.y-1.0)).r-texture2DRect(depthSampler,vec2(vertexDic.x,vertexDic.y+1.0)).r;\n\
202 tangentDic.z=2.0;\n\
203 tangentDic.w=-dot(vertexDic.xyz,tangentDic.xyz)/vertexDic.w;\n\
205 /* Transform the vertex and its tangent plane from depth image space to eye space: */\n\
206 vec4 vertexEc=modelview*vertexCc;\n\
207 vec3 normalEc=normalize((tangentModelviewDepthProjection*tangentDic).xyz);\n\
209 /* Initialize the color accumulators: */\n\
210 diffColor=gl_LightModel.ambient*gl_FrontMaterial.ambient;\n\
211 specColor=vec4(0.0,0.0,0.0,0.0);\n\
212 \n";
214 /* Call the appropriate light accumulation function for every enabled light source: */
215 bool firstLight = true;
216 for(int lightIndex = 0; lightIndex < lt.getMaxNumLights(); ++lightIndex)
217 if(lt.getLightState(lightIndex).isEnabled()) {
218 /* Create the light accumulation function: */
219 vertexFunctions.push_back('\n');
220 vertexFunctions += lt.createAccumulateLightFunction(lightIndex);
222 if(firstLight) {
223 vertexMain += "\
224 /* Call the light accumulation functions for all enabled light sources: */\n";
225 firstLight = false;
228 /* Call the light accumulation function from vertex shader's main function: */
229 vertexMain += "\
230 accumulateLight";
231 char liBuffer[12];
232 vertexMain.append(Misc::print(lightIndex, liBuffer + 11));
233 vertexMain +=
234 "(vertexEc,normalEc,gl_FrontMaterial.ambient,gl_FrontMaterial.diffuse,gl_FrontMaterial.specular,gl_FrontMaterial.shininess,diffColor,specColor);\n";
236 if(!firstLight)
237 vertexMain += "\
238 \n";
241 if(waterTable != 0 && dem == 0) {
242 /* Add declarations for water handling: */
243 vertexUniforms += "\
244 uniform mat4 waterTransform; // Transformation from camera space to water level texture coordinate space\n";
245 vertexVaryings += "\
246 varying vec2 waterTexCoord; // Texture coordinate for water level texture\n";
248 /* Add water handling code to vertex shader's main function: */
249 vertexMain += "\
250 /* Transform the vertex from camera space to water level texture coordinate space: */\n\
251 waterTexCoord=(waterTransform*vertexCc).xy;\n\
252 \n";
255 /* Finish the vertex shader's main function: */
256 vertexMain += "\
257 /* Transform vertex from depth image space to clip space: */\n\
258 gl_Position=projectionModelviewDepthProjection*vertexDic;\n\
259 }\n";
261 /* Compile the vertex shader: */
262 shaders.push_back(glCompileVertexShaderFromStrings(7, vertexFunctions.c_str(), "\t\t\n",
263 vertexUniforms.c_str(), "\t\t\n", vertexVaryings.c_str(), "\t\t\n", vertexMain.c_str()));
265 /*********************************************************************
266 Assemble and compile the surface rendering fragment shaders:
267 *********************************************************************/
269 /* Assemble the fragment shader's function declarations: */
270 std::string fragmentDeclarations;
272 /* Assemble the fragment shader's uniform and varying variables: */
273 std::string fragmentUniforms;
274 std::string fragmentVaryings;
276 /* Assemble the fragment shader's main function: */
277 std::string fragmentMain = "\
278 void main()\n\
279 {\n";
281 if(dem != 0) {
282 /* Add declarations for DEM matching: */
283 fragmentVaryings += "\
284 varying float demDist; // Scaled signed distance from surface to DEM\n";
286 /* Add DEM matching code to the fragment shader's main function: */
287 fragmentMain += "\
288 /* Calculate the fragment's color from a double-ramp function: */\n\
289 vec4 baseColor;\n\
290 if(demDist<0.0)\n\
291 baseColor=mix(vec4(1.0,1.0,1.0,1.0),vec4(1.0,0.0,0.0,1.0),min(-demDist,1.0));\n\
292 else\n\
293 baseColor=mix(vec4(1.0,1.0,1.0,1.0),vec4(0.0,0.0,1.0,1.0),min(demDist,1.0));\n\
294 \n";
295 } else {
296 if(elevationColorMap != 0) {
297 /* Add declarations for height mapping: */
298 fragmentUniforms += "\
299 uniform sampler1D heightColorMapSampler;\n";
300 fragmentVaryings += "\
301 varying float heightColorMapTexCoord; // Texture coordinate for the height color map\n";
303 /* Add height mapping code to the fragment shader's main function: */
304 fragmentMain += "\
305 /* Get the fragment's color from the height color map: */\n\
306 vec4 baseColor=texture1D(heightColorMapSampler,heightColorMapTexCoord);\n\
307 \n";
308 } else {
309 fragmentMain += "\
310 /* Set the surface's base color to white: */\n\
311 vec4 baseColor=vec4(1.0,1.0,1.0,1.0);\n\
312 \n";
315 if(drawDippingBed) {
316 /* Add declarations for dipping bed rendering: */
317 fragmentUniforms += "\
318 uniform float dippingBedThickness; // Thickness of dipping bed in camera-space units\n";
320 fragmentVaryings += "\
321 varying float dippingBedDistance; // Vertex distance to dipping bed plane\n";
323 /* Add dipping bed code to fragment shader's main function: */
324 fragmentMain += "\
325 /* Check fragment's dipping plane distance against dipping bed thickness: */\n\
326 float w=fwidth(dippingBedDistance)*1.0;\n\
327 if(dippingBedDistance<0.0)\n\
328 baseColor=mix(baseColor,vec4(1.0,0.0,0.0,1.0),smoothstep(-dippingBedThickness*0.5-w,-dippingBedThickness*0.5+w,dippingBedDistance));\n\
329 else\n\
330 baseColor=mix(vec4(1.0,0.0,0.0,1.0),baseColor,smoothstep(dippingBedThickness*0.5-w,dippingBedThickness*0.5+w,dippingBedDistance));\n\
331 \n";
335 if(drawContourLines) {
336 /* Declare the contour line function: */
337 fragmentDeclarations += "\
338 void addContourLines(in vec2,inout vec4);\n";
340 /* Compile the contour line shader: */
341 shaders.push_back(compileFragmentShader("SurfaceAddContourLines"));
343 /* Call contour line function from fragment shader's main function: */
344 fragmentMain += "\
345 /* Modulate the base color by contour line color: */\n\
346 addContourLines(gl_FragCoord.xy,baseColor);\n\
347 \n";
350 if(illuminate) {
351 /* Declare the illumination function: */
352 fragmentDeclarations += "\
353 void illuminate(inout vec4);\n";
355 /* Compile the illumination shader: */
356 shaders.push_back(compileFragmentShader("SurfaceIlluminate"));
358 /* Call illumination function from fragment shader's main function: */
359 fragmentMain += "\
360 /* Apply illumination to the base color: */\n\
361 illuminate(baseColor);\n\
362 \n";
365 if(waterTable != 0 && dem == 0) {
366 /* Declare the water handling functions: */
367 fragmentDeclarations += "\
368 void addWaterColor(in vec2,inout vec4);\n\
369 void addWaterColorAdvected(inout vec4);\n";
371 /* Compile the water handling shader: */
372 shaders.push_back(compileFragmentShader("SurfaceAddWaterColor"));
374 /* Call water coloring function from fragment shader's main function: */
375 if(advectWaterTexture) {
376 fragmentMain += "\
377 /* Modulate the base color with water color: */\n\
378 addWaterColorAdvected(baseColor);\n\
379 \n";
380 } else {
381 fragmentMain += "\
382 /* Modulate the base color with water color: */\n\
383 addWaterColor(gl_FragCoord.xy,baseColor);\n\
384 \n";
388 /* Finish the fragment shader's main function: */
389 fragmentMain += "\
390 /* Assign the final color to the fragment: */\n\
391 gl_FragColor=baseColor;\n\
392 }\n";
394 /* Compile the fragment shader: */
395 shaders.push_back(glCompileFragmentShaderFromStrings(7, fragmentDeclarations.c_str(), "\t\t\n",
396 fragmentUniforms.c_str(), "\t\t\n", fragmentVaryings.c_str(), "\t\t\n", fragmentMain.c_str()));
398 /* Link the shader program: */
399 result = glLinkShader(shaders);
401 /* Release all compiled shaders: */
402 for(std::vector<GLhandleARB>::iterator shIt = shaders.begin(); shIt != shaders.end(); ++shIt)
403 glDeleteObjectARB(*shIt);
405 /*******************************************************************
406 Query the shader program's uniform locations:
407 *******************************************************************/
409 GLint* ulPtr = uniformLocations;
411 /* Query common uniform variables: */
412 *(ulPtr++) = glGetUniformLocationARB(result, "depthSampler");
413 *(ulPtr++) = glGetUniformLocationARB(result, "depthProjection");
414 if(dem != 0) {
415 /* Query DEM matching uniform variables: */
416 *(ulPtr++) = glGetUniformLocationARB(result, "demTransform");
417 *(ulPtr++) = glGetUniformLocationARB(result, "demSampler");
418 *(ulPtr++) = glGetUniformLocationARB(result, "demDistScale");
419 } else if(elevationColorMap != 0) {
420 /* Query height color mapping uniform variables: */
421 *(ulPtr++) = glGetUniformLocationARB(result, "heightColorMapPlaneEq");
422 *(ulPtr++) = glGetUniformLocationARB(result, "heightColorMapSampler");
424 if(drawContourLines) {
425 *(ulPtr++) = glGetUniformLocationARB(result, "pixelCornerElevationSampler");
426 *(ulPtr++) = glGetUniformLocationARB(result, "contourLineFactor");
428 if(drawDippingBed) {
429 if(dippingBedFolded)
430 *(ulPtr++) = glGetUniformLocationARB(result, "dbc");
431 else
432 *(ulPtr++) = glGetUniformLocationARB(result, "dippingBedPlaneEq");
433 *(ulPtr++) = glGetUniformLocationARB(result, "dippingBedThickness");
435 if(illuminate) {
436 /* Query illumination uniform variables: */
437 *(ulPtr++) = glGetUniformLocationARB(result, "modelview");
438 *(ulPtr++) = glGetUniformLocationARB(result, "tangentModelviewDepthProjection");
440 if(waterTable != 0 && dem == 0) {
441 /* Query water handling uniform variables: */
442 *(ulPtr++) = glGetUniformLocationARB(result, "waterTransform");
443 *(ulPtr++) = glGetUniformLocationARB(result, "bathymetrySampler");
444 *(ulPtr++) = glGetUniformLocationARB(result, "quantitySampler");
445 *(ulPtr++) = glGetUniformLocationARB(result, "waterCellSize");
446 *(ulPtr++) = glGetUniformLocationARB(result, "waterOpacity");
447 *(ulPtr++) = glGetUniformLocationARB(result, "waterAnimationTime");
449 *(ulPtr++) = glGetUniformLocationARB(result, "projectionModelviewDepthProjection");
450 } catch(...) {
451 /* Clean up and re-throw the exception: */
452 for(std::vector<GLhandleARB>::iterator shIt = shaders.begin(); shIt != shaders.end(); ++shIt)
453 glDeleteObjectARB(*shIt);
454 throw;
457 return result;
460 void SurfaceRenderer::renderPixelCornerElevations(const int viewport[4],
461 const PTransform& projectionModelview, GLContextData& contextData,
462 SurfaceRenderer::DataItem* dataItem) const {
463 /* Save the currently-bound frame buffer and clear color: */
464 GLint currentFrameBuffer;
465 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &currentFrameBuffer);
466 GLfloat currentClearColor[4];
467 glGetFloatv(GL_COLOR_CLEAR_VALUE, currentClearColor);
469 /* Check if the contour line rendering frame buffer needs to be created: */
470 if(dataItem->contourLineFramebufferObject == 0) {
471 /* Initialize the frame buffer: */
472 for(int i = 0; i < 2; ++i)
473 dataItem->contourLineFramebufferSize[i] = 0;
474 glGenFramebuffersEXT(1, &dataItem->contourLineFramebufferObject);
475 glGenRenderbuffersEXT(1, &dataItem->contourLineDepthBufferObject);
476 glGenTextures(1, &dataItem->contourLineColorTextureObject);
479 /* Bind the contour line rendering frame buffer object: */
480 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->contourLineFramebufferObject);
482 /* Check if the contour line frame buffer needs to be resized: */
483 if(dataItem->contourLineFramebufferSize[0] != (unsigned int)(viewport[2] + 1)
484 || dataItem->contourLineFramebufferSize[1] != (unsigned int)(viewport[3] + 1)) {
485 /* Remember if the render buffers must still be attached to the frame buffer: */
486 bool mustAttachBuffers = dataItem->contourLineFramebufferSize[0] == 0
487 && dataItem->contourLineFramebufferSize[1] == 0;
489 /* Update the frame buffer size: */
490 for(int i = 0; i < 2; ++i)
491 dataItem->contourLineFramebufferSize[i] = (unsigned int)(viewport[2 + i] + 1);
493 /* Resize the topographic contour line rendering depth buffer: */
494 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, dataItem->contourLineDepthBufferObject);
495 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,
496 dataItem->contourLineFramebufferSize[0], dataItem->contourLineFramebufferSize[1]);
497 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
499 /* Resize the topographic contour line rendering color texture: */
500 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->contourLineColorTextureObject);
501 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
502 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
503 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
504 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
505 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_R32F, dataItem->contourLineFramebufferSize[0],
506 dataItem->contourLineFramebufferSize[1], 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);
507 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
509 if(mustAttachBuffers) {
510 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT,
511 dataItem->contourLineDepthBufferObject);
512 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB,
513 dataItem->contourLineColorTextureObject, 0);
514 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
515 glReadBuffer(GL_NONE);
519 /* Extend the viewport to render the corners of all pixels: */
520 glViewport(0, 0, viewport[2] + 1, viewport[3] + 1);
521 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
522 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
524 /* Shift the projection matrix by half a pixel to render the corners of the final pixels: */
525 PTransform shiftedProjectionModelview = projectionModelview;
526 PTransform::Matrix& spmm = shiftedProjectionModelview.getMatrix();
527 Scalar xs = Scalar(viewport[2]) / Scalar(viewport[2] + 1);
528 Scalar ys = Scalar(viewport[3]) / Scalar(viewport[3] + 1);
529 for(int j = 0; j < 4; ++j) {
530 spmm(0, j) *= xs;
531 spmm(1, j) *= ys;
534 /* Render the surface elevation into the half-pixel offset frame buffer: */
535 depthImageRenderer->renderElevation(shiftedProjectionModelview, contextData);
537 /* Restore the original viewport: */
538 glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
540 /* Restore the original clear color and frame buffer binding: */
541 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, currentFrameBuffer);
542 glClearColor(currentClearColor[0], currentClearColor[1], currentClearColor[2],
543 currentClearColor[3]);
546 SurfaceRenderer::SurfaceRenderer(const DepthImageRenderer* sDepthImageRenderer)
547 : depthImageRenderer(sDepthImageRenderer),
548 drawContourLines(true), contourLineFactor(1.0f),
549 elevationColorMap(0),
550 drawDippingBed(false), dippingBedFolded(false),
551 dippingBedPlane(Plane::Vector(0, 0, 1), 0.0f), dippingBedThickness(1),
552 dem(0), demDistScale(1.0f),
553 illuminate(false),
554 waterTable(0), advectWaterTexture(false), waterOpacity(2.0f),
555 surfaceSettingsVersion(1),
556 animationTime(0.0) {
557 /* Copy the depth image size: */
558 for(int i = 0; i < 2; ++i)
559 depthImageSize[i] = depthImageRenderer->getDepthImageSize(i);
561 /* Check if the depth projection matrix retains right-handedness: */
562 const PTransform& depthProjection = depthImageRenderer->getDepthProjection();
563 Point p1 = depthProjection.transform(Point(0, 0, 0));
564 Point p2 = depthProjection.transform(Point(1, 0, 0));
565 Point p3 = depthProjection.transform(Point(0, 1, 0));
566 Point p4 = depthProjection.transform(Point(0, 0, 1));
567 bool depthProjectionInverts = ((p2 - p1) ^ (p3 - p1)) * (p4 - p1) < Scalar(0);
569 /* Calculate the transposed tangent plane depth projection: */
570 tangentDepthProjection = Geometry::invert(depthProjection);
571 if(depthProjectionInverts)
572 tangentDepthProjection *= PTransform::scale(PTransform::Scale(-1, -1, -1));
574 /* Monitor the external shader source files: */
575 fileMonitor.addPath((std::string(CONFIG_SHADERDIR) +
576 std::string("/SurfaceAddContourLines.fs")).c_str(), IO::FileMonitor::Modified,
577 Misc::createFunctionCall(this, &SurfaceRenderer::shaderSourceFileChanged));
578 fileMonitor.addPath((std::string(CONFIG_SHADERDIR) + std::string("/SurfaceIlluminate.fs")).c_str(),
579 IO::FileMonitor::Modified, Misc::createFunctionCall(this,
580 &SurfaceRenderer::shaderSourceFileChanged));
581 fileMonitor.addPath((std::string(CONFIG_SHADERDIR) +
582 std::string("/SurfaceAddWaterColor.fs")).c_str(), IO::FileMonitor::Modified,
583 Misc::createFunctionCall(this, &SurfaceRenderer::shaderSourceFileChanged));
584 fileMonitor.startPolling();
587 void SurfaceRenderer::initContext(GLContextData& contextData) const {
588 /* Create a data item and add it to the context: */
589 DataItem* dataItem = new DataItem;
590 contextData.addDataItem(this, dataItem);
592 /* Create the height map render shader: */
593 dataItem->heightMapShader = createSinglePassSurfaceShader(*contextData.getLightTracker(),
594 dataItem->heightMapShaderUniforms);
595 dataItem->surfaceSettingsVersion = surfaceSettingsVersion;
596 dataItem->lightTrackerVersion = contextData.getLightTracker()->getVersion();
598 /* Create the global ambient height map render shader: */
599 dataItem->globalAmbientHeightMapShader =
600 linkVertexAndFragmentShader("SurfaceGlobalAmbientHeightMapShader");
601 dataItem->globalAmbientHeightMapShaderUniforms[0] = glGetUniformLocationARB(
602 dataItem->globalAmbientHeightMapShader, "depthSampler");
603 dataItem->globalAmbientHeightMapShaderUniforms[1] = glGetUniformLocationARB(
604 dataItem->globalAmbientHeightMapShader, "depthProjection");
605 dataItem->globalAmbientHeightMapShaderUniforms[2] = glGetUniformLocationARB(
606 dataItem->globalAmbientHeightMapShader, "basePlane");
607 dataItem->globalAmbientHeightMapShaderUniforms[3] = glGetUniformLocationARB(
608 dataItem->globalAmbientHeightMapShader, "pixelCornerElevationSampler");
609 dataItem->globalAmbientHeightMapShaderUniforms[4] = glGetUniformLocationARB(
610 dataItem->globalAmbientHeightMapShader, "contourLineFactor");
611 dataItem->globalAmbientHeightMapShaderUniforms[5] = glGetUniformLocationARB(
612 dataItem->globalAmbientHeightMapShader, "heightColorMapSampler");
613 dataItem->globalAmbientHeightMapShaderUniforms[6] = glGetUniformLocationARB(
614 dataItem->globalAmbientHeightMapShader, "heightColorMapTransformation");
615 dataItem->globalAmbientHeightMapShaderUniforms[7] = glGetUniformLocationARB(
616 dataItem->globalAmbientHeightMapShader, "waterLevelSampler");
617 dataItem->globalAmbientHeightMapShaderUniforms[8] = glGetUniformLocationARB(
618 dataItem->globalAmbientHeightMapShader, "waterLevelTextureTransformation");
619 dataItem->globalAmbientHeightMapShaderUniforms[9] = glGetUniformLocationARB(
620 dataItem->globalAmbientHeightMapShader, "waterOpacity");
622 /* Create the shadowed illuminated height map render shader: */
623 dataItem->shadowedIlluminatedHeightMapShader =
624 linkVertexAndFragmentShader("SurfaceShadowedIlluminatedHeightMapShader");
625 dataItem->shadowedIlluminatedHeightMapShaderUniforms[0] = glGetUniformLocationARB(
626 dataItem->shadowedIlluminatedHeightMapShader, "depthSampler");
627 dataItem->shadowedIlluminatedHeightMapShaderUniforms[1] = glGetUniformLocationARB(
628 dataItem->shadowedIlluminatedHeightMapShader, "depthProjection");
629 dataItem->shadowedIlluminatedHeightMapShaderUniforms[2] = glGetUniformLocationARB(
630 dataItem->shadowedIlluminatedHeightMapShader, "tangentDepthProjection");
631 dataItem->shadowedIlluminatedHeightMapShaderUniforms[3] = glGetUniformLocationARB(
632 dataItem->shadowedIlluminatedHeightMapShader, "basePlane");
633 dataItem->shadowedIlluminatedHeightMapShaderUniforms[4] = glGetUniformLocationARB(
634 dataItem->shadowedIlluminatedHeightMapShader, "pixelCornerElevationSampler");
635 dataItem->shadowedIlluminatedHeightMapShaderUniforms[5] = glGetUniformLocationARB(
636 dataItem->shadowedIlluminatedHeightMapShader, "contourLineFactor");
637 dataItem->shadowedIlluminatedHeightMapShaderUniforms[6] = glGetUniformLocationARB(
638 dataItem->shadowedIlluminatedHeightMapShader, "heightColorMapSampler");
639 dataItem->shadowedIlluminatedHeightMapShaderUniforms[7] = glGetUniformLocationARB(
640 dataItem->shadowedIlluminatedHeightMapShader, "heightColorMapTransformation");
641 dataItem->shadowedIlluminatedHeightMapShaderUniforms[8] = glGetUniformLocationARB(
642 dataItem->shadowedIlluminatedHeightMapShader, "waterLevelSampler");
643 dataItem->shadowedIlluminatedHeightMapShaderUniforms[9] = glGetUniformLocationARB(
644 dataItem->shadowedIlluminatedHeightMapShader, "waterLevelTextureTransformation");
645 dataItem->shadowedIlluminatedHeightMapShaderUniforms[10] = glGetUniformLocationARB(
646 dataItem->shadowedIlluminatedHeightMapShader, "waterOpacity");
647 dataItem->shadowedIlluminatedHeightMapShaderUniforms[11] = glGetUniformLocationARB(
648 dataItem->shadowedIlluminatedHeightMapShader, "shadowTextureSampler");
649 dataItem->shadowedIlluminatedHeightMapShaderUniforms[12] = glGetUniformLocationARB(
650 dataItem->shadowedIlluminatedHeightMapShader, "shadowProjection");
653 void SurfaceRenderer::setDrawContourLines(bool newDrawContourLines) {
654 drawContourLines = newDrawContourLines;
655 ++surfaceSettingsVersion;
658 void SurfaceRenderer::setContourLineDistance(GLfloat newContourLineDistance) {
659 /* Set the new contour line factor: */
660 contourLineFactor = 1.0f / newContourLineDistance;
663 void SurfaceRenderer::setElevationColorMap(ElevationColorMap* newElevationColorMap) {
664 /* Check if setting this elevation color map invalidates the shader: */
665 if(dem == 0 && ((newElevationColorMap != 0 && elevationColorMap == 0)
666 || (newElevationColorMap == 0 && elevationColorMap != 0)))
667 ++surfaceSettingsVersion;
669 /* Set the elevation color map: */
670 elevationColorMap = newElevationColorMap;
673 void SurfaceRenderer::setDrawDippingBed(bool newDrawDippingBed) {
674 drawDippingBed = newDrawDippingBed;
675 ++surfaceSettingsVersion;
678 void SurfaceRenderer::setDippingBedPlane(const SurfaceRenderer::Plane& newDippingBedPlane) {
679 /* Set the dipping bed mode to planar: */
680 if(dippingBedFolded) {
681 dippingBedFolded = false;
682 ++surfaceSettingsVersion;
685 /* Set the dipping bed's plane equation: */
686 dippingBedPlane = newDippingBedPlane;
689 void SurfaceRenderer::setDippingBedCoeffs(const GLfloat newDippingBedCoeffs[5]) {
690 /* Set the dipping bed mode to folded: */
691 if(!dippingBedFolded) {
692 dippingBedFolded = true;
693 ++surfaceSettingsVersion;
696 /* Set the dipping bed's coefficients: */
697 for(int i = 0; i < 5; ++i)
698 dippingBedCoeffs[i] = newDippingBedCoeffs[i];
701 void SurfaceRenderer::setDippingBedThickness(GLfloat newDippingBedThickness) {
702 dippingBedThickness = newDippingBedThickness;
705 void SurfaceRenderer::setDem(DEM* newDem) {
706 /* Check if setting this DEM invalidates the shader: */
707 if((newDem != 0 && dem == 0) || (newDem == 0 && dem != 0))
708 ++surfaceSettingsVersion;
710 /* Set the new DEM: */
711 dem = newDem;
714 void SurfaceRenderer::setDemDistScale(GLfloat newDemDistScale) {
715 demDistScale = newDemDistScale;
718 void SurfaceRenderer::setIlluminate(bool newIlluminate) {
719 illuminate = newIlluminate;
720 ++surfaceSettingsVersion;
723 void SurfaceRenderer::setWaterTable(WaterTable2* newWaterTable) {
724 waterTable = newWaterTable;
725 ++surfaceSettingsVersion;
728 void SurfaceRenderer::setAdvectWaterTexture(bool newAdvectWaterTexture) {
729 advectWaterTexture = false; // newAdvectWaterTexture;
730 ++surfaceSettingsVersion;
733 void SurfaceRenderer::setWaterOpacity(GLfloat newWaterOpacity) {
734 /* Set the new opacity factor: */
735 waterOpacity = newWaterOpacity;
738 void SurfaceRenderer::setAnimationTime(double newAnimationTime) {
739 /* Set the new animation time: */
740 animationTime = newAnimationTime;
742 /* Poll the file monitor: */
743 fileMonitor.processEvents();
746 void SurfaceRenderer::renderSinglePass(const int viewport[4], const PTransform& projection,
747 const OGTransform& modelview, GLContextData& contextData) const {
748 /* Get the data item: */
749 DataItem* dataItem = contextData.retrieveDataItem<DataItem>(this);
751 /* Calculate the required matrices: */
752 PTransform projectionModelview = projection;
753 projectionModelview *= modelview;
755 /* Check if contour line rendering is enabled: */
756 if(drawContourLines) {
757 /* Run the first rendering pass to create a half-pixel offset texture of surface elevations: */
758 renderPixelCornerElevations(viewport, projectionModelview, contextData, dataItem);
759 } else if(dataItem->contourLineFramebufferObject != 0) {
760 /* Delete the contour line rendering frame buffer: */
761 glDeleteFramebuffersEXT(1, &dataItem->contourLineFramebufferObject);
762 dataItem->contourLineFramebufferObject = 0;
763 glDeleteRenderbuffersEXT(1, &dataItem->contourLineDepthBufferObject);
764 dataItem->contourLineDepthBufferObject = 0;
765 glDeleteTextures(1, &dataItem->contourLineColorTextureObject);
766 dataItem->contourLineColorTextureObject = 0;
769 /* Check if the single-pass surface shader is outdated: */
770 if(dataItem->surfaceSettingsVersion != surfaceSettingsVersion || (illuminate
771 && dataItem->lightTrackerVersion != contextData.getLightTracker()->getVersion())) {
772 /* Rebuild the shader: */
773 try {
774 GLhandleARB newShader = createSinglePassSurfaceShader(*contextData.getLightTracker(),
775 dataItem->heightMapShaderUniforms);
776 glDeleteObjectARB(dataItem->heightMapShader);
777 dataItem->heightMapShader = newShader;
778 } catch(const std::runtime_error& err) {
779 Misc::formattedUserError("SurfaceRenderer::renderSinglePass: Caught exception %s while rebuilding surface shader",
780 err.what());
783 /* Mark the shader as up-to-date: */
784 dataItem->surfaceSettingsVersion = surfaceSettingsVersion;
785 dataItem->lightTrackerVersion = contextData.getLightTracker()->getVersion();
788 /* Bind the single-pass surface shader: */
789 glUseProgramObjectARB(dataItem->heightMapShader);
790 const GLint* ulPtr = dataItem->heightMapShaderUniforms;
792 /* Bind the current depth image texture: */
793 glActiveTextureARB(GL_TEXTURE0_ARB);
794 depthImageRenderer->bindDepthTexture(contextData);
795 glUniform1iARB(*(ulPtr++), 0);
797 /* Upload the depth projection matrix: */
798 depthImageRenderer->uploadDepthProjection(*(ulPtr++));
800 if(dem != 0) {
801 /* Upload the DEM transformation: */
802 dem->uploadDemTransform(*(ulPtr++));
804 /* Bind the DEM texture: */
805 glActiveTextureARB(GL_TEXTURE1_ARB);
806 dem->bindTexture(contextData);
807 glUniform1iARB(*(ulPtr++), 1);
809 /* Upload the DEM distance scale factor: */
810 glUniform1fARB(*(ulPtr++), 1.0f / (demDistScale * dem->getVerticalScale()));
811 } else if(elevationColorMap != 0) {
812 /* Upload the texture mapping plane equation: */
813 elevationColorMap->uploadTexturePlane(*(ulPtr++));
815 /* Bind the height color map texture: */
816 glActiveTextureARB(GL_TEXTURE1_ARB);
817 elevationColorMap->bindTexture(contextData);
818 glUniform1iARB(*(ulPtr++), 1);
821 if(drawContourLines) {
822 /* Bind the pixel corner elevation texture: */
823 glActiveTextureARB(GL_TEXTURE2_ARB);
824 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->contourLineColorTextureObject);
825 glUniform1iARB(*(ulPtr++), 2);
827 /* Upload the contour line distance factor: */
828 glUniform1fARB(*(ulPtr++), contourLineFactor);
831 if(drawDippingBed) {
832 if(dippingBedFolded) {
833 /* Upload the dipping bed coefficients: */
834 glUniformARB<1>(*(ulPtr++), 5, dippingBedCoeffs);
835 } else {
836 /* Upload the dipping bed plane equation: */
837 GLfloat planeEq[4];
838 for(int i = 0; i < 3; ++i)
839 planeEq[i] = dippingBedPlane.getNormal()[i];
840 planeEq[3] = -dippingBedPlane.getOffset();
841 glUniformARB<4>(*(ulPtr++), 1, planeEq);
844 /* Upload the dipping bed thickness: */
845 glUniform1fARB(*(ulPtr++), dippingBedThickness);
848 if(illuminate) {
849 /* Upload the modelview matrix: */
850 glUniformARB(*(ulPtr++), modelview);
852 /* Calculate and upload the tangent-plane modelview depth projection matrix: */
853 PTransform tangentModelviewDepthProjection = tangentDepthProjection;
854 tangentModelviewDepthProjection *= Geometry::invert(modelview);
855 const Scalar* tmdpPtr = tangentModelviewDepthProjection.getMatrix().getEntries();
856 GLfloat matrix[16];
857 GLfloat* mPtr = matrix;
858 for(int i = 0; i < 16; ++i, ++tmdpPtr, ++mPtr)
859 *mPtr = GLfloat(*tmdpPtr);
860 glUniformMatrix4fvARB(*(ulPtr++), 1, GL_FALSE, matrix);
863 if(waterTable != 0 && dem == 0) {
864 /* Upload the water table texture coordinate matrix: */
865 waterTable->uploadWaterTextureTransform(*(ulPtr++));
867 /* Bind the bathymetry texture: */
868 glActiveTextureARB(GL_TEXTURE3_ARB);
869 waterTable->bindBathymetryTexture(contextData);
870 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
871 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
872 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
873 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
874 glUniform1iARB(*(ulPtr++), 3);
876 /* Bind the quantities texture: */
877 glActiveTextureARB(GL_TEXTURE4_ARB);
878 waterTable->bindQuantityTexture(contextData);
879 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
880 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
881 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
882 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
883 glUniform1iARB(*(ulPtr++), 4);
885 /* Upload the water grid cell size for normal vector calculation: */
886 glUniformARB<2>(*(ulPtr++), 1, waterTable->getCellSize());
888 /* Upload the water opacity factor: */
889 glUniform1fARB(*(ulPtr++), waterOpacity);
891 /* Upload the water animation time: */
892 glUniform1fARB(*(ulPtr++), GLfloat(animationTime));
895 /* Upload the combined projection, modelview, and depth unprojection matrix: */
896 PTransform projectionModelviewDepthProjection = projectionModelview;
897 projectionModelviewDepthProjection *= depthImageRenderer->getDepthProjection();
898 glUniformARB(*(ulPtr++), projectionModelviewDepthProjection);
900 /* Draw the surface: */
901 depthImageRenderer->renderSurfaceTemplate(contextData);
903 /* Unbind all textures and buffers: */
904 if(waterTable != 0 && dem == 0) {
905 glActiveTextureARB(GL_TEXTURE4_ARB);
906 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
907 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
908 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
909 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
910 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
911 glActiveTextureARB(GL_TEXTURE3_ARB);
912 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
913 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
914 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
915 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
916 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
918 if(drawContourLines) {
919 glActiveTextureARB(GL_TEXTURE2_ARB);
920 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
922 if(dem != 0) {
923 glActiveTextureARB(GL_TEXTURE1_ARB);
924 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
925 } else if(elevationColorMap != 0) {
926 glActiveTextureARB(GL_TEXTURE1_ARB);
927 glBindTexture(GL_TEXTURE_1D, 0);
929 glActiveTextureARB(GL_TEXTURE0_ARB);
930 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
932 /* Unbind the height map shader: */
933 glUseProgramObjectARB(0);
936 #if 0
938 void SurfaceRenderer::renderGlobalAmbientHeightMap(GLuint heightColorMapTexture,
939 GLContextData& contextData) const {
940 /* Get the data item: */
941 DataItem* dataItem = contextData.retrieveDataItem<DataItem>(this);
943 /* Check if contour line rendering is enabled: */
944 if(drawContourLines) {
945 /* Run the first rendering pass to create a half-pixel offset texture of surface elevations: */
946 glPrepareContourLines(contextData);
947 } else if(dataItem->contourLineFramebufferObject != 0) {
948 /* Delete the contour line rendering frame buffer: */
949 glDeleteFramebuffersEXT(1, &dataItem->contourLineFramebufferObject);
950 dataItem->contourLineFramebufferObject = 0;
951 glDeleteRenderbuffersEXT(1, &dataItem->contourLineDepthBufferObject);
952 dataItem->contourLineDepthBufferObject = 0;
953 glDeleteTextures(1, &dataItem->contourLineColorTextureObject);
954 dataItem->contourLineColorTextureObject = 0;
957 /* Bind the global ambient height map shader: */
958 glUseProgramObjectARB(dataItem->globalAmbientHeightMapShader);
960 /* Bind the vertex and index buffers: */
961 glBindBufferARB(GL_ARRAY_BUFFER_ARB, dataItem->vertexBuffer);
962 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dataItem->indexBuffer);
964 /* Set up the depth image texture: */
965 if(!usePreboundDepthTexture) {
966 glActiveTextureARB(GL_TEXTURE0_ARB);
967 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->depthTexture);
969 /* Check if the texture is outdated: */
970 if(dataItem->depthTextureVersion != depthImageVersion) {
971 /* Upload the new depth texture: */
972 glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, size[0], size[1], GL_LUMINANCE, GL_FLOAT,
973 depthImage.getBuffer());
975 /* Mark the depth texture as current: */
976 dataItem->depthTextureVersion = depthImageVersion;
979 glUniform1iARB(dataItem->globalAmbientHeightMapShaderUniforms[0], 0);
981 /* Upload the depth projection matrix: */
982 glUniformMatrix4fvARB(dataItem->globalAmbientHeightMapShaderUniforms[1], 1, GL_FALSE,
983 depthProjectionMatrix);
985 /* Upload the base plane equation: */
986 glUniformARB<4>(dataItem->globalAmbientHeightMapShaderUniforms[2], 1, basePlaneEq);
988 /* Bind the pixel corner elevation texture: */
989 glActiveTextureARB(GL_TEXTURE1_ARB);
990 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->contourLineColorTextureObject);
991 glUniform1iARB(dataItem->globalAmbientHeightMapShaderUniforms[3], 1);
993 /* Upload the contour line distance factor: */
994 glUniform1fARB(dataItem->globalAmbientHeightMapShaderUniforms[4], contourLineFactor);
996 /* Bind the height color map texture: */
997 glActiveTextureARB(GL_TEXTURE2_ARB);
998 glBindTexture(GL_TEXTURE_1D, heightColorMapTexture);
999 glUniform1iARB(dataItem->globalAmbientHeightMapShaderUniforms[5], 2);
1001 /* Upload the height color map texture coordinate transformation: */
1002 glUniform2fARB(dataItem->globalAmbientHeightMapShaderUniforms[6], heightMapScale, heightMapOffset);
1004 if(waterTable != 0) {
1005 /* Bind the water level texture: */
1006 glActiveTextureARB(GL_TEXTURE3_ARB);
1007 //waterTable->bindWaterLevelTexture(contextData);
1008 glUniform1iARB(dataItem->globalAmbientHeightMapShaderUniforms[7], 3);
1010 /* Upload the water table texture coordinate matrix: */
1011 glUniformMatrix4fvARB(dataItem->globalAmbientHeightMapShaderUniforms[8], 1, GL_FALSE,
1012 waterTable->getWaterTextureMatrix());
1014 /* Upload the water opacity factor: */
1015 glUniform1fARB(dataItem->globalAmbientHeightMapShaderUniforms[9], waterOpacity);
1018 /* Draw the surface: */
1019 typedef GLGeometry::Vertex<void, 0, void, 0, void, float, 3> Vertex;
1020 GLVertexArrayParts::enable(Vertex::getPartsMask());
1021 glVertexPointer(static_cast<const Vertex*>(0));
1022 for(unsigned int y = 1; y < size[1]; ++y)
1023 glDrawElements(GL_QUAD_STRIP, size[0] * 2, GL_UNSIGNED_INT,
1024 static_cast<const GLuint*>(0) + (y - 1)*size[0] * 2);
1025 GLVertexArrayParts::disable(Vertex::getPartsMask());
1027 /* Unbind all textures and buffers: */
1028 if(waterTable != 0) {
1029 glActiveTextureARB(GL_TEXTURE3_ARB);
1030 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
1032 glActiveTextureARB(GL_TEXTURE2_ARB);
1033 glBindTexture(GL_TEXTURE_1D, 0);
1034 glActiveTextureARB(GL_TEXTURE1_ARB);
1035 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
1036 if(!usePreboundDepthTexture) {
1037 glActiveTextureARB(GL_TEXTURE0_ARB);
1038 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
1040 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1041 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1043 /* Unbind the global ambient height map shader: */
1044 glUseProgramObjectARB(0);
1047 void SurfaceRenderer::renderShadowedIlluminatedHeightMap(GLuint heightColorMapTexture,
1048 GLuint shadowTexture, const PTransform& shadowProjection, GLContextData& contextData) const {
1049 /* Get the data item: */
1050 DataItem* dataItem = contextData.retrieveDataItem<DataItem>(this);
1052 /* Bind the shadowed illuminated height map shader: */
1053 glUseProgramObjectARB(dataItem->shadowedIlluminatedHeightMapShader);
1055 /* Bind the vertex and index buffers: */
1056 glBindBufferARB(GL_ARRAY_BUFFER_ARB, dataItem->vertexBuffer);
1057 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dataItem->indexBuffer);
1059 /* Set up the depth image texture: */
1060 if(!usePreboundDepthTexture) {
1061 glActiveTextureARB(GL_TEXTURE0_ARB);
1062 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->depthTexture);
1064 /* Check if the texture is outdated: */
1065 if(dataItem->depthTextureVersion != depthImageVersion) {
1066 /* Upload the new depth texture: */
1067 glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, size[0], size[1], GL_LUMINANCE, GL_FLOAT,
1068 depthImage.getBuffer());
1070 /* Mark the depth texture as current: */
1071 dataItem->depthTextureVersion = depthImageVersion;
1074 glUniform1iARB(dataItem->shadowedIlluminatedHeightMapShaderUniforms[0], 0);
1076 /* Upload the depth projection matrix: */
1077 glUniformMatrix4fvARB(dataItem->shadowedIlluminatedHeightMapShaderUniforms[1], 1, GL_FALSE,
1078 depthProjectionMatrix);
1080 /* Upload the tangent-plane depth projection matrix: */
1081 glUniformMatrix4fvARB(dataItem->shadowedIlluminatedHeightMapShaderUniforms[2], 1, GL_FALSE,
1082 tangentDepthProjectionMatrix);
1084 /* Upload the base plane equation: */
1085 glUniformARB<4>(dataItem->shadowedIlluminatedHeightMapShaderUniforms[3], 1, basePlaneEq);
1087 /* Bind the pixel corner elevation texture: */
1088 glActiveTextureARB(GL_TEXTURE1_ARB);
1089 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->contourLineColorTextureObject);
1090 glUniform1iARB(dataItem->shadowedIlluminatedHeightMapShaderUniforms[4], 1);
1092 /* Upload the contour line distance factor: */
1093 glUniform1fARB(dataItem->shadowedIlluminatedHeightMapShaderUniforms[5], contourLineFactor);
1095 /* Bind the height color map texture: */
1096 glActiveTextureARB(GL_TEXTURE2_ARB);
1097 glBindTexture(GL_TEXTURE_1D, heightColorMapTexture);
1098 glUniform1iARB(dataItem->shadowedIlluminatedHeightMapShaderUniforms[6], 2);
1100 /* Upload the height color map texture coordinate transformation: */
1101 glUniform2fARB(dataItem->shadowedIlluminatedHeightMapShaderUniforms[7], heightMapScale,
1102 heightMapOffset);
1104 if(waterTable != 0) {
1105 /* Bind the water level texture: */
1106 glActiveTextureARB(GL_TEXTURE3_ARB);
1107 //waterTable->bindWaterLevelTexture(contextData);
1108 glUniform1iARB(dataItem->shadowedIlluminatedHeightMapShaderUniforms[8], 3);
1110 /* Upload the water table texture coordinate matrix: */
1111 glUniformMatrix4fvARB(dataItem->shadowedIlluminatedHeightMapShaderUniforms[9], 1, GL_FALSE,
1112 waterTable->getWaterTextureMatrix());
1114 /* Upload the water opacity factor: */
1115 glUniform1fARB(dataItem->shadowedIlluminatedHeightMapShaderUniforms[10], waterOpacity);
1118 /* Bind the shadow texture: */
1119 glActiveTextureARB(GL_TEXTURE4_ARB);
1120 glBindTexture(GL_TEXTURE_2D, shadowTexture);
1121 glUniform1iARB(dataItem->shadowedIlluminatedHeightMapShaderUniforms[11], 4);
1123 /* Upload the combined shadow viewport, shadow projection and modelview, and depth projection matrix: */
1124 PTransform spdp(1.0);
1125 spdp.getMatrix()(0, 0) = 0.5;
1126 spdp.getMatrix()(0, 3) = 0.5;
1127 spdp.getMatrix()(1, 1) = 0.5;
1128 spdp.getMatrix()(1, 3) = 0.5;
1129 spdp.getMatrix()(2, 2) = 0.5;
1130 spdp.getMatrix()(2, 3) = 0.5;
1131 spdp *= shadowProjection;
1132 spdp *= depthProjection;
1133 GLfloat spdpMatrix[16];
1134 GLfloat* spdpPtr = spdpMatrix;
1135 for(int j = 0; j < 4; ++j)
1136 for(int i = 0; i < 4; ++i, ++spdpPtr)
1137 *spdpPtr = GLfloat(spdp.getMatrix()(i, j));
1138 glUniformMatrix4fvARB(dataItem->shadowedIlluminatedHeightMapShaderUniforms[12], 1, GL_FALSE,
1139 spdpMatrix);
1141 /* Draw the surface: */
1142 typedef GLGeometry::Vertex<void, 0, void, 0, void, float, 3> Vertex;
1143 GLVertexArrayParts::enable(Vertex::getPartsMask());
1144 glVertexPointer(static_cast<const Vertex*>(0));
1145 for(unsigned int y = 1; y < size[1]; ++y)
1146 glDrawElements(GL_QUAD_STRIP, size[0] * 2, GL_UNSIGNED_INT,
1147 static_cast<const GLuint*>(0) + (y - 1)*size[0] * 2);
1148 GLVertexArrayParts::disable(Vertex::getPartsMask());
1150 /* Unbind all textures and buffers: */
1151 if(waterTable != 0) {
1152 glActiveTextureARB(GL_TEXTURE3_ARB);
1153 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
1155 glActiveTextureARB(GL_TEXTURE2_ARB);
1156 glBindTexture(GL_TEXTURE_1D, 0);
1157 glActiveTextureARB(GL_TEXTURE1_ARB);
1158 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
1159 if(!usePreboundDepthTexture) {
1160 glActiveTextureARB(GL_TEXTURE0_ARB);
1161 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
1163 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1164 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1166 /* Unbind the shadowed illuminated height map shader: */
1167 glUseProgramObjectARB(0);
1170 #endif