Add ContourLineExtractor to Sandbox
[SARndbox.git] / WaterTable2.cpp
blob43df8281c680a570ca0a908b8245b0197e8e0449
1 /***********************************************************************
2 WaterTable2 - Class to simulate water flowing over a surface using
3 improved water flow simulation based on Saint-Venant system of partial
4 differenctial equations.
5 Copyright (c) 2012-2016 Oliver Kreylos
7 This file is part of the Augmented Reality Sandbox (SARndbox).
9 The Augmented Reality Sandbox is free software; you can redistribute it
10 and/or modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version.
14 The Augmented Reality Sandbox is distributed in the hope that it will be
15 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU General Public License along
20 with the Augmented Reality Sandbox; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 ***********************************************************************/
24 #include "WaterTable2.h"
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string>
29 #include <Math/Math.h>
30 #include <Geometry/AffineCombiner.h>
31 #include <Geometry/Vector.h>
32 #include <GL/gl.h>
33 #include <GL/Extensions/GLARBDrawBuffers.h>
34 #include <GL/Extensions/GLARBFragmentShader.h>
35 #include <GL/Extensions/GLARBMultitexture.h>
36 #include <GL/Extensions/GLARBShaderObjects.h>
37 #include <GL/Extensions/GLARBTextureFloat.h>
38 #include <GL/Extensions/GLARBTextureRectangle.h>
39 #include <GL/Extensions/GLARBTextureRg.h>
40 #include <GL/Extensions/GLARBVertexShader.h>
41 #include <GL/Extensions/GLEXTFramebufferObject.h>
42 #include <GL/GLContextData.h>
43 #include <GL/GLTransformationWrappers.h>
45 #include "DepthImageRenderer.h"
46 #include "ShaderHelper.h"
48 // DEBUGGING
49 // #include <iostream>
51 namespace {
53 /****************
54 Helper functions:
55 ****************/
57 GLfloat* makeBuffer(int width, int height, int numComponents, ...) {
58 va_list ap;
59 va_start(ap, numComponents);
60 GLfloat fill[4];
61 for(int i = 0; i < numComponents && i < 4; ++i)
62 fill[i] = GLfloat(va_arg(ap, double));
63 va_end(ap);
65 GLfloat* buffer = new GLfloat[height * width * numComponents];
66 GLfloat* bPtr = buffer;
67 for(int y = 0; y < height; ++y)
68 for(int x = 0; x < width; ++x, bPtr += numComponents)
69 for(int i = 0; i < numComponents; ++i)
70 bPtr[i] = fill[i];
72 return buffer;
77 /**************************************
78 Methods of class WaterTable2::DataItem:
79 **************************************/
81 WaterTable2::DataItem::DataItem(void)
82 : currentBathymetry(0), bathymetryVersion(0), currentQuantity(0),
83 derivativeTextureObject(0), waterTextureObject(0),
84 bathymetryFramebufferObject(0), derivativeFramebufferObject(0), maxStepSizeFramebufferObject(0),
85 integrationFramebufferObject(0), waterFramebufferObject(0),
86 bathymetryShader(0), waterAdaptShader(0), derivativeShader(0), maxStepSizeShader(0),
87 boundaryShader(0), eulerStepShader(0), rungeKuttaStepShader(0), waterAddShader(0), waterShader(0) {
88 for(int i = 0; i < 2; ++i) {
89 bathymetryTextureObjects[i] = 0;
90 maxStepSizeTextureObjects[i] = 0;
92 for(int i = 0; i < 3; ++i)
93 quantityTextureObjects[i] = 0;
95 /* Initialize all required OpenGL extensions: */
96 GLARBDrawBuffers::initExtension();
97 GLARBFragmentShader::initExtension();
98 GLARBMultitexture::initExtension();
99 GLARBShaderObjects::initExtension();
100 GLARBTextureFloat::initExtension();
101 GLARBTextureRectangle::initExtension();
102 GLARBTextureRg::initExtension();
103 GLARBVertexShader::initExtension();
104 GLEXTFramebufferObject::initExtension();
107 WaterTable2::DataItem::~DataItem(void) {
108 /* Delete all allocated shaders, textures, and buffers: */
109 glDeleteTextures(2, bathymetryTextureObjects);
110 glDeleteTextures(3, quantityTextureObjects);
111 glDeleteTextures(1, &derivativeTextureObject);
112 glDeleteTextures(2, maxStepSizeTextureObjects);
113 glDeleteTextures(1, &waterTextureObject);
114 glDeleteFramebuffersEXT(1, &bathymetryFramebufferObject);
115 glDeleteFramebuffersEXT(1, &derivativeFramebufferObject);
116 glDeleteFramebuffersEXT(1, &maxStepSizeFramebufferObject);
117 glDeleteFramebuffersEXT(1, &integrationFramebufferObject);
118 glDeleteFramebuffersEXT(1, &waterFramebufferObject);
119 glDeleteObjectARB(bathymetryShader);
120 glDeleteObjectARB(waterAdaptShader);
121 glDeleteObjectARB(derivativeShader);
122 glDeleteObjectARB(maxStepSizeShader);
123 glDeleteObjectARB(boundaryShader);
124 glDeleteObjectARB(eulerStepShader);
125 glDeleteObjectARB(rungeKuttaStepShader);
126 glDeleteObjectARB(waterAddShader);
127 glDeleteObjectARB(waterShader);
130 /****************************
131 Methods of class WaterTable2:
132 ****************************/
134 void WaterTable2::calcTransformations(void) {
135 /* Calculate the combined modelview and projection matrix to render depth images into the bathymetry grid: */
137 bathymetryPmv = PTransform::identity;
138 PTransform::Matrix& bpmvm = bathymetryPmv.getMatrix();
139 Scalar hw = Math::div2(cellSize[0]);
140 Scalar left = domain.min[0] + hw;
141 Scalar right = domain.max[0] - hw;
142 Scalar hh = Math::div2(cellSize[1]);
143 Scalar bottom = domain.min[1] + hh;
144 Scalar top = domain.max[1] - hh;
145 Scalar near = -domain.max[2];
146 Scalar far = -domain.min[2];
147 bpmvm(0, 0) = Scalar(2) / (right - left);
148 bpmvm(0, 3) = -(right + left) / (right - left);
149 bpmvm(1, 1) = Scalar(2) / (top - bottom);
150 bpmvm(1, 3) = -(top + bottom) / (top - bottom);
151 bpmvm(2, 2) = Scalar(-2) / (far - near);
152 bpmvm(2, 3) = -(far + near) / (far - near);
153 bathymetryPmv *= baseTransform;
156 /* Calculate the combined modelview and projection matrix to render water-adding geometry into the water texture: */
158 waterAddPmv = PTransform::identity;
159 PTransform::Matrix& wapmvm = waterAddPmv.getMatrix();
160 Scalar left = domain.min[0];
161 Scalar right = domain.max[0];
162 Scalar bottom = domain.min[1];
163 Scalar top = domain.max[1];
164 Scalar near = -domain.max[2] * Scalar(5);
165 Scalar far = -domain.min[2];
166 wapmvm(0, 0) = Scalar(2) / (right - left);
167 wapmvm(0, 3) = -(right + left) / (right - left);
168 wapmvm(1, 1) = Scalar(2) / (top - bottom);
169 wapmvm(1, 3) = -(top + bottom) / (top - bottom);
170 wapmvm(2, 2) = Scalar(-2) / (far - near);
171 wapmvm(2, 3) = -(far + near) / (far - near);
172 waterAddPmv *= baseTransform;
175 /* Convert the water addition matrix to column-major OpenGL format: */
176 GLfloat* wapPtr = waterAddPmvMatrix;
177 for(int j = 0; j < 4; ++j)
178 for(int i = 0; i < 4; ++i, ++wapPtr)
179 *wapPtr = GLfloat(waterAddPmv.getMatrix()(i, j));
181 /* Calculate a transformation from camera space into water texture space: */
182 waterTextureTransform = PTransform::identity;
183 PTransform::Matrix& wttm = waterTextureTransform.getMatrix();
184 wttm(0, 0) = Scalar(size[0]) / (domain.max[0] - domain.min[0]);
185 wttm(0, 3) = wttm(0, 0) * -domain.min[0];
186 wttm(1, 1) = Scalar(size[1]) / (domain.max[1] - domain.min[1]);
187 wttm(1, 3) = wttm(1, 1) * -domain.min[1];
188 waterTextureTransform *= baseTransform;
190 /* Convert the water texture transform to column-major OpenGL format: */
191 GLfloat* wttmPtr = waterTextureTransformMatrix;
192 for(int j = 0; j < 4; ++j)
193 for(int i = 0; i < 4; ++i, ++wttmPtr)
194 *wttmPtr = GLfloat(wttm(i, j));
197 GLfloat WaterTable2::calcDerivative(WaterTable2::DataItem* dataItem, GLuint quantityTextureObject,
198 bool calcMaxStepSize) const {
199 /*********************************************************************
200 Step 1: Calculate partial spatial derivatives, partial fluxes across
201 cell boundaries, and the temporal derivative.
202 *********************************************************************/
204 /* Set up the derivative computation frame buffer: */
205 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->derivativeFramebufferObject);
206 glViewport(0, 0, size[0], size[1]);
208 /* Set up the temporal derivative computation shader: */
209 glUseProgramObjectARB(dataItem->derivativeShader);
210 glUniformARB<2>(dataItem->derivativeShaderUniformLocations[0], 1, cellSize);
211 glUniformARB(dataItem->derivativeShaderUniformLocations[1], theta);
212 glUniformARB(dataItem->derivativeShaderUniformLocations[2], g);
213 glUniformARB(dataItem->derivativeShaderUniformLocations[3], epsilon);
214 glActiveTextureARB(GL_TEXTURE0_ARB);
215 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
216 dataItem->bathymetryTextureObjects[dataItem->currentBathymetry]);
217 glUniform1iARB(dataItem->derivativeShaderUniformLocations[4], 0);
218 glActiveTextureARB(GL_TEXTURE1_ARB);
219 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, quantityTextureObject);
220 glUniform1iARB(dataItem->derivativeShaderUniformLocations[5], 1);
222 /* Run the temporal derivative computation: */
223 glBegin(GL_QUADS);
224 glVertex2i(0, 0);
225 glVertex2i(size[0], 0);
226 glVertex2i(size[0], size[1]);
227 glVertex2i(0, size[1]);
228 glEnd();
230 /* Unbind unneeded textures: */
231 glActiveTextureARB(GL_TEXTURE1_ARB);
232 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
234 /*********************************************************************
235 Step 2: Gather the maximum step size by reducing the maximum step size
236 texture.
237 *********************************************************************/
239 GLfloat stepSize = maxStepSize;
241 if(calcMaxStepSize) {
242 /* Set up the maximum step size reduction shader: */
243 glUseProgramObjectARB(dataItem->maxStepSizeShader);
245 /* Bind the maximum step size computation frame buffer: */
246 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->maxStepSizeFramebufferObject);
248 /* Reduce the maximum step size texture in a sequence of half-reduction steps: */
249 int reducedWidth = size[0];
250 int reducedHeight = size[1];
251 int currentMaxStepSizeTexture = 0;
252 while(reducedWidth > 1 || reducedHeight > 1) {
253 /* Set up the simulation frame buffer for maximum step size reduction: */
254 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + (1 - currentMaxStepSizeTexture));
256 /* Reduce the viewport by a factor of two: */
257 glViewport(0, 0, (reducedWidth + 1) / 2, (reducedHeight + 1) / 2);
258 glUniformARB(dataItem->maxStepSizeShaderUniformLocations[0], GLfloat(reducedWidth - 1),
259 GLfloat(reducedHeight - 1));
261 /* Bind the current max step size texture: */
262 glActiveTextureARB(GL_TEXTURE0_ARB);
263 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
264 dataItem->maxStepSizeTextureObjects[currentMaxStepSizeTexture]);
265 glUniform1iARB(dataItem->maxStepSizeShaderUniformLocations[1], 0);
267 /* Run the reduction step: */
268 glBegin(GL_QUADS);
269 glVertex2i(0, 0);
270 glVertex2i(size[0], 0);
271 glVertex2i(size[0], size[1]);
272 glVertex2i(0, size[1]);
273 glEnd();
275 /* Go to the next step: */
276 reducedWidth = (reducedWidth + 1) / 2;
277 reducedHeight = (reducedHeight + 1) / 2;
278 currentMaxStepSizeTexture = 1 - currentMaxStepSizeTexture;
281 /* Read the final value written into the last reduced 1x1 frame buffer: */
282 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + currentMaxStepSizeTexture);
283 glReadPixels(0, 0, 1, 1, GL_LUMINANCE, GL_FLOAT, &stepSize);
285 /* Limit the step size to the client-specified range: */
286 stepSize = Math::min(stepSize, maxStepSize);
289 return stepSize;
292 WaterTable2::WaterTable2(GLsizei width, GLsizei height, const GLfloat sCellSize[2])
293 : depthImageRenderer(0),
294 baseTransform(ONTransform::identity),
295 dryBoundary(true),
296 readBathymetryRequest(0U), readBathymetryBuffer(0), readBathymetryReply(0U) {
297 /* Initialize the water table size and cell size: */
298 size[0] = width;
299 size[1] = height;
300 for(int i = 0; i < 2; ++i)
301 cellSize[i] = sCellSize[i];
303 /* Calculate a simulation domain: */
304 for(int i = 0; i < 2; ++i) {
305 domain.min[i] = Scalar(0);
306 domain.max[i] = Scalar(size[i]) * Scalar(cellSize[i]);
309 /* Calculate the water table transformations: */
310 calcTransformations();
312 /* Initialize simulation parameters: */
313 theta = 1.3f;
314 g = 9.81f;
315 epsilon = 0.01f * Math::max(Math::max(cellSize[0], cellSize[1]), 1.0f);
316 attenuation = 127.0f / 128.0f; // 31.0f/32.0f;
317 maxStepSize = 1.0f;
319 /* Initialize the water deposit amount: */
320 waterDeposit = 0.0f;
323 WaterTable2::WaterTable2(GLsizei width, GLsizei height,
324 const DepthImageRenderer* sDepthImageRenderer, const Point basePlaneCorners[4])
325 : depthImageRenderer(sDepthImageRenderer),
326 dryBoundary(true),
327 readBathymetryRequest(0U), readBathymetryBuffer(0), readBathymetryReply(0U) {
328 /* Initialize the water table size: */
329 size[0] = width;
330 size[1] = height;
332 /* Project the corner points to the base plane and calculate their centroid: */
333 const Plane& basePlane = depthImageRenderer->getBasePlane();
334 Point bpc[4];
335 Point::AffineCombiner centroidC;
336 for(int i = 0; i < 4; ++i) {
337 bpc[i] = basePlane.project(basePlaneCorners[i]);
338 centroidC.addPoint(bpc[i]);
340 Point baseCentroid = centroidC.getPoint();
342 /* Calculate the transformation from camera space to upright elevation model space: */
343 typedef Point::Vector Vector;
344 Vector z = basePlane.getNormal();
345 Vector x = (bpc[1] - bpc[0]) + (bpc[3] - bpc[2]);
346 Vector y = z ^ x;
347 baseTransform = ONTransform::translateFromOriginTo(baseCentroid);
348 baseTransform *= ONTransform::rotate(ONTransform::Rotation::fromBaseVectors(x, y));
349 baseTransform.doInvert();
351 /* Calculate the domain of upright elevation model space: */
352 domain = Box::empty;
353 for(int i = 0; i < 4; ++i)
354 domain.addPoint(baseTransform.transform(bpc[i]));
355 domain.min[2] = Scalar(-20);
356 domain.max[2] = Scalar(100);
358 /* Calculate the grid's cell size: */
359 for(int i = 0; i < 2; ++i)
360 cellSize[i] = GLfloat((domain.max[i] - domain.min[i]) / Scalar(size[i]));
362 // DEBUGGING
363 // std::cout<<cellSize[0]<<" x "<<cellSize[1]<<std::endl;
365 /* Calculate the water table transformations: */
366 calcTransformations();
368 /* Initialize simulation parameters: */
369 theta = 1.3f;
370 g = 9.81f;
371 epsilon = 0.01f * Math::max(Math::max(cellSize[0], cellSize[1]), 1.0f);
372 attenuation = 127.0f / 128.0f; // 31.0f/32.0f;
373 maxStepSize = 1.0f;
375 /* Initialize the water deposit amount: */
376 waterDeposit = 0.0f;
379 WaterTable2::~WaterTable2(void) {
382 void WaterTable2::initContext(GLContextData& contextData) const {
383 /* Create a data item and add it to the context: */
384 DataItem* dataItem = new DataItem;
385 contextData.addDataItem(this, dataItem);
387 glActiveTextureARB(GL_TEXTURE0_ARB);
390 /* Create the vertex-centered bathymetry textures, replacing the outermost layer of cells with ghost cells: */
391 glGenTextures(2, dataItem->bathymetryTextureObjects);
392 GLfloat* b = makeBuffer(size[0] - 1, size[1] - 1, 1, double(domain.min[2]));
393 for(int i = 0; i < 2; ++i) {
394 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->bathymetryTextureObjects[i]);
395 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
396 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
397 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
398 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
399 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_R32F, size[0] - 1, size[1] - 1, 0, GL_LUMINANCE,
400 GL_FLOAT, b);
402 delete[] b;
406 /* Create the cell-centered quantity state textures: */
407 glGenTextures(3, dataItem->quantityTextureObjects);
408 GLfloat* q = makeBuffer(size[0], size[1], 3, double(domain.min[2]), 0.0, 0.0);
409 for(int i = 0; i < 3; ++i) {
410 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->quantityTextureObjects[i]);
411 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
412 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
413 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
414 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
415 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB32F, size[0], size[1], 0, GL_RGB, GL_FLOAT, q);
417 delete[] q;
421 /* Create the cell-centered temporal derivative texture: */
422 glGenTextures(1, &dataItem->derivativeTextureObject);
423 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->derivativeTextureObject);
424 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
425 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
426 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
427 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
428 GLfloat* qt = makeBuffer(size[0], size[1], 3, 0.0, 0.0, 0.0);
429 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB32F, size[0], size[1], 0, GL_RGB, GL_FLOAT, qt);
430 delete[] qt;
434 /* Create the cell-centered maximum step size gathering textures: */
435 glGenTextures(2, dataItem->maxStepSizeTextureObjects);
436 GLfloat* mss = makeBuffer(size[0], size[1], 1, 10000.0);
437 for(int i = 0; i < 2; ++i) {
438 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->maxStepSizeTextureObjects[i]);
439 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
440 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
441 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
442 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
443 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_R32F, size[0], size[1], 0, GL_LUMINANCE, GL_FLOAT,
444 mss);
446 delete[] mss;
450 /* Create the cell-centered water texture: */
451 glGenTextures(1, &dataItem->waterTextureObject);
452 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->waterTextureObject);
453 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
454 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
455 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
456 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
457 GLfloat* w = makeBuffer(size[0], size[1], 1, 0.0);
458 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_R32F, size[0], size[1], 0, GL_LUMINANCE, GL_FLOAT, w);
459 delete[] w;
462 /* Protect the newly-created textures: */
463 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
465 /* Save the currently bound frame buffer: */
466 GLint currentFrameBuffer;
467 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &currentFrameBuffer);
470 /* Create the bathymetry rendering frame buffer: */
471 glGenFramebuffersEXT(1, &dataItem->bathymetryFramebufferObject);
472 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->bathymetryFramebufferObject);
474 /* Attach the bathymetry textures to the bathymetry rendering frame buffer: */
475 for(int i = 0; i < 2; ++i)
476 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i,
477 GL_TEXTURE_RECTANGLE_ARB, dataItem->bathymetryTextureObjects[i], 0);
478 glDrawBuffer(GL_NONE);
479 glReadBuffer(GL_NONE);
483 /* Create the temporal derivative computation frame buffer: */
484 glGenFramebuffersEXT(1, &dataItem->derivativeFramebufferObject);
485 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->derivativeFramebufferObject);
487 /* Attach the derivative and maximum step size textures to the temporal derivative computation frame buffer: */
488 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB,
489 dataItem->derivativeTextureObject, 0);
490 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB,
491 dataItem->maxStepSizeTextureObjects[0], 0);
492 GLenum drawBuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
493 glDrawBuffersARB(2, drawBuffers);
494 glReadBuffer(GL_NONE);
498 /* Create the maximum step size computation frame buffer: */
499 glGenFramebuffersEXT(1, &dataItem->maxStepSizeFramebufferObject);
500 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->maxStepSizeFramebufferObject);
502 /* Attach the maximum step size textures to the maximum step size computation frame buffer: */
503 for(int i = 0; i < 2; ++i)
504 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i,
505 GL_TEXTURE_RECTANGLE_ARB, dataItem->maxStepSizeTextureObjects[i], 0);
506 glDrawBuffer(GL_NONE);
507 glReadBuffer(GL_NONE);
511 /* Create the integration step frame buffer: */
512 glGenFramebuffersEXT(1, &dataItem->integrationFramebufferObject);
513 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->integrationFramebufferObject);
515 /* Attach the quantity textures to the integration step frame buffer: */
516 for(int i = 0; i < 3; ++i)
517 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i,
518 GL_TEXTURE_RECTANGLE_ARB, dataItem->quantityTextureObjects[i], 0);
519 glDrawBuffer(GL_NONE);
520 glReadBuffer(GL_NONE);
524 /* Create the water frame buffer: */
525 glGenFramebuffersEXT(1, &dataItem->waterFramebufferObject);
526 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->waterFramebufferObject);
528 /* Attach the water texture to the water frame buffer: */
529 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB,
530 dataItem->waterTextureObject, 0);
531 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
532 glReadBuffer(GL_NONE);
535 /* Restore the previously bound frame buffer: */
536 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, currentFrameBuffer);
538 /* Create a simple vertex shader to render quads in pixel space: */
539 static const char* vertexShaderSourceTemplate =
540 "void main(){gl_Position=vec4(gl_Vertex.x*%f-1.0,gl_Vertex.y*%f-1.0,0.0,1.0);}";
541 char vertexShaderSource[256];
542 snprintf(vertexShaderSource, sizeof(vertexShaderSource), vertexShaderSourceTemplate,
543 2.0 / double(size[0]), 2.0 / double(size[1]));
545 /* Create the bathymetry update shader: */
547 GLhandleARB vertexShader = glCompileVertexShaderFromString(vertexShaderSource);
548 GLhandleARB fragmentShader = compileFragmentShader("Water2BathymetryUpdateShader");
549 dataItem->bathymetryShader = glLinkShader(vertexShader, fragmentShader);
550 glDeleteObjectARB(vertexShader);
551 glDeleteObjectARB(fragmentShader);
552 dataItem->bathymetryShaderUniformLocations[0] = glGetUniformLocationARB(dataItem->bathymetryShader,
553 "oldBathymetrySampler");
554 dataItem->bathymetryShaderUniformLocations[1] = glGetUniformLocationARB(dataItem->bathymetryShader,
555 "newBathymetrySampler");
556 dataItem->bathymetryShaderUniformLocations[2] = glGetUniformLocationARB(dataItem->bathymetryShader,
557 "quantitySampler");
560 /* Create the water adaptation shader: */
562 GLhandleARB vertexShader = glCompileVertexShaderFromString(vertexShaderSource);
563 GLhandleARB fragmentShader = compileFragmentShader("Water2WaterAdaptShader");
564 dataItem->waterAdaptShader = glLinkShader(vertexShader, fragmentShader);
565 glDeleteObjectARB(vertexShader);
566 glDeleteObjectARB(fragmentShader);
567 dataItem->waterAdaptShaderUniformLocations[0] = glGetUniformLocationARB(dataItem->waterAdaptShader,
568 "bathymetrySampler");
569 dataItem->waterAdaptShaderUniformLocations[1] = glGetUniformLocationARB(dataItem->waterAdaptShader,
570 "newQuantitySampler");
573 /* Create the temporal derivative computation shader: */
575 GLhandleARB vertexShader = glCompileVertexShaderFromString(vertexShaderSource);
576 GLhandleARB fragmentShader = compileFragmentShader("Water2SlopeAndFluxAndDerivativeShader");
577 dataItem->derivativeShader = glLinkShader(vertexShader, fragmentShader);
578 glDeleteObjectARB(vertexShader);
579 glDeleteObjectARB(fragmentShader);
580 dataItem->derivativeShaderUniformLocations[0] = glGetUniformLocationARB(dataItem->derivativeShader,
581 "cellSize");
582 dataItem->derivativeShaderUniformLocations[1] = glGetUniformLocationARB(dataItem->derivativeShader,
583 "theta");
584 dataItem->derivativeShaderUniformLocations[2] = glGetUniformLocationARB(dataItem->derivativeShader,
585 "g");
586 dataItem->derivativeShaderUniformLocations[3] = glGetUniformLocationARB(dataItem->derivativeShader,
587 "epsilon");
588 dataItem->derivativeShaderUniformLocations[4] = glGetUniformLocationARB(dataItem->derivativeShader,
589 "bathymetrySampler");
590 dataItem->derivativeShaderUniformLocations[5] = glGetUniformLocationARB(dataItem->derivativeShader,
591 "quantitySampler");
594 /* Create the maximum step size gathering shader: */
596 GLhandleARB vertexShader = glCompileVertexShaderFromString(vertexShaderSource);
597 GLhandleARB fragmentShader = compileFragmentShader("Water2MaxStepSizeShader");
598 dataItem->maxStepSizeShader = glLinkShader(vertexShader, fragmentShader);
599 glDeleteObjectARB(vertexShader);
600 glDeleteObjectARB(fragmentShader);
601 dataItem->maxStepSizeShaderUniformLocations[0] = glGetUniformLocationARB(
602 dataItem->maxStepSizeShader, "fullTextureSize");
603 dataItem->maxStepSizeShaderUniformLocations[1] = glGetUniformLocationARB(
604 dataItem->maxStepSizeShader, "maxStepSizeSampler");
607 /* Create the boundary condition shader: */
609 GLhandleARB vertexShader = glCompileVertexShaderFromString(vertexShaderSource);
610 GLhandleARB fragmentShader = compileFragmentShader("Water2BoundaryShader");
611 dataItem->boundaryShader = glLinkShader(vertexShader, fragmentShader);
612 glDeleteObjectARB(vertexShader);
613 glDeleteObjectARB(fragmentShader);
614 dataItem->boundaryShaderUniformLocations[0] = glGetUniformLocationARB(dataItem->boundaryShader,
615 "bathymetrySampler");
618 /* Create the Euler integration step shader: */
620 GLhandleARB vertexShader = glCompileVertexShaderFromString(vertexShaderSource);
621 GLhandleARB fragmentShader = compileFragmentShader("Water2EulerStepShader");
622 dataItem->eulerStepShader = glLinkShader(vertexShader, fragmentShader);
623 glDeleteObjectARB(vertexShader);
624 glDeleteObjectARB(fragmentShader);
625 dataItem->eulerStepShaderUniformLocations[0] = glGetUniformLocationARB(dataItem->eulerStepShader,
626 "stepSize");
627 dataItem->eulerStepShaderUniformLocations[1] = glGetUniformLocationARB(dataItem->eulerStepShader,
628 "attenuation");
629 dataItem->eulerStepShaderUniformLocations[2] = glGetUniformLocationARB(dataItem->eulerStepShader,
630 "quantitySampler");
631 dataItem->eulerStepShaderUniformLocations[3] = glGetUniformLocationARB(dataItem->eulerStepShader,
632 "derivativeSampler");
635 /* Create the Runge-Kutta integration step shader: */
637 GLhandleARB vertexShader = glCompileVertexShaderFromString(vertexShaderSource);
638 GLhandleARB fragmentShader = compileFragmentShader("Water2RungeKuttaStepShader");
639 dataItem->rungeKuttaStepShader = glLinkShader(vertexShader, fragmentShader);
640 glDeleteObjectARB(vertexShader);
641 glDeleteObjectARB(fragmentShader);
642 dataItem->rungeKuttaStepShaderUniformLocations[0] = glGetUniformLocationARB(
643 dataItem->rungeKuttaStepShader, "stepSize");
644 dataItem->rungeKuttaStepShaderUniformLocations[1] = glGetUniformLocationARB(
645 dataItem->rungeKuttaStepShader, "attenuation");
646 dataItem->rungeKuttaStepShaderUniformLocations[2] = glGetUniformLocationARB(
647 dataItem->rungeKuttaStepShader, "quantitySampler");
648 dataItem->rungeKuttaStepShaderUniformLocations[3] = glGetUniformLocationARB(
649 dataItem->rungeKuttaStepShader, "quantityStarSampler");
650 dataItem->rungeKuttaStepShaderUniformLocations[4] = glGetUniformLocationARB(
651 dataItem->rungeKuttaStepShader, "derivativeSampler");
654 /* Create the water adder rendering shader: */
656 GLhandleARB vertexShader = compileVertexShader("Water2WaterAddShader");
657 GLhandleARB fragmentShader = compileFragmentShader("Water2WaterAddShader");
658 dataItem->waterAddShader = glLinkShader(vertexShader, fragmentShader);
659 glDeleteObjectARB(vertexShader);
660 glDeleteObjectARB(fragmentShader);
661 dataItem->waterAddShaderUniformLocations[0] = glGetUniformLocationARB(dataItem->waterAddShader,
662 "pmv");
663 dataItem->waterAddShaderUniformLocations[1] = glGetUniformLocationARB(dataItem->waterAddShader,
664 "stepSize");
665 dataItem->waterAddShaderUniformLocations[2] = glGetUniformLocationARB(dataItem->waterAddShader,
666 "waterSampler");
669 /* Create the water shader: */
671 GLhandleARB vertexShader = glCompileVertexShaderFromString(vertexShaderSource);
672 GLhandleARB fragmentShader = compileFragmentShader("Water2WaterUpdateShader");
673 dataItem->waterShader = glLinkShader(vertexShader, fragmentShader);
674 glDeleteObjectARB(vertexShader);
675 glDeleteObjectARB(fragmentShader);
676 dataItem->waterShaderUniformLocations[0] = glGetUniformLocationARB(dataItem->waterShader,
677 "bathymetrySampler");
678 dataItem->waterShaderUniformLocations[1] = glGetUniformLocationARB(dataItem->waterShader,
679 "quantitySampler");
680 dataItem->waterShaderUniformLocations[2] = glGetUniformLocationARB(dataItem->waterShader,
681 "waterSampler");
685 void WaterTable2::setElevationRange(Scalar newMin, Scalar newMax) {
686 /* Set the new elevation range: */
687 domain.min[2] = newMin;
688 domain.max[2] = newMax;
690 /* Recalculate the water table transformations: */
691 calcTransformations();
694 void WaterTable2::setAttenuation(GLfloat newAttenuation) {
695 attenuation = newAttenuation;
698 void WaterTable2::setMaxStepSize(GLfloat newMaxStepSize) {
699 maxStepSize = newMaxStepSize;
702 void WaterTable2::addRenderFunction(const AddWaterFunction* newRenderFunction) {
703 /* Store the new render function: */
704 renderFunctions.push_back(newRenderFunction);
707 void WaterTable2::removeRenderFunction(const AddWaterFunction* removeRenderFunction) {
708 /* Find the given render function in the list and remove it: */
709 for(std::vector<const AddWaterFunction*>::iterator rfIt = renderFunctions.begin();
710 rfIt != renderFunctions.end(); ++rfIt)
711 if(*rfIt == removeRenderFunction) {
712 /* Remove the list element: */
713 renderFunctions.erase(rfIt);
714 break;
718 void WaterTable2::setWaterDeposit(GLfloat newWaterDeposit) {
719 waterDeposit = newWaterDeposit;
722 void WaterTable2::setDryBoundary(bool newDryBoundary) {
723 dryBoundary = newDryBoundary;
726 void WaterTable2::updateBathymetry(GLContextData& contextData) const {
727 /* Get the data item: */
728 DataItem* dataItem = contextData.retrieveDataItem<DataItem>(this);
730 /* Check if the current bathymetry texture is outdated: */
731 if(dataItem->bathymetryVersion != depthImageRenderer->getDepthImageVersion()) {
732 /* Save relevant OpenGL state: */
733 glPushAttrib(GL_VIEWPORT_BIT);
734 GLint currentFrameBuffer;
735 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &currentFrameBuffer);
736 GLfloat currentClearColor[4];
737 glGetFloatv(GL_COLOR_CLEAR_VALUE, currentClearColor);
739 /* Bind the bathymetry rendering frame buffer and clear it: */
740 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->bathymetryFramebufferObject);
741 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + (1 - dataItem->currentBathymetry));
742 glViewport(0, 0, size[0] - 1, size[1] - 1);
743 glClearColor(GLfloat(domain.min[2]), 0.0f, 0.0f, 1.0f);
744 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
746 /* Render the surface into the bathymetry grid: */
747 depthImageRenderer->renderElevation(bathymetryPmv, contextData);
749 /* Set up the integration frame buffer to update the conserved quantities based on bathymetry changes: */
750 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->integrationFramebufferObject);
751 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + (1 - dataItem->currentQuantity));
752 glViewport(0, 0, size[0], size[1]);
754 /* Set up the bathymetry update shader: */
755 glUseProgramObjectARB(dataItem->bathymetryShader);
756 glActiveTextureARB(GL_TEXTURE0_ARB);
757 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
758 dataItem->bathymetryTextureObjects[dataItem->currentBathymetry]);
759 glUniform1iARB(dataItem->bathymetryShaderUniformLocations[0], 0);
760 glActiveTextureARB(GL_TEXTURE1_ARB);
761 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
762 dataItem->bathymetryTextureObjects[1 - dataItem->currentBathymetry]);
763 glUniform1iARB(dataItem->bathymetryShaderUniformLocations[1], 1);
765 /* Check if the current bathymetry grid was requested: */
766 if(readBathymetryReply != readBathymetryRequest) {
767 /* Read back the bathymetry grid into the supplied buffer: */
768 glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RED, GL_FLOAT, readBathymetryBuffer);
770 /* Finish the request: */
771 readBathymetryReply = readBathymetryRequest;
774 glActiveTextureARB(GL_TEXTURE2_ARB);
775 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
776 dataItem->quantityTextureObjects[dataItem->currentQuantity]);
777 glUniform1iARB(dataItem->bathymetryShaderUniformLocations[2], 2);
779 /* Run the bathymetry update: */
780 glBegin(GL_QUADS);
781 glVertex2i(0, 0);
782 glVertex2i(size[0], 0);
783 glVertex2i(size[0], size[1]);
784 glVertex2i(0, size[1]);
785 glEnd();
787 /* Unbind all shaders and textures: */
788 glUseProgramObjectARB(0);
789 glActiveTextureARB(GL_TEXTURE2_ARB);
790 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
791 glActiveTextureARB(GL_TEXTURE1_ARB);
792 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
793 glActiveTextureARB(GL_TEXTURE0_ARB);
794 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
796 /* Restore OpenGL state: */
797 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, currentFrameBuffer);
798 glClearColor(currentClearColor[0], currentClearColor[1], currentClearColor[2],
799 currentClearColor[3]);
800 glPopAttrib();
802 /* Update the bathymetry and quantity grids: */
803 dataItem->currentBathymetry = 1 - dataItem->currentBathymetry;
804 dataItem->bathymetryVersion = depthImageRenderer->getDepthImageVersion();
805 dataItem->currentQuantity = 1 - dataItem->currentQuantity;
809 void WaterTable2::updateBathymetry(const GLfloat* bathymetryGrid,
810 GLContextData& contextData) const {
811 /* Get the data item: */
812 DataItem* dataItem = contextData.retrieveDataItem<DataItem>(this);
814 /* Set up the integration frame buffer to update the conserved quantities based on bathymetry changes: */
815 glPushAttrib(GL_VIEWPORT_BIT);
816 GLint currentFrameBuffer;
817 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &currentFrameBuffer);
818 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->integrationFramebufferObject);
819 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + (1 - dataItem->currentQuantity));
820 glViewport(0, 0, size[0], size[1]);
822 /* Set up the bathymetry update shader: */
823 glUseProgramObjectARB(dataItem->bathymetryShader);
824 glActiveTextureARB(GL_TEXTURE0_ARB);
825 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
826 dataItem->bathymetryTextureObjects[dataItem->currentBathymetry]);
827 glUniform1iARB(dataItem->bathymetryShaderUniformLocations[0], 0);
829 /* Upload the new bathymetry grid: */
830 glActiveTextureARB(GL_TEXTURE1_ARB);
831 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
832 dataItem->bathymetryTextureObjects[1 - dataItem->currentBathymetry]);
833 glUniform1iARB(dataItem->bathymetryShaderUniformLocations[1], 1);
834 glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, size[0] - 1, size[1] - 1, GL_LUMINANCE,
835 GL_FLOAT, bathymetryGrid);
837 glActiveTextureARB(GL_TEXTURE2_ARB);
838 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
839 dataItem->quantityTextureObjects[dataItem->currentQuantity]);
840 glUniform1iARB(dataItem->bathymetryShaderUniformLocations[2], 2);
842 /* Run the bathymetry update: */
843 glBegin(GL_QUADS);
844 glVertex2i(0, 0);
845 glVertex2i(size[0], 0);
846 glVertex2i(size[0], size[1]);
847 glVertex2i(0, size[1]);
848 glEnd();
850 /* Unbind all shaders and textures: */
851 glActiveTextureARB(GL_TEXTURE2_ARB);
852 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
853 glActiveTextureARB(GL_TEXTURE1_ARB);
854 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
855 glActiveTextureARB(GL_TEXTURE0_ARB);
856 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
857 glUseProgramObjectARB(0);
859 /* Restore OpenGL state: */
860 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, currentFrameBuffer);
861 glPopAttrib();
863 /* Update the bathymetry and quantity grids: */
864 dataItem->currentBathymetry = 1 - dataItem->currentBathymetry;
865 dataItem->currentQuantity = 1 - dataItem->currentQuantity;
868 void WaterTable2::setWaterLevel(const GLfloat* waterGrid, GLContextData& contextData) const {
869 /* Get the data item: */
870 DataItem* dataItem = contextData.retrieveDataItem<DataItem>(this);
872 /* Set up the integration frame buffer to adapt the new water level to the current bathymetry: */
873 glPushAttrib(GL_VIEWPORT_BIT);
874 GLint currentFrameBuffer;
875 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &currentFrameBuffer);
876 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->integrationFramebufferObject);
877 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + (1 - dataItem->currentQuantity));
878 glViewport(0, 0, size[0], size[1]);
880 /* Bind the water adaptation shader: */
881 glUseProgramObjectARB(dataItem->waterAdaptShader);
883 /* Bind the current bathymetry texture: */
884 glActiveTextureARB(GL_TEXTURE0_ARB);
885 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
886 dataItem->bathymetryTextureObjects[dataItem->currentBathymetry]);
887 glUniform1iARB(dataItem->waterAdaptShaderUniformLocations[0], 0);
889 /* Bind the current quantity texture: */
890 glActiveTextureARB(GL_TEXTURE1_ARB);
891 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
892 dataItem->quantityTextureObjects[dataItem->currentQuantity]);
893 glUniform1iARB(dataItem->waterAdaptShaderUniformLocations[1], 1);
895 /* Upload the new water level texture: */
896 glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, size[0], size[1], GL_RED, GL_FLOAT, waterGrid);
898 /* Run the water adaptation shader: */
899 glBegin(GL_QUADS);
900 glVertex2i(0, 0);
901 glVertex2i(size[0], 0);
902 glVertex2i(size[0], size[1]);
903 glVertex2i(0, size[1]);
904 glEnd();
906 /* Unbind all shaders and textures: */
907 glActiveTextureARB(GL_TEXTURE1_ARB);
908 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
909 glActiveTextureARB(GL_TEXTURE0_ARB);
910 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
911 glUseProgramObjectARB(0);
913 /* Restore OpenGL state: */
914 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, currentFrameBuffer);
915 glPopAttrib();
917 /* Update the quantity grid: */
918 dataItem->currentQuantity = 1 - dataItem->currentQuantity;
921 GLfloat WaterTable2::runSimulationStep(bool forceStepSize, GLContextData& contextData) const {
922 /* Get the data item: */
923 DataItem* dataItem = contextData.retrieveDataItem<DataItem>(this);
925 /* Save relevant OpenGL state: */
926 glPushAttrib(GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
927 GLint currentFrameBuffer;
928 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &currentFrameBuffer);
930 /*********************************************************************
931 Step 1: Calculate temporal derivative of most recent quantities.
932 *********************************************************************/
934 GLfloat stepSize = calcDerivative(dataItem,
935 dataItem->quantityTextureObjects[dataItem->currentQuantity], !forceStepSize);
937 /*********************************************************************
938 Step 2: Perform the tentative Euler integration step.
939 *********************************************************************/
941 /* Set up the Euler step integration frame buffer: */
942 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->integrationFramebufferObject);
943 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + 2);
944 glViewport(0, 0, size[0], size[1]);
946 /* Set up the Euler integration step shader: */
947 glUseProgramObjectARB(dataItem->eulerStepShader);
948 glUniformARB(dataItem->eulerStepShaderUniformLocations[0], stepSize);
949 glUniformARB(dataItem->eulerStepShaderUniformLocations[1], Math::pow(attenuation, stepSize));
950 glActiveTextureARB(GL_TEXTURE0_ARB);
951 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
952 dataItem->quantityTextureObjects[dataItem->currentQuantity]);
953 glUniform1iARB(dataItem->eulerStepShaderUniformLocations[2], 0);
954 glActiveTextureARB(GL_TEXTURE1_ARB);
955 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->derivativeTextureObject);
956 glUniform1iARB(dataItem->eulerStepShaderUniformLocations[3], 1);
958 /* Run the Euler integration step: */
959 glBegin(GL_QUADS);
960 glVertex2i(0, 0);
961 glVertex2i(size[0], 0);
962 glVertex2i(size[0], size[1]);
963 glVertex2i(0, size[1]);
964 glEnd();
966 /*********************************************************************
967 Step 3: Calculate temporal derivative of intermediate quantities.
968 *********************************************************************/
970 calcDerivative(dataItem, dataItem->quantityTextureObjects[2], false);
972 /*********************************************************************
973 Step 4: Perform the final Runge-Kutta integration step.
974 *********************************************************************/
976 /* Set up the Runge-Kutta step integration frame buffer: */
977 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->integrationFramebufferObject);
978 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + (1 - dataItem->currentQuantity));
979 glViewport(0, 0, size[0], size[1]);
981 /* Set up the Runge-Kutta integration step shader: */
982 glUseProgramObjectARB(dataItem->rungeKuttaStepShader);
983 glUniformARB(dataItem->rungeKuttaStepShaderUniformLocations[0], stepSize);
984 glUniformARB(dataItem->rungeKuttaStepShaderUniformLocations[1], Math::pow(attenuation, stepSize));
985 glActiveTextureARB(GL_TEXTURE0_ARB);
986 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
987 dataItem->quantityTextureObjects[dataItem->currentQuantity]);
988 glUniform1iARB(dataItem->rungeKuttaStepShaderUniformLocations[2], 0);
989 glActiveTextureARB(GL_TEXTURE1_ARB);
990 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->quantityTextureObjects[2]);
991 glUniform1iARB(dataItem->rungeKuttaStepShaderUniformLocations[3], 1);
992 glActiveTextureARB(GL_TEXTURE2_ARB);
993 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->derivativeTextureObject);
994 glUniform1iARB(dataItem->rungeKuttaStepShaderUniformLocations[4], 2);
996 /* Run the Runge-Kutta integration step: */
997 glBegin(GL_QUADS);
998 glVertex2i(0, 0);
999 glVertex2i(size[0], 0);
1000 glVertex2i(size[0], size[1]);
1001 glVertex2i(0, size[1]);
1002 glEnd();
1004 if(dryBoundary) {
1005 /* Set up the boundary condition shader to enforce dry boundaries: */
1006 glUseProgramObjectARB(dataItem->boundaryShader);
1007 glActiveTextureARB(GL_TEXTURE0_ARB);
1008 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
1009 dataItem->bathymetryTextureObjects[dataItem->currentBathymetry]);
1010 glUniform1iARB(dataItem->boundaryShaderUniformLocations[0], 0);
1012 /* Run the boundary condition shader on the outermost layer of pixels: */
1013 //glColorMask(GL_TRUE,GL_FALSE,GL_FALSE,GL_FALSE);
1014 glBegin(GL_LINE_LOOP);
1015 glVertex2f(0.5f, 0.5f);
1016 glVertex2f(GLfloat(size[0]) - 0.5f, 0.5f);
1017 glVertex2f(GLfloat(size[0]) - 0.5f, GLfloat(size[1]) - 0.5f);
1018 glVertex2f(0.5f, GLfloat(size[1]) - 0.5f);
1019 glEnd();
1020 //glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
1023 /* Update the current quantities: */
1024 dataItem->currentQuantity = 1 - dataItem->currentQuantity;
1026 if(waterDeposit != 0.0f || !renderFunctions.empty()) {
1027 /* Save OpenGL state: */
1028 GLfloat currentClearColor[4];
1029 glGetFloatv(GL_COLOR_CLEAR_VALUE, currentClearColor);
1031 /*******************************************************************
1032 Step 5: Render all water sources and sinks additively into the water
1033 texture.
1034 *******************************************************************/
1036 /* Set up and clear the water frame buffer: */
1037 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->waterFramebufferObject);
1038 glViewport(0, 0, size[0], size[1]);
1039 glClearColor(waterDeposit * stepSize, 0.0f, 0.0f, 0.0f);
1040 glClear(GL_COLOR_BUFFER_BIT);
1042 /* Enable additive rendering: */
1043 glEnable(GL_BLEND);
1044 glBlendFunc(GL_ONE, GL_ONE);
1046 /* Set up the water adding shader: */
1047 glUseProgramObjectARB(dataItem->waterAddShader);
1048 glUniformMatrix4fvARB(dataItem->waterAddShaderUniformLocations[0], 1, GL_FALSE, waterAddPmvMatrix);
1049 glUniform1fARB(dataItem->waterAddShaderUniformLocations[1], stepSize);
1051 /* Bind the water texture: */
1052 glActiveTextureARB(GL_TEXTURE0_ARB);
1053 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->waterTextureObject);
1054 glUniform1iARB(dataItem->waterAddShaderUniformLocations[2], 0);
1056 /* Call all render functions: */
1057 for(std::vector<const AddWaterFunction*>::const_iterator rfIt = renderFunctions.begin();
1058 rfIt != renderFunctions.end(); ++rfIt)
1059 (**rfIt)(contextData);
1061 /* Restore OpenGL state: */
1062 glDisable(GL_BLEND);
1063 glClearColor(currentClearColor[0], currentClearColor[1], currentClearColor[2],
1064 currentClearColor[3]);
1066 /*******************************************************************
1067 Step 6: Update the conserved quantities based on the water texture.
1068 *******************************************************************/
1070 /* Set up the integration frame buffer to update the conserved quantities based on the water texture: */
1071 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dataItem->integrationFramebufferObject);
1072 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + (1 - dataItem->currentQuantity));
1073 glViewport(0, 0, size[0], size[1]);
1075 /* Set up the water update shader: */
1076 glUseProgramObjectARB(dataItem->waterShader);
1077 glActiveTextureARB(GL_TEXTURE0_ARB);
1078 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
1079 dataItem->bathymetryTextureObjects[dataItem->currentBathymetry]);
1080 glUniform1iARB(dataItem->waterShaderUniformLocations[0], 0);
1081 glActiveTextureARB(GL_TEXTURE1_ARB);
1082 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
1083 dataItem->quantityTextureObjects[dataItem->currentQuantity]);
1084 glUniform1iARB(dataItem->waterShaderUniformLocations[1], 1);
1085 glActiveTextureARB(GL_TEXTURE2_ARB);
1086 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, dataItem->waterTextureObject);
1087 glUniform1iARB(dataItem->waterShaderUniformLocations[2], 2);
1089 /* Run the water update: */
1090 glBegin(GL_QUADS);
1091 glVertex2i(0, 0);
1092 glVertex2i(size[0], 0);
1093 glVertex2i(size[0], size[1]);
1094 glVertex2i(0, size[1]);
1095 glEnd();
1097 /* Update the current quantities: */
1098 dataItem->currentQuantity = 1 - dataItem->currentQuantity;
1101 /* Unbind all shaders and textures: */
1102 glUseProgramObjectARB(0);
1103 glActiveTextureARB(GL_TEXTURE2_ARB);
1104 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
1105 glActiveTextureARB(GL_TEXTURE1_ARB);
1106 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
1107 glActiveTextureARB(GL_TEXTURE0_ARB);
1108 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
1110 /* Restore OpenGL state: */
1111 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, currentFrameBuffer);
1112 glPopAttrib();
1114 /* Return the Runge-Kutta step's step size: */
1115 return stepSize;
1118 void WaterTable2::bindBathymetryTexture(GLContextData& contextData) const {
1119 /* Get the data item: */
1120 DataItem* dataItem = contextData.retrieveDataItem<DataItem>(this);
1122 /* Bind the bathymetry texture: */
1123 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
1124 dataItem->bathymetryTextureObjects[dataItem->currentBathymetry]);
1127 void WaterTable2::bindQuantityTexture(GLContextData& contextData) const {
1128 /* Get the data item: */
1129 DataItem* dataItem = contextData.retrieveDataItem<DataItem>(this);
1131 /* Bind the conserved quantities texture: */
1132 glBindTexture(GL_TEXTURE_RECTANGLE_ARB,
1133 dataItem->quantityTextureObjects[dataItem->currentQuantity]);
1136 void WaterTable2::uploadWaterTextureTransform(GLint location) const {
1137 /* Upload the matrix to OpenGL: */
1138 glUniformMatrix4fvARB(location, 1, GL_FALSE, waterTextureTransformMatrix);
1141 bool WaterTable2::requestBathymetry(GLfloat* newReadBathymetryBuffer) {
1142 /* Check if the previous bathymetry request has been fulfilled: */
1143 if(readBathymetryReply == readBathymetryRequest) {
1144 /* Set up the new bathymetry request: */
1145 ++readBathymetryRequest;
1146 readBathymetryBuffer = newReadBathymetryBuffer;
1148 return true;
1149 } else
1150 return false;