/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: hdavid, amaechler INSPIRED BY http://www.codesampler.com/usersrc/usersrc_6.htm#oglu_sky_dome_shader */ #include "cloud_effect.h" #include "util/loading/load_param.h" #include "util/loading/factory.h" #include "util/loading/resource_manager.h" #include "material.h" #include "state.h" #include "p_node.h" #include "shader.h" #include "shell_command.h" #include "t_animation.h" #include "script_class.h" #include "parser/tinyxml/tinyxml.h" Vector CloudEffect::cloudColor; Vector CloudEffect::skyColor; Vector CloudEffect::newCloudColor; Vector CloudEffect::newSkyColor; bool CloudEffect::fadeSky; bool CloudEffect::fadeCloud; float CloudEffect::fadeTime; bool CloudEffect::flashSkyActivate; float CloudEffect::localTimer; float CloudEffect::flashTime; using namespace std; SHELL_COMMAND(activate, CloudEffect, activateCloud); SHELL_COMMAND(deactivate, CloudEffect, deactivateCloud); SHELL_COMMAND(skyColor, CloudEffect, shellSkyColor); SHELL_COMMAND(cloudColor, CloudEffect, shellCloudColor); CREATE_SCRIPTABLE_CLASS(CloudEffect, CL_CLOUD_EFFECT, addMethod("skyColor", ExecutorLua4(&CloudEffect::shellSkyColor)) ->addMethod("cloudColor", ExecutorLua4(&CloudEffect::shellCloudColor)) ); CREATE_FACTORY(CloudEffect, CL_CLOUD_EFFECT); CloudEffect::CloudEffect(const TiXmlElement* root) { this->setClassID(CL_CLOUD_EFFECT, "CloudEffect"); this->init(); if (root != NULL) this->loadParams(root); if(cloudActivate) this->activate(); } CloudEffect::~CloudEffect() { this->deactivate(); if (glIsTexture(noise3DTexName)) glDeleteTextures(1, &noise3DTexName); delete shader; } void CloudEffect::init() { PRINTF(0)("Initializing CloudEffect\n"); // default values this->offsetZ = 0; this->animationSpeed = 2; this->scale = 0.0004f; this->atmosphericRadius = 4000; this->planetRadius = 1500; this->divs = 15; fadeSky = false; fadeCloud = false; flashSkyActivate = false; localTimer = 0; flashTime = 0; skyColor = Vector(0.0f, 0.0f, 0.8f); cloudColor = Vector(0.8f, 0.8f, 0.8f); newSkyColor = skyColor; newCloudColor = cloudColor; this->noise3DTexSize = 128; this->noise3DTexName = 0; this->make3DNoiseTexture(); glGenTextures(1, &noise3DTexName); glBindTexture(GL_TEXTURE_3D, noise3DTexName); glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT); glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, noise3DTexSize, noise3DTexSize, noise3DTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, noise3DTexPtr); this->skydome = new Skydome(); this->skydome->setTexture(noise3DTexName); this->shader = new Shader(ResourceManager::getInstance()->getDataDir() + "/shaders/cloud.vert", ResourceManager::getInstance()->getDataDir() + "/shaders/cloud.frag"); this->shader->activateShader(); Shader::Uniform(shader, "Noise").set(0); this->offset = new Shader::Uniform(shader, "Offset"); this->skycolor = new Shader::Uniform(shader, "SkyColor"); this->cloudcolor = new Shader::Uniform(shader, "CloudColor"); this->shader->deactivateShader(); this->skydome->setShader(shader); } void CloudEffect::loadParams(const TiXmlElement* root) { WeatherEffect::loadParams(root); LoadParam(root, "speed", this, CloudEffect, setAnimationSpeed); LoadParam(root, "scale", this, CloudEffect, setCloudScale); LoadParam(root, "cloudcolor", this, CloudEffect, setCloudColor); LoadParam(root, "skycolor", this, CloudEffect, setSkyColor); LoadParam(root, "planetRadius", this, CloudEffect, setPlanetRadius); LoadParam(root, "atmosphericRadius", this, CloudEffect, setAtmosphericRadius); LoadParam(root, "divisions", this, CloudEffect, setDivisions); LOAD_PARAM_START_CYCLE(root, element); { LoadParam_CYCLE(element, "option", this, CloudEffect, setCloudOption); } LOAD_PARAM_END_CYCLE(element); } void CloudEffect::activate() { PRINTF(0)( "Activating\n"); // Can only be set after the loadParams call this->shader->activateShader(); Shader::Uniform(shader, "Scale").set(this->scale); this->skycolor->set (skyColor.x, skyColor.y, skyColor.z); this->cloudcolor->set (cloudColor.x, cloudColor.y, cloudColor.z); this->shader->deactivateShader(); this->skydome->generateSkyPlane(this->divs, this->planetRadius, this->atmosphericRadius, 1, 1); this->skydome->activate(); this->cloudActivate = true; } void CloudEffect::deactivate() { PRINTF(0)("Deactivating CloudEffect\n"); this->skydome->deactivate(); this->cloudActivate = false; } void CloudEffect::draw() const {} void CloudEffect::tick (float dt) { if (this->cloudActivate) { localTimer += dt; this->offsetZ += 0.05 * dt * this->animationSpeed; this->shader->activateShader(); this->offset->set(0.0f, 0.0f, offsetZ); if (flashSkyActivate) { this->skycolor->set(1, 1, 1); PRINTF(0)("SkyColor set to white\n"); if (localTimer > flashTime) { flashSkyActivate = false; this->skycolor->set(this->skyColor.x, this->skyColor.y, this->skyColor.z); PRINTF(0)("SkyColor reset\n"); } } else { if(cloudColor != newCloudColor) { if(fadeCloud) { this->cloudColorFadeX = new tAnimation(this, &CloudEffect::setColorCloudX); this->cloudColorFadeX->setInfinity(ANIM_INF_CONSTANT); this->cloudColorFadeY = new tAnimation(this, &CloudEffect::setColorCloudY); this->cloudColorFadeY->setInfinity(ANIM_INF_CONSTANT); this->cloudColorFadeZ = new tAnimation(this, &CloudEffect::setColorCloudZ); this->cloudColorFadeZ->setInfinity(ANIM_INF_CONSTANT); this->cloudColorFadeX->addKeyFrame(cloudColor.x, fadeTime, ANIM_LINEAR); this->cloudColorFadeX->addKeyFrame(newCloudColor.x, 0, ANIM_LINEAR); this->cloudColorFadeY->addKeyFrame(cloudColor.y, fadeTime, ANIM_LINEAR); this->cloudColorFadeY->addKeyFrame(newCloudColor.y, 0, ANIM_LINEAR); this->cloudColorFadeZ->addKeyFrame(cloudColor.z, fadeTime, ANIM_LINEAR); this->cloudColorFadeZ->addKeyFrame(newCloudColor.z, 0, ANIM_LINEAR); fadeCloud = false; this->cloudColorFadeX->replay(); this->cloudColorFadeY->replay(); this->cloudColorFadeZ->replay(); } this->cloudcolor->set(this->cloudColor.x, this->cloudColor.y, this->cloudColor.z); } if(skyColor != newSkyColor) { if(fadeSky) { this->skyColorFadeX = new tAnimation(this, &CloudEffect::setColorSkyX); this->skyColorFadeX->setInfinity(ANIM_INF_CONSTANT); this->skyColorFadeY = new tAnimation(this, &CloudEffect::setColorSkyY); this->skyColorFadeY->setInfinity(ANIM_INF_CONSTANT); this->skyColorFadeZ = new tAnimation(this, &CloudEffect::setColorSkyZ); this->skyColorFadeZ->setInfinity(ANIM_INF_CONSTANT); this->skyColorFadeX->addKeyFrame(skyColor.x, fadeTime, ANIM_LINEAR); this->skyColorFadeX->addKeyFrame(newSkyColor.x, 0, ANIM_LINEAR); this->skyColorFadeY->addKeyFrame(skyColor.y, fadeTime, ANIM_LINEAR); this->skyColorFadeY->addKeyFrame(newSkyColor.y, 0, ANIM_LINEAR); this->skyColorFadeZ->addKeyFrame(skyColor.z, fadeTime, ANIM_LINEAR); this->skyColorFadeZ->addKeyFrame(newSkyColor.z, 0, ANIM_LINEAR); fadeSky = false; this->skyColorFadeX->replay(); this->skyColorFadeY->replay(); this->skyColorFadeZ->replay(); } this->skycolor->set(this->skyColor.x, this->skyColor.y, this->skyColor.z); } } this->shader->deactivateShader(); } } void CloudEffect::setColorSkyX(float color) { skyColor.x = color; } void CloudEffect::setColorSkyY(float color) { skyColor.y = color; } void CloudEffect::setColorSkyZ(float color) { skyColor.z = color; } void CloudEffect::setColorCloudX(float color) { cloudColor.x = color; } void CloudEffect::setColorCloudY(float color) { cloudColor.y = color; } void CloudEffect::setColorCloudZ(float color) { cloudColor.z = color; } void CloudEffect::changeSkyColor(Vector color, float time) { newSkyColor = color; fadeSky = true; fadeTime = time; } void CloudEffect::changeCloudColor(Vector color, float time) { newCloudColor = color; fadeCloud = true; fadeTime = time; } void CloudEffect::shellSkyColor(float colorX, float colorY, float colorZ, float time) { changeSkyColor( Vector(colorX, colorY, colorZ), time); } void CloudEffect::shellCloudColor(float colorX, float colorY, float colorZ, float time) { changeCloudColor( Vector(colorX, colorY, colorZ), time); } void CloudEffect::flashSky( float time ) { flashSkyActivate = true; localTimer = 0; flashTime = time; } void CloudEffect::make3DNoiseTexture() { int f, i, j, k, inc; int startFrequency = 4; int numOctaves = 4; double ni[3]; double inci, incj, inck; int frequency = startFrequency; GLubyte *ptr; double amp = 0.5; if ((noise3DTexPtr = (GLubyte *) malloc(noise3DTexSize * noise3DTexSize * noise3DTexSize * 4)) == NULL) PRINTF(0)("ERROR: Could not allocate 3D noise texture\n"); for (f=0, inc=0; f < numOctaves; ++f, frequency *= 2, ++inc, amp *= 0.5) { SetNoiseFrequency(frequency); ptr = noise3DTexPtr; ni[0] = ni[1] = ni[2] = 0; inci = 1.0 / (noise3DTexSize / frequency); for (i=0; i