Files
GDevelop/Extensions/Light/LightObject.cpp
T
2015-11-01 17:06:23 +01:00

310 lines
11 KiB
C++

/**
GDevelop - Light Extension
Copyright (c) 2008-2015 Florian Rival (Florian.Rival@gmail.com)
This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
#include <wx/wx.h> //Must be placed first, otherwise we get nice errors relative to "cannot convert 'const TCHAR*'..." in wx/msw/winundef.h
#endif
#include <SFML/Graphics.hpp>
#include "GDCore/Tools/Localization.h"
#include "GDCpp/Project/Object.h"
#include "GDCpp/RuntimeScene.h"
#include "GDCpp/ImageManager.h"
#include "GDCpp/Serialization/SerializerElement.h"
#include "GDCpp/FontManager.h"
#include "GDCpp/Project/InitialInstance.h"
#include "GDCpp/Polygon2d.h"
#include "GDCpp/CommonTools.h"
#include "GDCore/Tools/Localization.h"
#include "LightObject.h"
#include "LightManager.h"
#if defined(GD_IDE_ONLY)
#include "GDCpp/CommonTools.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/IDE/Dialogs/MainFrameWrapper.h"
#include "LightObjectEditor.h"
#endif
using namespace std;
std::map<const gd::Layout*, std::weak_ptr<Light_Manager> > RuntimeLightObject::lightManagersList;
#if defined(GD_IDE_ONLY)
sf::Texture LightObject::edittimeIconImage;
sf::Sprite LightObject::edittimeIcon;
#endif
LightObject::LightObject(gd::String name_) :
Object(name_),
light(sf::Vector2f(0,0)/*(Useless)*/, 150, 128, 16, sf::Color(255,255,255)),
globalLight(false),
globalLightColor(128,128,128,150)
{
}
void LightObject::DoUnserializeFrom(gd::Project & project, const gd::SerializerElement & element)
{
SetIntensity(element.GetIntAttribute("intensity", 255));
SetRadius(element.GetIntAttribute("radius", 180));
SetQuality(element.GetIntAttribute("quality", 16));
{
int r = element.GetIntAttribute("colorR", 255);
int g = element.GetIntAttribute("colorG", 255);
int b = element.GetIntAttribute("colorB", 255);
SetColor(sf::Color(r,g,b));
}
globalLight = element.GetBoolAttribute("globalLight", false);
{
int r = element.GetIntAttribute("globalColorR", 255);
int g = element.GetIntAttribute("globalColorG", 255);
int b = element.GetIntAttribute("globalColorB", 255);
int a = element.GetIntAttribute("globalColorA", 255);
globalLightColor = sf::Color(r,g,b,a);
}
}
#if defined(GD_IDE_ONLY)
void LightObject::DoSerializeTo(gd::SerializerElement & element) const
{
element.SetAttribute("intensity", GetIntensity());
element.SetAttribute("radius", GetRadius());
element.SetAttribute("quality", GetQuality());
element.SetAttribute("colorR", GetColor().r);
element.SetAttribute("colorG", GetColor().g);
element.SetAttribute("colorB", GetColor().b);
element.SetAttribute("globalLight", globalLight);
element.SetAttribute("globalColorR", globalLightColor.r);
element.SetAttribute("globalColorG", globalLightColor.g);
element.SetAttribute("globalColorB", globalLightColor.b);
element.SetAttribute("globalColorA", globalLightColor.a);
}
#endif
RuntimeLightObject::RuntimeLightObject(RuntimeScene & scene, const gd::Object & object) :
RuntimeObject(scene, object),
angle(0)
{
const LightObject & lightObject = static_cast<const LightObject&>(object);
globalLight = lightObject.IsGlobalLight();
globalLightColor = lightObject.GetGlobalColor();
light = Light(sf::Vector2f(GetX(),GetY()), lightObject.GetIntensity(), lightObject.GetRadius(), lightObject.GetQuality(), lightObject.GetColor());
//Get a manager for the scene
if ( lightManagersList[&scene].expired() )
{
manager = std::shared_ptr<Light_Manager>(new Light_Manager);
lightManagersList[&scene] = manager;
}
else
manager = lightManagersList[&scene].lock();
//Load ( only once for each scene ) the common blur effect, shared by all lights.
if ( !manager->commonBlurEffectLoaded )
{
manager->commonBlurEffect.loadFromMemory("uniform sampler2D texture;\nuniform float offset;\n\nvoid main()\n{\n vec2 offx = vec2(offset, 0.0);\n vec2 offy = vec2(0.0, offset);\n\n vec4 pixel = texture2D(texture, gl_TexCoord[0].xy) * 1 +\n texture2D(texture, gl_TexCoord[0].xy - offx) * 2 +\n texture2D(texture, gl_TexCoord[0].xy + offx) * 2 +\n texture2D(texture, gl_TexCoord[0].xy - offy) * 2 +\n texture2D(texture, gl_TexCoord[0].xy + offy) * 2 +\n texture2D(texture, gl_TexCoord[0].xy - offx - offy) * 1 +\n texture2D(texture, gl_TexCoord[0].xy - offx + offy) * 1 +\n texture2D(texture, gl_TexCoord[0].xy + offx - offy) * 1 +\n texture2D(texture, gl_TexCoord[0].xy + offx + offy) * 1;\n\n gl_FragColor = gl_Color * (pixel / 13.0);\n}\n",
sf::Shader::Fragment);
manager->commonBlurEffect.setParameter("texture", sf::Shader::CurrentTexture);
manager->commonBlurEffectLoaded = true;
}
UpdateGlobalLightMembers();
}
void RuntimeLightObject::UpdateGlobalLightMembers()
{
if ( globalLight )
{
//Create supplementary members for the global light
if ( !globalLightImage ) globalLightImage = std::shared_ptr<sf::RenderTexture>(new sf::RenderTexture);
}
else
{
//Not a global light, destroy all members related to
globalLightImage.reset();
}
}
/**
* Render object at runtime
*/
bool RuntimeLightObject::Draw( sf::RenderTarget& window )
{
//Don't draw anything if hidden
if ( hidden ) return true;
if ( !manager ) return false;
if ( updateClock.getElapsedTime().asMilliseconds() > 25 )
{
light.Generate(manager->walls);
updateClock.restart(); //Update each 25 milliseconds
}
if ( globalLight )
{
//Create render image
if ( globalLightImage->getSize().x != window.getSize().x || globalLightImage->getSize().y != window.getSize().y )
globalLightImage->create(window.getSize().x, window.getSize().y);
//Render light on an intermediate image
globalLightImage->clear(globalLightColor);
globalLightImage->setView(window.getView());
light.Draw(globalLightImage.get());
globalLightImage->display();
//Display the intermediate image
sf::Sprite sprite;
sprite.setTexture(globalLightImage->getTexture());
manager->commonBlurEffect.setParameter("offset",0.005 * 1);
window.setView(sf::View(sf::FloatRect(0,0,window.getSize().x, window.getSize().y)));
sf::RenderStates renderStates;
renderStates.blendMode = sf::BlendMultiply;
renderStates.shader = &manager->commonBlurEffect;
window.draw(sprite, renderStates);
window.setView(globalLightImage->getView());
}
else
{
light.Draw(&window);
}
//Debug draw
/*for (std::size_t i = 0;i<manager->walls.size();++i)
{
sf::Shape shape = sf::Shape::Line(manager->walls[i]->pt1, manager->walls[i]->pt2, 1, sf::Color(255,0,0));
window.draw(shape);
}*/
return true;
}
#if defined(GD_IDE_ONLY)
void LightObject::DrawInitialInstance(gd::InitialInstance & instance, sf::RenderTarget & renderTarget, gd::Project & project, gd::Layout & layout)
{
edittimeIcon.setPosition(instance.GetX(), instance.GetY());
renderTarget.draw(edittimeIcon);
}
sf::Vector2f LightObject::GetInitialInstanceDefaultSize(gd::InitialInstance & instance, gd::Project & project, gd::Layout & layout) const
{
return sf::Vector2f(32,32);
}
void LightObject::LoadEdittimeIcon()
{
edittimeIconImage.loadFromFile("CppPlatform/Extensions/lightIcon32.png");
edittimeIconImage.setSmooth(false);
edittimeIcon.setTexture(edittimeIconImage);
}
bool LightObject::GenerateThumbnail(const gd::Project & project, wxBitmap & thumbnail) const
{
#if !defined(GD_NO_WX_GUI)
thumbnail = wxBitmap("CppPlatform/Extensions/lightIcon24.png", wxBITMAP_TYPE_ANY);
#endif
return true;
}
void LightObject::EditObject( wxWindow* parent, gd::Project & game, gd::MainFrameWrapper & mainFrameWrapper )
{
#if !defined(GD_NO_WX_GUI)
LightObjectEditor dialog(parent, game, *this);
dialog.ShowModal();
#endif
}
void RuntimeLightObject::GetPropertyForDebugger(std::size_t propertyNb, gd::String & name, gd::String & value) const
{
if ( propertyNb == 0 ) {name = _("Color"); value = gd::String::From(GetColor().r)+";"+gd::String::From(GetColor().g)+";"+gd::String::From(GetColor().b);}
else if ( propertyNb == 1 ) {name = _("Intensity"); value = gd::String::From(GetIntensity());}
else if ( propertyNb == 2 ) {name = _("Radius"); value = gd::String::From(GetRadius());}
else if ( propertyNb == 2 ) {name = _("Quality"); value = gd::String::From(GetQuality());}
}
bool RuntimeLightObject::ChangeProperty(std::size_t propertyNb, gd::String newValue)
{
if ( propertyNb == 0 )
{
gd::String r, gb, g, b;
{
size_t separationPos = newValue.find(";");
if ( separationPos > newValue.length())
return false;
r = newValue.substr(0, separationPos);
gb = newValue.substr(separationPos+1, newValue.length());
}
{
size_t separationPos = gb.find(";");
if ( separationPos > gb.length())
return false;
g = gb.substr(0, separationPos);
b = gb.substr(separationPos+1, gb.length());
}
SetColor(sf::Color(r.To<int>(), g.To<int>(), b.To<int>()));
}
else if ( propertyNb == 1 ) { SetIntensity(newValue.To<float>()); }
else if ( propertyNb == 2 ) { SetRadius(newValue.To<float>()); }
else if ( propertyNb == 3 ) { SetQuality(newValue.To<int>()); }
return true;
}
std::size_t RuntimeLightObject::GetNumberOfProperties() const
{
return 2;
}
#endif
void RuntimeLightObject::OnPositionChanged()
{
light.SetPosition(sf::Vector2f(GetX(),GetY()));
}
void RuntimeLightObject::SetColor(const gd::String & colorStr)
{
vector < gd::String > colors = colorStr.Split(U';');
if ( colors.size() < 3 ) return; //La couleur est incorrecte
SetColor(sf::Color( colors[0].To<int>(), colors[1].To<int>(), colors[2].To<int>() ));
}
void RuntimeLightObject::SetGlobalColor(const gd::String & colorStr)
{
vector < gd::String > colors = colorStr.Split(U';');
if ( colors.size() < 3 ) return; //La couleur est incorrecte
SetGlobalColor(sf::Color( colors[0].To<int>(),colors[1].To<int>(),colors[2].To<int>() ));
}
RuntimeObject * CreateRuntimeLightObject(RuntimeScene & scene, const gd::Object & object)
{
return new RuntimeLightObject(scene, object);
}
gd::Object * CreateLightObject(gd::String name)
{
return new LightObject(name);
}