1 /***********************************************************************
2 WaterRenderer - Class to render a water surface defined by regular grids
3 of vertex-centered bathymetry and cell-centered water level values.
4 Copyright (c) 2014 Oliver Kreylos
6 This file is part of the Augmented Reality Sandbox (SARndbox).
8 The Augmented Reality Sandbox is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
13 The Augmented Reality Sandbox is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License along
19 with the Augmented Reality Sandbox; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 ***********************************************************************/
23 #include "WaterRenderer.h"
29 #include <GL/GLVertexArrayParts.h>
30 #include <GL/GLContextData.h>
31 #include <GL/Extensions/GLARBFragmentShader.h>
32 #include <GL/Extensions/GLARBMultitexture.h>
33 #include <GL/Extensions/GLARBShaderObjects.h>
34 #include <GL/Extensions/GLARBTextureFloat.h>
35 #include <GL/Extensions/GLARBTextureRectangle.h>
36 #include <GL/Extensions/GLARBTextureRg.h>
37 #include <GL/Extensions/GLARBVertexBufferObject.h>
38 #include <GL/Extensions/GLARBVertexShader.h>
39 #include <GL/GLTransformationWrappers.h>
41 #include "WaterTable2.h"
42 #include "ShaderHelper.h"
44 /****************************************
45 Methods of class WaterRenderer::DataItem:
46 ****************************************/
48 WaterRenderer::DataItem::DataItem(void)
49 : vertexBuffer(0), indexBuffer(0),
51 /* Initialize all required extensions: */
52 GLARBFragmentShader::initExtension();
53 GLARBMultitexture::initExtension();
54 GLARBShaderObjects::initExtension();
55 GLARBTextureFloat::initExtension();
56 GLARBTextureRectangle::initExtension();
57 GLARBTextureRg::initExtension();
58 GLARBVertexBufferObject::initExtension();
59 GLARBVertexShader::initExtension();
61 /* Allocate the buffers: */
62 glGenBuffersARB(1, &vertexBuffer
);
63 glGenBuffersARB(1, &indexBuffer
);
66 WaterRenderer::DataItem::~DataItem(void) {
67 /* Release all allocated buffers and shaders: */
68 glDeleteBuffersARB(1, &vertexBuffer
);
69 glDeleteBuffersARB(1, &indexBuffer
);
70 glDeleteObjectARB(waterShader
);
73 /******************************
74 Methods of class WaterRenderer:
75 ******************************/
77 WaterRenderer::WaterRenderer(const WaterTable2
* sWaterTable
)
78 : waterTable(sWaterTable
) {
79 /* Copy the water table's grid sizes and grid cell size: */
80 for(int i
= 0; i
< 2; ++i
) {
81 bathymetryGridSize
[i
] = waterTable
->getSize()[i
] - 1;
82 waterGridSize
[i
] = waterTable
->getSize()[i
];
83 cellSize
[i
] = waterTable
->getCellSize()[i
];
86 /* Get the water table's domain: */
87 const WaterTable2::Box
& wd
= waterTable
->getDomain();
89 /* Calculate the transformation from grid space to world space: */
90 gridTransform
= PTransform::identity
;
91 PTransform::Matrix
& gtm
= gridTransform
.getMatrix();
92 gtm(0, 0) = (wd
.max
[0] - wd
.min
[0]) / Scalar(waterGridSize
[0]);
93 gtm(0, 3) = wd
.min
[0];
94 gtm(1, 1) = (wd
.max
[1] - wd
.min
[1]) / Scalar(waterGridSize
[1]);
95 gtm(1, 3) = wd
.min
[1];
96 gridTransform
.leftMultiply(Geometry::invert(waterTable
->getBaseTransform()));
98 /* Calculate the transposed tangent-plane transformation from grid space to world space: */
99 tangentGridTransform
= PTransform::identity
;
100 PTransform::Matrix
& tgtm
= tangentGridTransform
.getMatrix();
101 tgtm(0, 0) = Scalar(waterGridSize
[0]) / (wd
.max
[0] - wd
.min
[0]);
102 tgtm(0, 3) = -wd
.min
[0] * tgtm(0, 0);
103 tgtm(1, 1) = Scalar(waterGridSize
[1]) / (wd
.max
[1] - wd
.min
[1]);
104 tgtm(1, 3) = -wd
.min
[1] * tgtm(1, 1);
105 tangentGridTransform
*= waterTable
->getBaseTransform();
108 void WaterRenderer::initContext(GLContextData
& contextData
) const {
109 /* Create a data item and add it to the context: */
110 DataItem
* dataItem
= new DataItem
;
111 contextData
.addDataItem(this, dataItem
);
113 /* Upload the grid of template vertices into the vertex buffer: */
114 glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dataItem
->vertexBuffer
);
115 glBufferDataARB(GL_ARRAY_BUFFER_ARB
, waterGridSize
[1]*waterGridSize
[0]*sizeof(Vertex
), 0,
117 Vertex
* vPtr
= static_cast<Vertex
*>(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_WRITE_ONLY_ARB
));
118 for(unsigned int y
= 0; y
< waterGridSize
[1]; ++y
)
119 for(unsigned int x
= 0; x
< waterGridSize
[0]; ++x
, ++vPtr
) {
120 /* Set the template vertex' position to the pixel center's position: */
121 vPtr
->position
[0] = GLfloat(x
) + 0.5f
;
122 vPtr
->position
[1] = GLfloat(y
) + 0.5f
;
124 glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
);
125 glBindBufferARB(GL_ARRAY_BUFFER_ARB
, 0);
127 /* Upload the surface's triangle indices into the index buffer: */
128 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, dataItem
->indexBuffer
);
129 glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB
,
130 (waterGridSize
[1] - 1)*waterGridSize
[0] * 2 * sizeof(GLuint
), 0, GL_STATIC_DRAW_ARB
);
131 GLuint
* iPtr
= static_cast<GLuint
*>(glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
,
133 for(unsigned int y
= 1; y
< waterGridSize
[1]; ++y
)
134 for(unsigned int x
= 0; x
< waterGridSize
[0]; ++x
, iPtr
+= 2) {
135 iPtr
[0] = GLuint(y
* waterGridSize
[0] + x
);
136 iPtr
[1] = GLuint((y
- 1) * waterGridSize
[0] + x
);
138 glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
);
139 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
141 /* Create the water rendering shader: */
142 dataItem
->waterShader
= linkVertexAndFragmentShader("WaterRenderingShader");
143 GLint
* ulPtr
= dataItem
->waterShaderUniforms
;
144 *(ulPtr
++) = glGetUniformLocationARB(dataItem
->waterShader
, "quantitySampler");
145 *(ulPtr
++) = glGetUniformLocationARB(dataItem
->waterShader
, "bathymetrySampler");
146 *(ulPtr
++) = glGetUniformLocationARB(dataItem
->waterShader
, "modelviewGridMatrix");
147 *(ulPtr
++) = glGetUniformLocationARB(dataItem
->waterShader
, "tangentModelviewGridMatrix");
148 *(ulPtr
++) = glGetUniformLocationARB(dataItem
->waterShader
, "projectionModelviewGridMatrix");
151 void WaterRenderer::render(const PTransform
& projection
, const OGTransform
& modelview
,
152 GLContextData
& contextData
) const {
153 /* Get the data item: */
154 DataItem
* dataItem
= contextData
.retrieveDataItem
<DataItem
>(this);
156 /* Calculate the required matrices: */
157 PTransform projectionModelview
= projection
;
158 projectionModelview
*= modelview
;
160 /* Bind the water rendering shader: */
161 glUseProgramObjectARB(dataItem
->waterShader
);
162 const GLint
* ulPtr
= dataItem
->waterShaderUniforms
;
164 /* Bind the water quantity texture: */
165 glActiveTextureARB(GL_TEXTURE0_ARB
);
166 waterTable
->bindQuantityTexture(contextData
);
167 glUniform1iARB(*(ulPtr
++), 0);
169 /* Bind the bathymetry texture: */
170 glActiveTextureARB(GL_TEXTURE1_ARB
);
171 waterTable
->bindBathymetryTexture(contextData
);
172 glUniform1iARB(*(ulPtr
++), 1);
174 /* Calculate and upload the vertex transformation from grid space to eye space: */
175 PTransform modelviewGridTransform
= gridTransform
;
176 modelviewGridTransform
.leftMultiply(modelview
);
177 glUniformARB(*(ulPtr
++), modelviewGridTransform
);
179 /* Calculate the transposed tangent plane transformation from grid space to eye space: */
180 PTransform tangentModelviewGridTransform
= tangentGridTransform
;
181 tangentModelviewGridTransform
*= Geometry::invert(modelview
);
183 /* Transpose and upload the transposed tangent plane transformation: */
184 const Scalar
* tmvgtPtr
= tangentModelviewGridTransform
.getMatrix().getEntries();
185 GLfloat tangentModelviewGridTransformMatrix
[16];
186 GLfloat
* tmvgtmPtr
= tangentModelviewGridTransformMatrix
;
187 for(int i
= 0; i
< 16; ++i
, ++tmvgtPtr
, ++tmvgtmPtr
)
188 *tmvgtmPtr
= GLfloat(*tmvgtPtr
);
189 glUniformMatrix4fvARB(*(ulPtr
++), 1, GL_FALSE
, tangentModelviewGridTransformMatrix
);
191 /* Calculate and upload the vertex transformation from grid space to clip space: */
192 PTransform projectionModelviewGridTransform
= gridTransform
;
193 projectionModelviewGridTransform
.leftMultiply(modelview
);
194 projectionModelviewGridTransform
.leftMultiply(projection
);
195 glUniformARB(*(ulPtr
++), projectionModelviewGridTransform
);
197 /* Bind the vertex and index buffers: */
198 glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dataItem
->vertexBuffer
);
199 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, dataItem
->indexBuffer
);
201 /* Draw the surface: */
202 GLVertexArrayParts::enable(Vertex::getPartsMask());
203 glVertexPointer(static_cast<const Vertex
*>(0));
204 GLuint
* indexPtr
= 0;
205 for(unsigned int y
= 1; y
< waterGridSize
[1]; ++y
, indexPtr
+= waterGridSize
[0] * 2)
206 glDrawElements(GL_QUAD_STRIP
, waterGridSize
[0] * 2, GL_UNSIGNED_INT
, indexPtr
);
207 GLVertexArrayParts::disable(Vertex::getPartsMask());
209 /* Unbind all textures and buffers: */
210 glBindBufferARB(GL_ARRAY_BUFFER_ARB
, 0);
211 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
212 glBindTexture(GL_TEXTURE_RECTANGLE_ARB
, 0);
213 glActiveTextureARB(GL_TEXTURE0_ARB
);
214 glBindTexture(GL_TEXTURE_RECTANGLE_ARB
, 0);
216 /* Unbind the water rendering shader: */
217 glUseProgramObjectARB(0);