/** GDevelop - Tiled Sprite Extension Copyright (c) 2012-2016 Victor Levasseur (victorlevasseur01@orange.fr) Copyright (c) 2014-2016 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 //Must be placed first, otherwise we get errors relative to "cannot convert 'const TCHAR*'..." in wx/msw/winundef.h #include #endif #include "TiledSpriteObject.h" #include #include "GDCore/Tools/Localization.h" #include "GDCpp/Runtime/Project/Object.h" #include "GDCpp/Runtime/Project/Project.h" #include "GDCpp/Runtime/RuntimeScene.h" #include "GDCpp/Runtime/RuntimeGame.h" #include "GDCpp/Runtime/ImageManager.h" #include "GDCpp/Runtime/FontManager.h" #include "GDCpp/Runtime/Project/InitialInstance.h" #include "GDCpp/Runtime/Polygon2d.h" #include "GDCpp/Runtime/Serialization/SerializerElement.h" #include "GDCpp/Runtime/CommonTools.h" #if defined(GD_IDE_ONLY) #include "GDCore/IDE/Dialogs/MainFrameWrapper.h" #include "GDCore/IDE/Project/ArbitraryResourceWorker.h" #include "TiledSpriteObjectEditor.h" #endif using namespace std; TiledSpriteObject::TiledSpriteObject(gd::String name_) : Object(name_), textureName(""), width(32), height(32) { } void TiledSpriteObject::DoUnserializeFrom(gd::Project & project, const gd::SerializerElement & element) { textureName = element.GetStringAttribute("texture"); width = element.GetDoubleAttribute("width", 128); height = element.GetDoubleAttribute("height", 128); } #if defined(GD_IDE_ONLY) void TiledSpriteObject::DoSerializeTo(gd::SerializerElement & element) const { element.SetAttribute("texture", textureName); element.SetAttribute("width", width); element.SetAttribute("height", height); } void TiledSpriteObject::LoadResources(gd::Project & project, gd::Layout & layout) { texture = project.GetImageManager()->GetSFMLTexture(textureName); } #endif namespace { sf::Vector2f RotatePoint(sf::Vector2f point, float angle) { float t, cosa = cos(-angle), sina = sin(-angle); //We want a clockwise rotation t = point.x; point.x = t*cosa + point.y*sina; point.y = -t*sina + point.y*cosa; return point; } } RuntimeTiledSpriteObject::RuntimeTiledSpriteObject(RuntimeScene & scene, const TiledSpriteObject & tiledSpriteObject) : RuntimeObject(scene, tiledSpriteObject), width(32), height(32), xOffset(0), yOffset(), angle(0) { SetWidth(tiledSpriteObject.GetWidth()); SetHeight(tiledSpriteObject.GetHeight()); textureName = tiledSpriteObject.textureName; ChangeAndReloadImage(textureName, scene); } void RuntimeTiledSpriteObject::ChangeAndReloadImage(const gd::String &txtName, const RuntimeScene &scene) { textureName = txtName; texture = scene.GetImageManager()->GetSFMLTexture(textureName); } /** * Render object at runtime */ bool RuntimeTiledSpriteObject::Draw( sf::RenderTarget& window ) { //Don't draw anything if hidden if ( hidden ) return true; if(!texture) return true; #if defined(ANDROID) const unsigned int textureWidth = texture->texture.getSize().x; const unsigned int textureHeight = texture->texture.getSize().y; std::vector vertices; vertices.resize( (static_cast(GetWidth() / textureWidth) + 1u) * (static_cast(GetHeight() / textureHeight) + 1u) * 6 ); for(unsigned int i = 0; i < (static_cast(GetWidth() / textureWidth) + 1u); i++) { for(unsigned int j = 0; j < (static_cast(GetHeight() / textureHeight) + 1u); j++) { //Create the four vertices sf::Vector2f textureEndPosition( (i < static_cast(GetWidth() / textureWidth)) ? textureWidth : (GetWidth() - i * textureWidth), (j < static_cast(GetHeight() / textureHeight)) ? textureHeight : (GetHeight() - j * textureHeight) ); sf::Vertex topLeftCorner( sf::Vector2f(i * textureWidth, j * textureHeight), sf::Vector2f(0.f, 0.f) ); sf::Vertex topRightCorner( sf::Vector2f(i * textureWidth + textureEndPosition.x, j * textureHeight), sf::Vector2f(textureEndPosition.x, 0.f) ); sf::Vertex bottomRightCorner( sf::Vector2f(i * textureWidth + textureEndPosition.x, j * textureHeight + textureEndPosition.y), sf::Vector2f(textureEndPosition.x, textureEndPosition.y) ); sf::Vertex bottomLeftCorner( sf::Vector2f(i * textureWidth, j * textureHeight + textureEndPosition.y), sf::Vector2f(0.f, textureEndPosition.y) ); //Insert them to create two triangles const unsigned int firstVerticePos = (j * (static_cast(GetWidth() / textureWidth) + 1u) + i) * 6; vertices[firstVerticePos] = topLeftCorner; vertices[firstVerticePos+1u] = topRightCorner; vertices[firstVerticePos+2u] = bottomRightCorner; vertices[firstVerticePos+3u] = topLeftCorner; vertices[firstVerticePos+4u] = bottomRightCorner; vertices[firstVerticePos+5u] = bottomLeftCorner; } } sf::Transform transform; transform.translate(-GetWidth()/2.f, -GetHeight()/2.f); transform.rotate(angle); transform.translate(GetX()+GetWidth()/2.f, GetY()+GetHeight()/2.f); window.draw(vertices.data(), vertices.size(), sf::Triangles, sf::RenderStates(sf::BlendAlpha, transform, &texture->texture, nullptr)); #else sf::Vector2f centerPosition = sf::Vector2f(GetX()+GetCenterX(),GetY()+GetCenterY()); float angleInRad = angle*3.14159/180.0; texture->texture.setRepeated(true); sf::Vertex vertices[] = { sf::Vertex( centerPosition+RotatePoint(sf::Vector2f(-width/2,-height/2), angleInRad), sf::Vector2f(0+xOffset,0+yOffset)), sf::Vertex( centerPosition+RotatePoint(sf::Vector2f(+width/2,-height/2), angleInRad), sf::Vector2f(width+xOffset,0+yOffset)), sf::Vertex( centerPosition+RotatePoint(sf::Vector2f(-width/2,+height/2), angleInRad), sf::Vector2f(0+xOffset, height+yOffset)), sf::Vertex( centerPosition+RotatePoint(sf::Vector2f(+width/2,+height/2), angleInRad), sf::Vector2f(width+xOffset, height+yOffset)) }; window.draw(vertices, 4, sf::TrianglesStrip, &texture->texture); texture->texture.setRepeated(false); #endif return true; } #if defined(GD_IDE_ONLY) sf::Vector2f TiledSpriteObject::GetInitialInstanceDefaultSize(gd::InitialInstance & instance, gd::Project & project, gd::Layout & layout) const { return sf::Vector2f(width,height); } /** * Render object at edittime */ void TiledSpriteObject::DrawInitialInstance(gd::InitialInstance & instance, sf::RenderTarget & renderTarget, gd::Project & project, gd::Layout & layout) { if(!texture) return; float width = instance.HasCustomSize() ? instance.GetCustomWidth() : GetInitialInstanceDefaultSize(instance, project, layout).x; float height = instance.HasCustomSize() ? instance.GetCustomHeight() : GetInitialInstanceDefaultSize(instance, project, layout).y; float xOffset = 0; float yOffset = 0; sf::Vector2f centerPosition = sf::Vector2f(instance.GetX()+width/2, instance.GetY()+height/2); float angleInRad = instance.GetAngle()*3.14159/180.0; texture->texture.setRepeated(true); sf::Vertex vertices[] = { sf::Vertex( centerPosition+RotatePoint(sf::Vector2f(-width/2,-height/2), angleInRad), sf::Vector2f(0+xOffset,0+yOffset)), sf::Vertex( centerPosition+RotatePoint(sf::Vector2f(+width/2,-height/2), angleInRad), sf::Vector2f(width+xOffset,0+yOffset)), sf::Vertex( centerPosition+RotatePoint(sf::Vector2f(-width/2,+height/2), angleInRad), sf::Vector2f(0+xOffset, height+yOffset)), sf::Vertex( centerPosition+RotatePoint(sf::Vector2f(+width/2,+height/2), angleInRad), sf::Vector2f(width+xOffset, height+yOffset)) }; renderTarget.draw(vertices, 4, sf::TrianglesStrip, &texture->texture); texture->texture.setRepeated(false); } void TiledSpriteObject::ExposeResources(gd::ArbitraryResourceWorker & worker) { worker.ExposeImage(textureName); } bool TiledSpriteObject::GenerateThumbnail(const gd::Project & project, wxBitmap & thumbnail) const { #if !defined(GD_NO_WX_GUI) thumbnail = wxBitmap("CppPlatform/Extensions/TiledSpriteIcon24.png", wxBITMAP_TYPE_ANY); #endif return true; } void TiledSpriteObject::EditObject( wxWindow* parent, gd::Project & game, gd::MainFrameWrapper & mainFrameWrapper ) { #if !defined(GD_NO_WX_GUI) TiledSpriteObjectEditor dialog(parent, game, *this, mainFrameWrapper); dialog.ShowModal(); #endif } void RuntimeTiledSpriteObject::GetPropertyForDebugger(std::size_t propertyNb, gd::String & name, gd::String & value) const { if ( propertyNb == 0 ) {name = _("Width"); value = gd::String::From(width);} else if ( propertyNb == 1 ) {name = _("Height"); value = gd::String::From(height);} else if ( propertyNb == 2 ) {name = _("Angle"); value = gd::String::From(angle);} } bool RuntimeTiledSpriteObject::ChangeProperty(std::size_t propertyNb, gd::String newValue) { if ( propertyNb == 0 ) {width = newValue.To();} else if ( propertyNb == 1 ) {height = newValue.To();} else if ( propertyNb == 2 ) {angle = newValue.To();} return true; } std::size_t RuntimeTiledSpriteObject::GetNumberOfProperties() const { return 3; } #endif