Add basePlane equation to ContourLineExtractor
[SARndbox.git] / WaterRenderer.cpp
blob014c020ddb437bef7bf1562d2c48f55192abd3f0
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"
25 // DEBUGGING
26 #include <iostream>
28 #include <GL/gl.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),
50 waterShader(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,
116 GL_STATIC_DRAW_ARB);
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,
132 GL_WRITE_ONLY_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);