summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPiotr Dziwinski <piotrdz@gmail.com>2012-10-05 15:26:24 +0200
committerPiotr Dziwinski <piotrdz@gmail.com>2012-10-05 15:26:24 +0200
commit37302a2504811bf410b2485dbf65d5dedd8ba164 (patch)
treec71e9c4d26589f94982ab9031219c3e580faaffd
parent703f03f31622b357b0951d5a631a987cb888aa25 (diff)
downloadcolobot-37302a2504811bf410b2485dbf65d5dedd8ba164.tar.gz
colobot-37302a2504811bf410b2485dbf65d5dedd8ba164.tar.bz2
colobot-37302a2504811bf410b2485dbf65d5dedd8ba164.zip
CLightning rewrite
-rw-r--r--src/graphics/engine/lightning.cpp375
-rw-r--r--src/graphics/engine/lightning.h58
-rw-r--r--src/object/object.cpp4
3 files changed, 387 insertions, 50 deletions
diff --git a/src/graphics/engine/lightning.cpp b/src/graphics/engine/lightning.cpp
index 1b9cbf1..337d578 100644
--- a/src/graphics/engine/lightning.cpp
+++ b/src/graphics/engine/lightning.cpp
@@ -19,6 +19,17 @@
#include "graphics/engine/lightning.h"
#include "common/logger.h"
+#include "common/iman.h"
+
+#include "graphics/core/device.h"
+#include "graphics/engine/camera.h"
+#include "graphics/engine/terrain.h"
+
+#include "object/object.h"
+
+#include "object/auto/autopara.h"
+
+#include "math/geometry.h"
// Graphics module namespace
@@ -27,68 +38,380 @@ namespace Gfx {
CLightning::CLightning(CInstanceManager* iMan, CEngine* engine)
{
- GetLogger()->Trace("CLightning::CLightning() stub!\n");
- // TODO!
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_BLITZ, this);
+
+ m_engine = engine;
+ m_terrain = nullptr;
+ m_camera = nullptr;
+ m_sound = nullptr;
+
+ Flush();
}
CLightning::~CLightning()
{
- GetLogger()->Trace("CLightning::~CLightning() stub!\n");
- // TODO!
}
void CLightning::Flush()
{
- GetLogger()->Trace("CLightning::Flush() stub!\n");
- // TODO!
+ m_lightningExists = false;
+ m_phase = LP_WAIT;
+ m_speed = 0.0f;
+ m_progress = 0.0f;
+
+ for (int i = 0; i < FLASH_SEGMENTS; i++)
+ {
+ m_shift[i] = Math::Point(0.0f, 0.0f);
+ m_width[i] = 1.0f;
+ }
}
bool CLightning::EventProcess(const Event &event)
{
- GetLogger()->Trace("CLightning::EventProcess() stub!\n");
- // TODO!
+ if (event.type == EVENT_FRAME)
+ return EventFrame(event);
+
return true;
}
-bool CLightning::Create(float sleep, float delay, float magnetic)
+bool CLightning::EventFrame(const Event &event)
{
- GetLogger()->Trace("CLightning::Create() stub!\n");
- // TODO!
+ if (m_engine->GetPause()) return true;
+ if (m_engine->GetMovieLock()) return true;
+
+ m_progress += event.rTime*m_speed;
+
+ if (m_phase == LP_WAIT)
+ {
+ if (m_progress >= 1.0f)
+ {
+
+ m_pos.x = (Math::Rand()-0.5f)*(3200.0f-200.0f);
+ m_pos.z = (Math::Rand()-0.5f)*(3200.0f-200.0f);
+ m_pos.y = 0.0f;
+
+ CObject* obj = SearchObject(m_pos);
+ if (obj == nullptr)
+ {
+ m_terrain->AdjustToFloor(m_pos, true);
+ }
+ else
+ {
+ m_pos = obj->GetPosition(0);
+ m_terrain->AdjustToFloor(m_pos, true);
+
+ ObjectType type = obj->GetType();
+ if (type == OBJECT_BASE)
+ {
+ m_pos.y += 120.0f; // top of the rocket
+ }
+ else if (type == OBJECT_PARA)
+ {
+ CAutoPara* automat = dynamic_cast<CAutoPara*>(obj->GetAuto());
+ if (automat != nullptr)
+ automat->StartLightning();
+
+ m_pos.y += 67.0f; // top of lightning rod
+ }
+ else
+ {
+ obj->ExploObject(EXPLO_BOUM, 1.0f);
+ }
+ }
+
+ Math::Vector eye = m_engine->GetEyePt();
+ float dist = Math::Distance(m_pos, eye);
+ float deep = m_engine->GetDeepView();
+
+ if (dist < deep)
+ {
+ Math::Vector pos = eye+((m_pos-eye)*0.2f); // like so close!
+ m_sound->Play(SOUND_BLITZ, pos);
+
+ m_camera->StartOver(CAM_OVER_EFFECT_LIGHTNING, m_pos, 1.0f);
+
+ m_phase = LP_FLASH;
+ m_progress = 0.0f;
+ m_speed = 1.0f;
+ }
+ }
+ }
+
+ if (m_phase == LP_FLASH)
+ {
+ if (m_progress < 1.0f)
+ {
+ float max = 5.0f;
+ for (int i = 0; i < FLASH_SEGMENTS; i++)
+ {
+ max += 0.4f;
+
+ m_shift[i].x += (Math::Rand()-0.5f)*max*2.0f;
+ if ( m_shift[i].x < -max ) m_shift[i].x = -max;
+ if ( m_shift[i].x > max ) m_shift[i].x = max;
+
+ m_shift[i].y += (Math::Rand()-0.5f)*max*2.0f;
+ if ( m_shift[i].y < -max ) m_shift[i].y = -max;
+ if ( m_shift[i].y > max ) m_shift[i].y = max;
+
+ m_width[i] += (Math::Rand()-0.5f)*2.0f;
+ if ( m_width[i] < 1.0f ) m_width[i] = 1.0f;
+ if ( m_width[i] > 6.0f ) m_width[i] = 6.0f;
+ }
+ m_shift[0].x = 0.0f;
+ m_shift[0].y = 0.0f;
+ m_width[0] = 0.0f;
+ }
+ else
+ {
+ m_phase = LP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f / (1.0f+Math::Rand()*m_delay);
+ }
+ }
+
return true;
}
+bool CLightning::Create(float sleep, float delay, float magnetic)
+{
+ m_lightningExists = true;
+ if (sleep < 1.0f) sleep = 1.0f;
+ m_sleep = sleep;
+ m_delay = delay;
+ m_magnetic = magnetic;
+
+ m_phase = LP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f / m_sleep;
+
+ if (m_terrain == nullptr)
+ m_terrain = static_cast<CTerrain*>(m_iMan->SearchInstance(CLASS_TERRAIN));
+
+ if (m_camera == nullptr)
+ m_camera = static_cast<CCamera*>(m_iMan->SearchInstance(CLASS_CAMERA));
+
+ if (m_sound == nullptr)
+ m_sound = static_cast<CSoundInterface*>(m_iMan->SearchInstance(CLASS_SOUND));
+
+ return false;
+}
+
bool CLightning::GetStatus(float &sleep, float &delay, float &magnetic, float &progress)
{
- GetLogger()->Trace("CLightning::GetStatus() stub!\n");
- // TODO!
+ if (! m_lightningExists) return false;
+
+ sleep = m_sleep;
+ delay = m_delay;
+ magnetic = m_magnetic;
+ progress = m_progress;
+
return true;
}
bool CLightning::SetStatus(float sleep, float delay, float magnetic, float progress)
{
- GetLogger()->Trace("CLightning::SetStatus() stub!\n");
- // TODO!
+ m_lightningExists = true;
+
+ m_sleep = sleep;
+ m_delay = delay;
+ m_magnetic = magnetic;
+ m_progress = progress;
+ m_phase = LP_WAIT;
+ m_speed = 1.0f/m_sleep;
+
return true;
}
void CLightning::Draw()
{
- GetLogger()->Trace("CLightning::Draw() stub!\n");
- // TODO!
-}
+ if (!m_lightningExists) return;
+ if (m_phase != LP_FLASH) return;
-bool CLightning::EventFrame(const Event &event)
-{
- GetLogger()->Trace("CLightning::EventFrame() stub!\n");
- // TODO!
- return true;
+ CDevice* device = m_engine->GetDevice();
+
+ Math::Matrix mat;
+ mat.LoadIdentity();
+ device->SetTransform(TRANSFORM_WORLD, mat);
+
+ m_engine->SetTexture("effect00.png");
+ m_engine->SetState(ENG_RSTATE_TTEXTURE_BLACK);
+
+ Math::Point texInf;
+ texInf.x = 64.5f/256.0f;
+ texInf.y = 33.0f/256.0f;
+ Math::Point texSup;
+ texSup.x = 95.5f/256.0f;
+ texSup.y = 34.0f/256.0f; // blank
+
+ Math::Vector p1 = m_pos;
+ Math::Vector eye = m_engine->GetEyePt();
+ float a = Math::RotateAngle(eye.x-p1.x, eye.z-p1.z);
+ Math::Vector n = Math::Normalize(p1-eye);
+
+ Math::Vector corner[4];
+ Vertex vertex[4];
+
+ for (int i = 0; i < FLASH_SEGMENTS-1; i++)
+ {
+ Math::Vector p2 = p1;
+ p2.y += 8.0f+0.2f*i;
+
+ Math::Point rot;
+
+ Math::Vector p = p1;
+ p.x += m_width[i];
+ rot = Math::RotatePoint(Math::Point(p1.x, p1.z), a+Math::PI/2.0f, Math::Point(p.x, p.z));
+ corner[0].x = rot.x+m_shift[i].x;
+ corner[0].y = p1.y;
+ corner[0].z = rot.y+m_shift[i].y;
+ rot = Math::RotatePoint(Math::Point(p1.x, p1.z), a-Math::PI/2.0f, Math::Point(p.x, p.z));
+ corner[1].x = rot.x+m_shift[i].x;
+ corner[1].y = p1.y;
+ corner[1].z = rot.y+m_shift[i].y;
+
+ p = p2;
+ p.x += m_width[i+1];
+ rot = Math::RotatePoint(Math::Point(p2.x, p2.z), a+Math::PI/2.0f, Math::Point(p.x, p.z));
+ corner[2].x = rot.x+m_shift[i+1].x;
+ corner[2].y = p2.y;
+ corner[2].z = rot.y+m_shift[i+1].y;
+ rot = Math::RotatePoint(Math::Point(p2.x, p2.z), a-Math::PI/2.0f, Math::Point(p.x, p.z));
+ corner[3].x = rot.x+m_shift[i+1].x;
+ corner[3].y = p2.y;
+ corner[3].z = rot.y+m_shift[i+1].y;
+
+ if (p2.y < p1.y)
+ {
+ vertex[0] = Vertex(corner[1], n, Math::Point(texSup.x, texSup.y));
+ vertex[1] = Vertex(corner[0], n, Math::Point(texInf.x, texSup.y));
+ vertex[2] = Vertex(corner[3], n, Math::Point(texSup.x, texInf.y));
+ vertex[3] = Vertex(corner[2], n, Math::Point(texInf.x, texInf.y));
+ }
+ else
+ {
+ vertex[0] = Vertex(corner[0], n, Math::Point(texSup.x, texSup.y));
+ vertex[1] = Vertex(corner[1], n, Math::Point(texInf.x, texSup.y));
+ vertex[2] = Vertex(corner[2], n, Math::Point(texSup.x, texInf.y));
+ vertex[3] = Vertex(corner[3], n, Math::Point(texInf.x, texInf.y));
+ }
+
+ device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4);
+ m_engine->AddStatisticTriangle(2);
+
+ p1 = p2;
+ }
}
CObject* CLightning::SearchObject(Math::Vector pos)
{
- GetLogger()->Trace("CLightning::SearchObject() stub!\n");
- // TODO!
- return nullptr;
+ // Lightning conductors
+ std::vector<CObject*> paraObj;
+ paraObj.reserve(100);
+ std::vector<Math::Vector> paraObjPos;
+ paraObjPos.reserve(100);
+
+ // Seeking the object closest to the point of impact of lightning.
+ CObject* bestObj = 0;
+ float min = 100000.0f;
+ for (int i = 0; i < 1000000; i++)
+ {
+ CObject* obj = static_cast<CObject*>( m_iMan->SearchInstance(CLASS_OBJECT, i) );
+ if (obj == nullptr) break;
+
+ if (!obj->GetActif()) continue; // inactive object?
+ if (obj->GetTruck() != nullptr) continue; // object transported?
+
+ ObjectType type = obj->GetType();
+ if ( type == OBJECT_BASE ||
+ type == OBJECT_PARA ) // building a lightning effect?
+ {
+ paraObj.push_back(obj);
+ paraObjPos.push_back(obj->GetPosition(0));
+ }
+
+ float detect = 0.0f;
+ if ( type == OBJECT_BASE ||
+ type == OBJECT_DERRICK ||
+ type == OBJECT_FACTORY ||
+ type == OBJECT_REPAIR ||
+ type == OBJECT_DESTROYER||
+ type == OBJECT_STATION ||
+ type == OBJECT_CONVERT ||
+ type == OBJECT_TOWER ||
+ type == OBJECT_RESEARCH ||
+ type == OBJECT_RADAR ||
+ type == OBJECT_INFO ||
+ type == OBJECT_ENERGY ||
+ type == OBJECT_LABO ||
+ type == OBJECT_NUCLEAR ||
+ type == OBJECT_PARA ||
+ type == OBJECT_SAFE ||
+ type == OBJECT_HUSTON )
+ {
+ detect = m_magnetic;
+ }
+ if ( type == OBJECT_METAL ||
+ type == OBJECT_POWER ||
+ type == OBJECT_ATOMIC )
+ {
+ detect = m_magnetic*0.3f;
+ }
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ||
+ type == OBJECT_MOBILEdr )
+ {
+ detect = m_magnetic*0.5f;
+ }
+ if (detect == 0.0f) continue;
+
+ Math::Vector oPos = obj->GetPosition(0);
+ float dist = Math::DistanceProjected(oPos, pos);
+ if (dist > detect) continue;
+ if (dist < min)
+ {
+ min = dist;
+ bestObj = obj;
+ }
+ }
+
+ if (bestObj == nullptr)
+ return nullptr; // nothing found
+
+ // Under the protection of a lightning conductor?
+ Math::Vector oPos = bestObj->GetPosition(0);
+ for (int i = paraObj.size()-1; i >= 0; i--)
+ {
+ float dist = Math::DistanceProjected(oPos, paraObjPos[i]);
+ if (dist <= LTNG_PROTECTION_RADIUS)
+ return paraObj[i];
+ }
+
+ return bestObj;
}
diff --git a/src/graphics/engine/lightning.h b/src/graphics/engine/lightning.h
index d873c64..b21f681 100644
--- a/src/graphics/engine/lightning.h
+++ b/src/graphics/engine/lightning.h
@@ -30,7 +30,7 @@
class CInstanceManager;
class CObject;
-class CSound;
+class CSoundInterface;
// Graphics module namespace
@@ -40,21 +40,15 @@ class CEngine;
class CTerrain;
class CCamera;
+//! Radius of lightning protection
+const float LTNG_PROTECTION_RADIUS = 200.0f;
-const float BLITZPARA = 200.0f; // radius of lightning protection
-const short BLITZMAX = 50;
-
-enum BlitzPhase
-{
- BPH_WAIT,
- BPH_BLITZ,
-};
/**
* \class CLightning
* \brief Lightning effect renderer
*
- * Functions are only stubs for now.
+ * TODO: documentation
*/
class CLightning
{
@@ -62,35 +56,55 @@ public:
CLightning(CInstanceManager* iMan, CEngine* engine);
~CLightning();
- void Flush();
- bool EventProcess(const Event &event);
+ //! Triggers lightning
bool Create(float sleep, float delay, float magnetic);
+
+ //! Removes lightning
+ void Flush();
+
+ //! Gives the status of lightning
bool GetStatus(float &sleep, float &delay, float &magnetic, float &progress);
+ //! Specifies the status of lightning
bool SetStatus(float sleep, float delay, float magnetic, float progress);
+
+ //! Management of an event
+ bool EventProcess(const Event &event);
+
+ //! Draws lightning
void Draw();
protected:
+ //! Updates lightning
bool EventFrame(const Event &event);
+ //! Seeks for the object closest to the lightning
CObject* SearchObject(Math::Vector pos);
protected:
- CInstanceManager* m_iMan;
- CEngine* m_engine;
- CTerrain* m_terrain;
- CCamera* m_camera;
- CSound* m_sound;
+ CInstanceManager* m_iMan;
+ CEngine* m_engine;
+ CTerrain* m_terrain;
+ CCamera* m_camera;
+ CSoundInterface* m_sound;
- bool m_bBlitzExist;
+ bool m_lightningExists;
float m_sleep;
float m_delay;
float m_magnetic;
- BlitzPhase m_phase;
- float m_time;
+
float m_speed;
float m_progress;
Math::Vector m_pos;
- Math::Point m_shift[BLITZMAX];
- float m_width[BLITZMAX];
+
+ enum LightningPhase
+ {
+ LP_WAIT,
+ LP_FLASH,
+ };
+ LightningPhase m_phase;
+
+ static const short FLASH_SEGMENTS = 50;
+ Math::Point m_shift[FLASH_SEGMENTS];
+ float m_width[FLASH_SEGMENTS];
};
diff --git a/src/object/object.cpp b/src/object/object.cpp
index 77a7c25..5a1631f 100644
--- a/src/object/object.cpp
+++ b/src/object/object.cpp
@@ -2995,7 +2995,7 @@ bool CObject::CreateBuilding(Math::Vector pos, float angle, float height,
m_character.posPower = Math::Vector(5.0f, 3.0f, 0.0f);
CreateShadowCircle(6.0f, 1.0f);
- m_showLimitRadius = Gfx::BLITZPARA;
+ m_showLimitRadius = Gfx::LTNG_PROTECTION_RADIUS;
}
if ( m_type == OBJECT_NUCLEAR )
@@ -3048,7 +3048,7 @@ bool CObject::CreateBuilding(Math::Vector pos, float angle, float height,
SetGlobalSphere(Math::Vector(0.0f, 10.0f, 0.0f), 20.0f);
CreateShadowCircle(21.0f, 1.0f);
- m_showLimitRadius = Gfx::BLITZPARA;
+ m_showLimitRadius = Gfx::LTNG_PROTECTION_RADIUS;
}
if ( m_type == OBJECT_SAFE )