Waterflow
Visualize water in terrain
|
00001 00002 00003 00004 #include "myDrawable.h" 00005 #include "GL_utilities.h" 00006 00007 #include "Utilities.h" 00008 #include "LoadTGA.h" 00009 00010 #include "gtx/transform.hpp" 00011 #include "gtx/rotate_vector.hpp" 00012 #include "gtc/type_ptr.hpp" 00013 00014 myDrawable::myDrawable(GLuint program) 00015 : program(program) {} 00016 00017 GLuint myDrawable::lightBuffer; 00018 LightParams myDrawable::lightParam[2]; 00019 GLuint myDrawable::texIDs[TOTAL_TEXTURES]; 00020 00021 void myDrawable::setLights() { 00022 // =========== Lights information ========== 00023 00024 // Sun 00025 myDrawable::lightParam[0].position = { 0.58f, 0.58f, 0.58f }; // Since the sun is a directional source, this is the negative direction, not the position. 00026 myDrawable::lightParam[0].isDirectional = 1.0f; 00027 myDrawable::lightParam[0].color = { 1.0f, 1.0f, 1.0f }; 00028 myDrawable::lightParam[0].specularComponent = 50.0f; 00029 00030 // Calculating modified incoming light. 00031 00032 // ---This should NOT be done here when inModel is not a plane. This should at that point be moved to watershader.frag.--- 00033 // However, that is absolutely not trivial, since it requires information 00034 // about the surface fragment where the incident light refracted. If that 00035 // ends up being too complicated, this could be a decent approximation. 00036 float waterRefInd = 1.34451f; 00037 float airRefInd = 1.0f; 00038 glm::vec3 up = glm::vec3(0, 1, 0); 00039 glm::vec3 right = glm::cross(normalize(lightParam[0].position), up); 00040 // Snell's law. 00041 float theta1 = asinf(glm::length(right)); 00042 float theta2 = asinf(airRefInd * sinf(theta1) / waterRefInd); 00043 glm::vec3 waterSunPos = glm::rotate(lightParam[0].position, theta1, right); 00044 waterSunPos = glm::rotate(waterSunPos, -theta2, right); 00045 // ----------------------------------------------------------------------------------------------------------------------- 00046 00047 // Sun under the surface 00048 myDrawable::lightParam[1].position = waterSunPos; 00049 myDrawable::lightParam[1].isDirectional = 1.0f; 00050 myDrawable::lightParam[1].color = { 1.0f, 1.0f, 1.0f }; 00051 myDrawable::lightParam[1].specularComponent = 50.0f; 00052 00053 00054 glGenBuffers(1, &myDrawable::lightBuffer); 00055 00056 glBindBuffer(GL_UNIFORM_BUFFER, myDrawable::lightBuffer); 00057 glBufferData(GL_UNIFORM_BUFFER, sizeof(LightParams)* 2, &myDrawable::lightParam, GL_STATIC_DRAW); 00058 glBindBuffer(GL_UNIFORM_BUFFER, 0); 00059 00060 glBindBufferBase(GL_UNIFORM_BUFFER, 0, myDrawable::lightBuffer); 00061 00062 printError("Create Light"); 00063 } 00064 00065 void myDrawable::setTextures(GLuint* size) { 00066 glGenTextures(5, texIDs); 00067 00068 TextureData tempTex; 00069 memset(&tempTex, 0, sizeof(tempTex)); 00070 00071 // ===== Skybox Texture ===== 00072 00073 glActiveTexture(GL_TEXTURE0 + SKYBOX_TEXUNIT); 00074 glBindTexture(GL_TEXTURE_CUBE_MAP, texIDs[SKYBOX_TEXUNIT]); 00075 00076 GLuint cubeSide[] = { GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, GL_TEXTURE_CUBE_MAP_POSITIVE_Z }; 00077 const char *cubeImage[] = { "resources/Skycube/Xn.tga", "resources/Skycube/Xp.tga", "resources/Skycube/Yn.tga", "resources/Skycube/Yp.tga", "resources/Skycube/Zn.tga", "resources/Skycube/Zp.tga" }; 00078 00079 for (size_t i = 0; i < 6; i++) { 00080 LoadTGATextureData(cubeImage[i], &tempTex); 00081 00082 glTexImage2D(cubeSide[i], 0, GL_RGB, tempTex.width, tempTex.height, 0, GL_RGB, GL_UNSIGNED_BYTE, tempTex.imageData); 00083 } 00084 00085 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 00086 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 00087 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 00088 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 00089 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 00090 00091 // ===== Terrain Data Texture ===== 00092 00093 glActiveTexture(GL_TEXTURE0 + TERRAINDATA_TEXUNIT); 00094 glBindTexture(GL_TEXTURE_2D, texIDs[TERRAINDATA_TEXUNIT]); 00095 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 00096 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 00097 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 00098 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 00099 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, size[0], size[1]); 00100 00101 // ===== Grass/terrain color Texture ===== 00102 glActiveTexture(GL_TEXTURE0 + GRASS_TEXUNIT); 00103 #ifdef _WINDOWS 00104 // Path to the terrain color image file. 00105 std::string terrainColorPath = "resources/terrainColor.jpg"; 00106 sdlTexture* terrainColorTex = new sdlTexture(terrainColorPath, texIDs[GRASS_TEXUNIT]); 00107 if(terrainColorTex->getTexID() == -1) 00108 { 00109 // The texture ID of the sdlTexture will be -1 if the image could not be loaded. 00110 glBindTexture(GL_TEXTURE_2D, texIDs[GRASS_TEXUNIT]); 00111 // Below should be placeholder.tga once someone can convert better than I can. 00112 LoadTGATextureData("resources/grass.tga", &tempTex); 00113 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tempTex.width, tempTex.height, 0, GL_RGB, GL_UNSIGNED_BYTE, tempTex.imageData); 00114 } 00115 #else 00116 glBindTexture(GL_TEXTURE_2D, texIDs[GRASS_TEXUNIT]); 00117 LoadTGATextureData("resources/grass.tga", &tempTex); 00118 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tempTex.width, tempTex.height, 0, GL_RGB, GL_UNSIGNED_BYTE, tempTex.imageData); 00119 #endif 00120 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 00121 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 00122 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 00123 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 00124 00125 // ===== Dotted Texture ===== 00126 00127 glActiveTexture(GL_TEXTURE0 + DOTTED_TEXUNIT); 00128 glBindTexture(GL_TEXTURE_2D, texIDs[DOTTED_TEXUNIT]); 00129 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 00130 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 00131 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 00132 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 00133 LoadTGATextureData("resources/prickig.tga", &tempTex); 00134 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tempTex.width, tempTex.height, 0, GL_RGB, GL_UNSIGNED_BYTE, tempTex.imageData); 00135 00136 // ===== Noise Texture ===== 00137 00138 glActiveTexture(GL_TEXTURE0 + NOISE_TEXUNIT); 00139 glBindTexture(GL_TEXTURE_2D, texIDs[NOISE_TEXUNIT]); 00140 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 00141 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 00142 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 00143 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 00144 LoadTGATextureData("resources/noise.tga", &tempTex); 00145 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tempTex.width, tempTex.height, 0, GL_RGB, GL_UNSIGNED_BYTE, tempTex.imageData); 00146 00147 // ===== Grass Texture ===== 00148 00149 /*glActiveTexture(GL_TEXTURE0 + GRASS_TEXUNIT); 00150 glBindTexture(GL_TEXTURE_2D, texIDs[GRASS_TEXUNIT]); 00151 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 00152 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 00153 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 00154 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 00155 LoadTGATextureData("resources/grass.tga", &tempTex); 00156 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tempTex.width, tempTex.height, 0, GL_RGB, GL_UNSIGNED_BYTE, tempTex.imageData);*/ 00157 00158 // Just set this to not interfere (possible bug to look into) 00159 glActiveTexture(GL_TEXTURE0 + TOTAL_TEXTURES); 00160 00161 printError("Create textures!"); 00162 } 00163 00164 00165 SkyCube::SkyCube(GLuint program) 00166 : myDrawable(program) { 00167 /* Initialize skycube */ 00168 model = generateCube(10.0f); 00169 } 00170 00171 void SkyCube::draw() { 00172 glUniform1i(glGetUniformLocation(program, "cube_texture"), SKYBOX_TEXUNIT); 00173 00174 DrawModel(model, program, "in_Position", NULL, NULL); 00175 } 00176 00177 // ================================================================ 00178 00179 HeightMap::HeightMap(GLuint drawProgram, GLuint* sizes, GLfloat maxHeight, GLuint inputHeightBuffer) 00180 : myDrawable(drawProgram) { 00181 00182 dataWidth = sizes[0]; 00183 dataHeight = sizes[1]; 00184 dataTerrainHeight = maxHeight; 00185 numData = dataWidth * dataHeight; 00186 numIndices = (dataWidth - 1) * (dataHeight - 1) * 2 * 3; 00187 00188 heightBuffer = inputHeightBuffer; 00189 00190 texnum = 0; 00191 00192 initUpdate(); 00193 00194 initDraw(); 00195 } 00196 00197 void HeightMap::initUpdate() { 00198 00199 glGenBuffers(4, drawBuffers); 00200 00201 normalsProgram = compileComputeShader("src/shaders/normals.comp"); 00202 00203 glBindBuffer(GL_SHADER_STORAGE_BUFFER, drawBuffers[3]); // Normals 00204 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat)* 3 * numData, NULL, GL_STATIC_DRAW); 00205 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); 00206 00207 printError("init normals"); 00208 00209 heightMapProgram = compileComputeShader("src/shaders/heightMap.comp"); 00210 00211 glBindBuffer(GL_SHADER_STORAGE_BUFFER, drawBuffers[0]); // Vertex positions 00212 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat)* 3 * numData, NULL, GL_STATIC_DRAW); 00213 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); 00214 00215 glBindBuffer(GL_SHADER_STORAGE_BUFFER, drawBuffers[1]); // Texture coordinates 00216 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat)* 2 * numData, NULL, GL_STATIC_DRAW); 00217 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); 00218 00219 glBindBuffer(GL_SHADER_STORAGE_BUFFER, drawBuffers[2]); // Indices 00220 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLint)* numIndices, NULL, GL_STATIC_DRAW); 00221 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); 00222 00223 printError("init heightmap"); 00224 00225 textureProgram = compileComputeShader("src/shaders/textureData.comp"); 00226 00227 printError("init texturedata"); 00228 } 00229 00230 void HeightMap::initDraw() { 00231 00232 glGenVertexArrays(1, &drawVAO); 00233 00234 glUseProgram(program); 00235 00236 printError("init draw uniforms"); 00237 00238 GLint posAttrib = glGetAttribLocation(program, "in_Position"); 00239 GLint inNormAttrib = glGetAttribLocation(program, "in_Normal"); 00240 GLint inTexAttrib = glGetAttribLocation(program, "in_TexCoord"); 00241 00242 glBindVertexArray(drawVAO); 00243 00244 glBindBuffer(GL_ARRAY_BUFFER, drawBuffers[0]); //vertexBufferID 00245 glEnableVertexAttribArray(posAttrib); 00246 glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)* 3, 0); 00247 00248 printError("init draw1"); 00249 00250 glBindBuffer(GL_ARRAY_BUFFER, drawBuffers[1]); //texBufferID 00251 glEnableVertexAttribArray(inTexAttrib); 00252 glVertexAttribPointer(inTexAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)* 2, 0); 00253 00254 printError("init draw2"); 00255 00256 glBindBuffer(GL_ARRAY_BUFFER, drawBuffers[3]); //normalsBufferID 00257 glEnableVertexAttribArray(inNormAttrib); 00258 glVertexAttribPointer(inNormAttrib, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)* 3, 0); 00259 00260 printError("init draw3"); 00261 00262 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawBuffers[2]);//indicesBufferID 00263 00264 printError("init draw4"); 00265 00266 glBindVertexArray(0); 00267 00268 glBindBuffer(GL_ARRAY_BUFFER, 0); 00269 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 00270 00271 printError("init draw5"); 00272 00273 glUniform1i(glGetUniformLocation(program, "height_texUnit"), TERRAINDATA_TEXUNIT); 00274 glUniform1i(glGetUniformLocation(program, "sky_texUnit"), SKYBOX_TEXUNIT); 00275 glUniform1i(glGetUniformLocation(program, "terr_texUnit"), texnum + TERRAIN_FIRST_TEXUNIT); 00276 glUniform3f(glGetUniformLocation(program, "size"), (float)dataWidth, dataTerrainHeight, (float)dataHeight); 00277 00278 printError("init draw"); 00279 } 00280 00281 void HeightMap::generateHeightTexture() { 00282 00283 glUseProgram(textureProgram); 00284 00285 glBindImageTexture(0, myDrawable::texIDs[TERRAINDATA_TEXUNIT], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); 00286 00287 glUniform2i(glGetUniformLocation(textureProgram, "size"), dataWidth, dataHeight); 00288 glUniform1f(glGetUniformLocation(textureProgram, "maxHeight"), dataTerrainHeight); 00289 00290 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, heightBuffer); 00291 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, drawBuffers[3]); 00292 00293 glDispatchCompute((GLuint)ceil((GLfloat)dataWidth / 16.0f), (GLuint)ceil((GLfloat)dataHeight / 16.0f), 1); 00294 00295 printError("Generate terrain texture data"); 00296 } 00297 00298 void HeightMap::update() { 00299 00300 glUseProgram(normalsProgram); 00301 00302 glUniform2i(glGetUniformLocation(normalsProgram, "size"), dataWidth, dataHeight); 00303 00304 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, heightBuffer); 00305 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, drawBuffers[3]); 00306 00307 glDispatchCompute((GLuint)ceil((GLfloat)dataWidth / 16.0f), (GLuint)ceil((GLfloat)dataHeight / 16.0f), 1); 00308 00309 printError("Update normals"); 00310 00311 glBindBuffersBase(GL_SHADER_STORAGE_BUFFER, 0, 3, drawBuffers); 00312 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, heightBuffer); 00313 00314 glBindImageTexture(0, myDrawable::texIDs[TERRAINDATA_TEXUNIT], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); 00315 00316 glUseProgram(heightMapProgram); 00317 00318 if(dynamic_cast<Water*>(this) != nullptr){ 00319 glUniform1f(glGetUniformLocation(heightMapProgram, "scale"), dataTerrainHeight); 00320 }else{ 00321 glUniform1f(glGetUniformLocation(heightMapProgram, "scale"), -1.0f); 00322 } 00323 00324 00325 glUniform2i(glGetUniformLocation(heightMapProgram, "size"), dataWidth, dataHeight); 00326 glDispatchCompute((GLuint)ceil((GLfloat)dataWidth / 16.0f), (GLuint)ceil((GLfloat)dataHeight / 16.0f), 1); 00327 00328 printError("Update vertices"); 00329 } 00330 00331 void HeightMap::draw() { 00332 glUseProgram(program); 00333 glBindVertexArray(drawVAO); 00334 glUniform1i(glGetUniformLocation(program, "terr_texUnit"), texnum + TERRAIN_FIRST_TEXUNIT); 00335 glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_INT, 0L); 00336 00337 printError("Draw Heightmap"); 00338 } 00339 00340 void TW_CALL HeightMap::SetTextureCB(const void* value, void* clientData) { 00341 static_cast<HeightMap*>(clientData)->texnum = *static_cast<const GLuint*>(value); 00342 } 00343 void TW_CALL HeightMap::GetTextureCB(void* value, void* clientData) { 00344 *static_cast<int*>(value) = static_cast<Water*>(clientData)->texnum; 00345 } 00346 00347 00348 Water::Water(GLuint* drawPrograms, GLuint* sizes, GLfloat maxHeight, GLuint inputHeightBuffer) 00349 : HeightMap(drawPrograms[0], sizes, maxHeight, inputHeightBuffer) { 00350 transparency = 0.7f; 00351 maxDepth = 50.0f; 00352 00353 programToDraw = 0; 00354 programs[0] = drawPrograms[0]; 00355 programs[1] = drawPrograms[1]; 00356 00357 vaos[0] = drawVAO; 00358 00359 glUseProgram(programs[0]); 00360 glUniform1f(glGetUniformLocation(programs[0], "transparency"), transparency); 00361 glUseProgram(programs[1]); 00362 glUniform1f(glGetUniformLocation(programs[1], "maxDepth"), maxDepth); 00363 00364 initDepthProgram(); 00365 } 00366 00367 void Water::initDepthProgram() { 00368 GLuint tempVAO; 00369 glGenVertexArrays(1, &tempVAO); 00370 vaos[1] = tempVAO; 00371 00372 glUseProgram(programs[1]); 00373 00374 printError("init draw uniforms"); 00375 00376 GLint posAttrib = glGetAttribLocation(programs[1], "in_Position"); 00377 GLint inTexAttrib = glGetAttribLocation(programs[1], "in_TexCoord"); 00378 00379 glBindVertexArray(vaos[1]); 00380 00381 glBindBuffer(GL_ARRAY_BUFFER, drawBuffers[0]); //vertexBufferID 00382 glEnableVertexAttribArray(posAttrib); 00383 glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)* 3, 0); 00384 00385 printError("init draw1"); 00386 00387 glBindBuffer(GL_ARRAY_BUFFER, drawBuffers[1]); //texBufferID 00388 glEnableVertexAttribArray(inTexAttrib); 00389 glVertexAttribPointer(inTexAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)* 2, 0); 00390 00391 printError("init draw3"); 00392 00393 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawBuffers[2]);//indicesBufferID 00394 00395 printError("init draw4"); 00396 00397 glBindVertexArray(0); 00398 00399 glBindBuffer(GL_ARRAY_BUFFER, 0); 00400 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 00401 00402 printError("init draw5"); 00403 00404 glUniform1i(glGetUniformLocation(programs[1], "height_texUnit"), TERRAINDATA_TEXUNIT); 00405 glUniform3f(glGetUniformLocation(programs[1], "size"), (float)dataWidth, dataTerrainHeight, (float)dataHeight); 00406 00407 printError("init draw"); 00408 } 00409 00410 00411 void TW_CALL Water::SetTransparencyCB(const void* value, void* clientData) { 00412 Water* obj = static_cast<Water*>(clientData); 00413 obj->transparency = *static_cast<const float*>(value); 00414 glUseProgram(obj->programs[0]); 00415 glUniform1f(glGetUniformLocation(obj->programs[0], "transparency"), obj->transparency); 00416 } 00417 00418 void TW_CALL Water::SetDrawProgramCB(const void* value, void* clientData) { 00419 Water* obj = static_cast<Water*>(clientData); 00420 obj->programToDraw = *static_cast<const int*>(value); 00421 obj->program = obj->programs[obj->programToDraw]; 00422 obj->drawVAO = obj->vaos[obj->programToDraw]; 00423 } 00424 00425 void TW_CALL Water::SetMaxDepthCB(const void* value, void* clientData) { 00426 Water* obj = static_cast<Water*>(clientData); 00427 obj->maxDepth = *static_cast<const float*>(value); 00428 glUseProgram(obj->programs[1]); 00429 glUniform1f(glGetUniformLocation(obj->programs[1], "maxDepth"), obj->maxDepth); 00430 } 00431 00432 00433 void TW_CALL Water::GetTransparencyCB(void* value, void* clientData) { 00434 *static_cast<float*>(value) = static_cast<Water*>(clientData)->transparency; 00435 } 00436 00437 void TW_CALL Water::GetDrawProgramCB(void* value, void* clientData) { 00438 *static_cast<int*>(value) = static_cast<Water*>(clientData)->programToDraw; 00439 } 00440 00441 void TW_CALL Water::GetMaxDepthCB(void* value, void* clientData) { 00442 *static_cast<float*>(value) = static_cast<Water*>(clientData)->maxDepth; 00443 }