2012-06-22 14:31:55 +00:00
|
|
|
// * This file is part of the COLOBOT source code
|
|
|
|
// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
|
|
|
|
// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
|
|
|
|
// *
|
|
|
|
// * 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 3 of the License, or
|
|
|
|
// * (at your option) any later version.
|
|
|
|
// *
|
|
|
|
// * This program is distributed in the hope that it will be useful,
|
|
|
|
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// * GNU General Public License for more details.
|
|
|
|
// *
|
|
|
|
// * You should have received a copy of the GNU General Public License
|
|
|
|
// * along with this program. If not, see http://www.gnu.org/licenses/.
|
|
|
|
|
|
|
|
// cloud.cpp
|
|
|
|
|
2012-07-26 20:26:19 +00:00
|
|
|
#include "graphics/engine/cloud.h"
|
2012-06-22 14:31:55 +00:00
|
|
|
|
2012-08-08 21:51:19 +00:00
|
|
|
#include "common/iman.h"
|
2012-08-12 22:14:42 +00:00
|
|
|
#include "graphics/core/device.h"
|
2012-08-08 21:51:19 +00:00
|
|
|
#include "graphics/engine/engine.h"
|
|
|
|
#include "graphics/engine/terrain.h"
|
|
|
|
#include "math/geometry.h"
|
2012-06-22 14:31:55 +00:00
|
|
|
|
2012-08-08 21:51:19 +00:00
|
|
|
|
|
|
|
const int CLOUD_LINE_PREALLOCATE_COUNT = 100;
|
|
|
|
|
|
|
|
const int DIMEXPAND = 4; // extension of the dimensions
|
|
|
|
|
|
|
|
|
|
|
|
Gfx::CCloud::CCloud(CInstanceManager* iMan, Gfx::CEngine* engine)
|
|
|
|
{
|
|
|
|
m_iMan = iMan;
|
|
|
|
m_iMan->AddInstance(CLASS_CLOUD, this);
|
|
|
|
|
|
|
|
m_engine = engine;
|
|
|
|
m_terrain = nullptr;
|
|
|
|
|
|
|
|
m_level = 0.0f;
|
|
|
|
m_wind = Math::Vector(0.0f, 0.0f, 0.0f);
|
|
|
|
m_subdiv = 8;
|
|
|
|
m_enable = true;
|
|
|
|
|
2012-08-12 17:28:22 +00:00
|
|
|
m_lines.reserve(CLOUD_LINE_PREALLOCATE_COUNT);
|
2012-08-08 21:51:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Gfx::CCloud::~CCloud()
|
|
|
|
{
|
|
|
|
m_iMan = nullptr;
|
|
|
|
m_engine = nullptr;
|
|
|
|
m_terrain = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Gfx::CCloud::EventProcess(const Event &event)
|
|
|
|
{
|
2012-08-09 20:50:04 +00:00
|
|
|
if ( event.type == EVENT_FRAME )
|
|
|
|
return EventFrame(event);
|
2012-08-08 21:51:19 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Gfx::CCloud::EventFrame(const Event &event)
|
|
|
|
{
|
|
|
|
if (m_engine->GetPause()) return true;
|
|
|
|
|
|
|
|
m_time += event.rTime;
|
|
|
|
|
|
|
|
if (m_level == 0.0f) return true;
|
|
|
|
|
|
|
|
if (m_time - m_lastTest < 0.2f) return true;
|
|
|
|
|
2012-08-09 20:50:04 +00:00
|
|
|
m_lastTest = m_time;
|
2012-08-08 21:51:19 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Gfx::CCloud::AdjustLevel(Math::Vector &pos, Math::Vector &eye, float deep,
|
|
|
|
Math::Point &uv1, Math::Point &uv2)
|
|
|
|
{
|
|
|
|
uv1.x = (pos.x+20000.0f)/1280.0f;
|
|
|
|
uv1.y = (pos.z+20000.0f)/1280.0f;
|
|
|
|
uv1.x -= m_time*(m_wind.x/100.0f);
|
|
|
|
uv1.y -= m_time*(m_wind.z/100.0f);
|
|
|
|
|
|
|
|
uv2.x = 0.0f;
|
|
|
|
uv2.y = 0.0f;
|
|
|
|
|
|
|
|
float dist = Math::DistanceProjected(pos, eye);
|
|
|
|
float factor = powf(dist/deep, 2.0f);
|
|
|
|
pos.y -= m_level*factor*10.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Gfx::CCloud::Draw()
|
|
|
|
{
|
2012-08-12 22:14:42 +00:00
|
|
|
if (! m_enable) return;
|
|
|
|
if (m_level == 0.0f) return;
|
|
|
|
if (m_lines.empty()) return;
|
|
|
|
|
|
|
|
std::vector<Gfx::VertexTex2> vertices((m_brick+2)*2, Gfx::VertexTex2());
|
|
|
|
|
|
|
|
float iDeep = m_engine->GetDeepView();
|
|
|
|
float deep = (m_brick*m_size)/2.0f;
|
2012-08-08 21:51:19 +00:00
|
|
|
m_engine->SetDeepView(deep);
|
|
|
|
m_engine->SetFocus(m_engine->GetFocus());
|
|
|
|
m_engine->UpdateMatProj(); // increases the depth of view
|
|
|
|
|
2012-08-12 22:14:42 +00:00
|
|
|
float fogStart = deep*0.15f;
|
|
|
|
float fogEnd = deep*0.24f;
|
2012-08-08 21:51:19 +00:00
|
|
|
|
2012-08-12 22:14:42 +00:00
|
|
|
Gfx::CDevice* device = m_engine->GetDevice();
|
2012-08-08 21:51:19 +00:00
|
|
|
|
2012-08-12 22:14:42 +00:00
|
|
|
// TODO: do this better?
|
|
|
|
device->SetFogParams(Gfx::FOG_LINEAR, m_engine->GetFogColor( m_engine->GetRankView() ),
|
|
|
|
fogStart, fogEnd, 1.0f);
|
|
|
|
|
|
|
|
device->SetTransform(Gfx::TRANSFORM_VIEW, m_engine->GetMatView());
|
2012-08-08 21:51:19 +00:00
|
|
|
|
2012-08-12 22:14:42 +00:00
|
|
|
Gfx::Material material;
|
2012-08-08 21:51:19 +00:00
|
|
|
material.diffuse = m_diffuse;
|
|
|
|
material.ambient = m_ambient;
|
|
|
|
m_engine->SetMaterial(material);
|
|
|
|
|
2012-08-12 22:14:42 +00:00
|
|
|
m_engine->SetTexture(m_fileName, 0);
|
|
|
|
m_engine->SetTexture(m_fileName, 1);
|
2012-08-08 21:51:19 +00:00
|
|
|
|
2012-08-12 22:14:42 +00:00
|
|
|
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK | Gfx::ENG_RSTATE_FOG | Gfx::ENG_RSTATE_WRAP);
|
2012-08-08 21:51:19 +00:00
|
|
|
|
2012-08-12 22:14:42 +00:00
|
|
|
Math::Matrix matrix;
|
2012-08-08 21:51:19 +00:00
|
|
|
matrix.LoadIdentity();
|
2012-08-12 22:14:42 +00:00
|
|
|
device->SetTransform(Gfx::TRANSFORM_WORLD, matrix);
|
2012-08-08 21:51:19 +00:00
|
|
|
|
2012-08-12 22:14:42 +00:00
|
|
|
float size = m_size/2.0f;
|
|
|
|
Math::Vector eye = m_engine->GetEyePt();
|
|
|
|
Math::Vector n = Math::Vector(0.0f, -1.0f, 0.0f);
|
2012-08-08 21:51:19 +00:00
|
|
|
|
2012-08-12 22:14:42 +00:00
|
|
|
// Draws all the lines
|
|
|
|
for (int i = 0; i < static_cast<int>( m_lines.size() ); i++)
|
2012-08-08 21:51:19 +00:00
|
|
|
{
|
2012-08-12 22:14:42 +00:00
|
|
|
Math::Vector pos;
|
2012-08-08 21:51:19 +00:00
|
|
|
pos.y = m_level;
|
2012-08-12 17:28:22 +00:00
|
|
|
pos.z = m_lines[i].pz;
|
|
|
|
pos.x = m_lines[i].px1;
|
2012-08-08 21:51:19 +00:00
|
|
|
|
2012-08-12 22:14:42 +00:00
|
|
|
int vertexIndex = 0;
|
|
|
|
|
|
|
|
Math::Vector p;
|
|
|
|
Math::Point uv1, uv2;
|
|
|
|
|
2012-08-08 21:51:19 +00:00
|
|
|
p.x = pos.x-size;
|
|
|
|
p.z = pos.z+size;
|
|
|
|
p.y = pos.y;
|
|
|
|
AdjustLevel(p, eye, deep, uv1, uv2);
|
2012-08-12 22:14:42 +00:00
|
|
|
vertices[vertexIndex++] = Gfx::VertexTex2(p, n, uv1, uv2);
|
2012-08-08 21:51:19 +00:00
|
|
|
|
|
|
|
p.x = pos.x-size;
|
|
|
|
p.z = pos.z-size;
|
|
|
|
p.y = pos.y;
|
|
|
|
AdjustLevel(p, eye, deep, uv1, uv2);
|
2012-08-12 22:14:42 +00:00
|
|
|
vertices[vertexIndex++] = Gfx::VertexTex2(p, n, uv1, uv2);
|
2012-08-08 21:51:19 +00:00
|
|
|
|
2012-08-12 22:14:42 +00:00
|
|
|
for (int j = 0; j < m_lines[i].len; j++)
|
2012-08-08 21:51:19 +00:00
|
|
|
{
|
|
|
|
p.x = pos.x+size;
|
|
|
|
p.z = pos.z+size;
|
|
|
|
p.y = pos.y;
|
|
|
|
AdjustLevel(p, eye, deep, uv1, uv2);
|
2012-08-12 22:14:42 +00:00
|
|
|
vertices[vertexIndex++] = Gfx::VertexTex2(p, n, uv1, uv2);
|
2012-08-08 21:51:19 +00:00
|
|
|
|
|
|
|
p.x = pos.x+size;
|
|
|
|
p.z = pos.z-size;
|
|
|
|
p.y = pos.y;
|
|
|
|
AdjustLevel(p, eye, deep, uv1, uv2);
|
2012-08-12 22:14:42 +00:00
|
|
|
vertices[vertexIndex++] = Gfx::VertexTex2(p, n, uv1, uv2);
|
2012-08-08 21:51:19 +00:00
|
|
|
|
|
|
|
pos.x += size*2.0f;
|
|
|
|
}
|
|
|
|
|
2012-08-12 22:14:42 +00:00
|
|
|
device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, &vertices[0], vertexIndex);
|
|
|
|
m_engine->AddStatisticTriangle(vertexIndex - 2);
|
2012-08-08 21:51:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
m_engine->SetDeepView(iDeep);
|
|
|
|
m_engine->SetFocus(m_engine->GetFocus());
|
|
|
|
m_engine->UpdateMatProj(); // gives depth to initial
|
|
|
|
}
|
|
|
|
|
|
|
|
void Gfx::CCloud::CreateLine(int x, int y, int len)
|
|
|
|
{
|
|
|
|
Gfx::CloudLine line;
|
|
|
|
|
|
|
|
line.x = x;
|
|
|
|
line.y = y;
|
|
|
|
line.len = len;
|
|
|
|
|
|
|
|
float offset = m_brick*m_size/2.0f - m_size/2.0f;
|
|
|
|
|
|
|
|
line.px1 = m_size* line.x - offset;
|
|
|
|
line.px2 = m_size*(line.x+line.len) - offset;
|
|
|
|
line.pz = m_size* line.y - offset;
|
|
|
|
|
2012-08-12 17:28:22 +00:00
|
|
|
m_lines.push_back(line);
|
2012-08-08 21:51:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Gfx::CCloud::Create(const std::string& fileName,
|
|
|
|
Gfx::Color diffuse, Gfx::Color ambient,
|
|
|
|
float level)
|
|
|
|
{
|
|
|
|
m_diffuse = diffuse;
|
|
|
|
m_ambient = ambient;
|
|
|
|
m_level = level;
|
|
|
|
m_time = 0.0f;
|
|
|
|
m_lastTest = 0.0f;
|
|
|
|
m_fileName = fileName;
|
|
|
|
|
|
|
|
if (! m_fileName.empty())
|
2012-08-12 08:45:04 +00:00
|
|
|
m_engine->LoadTexture(m_fileName);
|
2012-08-08 21:51:19 +00:00
|
|
|
|
|
|
|
if (m_terrain == nullptr)
|
|
|
|
m_terrain = static_cast<CTerrain*>(m_iMan->SearchInstance(CLASS_TERRAIN));
|
|
|
|
|
|
|
|
m_wind = m_terrain->GetWind();
|
|
|
|
|
|
|
|
m_brick = m_terrain->GetBrick()*m_terrain->GetMosaic()*DIMEXPAND;
|
|
|
|
m_size = m_terrain->GetSize();
|
|
|
|
|
|
|
|
m_brick /= m_subdiv*DIMEXPAND;
|
|
|
|
m_size *= m_subdiv*DIMEXPAND;
|
|
|
|
|
|
|
|
if (m_level == 0.0f)
|
|
|
|
return;
|
|
|
|
|
2012-08-12 17:28:22 +00:00
|
|
|
m_lines.clear();
|
2012-08-08 21:51:19 +00:00
|
|
|
for (int y = 0; y < m_brick; y++)
|
|
|
|
CreateLine(0, y, m_brick);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Gfx::CCloud::Flush()
|
|
|
|
{
|
|
|
|
m_level = 0.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Gfx::CCloud::SetLevel(float level)
|
|
|
|
{
|
|
|
|
m_level = level;
|
|
|
|
|
|
|
|
Create(m_fileName, m_diffuse, m_ambient, m_level);
|
|
|
|
}
|
|
|
|
|
|
|
|
float Gfx::CCloud::GetLevel()
|
|
|
|
{
|
|
|
|
return m_level;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Gfx::CCloud::SetEnable(bool enable)
|
|
|
|
{
|
|
|
|
m_enable = enable;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Gfx::CCloud::GetEnable()
|
|
|
|
{
|
|
|
|
return m_enable;
|
|
|
|
}
|