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"
29 #include <Math/Math.h>
30 #include <Geometry/AffineCombiner.h>
31 #include <Geometry/Vector.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"
49 // #include <iostream>
57 GLfloat
* makeBuffer(int width
, int height
, int numComponents
, ...) {
59 va_start(ap
, numComponents
);
61 for(int i
= 0; i
< numComponents
&& i
< 4; ++i
)
62 fill
[i
] = GLfloat(va_arg(ap
, double));
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
)
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: */
225 glVertex2i(size
[0], 0);
226 glVertex2i(size
[0], size
[1]);
227 glVertex2i(0, size
[1]);
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
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: */
270 glVertex2i(size
[0], 0);
271 glVertex2i(size
[0], size
[1]);
272 glVertex2i(0, size
[1]);
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
);
292 WaterTable2::WaterTable2(GLsizei width
, GLsizei height
, const GLfloat sCellSize
[2])
293 : depthImageRenderer(0),
294 baseTransform(ONTransform::identity
),
296 readBathymetryRequest(0U), readBathymetryBuffer(0), readBathymetryReply(0U) {
297 /* Initialize the water table size and cell size: */
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: */
315 epsilon
= 0.01f
* Math::max(Math::max(cellSize
[0], cellSize
[1]), 1.0f
);
316 attenuation
= 127.0f
/ 128.0f
; // 31.0f/32.0f;
319 /* Initialize the water deposit amount: */
323 WaterTable2::WaterTable2(GLsizei width
, GLsizei height
,
324 const DepthImageRenderer
* sDepthImageRenderer
, const Point basePlaneCorners
[4])
325 : depthImageRenderer(sDepthImageRenderer
),
327 readBathymetryRequest(0U), readBathymetryBuffer(0), readBathymetryReply(0U) {
328 /* Initialize the water table size: */
332 /* Project the corner points to the base plane and calculate their centroid: */
333 const Plane
& basePlane
= depthImageRenderer
->getBasePlane();
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]);
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: */
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
]));
363 // std::cout<<cellSize[0]<<" x "<<cellSize[1]<<std::endl;
365 /* Calculate the water table transformations: */
366 calcTransformations();
368 /* Initialize simulation parameters: */
371 epsilon
= 0.01f
* Math::max(Math::max(cellSize
[0], cellSize
[1]), 1.0f
);
372 attenuation
= 127.0f
/ 128.0f
; // 31.0f/32.0f;
375 /* Initialize the water deposit amount: */
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
,
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
);
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
);
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
,
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
);
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
, ¤tFrameBuffer
);
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
,
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
,
582 dataItem
->derivativeShaderUniformLocations
[1] = glGetUniformLocationARB(dataItem
->derivativeShader
,
584 dataItem
->derivativeShaderUniformLocations
[2] = glGetUniformLocationARB(dataItem
->derivativeShader
,
586 dataItem
->derivativeShaderUniformLocations
[3] = glGetUniformLocationARB(dataItem
->derivativeShader
,
588 dataItem
->derivativeShaderUniformLocations
[4] = glGetUniformLocationARB(dataItem
->derivativeShader
,
589 "bathymetrySampler");
590 dataItem
->derivativeShaderUniformLocations
[5] = glGetUniformLocationARB(dataItem
->derivativeShader
,
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
,
627 dataItem
->eulerStepShaderUniformLocations
[1] = glGetUniformLocationARB(dataItem
->eulerStepShader
,
629 dataItem
->eulerStepShaderUniformLocations
[2] = glGetUniformLocationARB(dataItem
->eulerStepShader
,
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
,
663 dataItem
->waterAddShaderUniformLocations
[1] = glGetUniformLocationARB(dataItem
->waterAddShader
,
665 dataItem
->waterAddShaderUniformLocations
[2] = glGetUniformLocationARB(dataItem
->waterAddShader
,
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
,
680 dataItem
->waterShaderUniformLocations
[2] = glGetUniformLocationARB(dataItem
->waterShader
,
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
);
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
, ¤tFrameBuffer
);
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: */
782 glVertex2i(size
[0], 0);
783 glVertex2i(size
[0], size
[1]);
784 glVertex2i(0, size
[1]);
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]);
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
, ¤tFrameBuffer
);
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: */
845 glVertex2i(size
[0], 0);
846 glVertex2i(size
[0], size
[1]);
847 glVertex2i(0, size
[1]);
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
);
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
, ¤tFrameBuffer
);
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: */
901 glVertex2i(size
[0], 0);
902 glVertex2i(size
[0], size
[1]);
903 glVertex2i(0, size
[1]);
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
);
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
, ¤tFrameBuffer
);
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: */
961 glVertex2i(size
[0], 0);
962 glVertex2i(size
[0], size
[1]);
963 glVertex2i(0, size
[1]);
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: */
999 glVertex2i(size
[0], 0);
1000 glVertex2i(size
[0], size
[1]);
1001 glVertex2i(0, size
[1]);
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
);
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
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: */
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: */
1092 glVertex2i(size
[0], 0);
1093 glVertex2i(size
[0], size
[1]);
1094 glVertex2i(0, size
[1]);
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
);
1114 /* Return the Runge-Kutta step's step size: */
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
;