/* 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 "parser/tinyxml/tinyxml.h" Vector CloudEffect::cloudColor; Vector CloudEffect::skyColor; Vector CloudEffect::newCloudColor; Vector CloudEffect::newSkyColor; using namespace std; SHELL_COMMAND(activate, CloudEffect, activateCloud); SHELL_COMMAND(deactivate, CloudEffect, deactivateCloud); 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"); this->offsetZ = 0; this->animationSpeed = 2; this->scale = 0.0004f; this->atmosphericRadius = 4000; this->planetRadius = 1500; this->divs = 50; skyColor = Vector(0.0f, 0.0f, 0.8f); cloudColor = Vector(0.8f, 0.8f, 0.8f); newSkyColor = skyColor; newCloudColor = cloudColor; this->fadeTime = 3; 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->cloudActivate = true; } void CloudEffect::deactivate() { PRINTF(0)("Deactivating CloudEffect\n"); this->cloudActivate = false; } void CloudEffect::draw() const {} void CloudEffect::tick (float dt) { if (this->cloudActivate) { this->offsetZ += 0.05 * dt * this->animationSpeed; this->shader->activateShader(); this->offset->set(0.0f, 0.0f, offsetZ); //if(cloudColor != newCloudColor) //{ // TODO: fade from cloudColor to newCloudColor cloudColor = newCloudColor; this->cloudcolor->set(this->cloudColor.x, this->cloudColor.y, this->cloudColor.z); //} //if(cloudColor != newCloudColor) //{ // TODO: fade from skyColor to newSkyColor skyColor = newSkyColor; this->skycolor->set(this->skyColor.x, this->skyColor.y, this->skyColor.z); //} this->shader->deactivateShader(); } } void CloudEffect::changeSkyColor(Vector color) { newSkyColor = color; } void CloudEffect::changeCloudColor(Vector color) { newCloudColor = color; } 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