Merge from development branch heightmap to main.
[scorched3d.git] / src / client / water / Water2Renderer.cpp
blobb830d5e84c653bff2b2d0343479a7fee1a6f0d6f
1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2004
3 //
4 // This file is part of Scorched3D.
5 //
6 // Scorched3D is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
11 // Scorched3D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with Scorched3D; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 ////////////////////////////////////////////////////////////////////////////////
21 #include <water/Water2Renderer.h>
22 #include <water/Water2.h>
23 #include <water/WaterMapPoints.h>
24 #include <water/WaterWaves.h>
25 #include <common/Vector4.h>
26 #include <image/ImageFactory.h>
27 #include <image/ImageFactory.h>
28 #include <GLEXT/GLStateExtension.h>
29 #include <GLEXT/GLCamera.h>
30 #include <GLEXT/GLTextureCubeMap.h>
31 #include <client/ScorchedClient.h>
32 #include <sky/Sky.h>
33 #include <land/VisibilityPatchGrid.h>
34 #include <landscapemap/LandscapeMaps.h>
35 #include <landscapedef/LandscapeTex.h>
36 #include <landscapedef/LandscapeDefn.h>
37 #include <landscape/Landscape.h>
38 #include <graph/MainCamera.h>
39 #include <graph/OptionsDisplay.h>
41 #include <water/Water2Constants.h>
43 Water2Renderer::Water2Renderer() :
44 waterShader_(0),
45 currentPatch_(0), totalTime_(0.0f),
46 noShaderWaterTexture_(0)
50 Water2Renderer::~Water2Renderer()
54 void Water2Renderer::simulate(float frameTime)
56 totalTime_ += frameTime * 24.0f;
59 void Water2Renderer::draw(Water2 &water2, WaterMapPoints &points, WaterWaves &waves)
61 GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "WATER_PATCHSETUP");
62 // Choose correct water frame
63 Water2Patches &currentPatch = water2.getPatch(totalTime_);
64 if (&currentPatch != currentPatch_)
66 currentPatch_ = &currentPatch;
68 // Set the normal map for the current water frame
69 if (GLStateExtension::hasShaders() &&
70 !OptionsDisplay::instance()->getNoWaterMovement() &&
71 !OptionsDisplay::instance()->getSimpleWaterShaders())
73 normalTexture_.replace(currentPatch_->getNormalMap(),
74 GLStateExtension::hasHardwareMipmaps());
77 GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "WATER_PATCHSETUP");
79 // Draw waves
80 GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "WATER_WAVES");
81 waves.draw(*currentPatch_);
82 GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "WATER_WAVES");
84 // Draw Water
85 if (GLStateExtension::hasShaders() &&
86 OptionsDisplay::instance()->getUseWaterTexture())
88 drawWaterShaders(water2);
90 else
92 drawWaterNoShaders(water2);
95 GAMESTATE_PERF_COUNTER_START(ScorchedClient::instance()->getGameState(), "WATER_DRAWPOINTS");
96 drawPoints(points);
97 GAMESTATE_PERF_COUNTER_END(ScorchedClient::instance()->getGameState(), "WATER_DRAWPOINTS");
100 void Water2Renderer::drawPoints(WaterMapPoints &points)
102 if (!currentPatch_) return;
104 // Draw Points
105 points.draw(*currentPatch_);
108 void Water2Renderer::drawWaterShaders(Water2 &water2)
110 GLState state(GLState::LIGHTING_OFF | GLState::TEXTURE_ON | GLState::BLEND_ON);
112 glPushAttrib(GL_ALL_ATTRIB_BITS);
114 Vector cameraPos = GLCamera::getCurrentCamera()->getCurrentPos();
115 cameraPos[2] = -waterHeight_;
116 waterShader_->use();
117 waterShader_->set_uniform("viewpos", cameraPos);
119 // Tex 3
120 if (!OptionsDisplay::instance()->getSimpleWaterShaders())
122 waterShader_->set_gl_texture(currentPatch_->getAOF(), "tex_foamamount", 3);
125 // Tex 2
126 if (Landscape::instance()->getShadowFrameBuffer().bufferValid())
128 glActiveTextureARB(GL_TEXTURE2_ARB);
129 glEnable(GL_TEXTURE_2D);
130 waterShader_->set_gl_texture(Landscape::instance()->getShadowFrameBuffer(),
131 "tex_shadow", 2);
132 glMatrixMode(GL_TEXTURE);
133 glLoadMatrixf(Landscape::instance()->getShadowTextureMatrix());
134 glMatrixMode(GL_MODELVIEW);
137 // texture units / coordinates:
138 // tex0: noise map (color normals) / matching texcoords
139 // tex1: reflection map / matching texcoords
140 // tex2: foam
141 // tex3: amount of foam
143 // set up scale/translation of foam and noise maps
144 // we do not use the texture matrix here, as this would be overkill
145 // and would be clumsy
147 // need to divide by noise tile size here too (tex coordinates are in [0...1], not meters)
148 Vector D_0 = windDir1_ * (windSpeed1_ / (-64.0f * 6.0f)); // noise tile is 256/8=32m long
149 Vector D_1 = windDir2_ * (windSpeed2_ / (-16.0f * 6.0f)); // noise tile is 256/32=8m long
151 float mytime = totalTime_ / 24.0f;
152 Vector noise_0_pos = D_0 * mytime;
153 Vector noise_1_pos = D_1 * mytime;
154 noise_0_pos[2] = wavetile_length_rcp * 8.0f;
155 noise_1_pos[2] = wavetile_length_rcp * 32.0f;
157 //fixme: do we have to treat the viewer offset here, like with tex matrix
158 // setup below?!
160 // Tex 0
161 glActiveTextureARB(GL_TEXTURE0);
162 if (!OptionsDisplay::instance()->getSimpleWaterShaders())
164 waterShader_->set_uniform("noise_xform_0", noise_0_pos);
165 waterShader_->set_uniform("noise_xform_1", noise_1_pos);
166 waterShader_->set_gl_texture(normalTexture_, "tex_normal", 0);
169 const float noisetilescale = 1.0f/32.0f;//meters (128/16=8, 8tex/m).
170 glMatrixMode(GL_TEXTURE);
171 glLoadIdentity();
172 glScalef(noisetilescale, noisetilescale, 1.0f); // fixme adjust scale
173 glMatrixMode(GL_MODELVIEW);
175 // Tex 1
176 glActiveTextureARB(GL_TEXTURE1);
177 glEnable(GL_TEXTURE_2D);
178 waterShader_->set_gl_texture(reflectionTexture_, "tex_reflection", 1);
180 // Draw Water
181 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
182 drawWater(water2, waterShader_);
184 // Cleanup
185 waterShader_->use_fixed();
187 glActiveTextureARB(GL_TEXTURE2);
188 glMatrixMode(GL_TEXTURE);
189 glLoadIdentity();
190 glMatrixMode(GL_MODELVIEW);
191 glDisable(GL_TEXTURE_2D);
193 glActiveTextureARB(GL_TEXTURE1);
194 glMatrixMode(GL_TEXTURE);
195 glLoadIdentity();
196 glMatrixMode(GL_MODELVIEW);
197 glDisable(GL_TEXTURE_2D);
199 glActiveTextureARB(GL_TEXTURE0);
200 glMatrixMode(GL_TEXTURE);
201 glLoadIdentity();
202 glMatrixMode(GL_MODELVIEW);
204 glPopAttrib();
207 void Water2Renderer::drawWaterNoShaders(Water2 &water2)
209 glPushAttrib(GL_TEXTURE_BIT);
211 // Set up texture coordinate generation for reflections
212 static float PlaneS[] = { 0.0f, 1.0f / 20.0f, 0.0f, 0.0f };
213 static float PlaneT[] = { 1.0f / 20.0f, 0.0f, 0.0f, 0.0f };
215 if (GLStateExtension::hasMultiTex() &&
216 OptionsDisplay::instance()->getUseWaterTexture())
218 // Set up texture coordinate generation for base texture
219 glActiveTextureARB(GL_TEXTURE1);
220 glEnable(GL_TEXTURE_2D);
221 glEnable(GL_TEXTURE_GEN_S);
222 glEnable(GL_TEXTURE_GEN_T);
223 glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
224 glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
225 glTexGenfv(GL_S, GL_OBJECT_PLANE, PlaneS);
226 glTexGenfv(GL_T, GL_OBJECT_PLANE, PlaneT);
227 reflectionTexture_.draw(true);
229 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
230 glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2);
232 glActiveTextureARB(GL_TEXTURE0);
235 glColor4f(0.3f, 0.3f, 0.3f, 0.8f);
237 else
239 glColor4f(0.7f, 0.7f, 0.7f, 0.8f);
242 // Turn lighting on (if enabled)
243 unsigned int state = 0;
244 if (!OptionsDisplay::instance()->getNoModelLighting())
246 state =
247 GLState::LIGHTING_ON |
248 GLState::LIGHT1_ON;
250 Vector4 ambientColor(0.2f, 0.2f, 0.2f, 0.8f);
251 Vector4 diffuseColor(0.8f, 0.8f, 0.8f, 0.8f);
252 Vector4 specularColor(1.0f, 1.0f, 1.0f, 0.8f);
253 Vector4 emissiveColor(0.0f, 0.0f, 0.0f, 0.8f);
254 float shininess = 100.0f;
255 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambientColor);
256 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuseColor);
257 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specularColor);
258 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emissiveColor);
259 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
261 Landscape::instance()->getSky().getSun().setLightPosition();
264 if (!OptionsDisplay::instance()->getUseWaterTexture())
266 GLState currentState(GLState::LIGHTING_OFF | GLState::TEXTURE_OFF);
267 glColor3f(0.0f, 0.3f, 1.0f);
268 drawWater(water2, 0);
270 else if (GLStateExtension::hasCubeMap())
272 GLState currentState(state | GLState::TEXTURE_OFF | GLState::BLEND_ON | GLState::CUBEMAP_ON);
274 // Set up texture coordinate generation for cubemap reflections
275 glEnable(GL_TEXTURE_GEN_S);
276 glEnable(GL_TEXTURE_GEN_T);
277 glEnable(GL_TEXTURE_GEN_R);
278 glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT);
279 glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT);
280 glTexGenf(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT);
282 drawWater(water2, 0);
284 else if (GLStateExtension::hasSphereMap())
286 GLState currentState(state | GLState::TEXTURE_ON | GLState::BLEND_ON);
287 noShaderWaterTexture_->draw();
289 // Set up texture coordinate generation for spheremap reflections
290 glEnable(GL_TEXTURE_GEN_S);
291 glEnable(GL_TEXTURE_GEN_T);
292 glEnable(GL_TEXTURE_GEN_R);
293 glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
294 glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
295 glTexGenf(GL_R, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
297 drawWater(water2, 0);
299 else
301 GLState currentState(state | GLState::TEXTURE_ON | GLState::BLEND_ON);
302 noShaderWaterTexture_->draw();
304 // Set up texture coordinate generation for linear reflections
305 glEnable(GL_TEXTURE_GEN_S);
306 glEnable(GL_TEXTURE_GEN_T);
307 glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
308 glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
309 glTexGenfv(GL_S, GL_OBJECT_PLANE, PlaneS);
310 glTexGenfv(GL_T, GL_OBJECT_PLANE, PlaneT);
312 drawWater(water2, 0);
315 if (GLStateExtension::hasMultiTex())
317 glActiveTextureARB(GL_TEXTURE1);
318 glDisable(GL_TEXTURE_GEN_S);
319 glDisable(GL_TEXTURE_GEN_T);
320 glDisable(GL_TEXTURE_GEN_R);
321 glDisable(GL_TEXTURE_2D);
323 glActiveTextureARB(GL_TEXTURE0);
324 glDisable(GL_TEXTURE_GEN_S);
325 glDisable(GL_TEXTURE_GEN_T);
326 glDisable(GL_TEXTURE_GEN_R);
329 glPopAttrib();
332 void Water2Renderer::drawWater(Water2 &water2, GLSLShaderSetup *waterShader)
334 // Draw Water
335 Vector &cameraPos = GLCamera::getCurrentCamera()->getCurrentPos();
336 VisibilityPatchGrid::instance()->drawWater(
337 *currentPatch_, water2.getIndexs(), cameraPos, landscapeSize_, waterShader);
340 void Water2Renderer::generate(LandscapeTexBorderWater *water, ProgressCounter *counter)
342 currentPatch_ = 0;
343 if (GLStateExtension::hasShaders())
345 // Load shaders
346 if (!waterShader_)
348 GLSLShader::defines_list dl;
349 if (Landscape::instance()->getShadowFrameBuffer().bufferValid())
351 dl.push_back("USE_SHADOWS");
354 if (OptionsDisplay::instance()->getSimpleWaterShaders())
356 waterShader_ = new GLSLShaderSetup(
357 S3D::getDataFile("data/shaders/watersimple.vshader"),
358 S3D::getDataFile("data/shaders/watersimple.fshader"),
359 dl);
361 else
363 waterShader_ = new GLSLShaderSetup(
364 S3D::getDataFile("data/shaders/water.vshader"),
365 S3D::getDataFile("data/shaders/water.fshader"),
366 dl);
371 // Set the water height
372 waterHeight_ = water->height.asFloat();
374 // fixme: color depends also on weather. bad weather -> light is less bright
375 // so this will be computed implicitly. Environment can also change water color
376 // (light blue in tropic waters), water depth also important etc.
377 // this depends on sky color...
378 // good weather
379 // color wavetop = color(color(10, 10, 10), color(18, 93, 77), light_brightness);
380 // color wavebottom = color(color(10, 10, 20), color(18, 73, 107), light_brightness);
381 // rather bad weather
382 //fixme: multiply with light color here, not only light brightness.
383 //dim yellow light should result in dim yellow-green upwelling color, not dim green.
384 Vector4 light_color(water->wavelight, 1.0f);
385 Vector4 wavetopA(water->wavetopa, 0.0f);
386 Vector4 wavetopB(water->wavetopb, 0.0f);
387 Vector4 wavebottomA(water->wavebottoma, 0.0f);
388 Vector4 wavebottomB(water->wavebottomb, 0.0f);
389 Vector4 wavetop = light_color.lerp(wavetopA, wavetopB);
390 Vector4 wavebottom = light_color.lerp(wavebottomA, wavebottomB);
392 // Create textures
393 if (GLStateExtension::hasFBO() &&
394 GLStateExtension::hasShaders() &&
395 !OptionsDisplay::instance()->getNoWaterReflections())
397 reflectionTexture_.createBufferTexture(512, 512, false);
398 reflectionBuffer_.create(reflectionTexture_, true);
400 else
402 ImageHandle loadedBitmapWater =
403 ImageFactory::loadImageHandle(S3D::getDataFile(water->texture.c_str()));
404 ImageHandle bitmapWater2 = loadedBitmapWater.createResize(128, 128);
405 reflectionTexture_.create(bitmapWater2, true); // Not the reflection in this case
408 ImageHandle map = ImageFactory::createBlank(128, 128, false, 0);
409 normalTexture_.create(map, GLStateExtension::hasHardwareMipmaps());
411 LandscapeDefn &defn = *ScorchedClient::instance()->getLandscapeMaps().
412 getDefinitions().getDefn();
413 landscapeSize_ = Vector(defn.getLandscapeWidth(), defn.getLandscapeHeight());
415 if (GLStateExtension::hasShaders())
417 Vector upwelltop(wavetop[0], wavetop[1], wavetop[2]);
418 Vector upwellbot(wavebottom[0], wavebottom[1], wavebottom[2]);
419 Vector upwelltopbot = upwelltop - upwellbot;
421 waterShader_->use();
422 waterShader_->set_uniform("upwelltop", upwelltop);
423 waterShader_->set_uniform("upwellbot", upwellbot);
424 waterShader_->set_uniform("upwelltopbot", upwelltopbot);
425 if (!OptionsDisplay::instance()->getSimpleWaterShaders())
427 Vector landfoam;
428 waterShader_->set_uniform("landfoam", landfoam);
429 waterShader_->set_uniform("landscape_size", landscapeSize_);
431 waterShader_->use_fixed();
433 else
435 // Load the water reflection bitmap
436 // Create water cubemap texture
437 ImageHandle loadedBitmapWater =
438 ImageFactory::loadImageHandle(S3D::getDataFile(water->reflection.c_str()));
439 ImageHandle bitmapWater2 = loadedBitmapWater.createResize(256, 256);
440 delete noShaderWaterTexture_;
441 if (GLStateExtension::hasCubeMap())
443 GLTextureCubeMap *waterCubeMap = new GLTextureCubeMap();
444 waterCubeMap->create(bitmapWater2, false);
445 noShaderWaterTexture_ = waterCubeMap;
447 else
449 GLTexture *waterNormalMap = new GLTexture();
450 waterNormalMap->create(bitmapWater2, false);
451 noShaderWaterTexture_ = waterNormalMap;
455 // Setup wind dir/speed
456 windSpeed1_ = ScorchedClient::instance()->
457 getOptionsTransient().getWindSpeed().asFloat() * 2.0f + 3.0f;
458 windDir1_ = ScorchedClient::instance()->
459 getOptionsTransient().getWindDirection().asVector();
460 windDir1_[2] = 0.0f;
461 windSpeed2_ = MAX(0.0f, RAND * 2.0f - 1.0f + windSpeed1_);
462 windDir2_ = Vector(windDir1_[0] + RAND * 0.4f - 0.2f,
463 windDir1_[1] + RAND * 0.4f - 0.2f);
464 windDir1_.StoreNormalize();
465 windDir2_.StoreNormalize();