| 1 | /* | 
|---|
| 2 |   orxonox - the future of 3D-vertical-scrollers | 
|---|
| 3 |   | 
|---|
| 4 |   Copyright (C) 2004 orx | 
|---|
| 5 |   | 
|---|
| 6 |   This program 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, or (at your option) | 
|---|
| 9 |   any later version. | 
|---|
| 10 |   | 
|---|
| 11 | ### File Specific: | 
|---|
| 12 |   main-programmer: hdavid, amaechler | 
|---|
| 13 |   | 
|---|
| 14 |   INSPIRED BY http://www.codesampler.com/usersrc/usersrc_6.htm#oglu_sky_dome_shader | 
|---|
| 15 | */ | 
|---|
| 16 |  | 
|---|
| 17 | #include "cloud_effect.h" | 
|---|
| 18 |  | 
|---|
| 19 | #include "util/loading/load_param.h" | 
|---|
| 20 | #include "util/loading/factory.h" | 
|---|
| 21 | #include "util/loading/resource_manager.h" | 
|---|
| 22 |  | 
|---|
| 23 | #include "material.h" | 
|---|
| 24 | #include "state.h" | 
|---|
| 25 | #include "p_node.h" | 
|---|
| 26 | #include "shader.h" | 
|---|
| 27 | #include "shell_command.h" | 
|---|
| 28 |  | 
|---|
| 29 | #include "parser/tinyxml/tinyxml.h" | 
|---|
| 30 |  | 
|---|
| 31 | Vector  CloudEffect::cloudColor; | 
|---|
| 32 | Vector  CloudEffect::skyColor; | 
|---|
| 33 | Vector  CloudEffect::newCloudColor; | 
|---|
| 34 | Vector  CloudEffect::newSkyColor; | 
|---|
| 35 |  | 
|---|
| 36 | using namespace std; | 
|---|
| 37 |  | 
|---|
| 38 | SHELL_COMMAND(activate, CloudEffect, activateCloud); | 
|---|
| 39 | SHELL_COMMAND(deactivate, CloudEffect, deactivateCloud); | 
|---|
| 40 |  | 
|---|
| 41 | CREATE_FACTORY(CloudEffect, CL_CLOUD_EFFECT); | 
|---|
| 42 |  | 
|---|
| 43 | CloudEffect::CloudEffect(const TiXmlElement* root) | 
|---|
| 44 | { | 
|---|
| 45 |   this->setClassID(CL_CLOUD_EFFECT, "CloudEffect"); | 
|---|
| 46 |  | 
|---|
| 47 |   this->init(); | 
|---|
| 48 |  | 
|---|
| 49 |   if (root != NULL) | 
|---|
| 50 |     this->loadParams(root); | 
|---|
| 51 |  | 
|---|
| 52 |   if(cloudActivate) | 
|---|
| 53 |     this->activate(); | 
|---|
| 54 | } | 
|---|
| 55 |  | 
|---|
| 56 | CloudEffect::~CloudEffect() | 
|---|
| 57 | { | 
|---|
| 58 |   this->deactivate(); | 
|---|
| 59 |  | 
|---|
| 60 |   if (glIsTexture(noise3DTexName)) | 
|---|
| 61 |     glDeleteTextures(1, &noise3DTexName); | 
|---|
| 62 |  | 
|---|
| 63 |   delete shader; | 
|---|
| 64 | } | 
|---|
| 65 |  | 
|---|
| 66 |  | 
|---|
| 67 | void CloudEffect::init() | 
|---|
| 68 | { | 
|---|
| 69 |   PRINTF(0)("Initializing CloudEffect\n"); | 
|---|
| 70 |  | 
|---|
| 71 |   this->offsetZ = 0; | 
|---|
| 72 |   this->animationSpeed = 2; | 
|---|
| 73 |   this->scale = 0.0004f; | 
|---|
| 74 |   this->atmosphericRadius = 4000; | 
|---|
| 75 |   this->planetRadius = 1500; | 
|---|
| 76 |   this->divs = 50; | 
|---|
| 77 |  | 
|---|
| 78 |   skyColor = Vector(0.0f, 0.0f, 0.8f); | 
|---|
| 79 |   cloudColor = Vector(0.8f, 0.8f, 0.8f); | 
|---|
| 80 |   newSkyColor = skyColor; | 
|---|
| 81 |   newCloudColor = cloudColor; | 
|---|
| 82 |   this->fadeTime = 3; | 
|---|
| 83 |  | 
|---|
| 84 |   this->noise3DTexSize = 128; | 
|---|
| 85 |   this->noise3DTexName = 0; | 
|---|
| 86 |  | 
|---|
| 87 |   this->make3DNoiseTexture(); | 
|---|
| 88 |  | 
|---|
| 89 |   glGenTextures(1, &noise3DTexName); | 
|---|
| 90 |   glBindTexture(GL_TEXTURE_3D, noise3DTexName); | 
|---|
| 91 |  | 
|---|
| 92 |   glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT); | 
|---|
| 93 |   glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT); | 
|---|
| 94 |   glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT); | 
|---|
| 95 |   glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 
|---|
| 96 |   glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 
|---|
| 97 |  | 
|---|
| 98 |   glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, | 
|---|
| 99 |                noise3DTexSize, noise3DTexSize, noise3DTexSize, | 
|---|
| 100 |                0, GL_RGBA, GL_UNSIGNED_BYTE, noise3DTexPtr); | 
|---|
| 101 |  | 
|---|
| 102 |   this->skydome = new Skydome(); | 
|---|
| 103 |   this->skydome->setTexture(noise3DTexName); | 
|---|
| 104 |  | 
|---|
| 105 |   this->shader = new Shader(ResourceManager::getInstance()->getDataDir() + "/shaders/cloud.vert", | 
|---|
| 106 |                             ResourceManager::getInstance()->getDataDir() + "/shaders/cloud.frag"); | 
|---|
| 107 |  | 
|---|
| 108 |   this->shader->activateShader(); | 
|---|
| 109 |  | 
|---|
| 110 |   Shader::Uniform(shader, "Noise").set(0); | 
|---|
| 111 |  | 
|---|
| 112 |   this->offset = new Shader::Uniform(shader, "Offset"); | 
|---|
| 113 |   this->skycolor = new Shader::Uniform(shader, "SkyColor"); | 
|---|
| 114 |   this->cloudcolor = new Shader::Uniform(shader, "CloudColor"); | 
|---|
| 115 |  | 
|---|
| 116 |   this->shader->deactivateShader(); | 
|---|
| 117 |  | 
|---|
| 118 |   this->skydome->setShader(shader); | 
|---|
| 119 | } | 
|---|
| 120 |  | 
|---|
| 121 |  | 
|---|
| 122 | void CloudEffect::loadParams(const TiXmlElement* root) | 
|---|
| 123 | { | 
|---|
| 124 |   WeatherEffect::loadParams(root); | 
|---|
| 125 |  | 
|---|
| 126 |   LoadParam(root, "speed", this, CloudEffect, setAnimationSpeed); | 
|---|
| 127 |   LoadParam(root, "scale", this, CloudEffect, setCloudScale); | 
|---|
| 128 |   LoadParam(root, "cloudcolor", this, CloudEffect, setCloudColor); | 
|---|
| 129 |   LoadParam(root, "skycolor", this, CloudEffect, setSkyColor); | 
|---|
| 130 |  | 
|---|
| 131 |   LoadParam(root, "planetRadius", this, CloudEffect, setPlanetRadius); | 
|---|
| 132 |   LoadParam(root, "atmosphericRadius", this, CloudEffect, setAtmosphericRadius); | 
|---|
| 133 |   LoadParam(root, "divisions", this, CloudEffect, setDivisions); | 
|---|
| 134 |  | 
|---|
| 135 |   LOAD_PARAM_START_CYCLE(root, element); | 
|---|
| 136 |   { | 
|---|
| 137 |     LoadParam_CYCLE(element, "option", this, CloudEffect, setCloudOption); | 
|---|
| 138 |   } | 
|---|
| 139 |   LOAD_PARAM_END_CYCLE(element); | 
|---|
| 140 | } | 
|---|
| 141 |  | 
|---|
| 142 |  | 
|---|
| 143 | void CloudEffect::activate() | 
|---|
| 144 | { | 
|---|
| 145 |   PRINTF(0)( "Activating\n"); | 
|---|
| 146 |  | 
|---|
| 147 |   // Can only be set after the loadParams call | 
|---|
| 148 |   this->shader->activateShader(); | 
|---|
| 149 |   Shader::Uniform(shader, "Scale").set(this->scale); | 
|---|
| 150 |   this->skycolor->set(skyColor.x, skyColor.y, skyColor.z); | 
|---|
| 151 |   this->cloudcolor->set(cloudColor.x, cloudColor.y, cloudColor.z); | 
|---|
| 152 |   this->shader->deactivateShader(); | 
|---|
| 153 |  | 
|---|
| 154 |   this->skydome->generateSkyPlane(this->divs, this->planetRadius, this->atmosphericRadius, 1, 1); | 
|---|
| 155 |  | 
|---|
| 156 |   this->cloudActivate = true; | 
|---|
| 157 | } | 
|---|
| 158 |  | 
|---|
| 159 | void CloudEffect::deactivate() | 
|---|
| 160 | { | 
|---|
| 161 |   PRINTF(0)("Deactivating CloudEffect\n"); | 
|---|
| 162 |  | 
|---|
| 163 |   this->cloudActivate = false; | 
|---|
| 164 | } | 
|---|
| 165 |  | 
|---|
| 166 | void CloudEffect::draw() const | 
|---|
| 167 |   {} | 
|---|
| 168 |  | 
|---|
| 169 | void CloudEffect::tick (float dt) | 
|---|
| 170 | { | 
|---|
| 171 |   if (this->cloudActivate) | 
|---|
| 172 |   { | 
|---|
| 173 |     this->offsetZ += 0.05 * dt * this->animationSpeed; | 
|---|
| 174 |  | 
|---|
| 175 |     this->shader->activateShader(); | 
|---|
| 176 |     this->offset->set(0.0f, 0.0f, offsetZ); | 
|---|
| 177 |      | 
|---|
| 178 |     //if(cloudColor != newCloudColor) | 
|---|
| 179 |     //{ | 
|---|
| 180 |       // TODO: fade from cloudColor to newCloudColor | 
|---|
| 181 |       cloudColor = newCloudColor; | 
|---|
| 182 |       this->cloudcolor->set(this->cloudColor.x, this->cloudColor.y, this->cloudColor.z); | 
|---|
| 183 |     //} | 
|---|
| 184 |     //if(cloudColor != newCloudColor) | 
|---|
| 185 |     //{ | 
|---|
| 186 |       // TODO: fade from skyColor to newSkyColor | 
|---|
| 187 |       skyColor = newSkyColor; | 
|---|
| 188 |       this->skycolor->set(this->skyColor.x, this->skyColor.y, this->skyColor.z); | 
|---|
| 189 |     //} | 
|---|
| 190 |      | 
|---|
| 191 |     this->shader->deactivateShader(); | 
|---|
| 192 |   } | 
|---|
| 193 | } | 
|---|
| 194 |  | 
|---|
| 195 |  | 
|---|
| 196 | void CloudEffect::changeSkyColor(Vector color) | 
|---|
| 197 | { | 
|---|
| 198 |   newSkyColor = color; | 
|---|
| 199 | } | 
|---|
| 200 |  | 
|---|
| 201 |  | 
|---|
| 202 | void CloudEffect::changeCloudColor(Vector color) | 
|---|
| 203 | { | 
|---|
| 204 |   newCloudColor = color; | 
|---|
| 205 | } | 
|---|
| 206 |  | 
|---|
| 207 |  | 
|---|
| 208 | void CloudEffect::make3DNoiseTexture() | 
|---|
| 209 | { | 
|---|
| 210 |   int f, i, j, k, inc; | 
|---|
| 211 |   int startFrequency = 4; | 
|---|
| 212 |   int numOctaves = 4; | 
|---|
| 213 |   double ni[3]; | 
|---|
| 214 |   double inci, incj, inck; | 
|---|
| 215 |   int frequency = startFrequency; | 
|---|
| 216 |   GLubyte *ptr; | 
|---|
| 217 |   double amp = 0.5; | 
|---|
| 218 |  | 
|---|
| 219 |   if ((noise3DTexPtr = (GLubyte *) malloc(noise3DTexSize * | 
|---|
| 220 |                                           noise3DTexSize * | 
|---|
| 221 |                                           noise3DTexSize * 4)) == NULL) | 
|---|
| 222 |     PRINTF(0)("ERROR: Could not allocate 3D noise texture\n"); | 
|---|
| 223 |  | 
|---|
| 224 |   for (f=0, inc=0; f < numOctaves; | 
|---|
| 225 |        ++f, frequency *= 2, ++inc, amp *= 0.5) | 
|---|
| 226 |   { | 
|---|
| 227 |     SetNoiseFrequency(frequency); | 
|---|
| 228 |     ptr = noise3DTexPtr; | 
|---|
| 229 |     ni[0] = ni[1] = ni[2] = 0; | 
|---|
| 230 |  | 
|---|
| 231 |     inci = 1.0 / (noise3DTexSize / frequency); | 
|---|
| 232 |     for (i=0; i<noise3DTexSize; ++i, ni[0] += inci) | 
|---|
| 233 |     { | 
|---|
| 234 |       incj = 1.0 / (noise3DTexSize / frequency); | 
|---|
| 235 |       for (j=0; j<noise3DTexSize; ++j, ni[1] += incj) | 
|---|
| 236 |       { | 
|---|
| 237 |         inck = 1.0 / (noise3DTexSize / frequency); | 
|---|
| 238 |         for (k=0; k<noise3DTexSize; ++k, ni[2] += inck, ptr+= 4) | 
|---|
| 239 |         { | 
|---|
| 240 |           *(ptr+inc) = (GLubyte) (((noise3(ni)+1.0) * amp)*128.0); | 
|---|
| 241 |         } | 
|---|
| 242 |       } | 
|---|
| 243 |     } | 
|---|
| 244 |   } | 
|---|
| 245 | } | 
|---|
| 246 |  | 
|---|
| 247 | void CloudEffect::initNoise() | 
|---|
| 248 | { | 
|---|
| 249 |   int i, j, k; | 
|---|
| 250 |  | 
|---|
| 251 |   srand(30757); | 
|---|
| 252 |   for (i = 0 ; i < B ; i++) | 
|---|
| 253 |   { | 
|---|
| 254 |     p[i] = i; | 
|---|
| 255 |     g1[i] = (double)((rand() % (B + B)) - B) / B; | 
|---|
| 256 |  | 
|---|
| 257 |     for (j = 0 ; j < 2 ; j++) | 
|---|
| 258 |       g2[i][j] = (double)((rand() % (B + B)) - B) / B; | 
|---|
| 259 |     normalize2(g2[i]); | 
|---|
| 260 |  | 
|---|
| 261 |     for (j = 0 ; j < 3 ; j++) | 
|---|
| 262 |       g3[i][j] = (double)((rand() % (B + B)) - B) / B; | 
|---|
| 263 |     normalize3(g3[i]); | 
|---|
| 264 |   } | 
|---|
| 265 |  | 
|---|
| 266 |   while (--i) | 
|---|
| 267 |   { | 
|---|
| 268 |     k = p[i]; | 
|---|
| 269 |     p[i] = p[j = rand() % B]; | 
|---|
| 270 |     p[j] = k; | 
|---|
| 271 |   } | 
|---|
| 272 |  | 
|---|
| 273 |   for (i = 0 ; i < B + 2 ; i++) | 
|---|
| 274 |   { | 
|---|
| 275 |     p[B + i] = p[i]; | 
|---|
| 276 |     g1[B + i] = g1[i]; | 
|---|
| 277 |     for (j = 0 ; j < 2 ; j++) | 
|---|
| 278 |       g2[B + i][j] = g2[i][j]; | 
|---|
| 279 |     for (j = 0 ; j < 3 ; j++) | 
|---|
| 280 |       g3[B + i][j] = g3[i][j]; | 
|---|
| 281 |   } | 
|---|
| 282 | } | 
|---|
| 283 |  | 
|---|
| 284 | void CloudEffect::SetNoiseFrequency( int frequency) | 
|---|
| 285 | { | 
|---|
| 286 |   start = 1; | 
|---|
| 287 |   B = frequency; | 
|---|
| 288 |   BM = B-1; | 
|---|
| 289 | } | 
|---|
| 290 |  | 
|---|
| 291 | double CloudEffect::noise3( double vec[3]) | 
|---|
| 292 | { | 
|---|
| 293 |   int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; | 
|---|
| 294 |   double rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v; | 
|---|
| 295 |   int i, j; | 
|---|
| 296 |  | 
|---|
| 297 |   if (start) | 
|---|
| 298 |   { | 
|---|
| 299 |     start = 0; | 
|---|
| 300 |     initNoise(); | 
|---|
| 301 |   } | 
|---|
| 302 |  | 
|---|
| 303 |   setup(0, bx0,bx1, rx0,rx1); | 
|---|
| 304 |   setup(1, by0,by1, ry0,ry1); | 
|---|
| 305 |   setup(2, bz0,bz1, rz0,rz1); | 
|---|
| 306 |  | 
|---|
| 307 |   i = p[ bx0 ]; | 
|---|
| 308 |   j = p[ bx1 ]; | 
|---|
| 309 |  | 
|---|
| 310 |   b00 = p[ i + by0 ]; | 
|---|
| 311 |   b10 = p[ j + by0 ]; | 
|---|
| 312 |   b01 = p[ i + by1 ]; | 
|---|
| 313 |   b11 = p[ j + by1 ]; | 
|---|
| 314 |  | 
|---|
| 315 |   t  = s_curve(rx0); | 
|---|
| 316 |   sy = s_curve(ry0); | 
|---|
| 317 |   sz = s_curve(rz0); | 
|---|
| 318 |  | 
|---|
| 319 |   q = g3[ b00 + bz0 ] ; u = at3(rx0,ry0,rz0); | 
|---|
| 320 |   q = g3[ b10 + bz0 ] ; v = at3(rx1,ry0,rz0); | 
|---|
| 321 |   a = lerp(t, u, v); | 
|---|
| 322 |  | 
|---|
| 323 |   q = g3[ b01 + bz0 ] ; u = at3(rx0,ry1,rz0); | 
|---|
| 324 |   q = g3[ b11 + bz0 ] ; v = at3(rx1,ry1,rz0); | 
|---|
| 325 |   b = lerp(t, u, v); | 
|---|
| 326 |  | 
|---|
| 327 |   c = lerp(sy, a, b); | 
|---|
| 328 |  | 
|---|
| 329 |   q = g3[ b00 + bz1 ] ; u = at3(rx0,ry0,rz1); | 
|---|
| 330 |   q = g3[ b10 + bz1 ] ; v = at3(rx1,ry0,rz1); | 
|---|
| 331 |   a = lerp(t, u, v); | 
|---|
| 332 |  | 
|---|
| 333 |   q = g3[ b01 + bz1 ] ; u = at3(rx0,ry1,rz1); | 
|---|
| 334 |   q = g3[ b11 + bz1 ] ; v = at3(rx1,ry1,rz1); | 
|---|
| 335 |   b = lerp(t, u, v); | 
|---|
| 336 |  | 
|---|
| 337 |   d = lerp(sy, a, b); | 
|---|
| 338 |  | 
|---|
| 339 |   return lerp(sz, c, d); | 
|---|
| 340 | } | 
|---|
| 341 |  | 
|---|
| 342 | void CloudEffect::normalize2( double v[2]) | 
|---|
| 343 | { | 
|---|
| 344 |   double s; | 
|---|
| 345 |  | 
|---|
| 346 |   s = sqrt(v[0] * v[0] + v[1] * v[1]); | 
|---|
| 347 |   v[0] = v[0] / s; | 
|---|
| 348 |   v[1] = v[1] / s; | 
|---|
| 349 | } | 
|---|
| 350 |  | 
|---|
| 351 | void CloudEffect::normalize3( double v[3]) | 
|---|
| 352 | { | 
|---|
| 353 |   double s; | 
|---|
| 354 |  | 
|---|
| 355 |   s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); | 
|---|
| 356 |   v[0] = v[0] / s; | 
|---|
| 357 |   v[1] = v[1] / s; | 
|---|
| 358 |   v[2] = v[2] / s; | 
|---|
| 359 | } | 
|---|
| 360 |  | 
|---|