Added blur effect when the game is paused (issue #656)
Might be unstable, needs more testing. To enable, add PauseBlur=1 to [Experimental] section in colobot.inimaster
parent
8922bb5e84
commit
213fd6b203
|
@ -112,6 +112,7 @@ void CSettings::SaveSettings()
|
||||||
|
|
||||||
// Experimental settings
|
// Experimental settings
|
||||||
GetConfigFile().SetBoolProperty("Experimental", "TerrainShadows", engine->GetTerrainShadows());
|
GetConfigFile().SetBoolProperty("Experimental", "TerrainShadows", engine->GetTerrainShadows());
|
||||||
|
GetConfigFile().SetBoolProperty("Experimental", "PauseBlur", engine->GetPauseBlur());
|
||||||
|
|
||||||
CInput::GetInstancePointer()->SaveKeyBindings();
|
CInput::GetInstancePointer()->SaveKeyBindings();
|
||||||
|
|
||||||
|
@ -270,6 +271,9 @@ void CSettings::LoadSettings()
|
||||||
if (GetConfigFile().GetBoolProperty("Experimental", "TerrainShadows", bValue))
|
if (GetConfigFile().GetBoolProperty("Experimental", "TerrainShadows", bValue))
|
||||||
engine->SetTerrainShadows(bValue);
|
engine->SetTerrainShadows(bValue);
|
||||||
|
|
||||||
|
if (GetConfigFile().GetBoolProperty("Experimental", "PauseBlur", bValue))
|
||||||
|
engine->SetPauseBlur(bValue);
|
||||||
|
|
||||||
CInput::GetInstancePointer()->LoadKeyBindings();
|
CInput::GetInstancePointer()->LoadKeyBindings();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
#include "ui/controls/interface.h"
|
#include "ui/controls/interface.h"
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <SDL_surface.h>
|
||||||
#include <SDL_thread.h>
|
#include <SDL_thread.h>
|
||||||
|
|
||||||
template<> Gfx::CEngine* CSingleton<Gfx::CEngine>::m_instance = nullptr;
|
template<> Gfx::CEngine* CSingleton<Gfx::CEngine>::m_instance = nullptr;
|
||||||
|
@ -148,6 +149,7 @@ CEngine::CEngine(CApplication *app, CSystemUtils* systemUtils)
|
||||||
m_editIndentMode = true;
|
m_editIndentMode = true;
|
||||||
m_editIndentValue = 4;
|
m_editIndentValue = 4;
|
||||||
m_tracePrecision = 1.0f;
|
m_tracePrecision = 1.0f;
|
||||||
|
m_pauseBlur = false;
|
||||||
|
|
||||||
|
|
||||||
m_updateGeometry = false;
|
m_updateGeometry = false;
|
||||||
|
@ -3028,6 +3030,16 @@ EngineMouseType CEngine::GetMouseType()
|
||||||
return m_mouseType;
|
return m_mouseType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CEngine::SetPauseBlur(bool enable)
|
||||||
|
{
|
||||||
|
m_pauseBlur = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CEngine::GetPauseBlur()
|
||||||
|
{
|
||||||
|
return m_pauseBlur;
|
||||||
|
}
|
||||||
|
|
||||||
const Math::Matrix& CEngine::GetMatView()
|
const Math::Matrix& CEngine::GetMatView()
|
||||||
{
|
{
|
||||||
return m_matView;
|
return m_matView;
|
||||||
|
@ -3066,6 +3078,10 @@ void CEngine::UpdateMatProj()
|
||||||
void CEngine::ApplyChange()
|
void CEngine::ApplyChange()
|
||||||
{
|
{
|
||||||
SetFocus(m_focus);
|
SetFocus(m_focus);
|
||||||
|
|
||||||
|
// recapture 3D scene
|
||||||
|
if (m_worldCaptured)
|
||||||
|
m_captureWorld = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEngine::ClearDisplayCrashSpheres()
|
void CEngine::ClearDisplayCrashSpheres()
|
||||||
|
@ -3137,8 +3153,8 @@ void CEngine::Render()
|
||||||
|
|
||||||
UseMSAA(true);
|
UseMSAA(true);
|
||||||
|
|
||||||
DrawBackground(); // draws the background
|
if (!m_worldCaptured)
|
||||||
|
DrawBackground(); // draws the background
|
||||||
|
|
||||||
if (m_drawWorld)
|
if (m_drawWorld)
|
||||||
Draw3DScene();
|
Draw3DScene();
|
||||||
|
@ -3155,6 +3171,33 @@ void CEngine::Render()
|
||||||
|
|
||||||
void CEngine::Draw3DScene()
|
void CEngine::Draw3DScene()
|
||||||
{
|
{
|
||||||
|
// use currently captured scene for world
|
||||||
|
if (m_worldCaptured)
|
||||||
|
{
|
||||||
|
Math::Matrix identity;
|
||||||
|
|
||||||
|
m_device->SetTransform(TRANSFORM_PROJECTION, identity);
|
||||||
|
m_device->SetTransform(TRANSFORM_VIEW, identity);
|
||||||
|
m_device->SetTransform(TRANSFORM_WORLD, identity);
|
||||||
|
|
||||||
|
Vertex vertices[4];
|
||||||
|
|
||||||
|
vertices[0] = Vertex(Math::Vector(-1.0f, -1.0f, 0.0f), Math::Vector(0.0f, 1.0f, 0.0f), Math::Point(0.0f, 0.0f));
|
||||||
|
vertices[1] = Vertex(Math::Vector( 1.0f, -1.0f, 0.0f), Math::Vector(0.0f, 1.0f, 0.0f), Math::Point(1.0f, 0.0f));
|
||||||
|
vertices[2] = Vertex(Math::Vector(-1.0f, 1.0f, 0.0f), Math::Vector(0.0f, 1.0f, 0.0f), Math::Point(0.0f, 1.0f));
|
||||||
|
vertices[3] = Vertex(Math::Vector( 1.0f, 1.0f, 0.0f), Math::Vector(0.0f, 1.0f, 0.0f), Math::Point(1.0f, 1.0f));
|
||||||
|
|
||||||
|
m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, false);
|
||||||
|
|
||||||
|
m_device->SetTexture(TEXTURE_PRIMARY, m_capturedWorldTexture);
|
||||||
|
m_device->SetTextureEnabled(TEXTURE_PRIMARY, true);
|
||||||
|
m_device->SetTextureEnabled(TEXTURE_SECONDARY, false);
|
||||||
|
|
||||||
|
m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertices, 4);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, false);
|
m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, false);
|
||||||
|
|
||||||
UpdateGroundSpotTextures();
|
UpdateGroundSpotTextures();
|
||||||
|
@ -3237,7 +3280,6 @@ void CEngine::Draw3DScene()
|
||||||
if (!m_shadowMapping)
|
if (!m_shadowMapping)
|
||||||
DrawShadowSpots();
|
DrawShadowSpots();
|
||||||
|
|
||||||
|
|
||||||
m_app->StopPerformanceCounter(PCNT_RENDER_TERRAIN);
|
m_app->StopPerformanceCounter(PCNT_RENDER_TERRAIN);
|
||||||
|
|
||||||
// Draw other objects
|
// Draw other objects
|
||||||
|
@ -3407,6 +3449,117 @@ void CEngine::Draw3DScene()
|
||||||
DrawForegroundImage(); // draws the foreground
|
DrawForegroundImage(); // draws the foreground
|
||||||
|
|
||||||
if (! m_overFront) DrawOverColor(); // draws the foreground color
|
if (! m_overFront) DrawOverColor(); // draws the foreground color
|
||||||
|
|
||||||
|
// marked to capture currently rendered world
|
||||||
|
if (m_captureWorld)
|
||||||
|
{
|
||||||
|
// destroy existing texture
|
||||||
|
if (m_capturedWorldTexture.Valid())
|
||||||
|
{
|
||||||
|
m_device->DestroyTexture(m_capturedWorldTexture);
|
||||||
|
m_capturedWorldTexture = Texture();
|
||||||
|
}
|
||||||
|
|
||||||
|
// obtain pixels from screen
|
||||||
|
int width = m_size.x;
|
||||||
|
int height = m_size.y;
|
||||||
|
|
||||||
|
auto pixels = m_device->GetFrameBufferPixels();
|
||||||
|
unsigned char* data = reinterpret_cast<unsigned char*>(pixels->GetPixelsData());
|
||||||
|
|
||||||
|
// calculate 2nd mipmap
|
||||||
|
int newWidth = width / 4;
|
||||||
|
int newHeight = height / 4;
|
||||||
|
std::unique_ptr<unsigned char[]> mipmap(new unsigned char[4 * newWidth * newHeight]);
|
||||||
|
|
||||||
|
for (int x = 0; x < newWidth; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < newHeight; y++)
|
||||||
|
{
|
||||||
|
float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
int index = 4 * ((4 * x + i) + width * (4 * y + j));
|
||||||
|
|
||||||
|
for (int k = 0; k < 4; k++)
|
||||||
|
color[k] += data[index + k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = 4 * (x + newWidth * y);
|
||||||
|
|
||||||
|
for (int k = 0; k < 4; k++)
|
||||||
|
{
|
||||||
|
mipmap[index + k] = static_cast<unsigned char>(color[k] * (1.0f / 16.0f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate Gaussian blur
|
||||||
|
std::unique_ptr<unsigned char[]> blured(new unsigned char[4 * newWidth * newHeight]);
|
||||||
|
|
||||||
|
float matrix[7][7] =
|
||||||
|
{
|
||||||
|
{ 0.00000067f, 0.00002292f, 0.00019117f, 0.00038771f, 0.00019117f, 0.00002292f, 0.00000067f },
|
||||||
|
{ 0.00002292f, 0.00078634f, 0.00655965f, 0.01330373f, 0.00655965f, 0.00078633f, 0.00002292f },
|
||||||
|
{ 0.00019117f, 0.00655965f, 0.05472157f, 0.11098164f, 0.05472157f, 0.00655965f, 0.00019117f },
|
||||||
|
{ 0.00038771f, 0.01330373f, 0.11098164f, 0.22508352f, 0.11098164f, 0.01330373f, 0.00038771f },
|
||||||
|
{ 0.00019117f, 0.00655965f, 0.05472157f, 0.11098164f, 0.05472157f, 0.00655965f, 0.00019117f },
|
||||||
|
{ 0.00002292f, 0.00078633f, 0.00655965f, 0.01330373f, 0.00655965f, 0.00078633f, 0.00002292f },
|
||||||
|
{ 0.00000067f, 0.00002292f, 0.00019117f, 0.00038771f, 0.00019117f, 0.00002292f, 0.00000067f }
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int x = 0; x < newWidth; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < newHeight; y++)
|
||||||
|
{
|
||||||
|
float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
|
|
||||||
|
for (int i = -3; i <= 3; i++)
|
||||||
|
{
|
||||||
|
for (int j = -3; j <= 3; j++)
|
||||||
|
{
|
||||||
|
int xp = Math::Clamp(x + i, 0, newWidth - 1);
|
||||||
|
int yp = Math::Clamp(y + j, 0, newHeight - 1);
|
||||||
|
|
||||||
|
float weight = matrix[i + 3][j + 3];
|
||||||
|
|
||||||
|
int index = 4 * (newWidth * yp + xp);
|
||||||
|
|
||||||
|
for (int k = 0; k < 4; k++)
|
||||||
|
color[k] += weight * mipmap[index + k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = 4 * (newWidth * y + x);
|
||||||
|
|
||||||
|
for (int k = 0; k < 4; k++)
|
||||||
|
{
|
||||||
|
float value = Math::Clamp(color[k], 0.0f, 255.0f);
|
||||||
|
blured[index + k] = static_cast<unsigned char>(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create SDL surface and final texture
|
||||||
|
ImageData image;
|
||||||
|
image.surface = SDL_CreateRGBSurfaceFrom(blured.get(), newWidth, newHeight, 32, 0, 0, 0, 0, 0xFF000000);
|
||||||
|
|
||||||
|
TextureCreateParams params;
|
||||||
|
params.filter = TEX_FILTER_BILINEAR;
|
||||||
|
params.format = TEX_IMG_RGBA;
|
||||||
|
params.mipmap = false;
|
||||||
|
|
||||||
|
m_capturedWorldTexture = m_device->CreateTexture(&image, params);
|
||||||
|
|
||||||
|
SDL_FreeSurface(image.surface);
|
||||||
|
|
||||||
|
m_captureWorld = false;
|
||||||
|
m_worldCaptured = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEngine::DrawCrashSpheres()
|
void CEngine::DrawCrashSpheres()
|
||||||
|
@ -5190,6 +5343,22 @@ void CEngine::SetInterfaceCoordinates()
|
||||||
m_device->SetTransform(TRANSFORM_WORLD, m_matWorldInterface);
|
m_device->SetTransform(TRANSFORM_WORLD, m_matWorldInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CEngine::EnablePauseBlur()
|
||||||
|
{
|
||||||
|
if (!m_pauseBlur) return;
|
||||||
|
|
||||||
|
m_captureWorld = true;
|
||||||
|
m_worldCaptured = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CEngine::DisablePauseBlur()
|
||||||
|
{
|
||||||
|
if (!m_pauseBlur) return;
|
||||||
|
|
||||||
|
m_captureWorld = false;
|
||||||
|
m_worldCaptured = false;
|
||||||
|
}
|
||||||
|
|
||||||
void CEngine::SetWindowCoordinates()
|
void CEngine::SetWindowCoordinates()
|
||||||
{
|
{
|
||||||
Math::Matrix matWorldWindow;
|
Math::Matrix matWorldWindow;
|
||||||
|
|
|
@ -1162,6 +1162,12 @@ public:
|
||||||
EngineMouseType GetMouseType();
|
EngineMouseType GetMouseType();
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
//@{
|
||||||
|
//! Management of pause blur
|
||||||
|
void SetPauseBlur(bool enable);
|
||||||
|
bool GetPauseBlur();
|
||||||
|
//@}
|
||||||
|
|
||||||
//! Returns the view matrix
|
//! Returns the view matrix
|
||||||
const Math::Matrix& GetMatView();
|
const Math::Matrix& GetMatView();
|
||||||
//! Returns the camera center point
|
//! Returns the camera center point
|
||||||
|
@ -1199,6 +1205,9 @@ public:
|
||||||
void SetWindowCoordinates();
|
void SetWindowCoordinates();
|
||||||
void SetInterfaceCoordinates();
|
void SetInterfaceCoordinates();
|
||||||
|
|
||||||
|
void EnablePauseBlur();
|
||||||
|
void DisablePauseBlur();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Resets some states and flushes textures after device was changed (e.g. resoulution changed)
|
//! Resets some states and flushes textures after device was changed (e.g. resoulution changed)
|
||||||
/** Instead of calling this directly, send EVENT_RESOLUTION_CHANGED event **/
|
/** Instead of calling this directly, send EVENT_RESOLUTION_CHANGED event **/
|
||||||
|
@ -1408,6 +1417,7 @@ protected:
|
||||||
float m_terrainVision;
|
float m_terrainVision;
|
||||||
bool m_backForce;
|
bool m_backForce;
|
||||||
float m_tracePrecision;
|
float m_tracePrecision;
|
||||||
|
bool m_pauseBlur;
|
||||||
|
|
||||||
bool m_dirty;
|
bool m_dirty;
|
||||||
bool m_fog;
|
bool m_fog;
|
||||||
|
@ -1502,6 +1512,13 @@ protected:
|
||||||
|
|
||||||
//! Pause the animation updates
|
//! Pause the animation updates
|
||||||
bool m_pause = false;
|
bool m_pause = false;
|
||||||
|
|
||||||
|
//! true means that current 3D scene was captured and is not to be rendered again
|
||||||
|
bool m_worldCaptured = false;
|
||||||
|
//! true means that currently rendered world is to be captured
|
||||||
|
bool m_captureWorld = false;
|
||||||
|
//! Texture with captured 3D world
|
||||||
|
Texture m_capturedWorldTexture;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1601,6 +1601,8 @@ void CRobotMain::StartSuspend()
|
||||||
|
|
||||||
m_suspendInitCamera = m_camera->GetType();
|
m_suspendInitCamera = m_camera->GetType();
|
||||||
m_camera->SetType(Gfx::CAM_TYPE_DIALOG);
|
m_camera->SetType(Gfx::CAM_TYPE_DIALOG);
|
||||||
|
|
||||||
|
m_engine->EnablePauseBlur();
|
||||||
}
|
}
|
||||||
|
|
||||||
//! End of dialogue during the game
|
//! End of dialogue during the game
|
||||||
|
@ -1619,6 +1621,8 @@ void CRobotMain::StopSuspend()
|
||||||
m_displayText->HideText(false);
|
m_displayText->HideText(false);
|
||||||
|
|
||||||
m_camera->SetType(m_suspendInitCamera);
|
m_camera->SetType(m_suspendInitCamera);
|
||||||
|
|
||||||
|
m_engine->DisablePauseBlur();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,15 @@ inline float Max(float a, float b, float c, float d, float e)
|
||||||
return Math::Max( Math::Max(a, b), Math::Max(c, d), e );
|
return Math::Max( Math::Max(a, b), Math::Max(c, d), e );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Clamps the value to a range specified by min and max
|
||||||
|
template<typename T>
|
||||||
|
inline T Clamp(T value, T min, T max)
|
||||||
|
{
|
||||||
|
if (value < min) return min;
|
||||||
|
else if (value > max) return max;
|
||||||
|
else return value;
|
||||||
|
}
|
||||||
|
|
||||||
//! Returns the normalized value (0 .. 1)
|
//! Returns the normalized value (0 .. 1)
|
||||||
inline float Norm(float a)
|
inline float Norm(float a)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue