Prepare framework with Draw and DrawDecal split.
This commit is contained in:
parent
dd2ff24d85
commit
e3d0283fcb
@ -283,6 +283,7 @@
|
||||
<ClInclude Include="Monster.h" />
|
||||
<ClInclude Include="MonsterAttribute.h" />
|
||||
<ClInclude Include="MonsterStrategyHelpers.h" />
|
||||
<ClInclude Include="olcPGEX_Graphics2D.h" />
|
||||
<ClInclude Include="olcPGEX_TransformedView.h" />
|
||||
<ClInclude Include="olcPixelGameEngine.h" />
|
||||
<ClInclude Include="olcUTIL_Animate2D.h" />
|
||||
|
||||
@ -183,6 +183,9 @@
|
||||
<ClInclude Include="MenuComponent.h">
|
||||
<Filter>Header Files\Interface</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="olcPGEX_Graphics2D.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Player.cpp">
|
||||
|
||||
@ -19,7 +19,9 @@ Menu*Menu::InitializeInventoryWindow(){
|
||||
constexpr int buttonSize=24;
|
||||
constexpr int totalSpacing=buttonSize+itemSpacing;
|
||||
|
||||
Menu*inventoryWindow=new Menu(CENTERED,{totalSpacing*invWidth-itemSpacing,totalSpacing*(invHeight+1)-itemSpacing});
|
||||
vf2d windowSize={totalSpacing*invWidth-itemSpacing+1,totalSpacing*(invHeight+1)-itemSpacing+24};
|
||||
|
||||
Menu*inventoryWindow=new Menu(CENTERED,windowSize);
|
||||
|
||||
MenuFunc useItemFunc=[](MenuFuncData data){
|
||||
MenuItemButton*button=(MenuItemButton*)data.component;
|
||||
@ -34,9 +36,9 @@ Menu*Menu::InitializeInventoryWindow(){
|
||||
}
|
||||
}
|
||||
|
||||
MenuLabel*itemNameLabel=new MenuLabel{INVENTORY,vf2d{0,invHeight*totalSpacing-4},"",false,true};
|
||||
MenuLabel*itemNameLabel=new MenuLabel{INVENTORY,geom2d::rect<float>(vf2d{2,invHeight*totalSpacing-4},windowSize),"",false,true};
|
||||
inventoryWindow->AddComponent("itemName",itemNameLabel);
|
||||
MenuLabel*itemDescriptionLabel=new MenuLabel{INVENTORY,vf2d{2+inventoryWindow->size.x/2,invHeight*totalSpacing+4+itemSpacing},"",true,true};
|
||||
MenuLabel*itemDescriptionLabel=new MenuLabel{INVENTORY,geom2d::rect<float>(vf2d{2,invHeight*totalSpacing+itemSpacing},{windowSize.x-4,windowSize.y-108}),"",true,true};
|
||||
inventoryWindow->AddComponent("itemDescription",itemDescriptionLabel);
|
||||
|
||||
return inventoryWindow;
|
||||
|
||||
@ -17,7 +17,8 @@ Menu::Menu(){}
|
||||
|
||||
Menu::Menu(vf2d pos,vf2d size)
|
||||
:pos(pos==CENTERED?WINDOW_SIZE/2-size/2:vi2d{pos}),size(size){
|
||||
|
||||
r.Create(size.x,size.y);
|
||||
overlay.Create(WINDOW_SIZE.x,WINDOW_SIZE.y);
|
||||
}
|
||||
|
||||
void Menu::InitializeMenus(){
|
||||
@ -139,30 +140,65 @@ void Menu::Update(Crawler*game){
|
||||
};
|
||||
|
||||
void Menu::Draw(Crawler*game){
|
||||
|
||||
if(GetCurrentTheme().IsScaled()){
|
||||
DrawScaledWindow(game,pos);
|
||||
DrawScaledWindowBackground(game,pos);
|
||||
}else{
|
||||
DrawTiledWindow(game,pos);
|
||||
DrawTiledWindowBackground(game,pos);
|
||||
}
|
||||
|
||||
game->SetDrawTarget(r.Sprite());
|
||||
Pixel::Mode prevMode=game->GetPixelMode();
|
||||
game->SetPixelMode(Pixel::MASK);
|
||||
game->Clear(BLANK);
|
||||
for(auto&key:buttons){
|
||||
for(auto&button:key.second){
|
||||
button->Draw(game,pos,this==Menu::stack.back());
|
||||
button->Draw(game,{0,0},this==Menu::stack.back());
|
||||
}
|
||||
}
|
||||
for(auto&component:displayComponents){
|
||||
component->Draw(game,pos,this==Menu::stack.back());
|
||||
component->Draw(game,{0,0},this==Menu::stack.back());
|
||||
}
|
||||
game->SetPixelMode(prevMode);
|
||||
game->SetDrawTarget(nullptr);
|
||||
r.Decal()->Update();
|
||||
game->DrawDecal(pos,r.Decal());
|
||||
for(auto&key:buttons){
|
||||
for(auto&button:key.second){
|
||||
button->DrawDecal(game,{0,0},this==Menu::stack.back());
|
||||
}
|
||||
}
|
||||
for(auto&component:displayComponents){
|
||||
component->DrawDecal(game,{0,0},this==Menu::stack.back());
|
||||
}
|
||||
|
||||
if(GetCurrentTheme().IsScaled()){
|
||||
DrawScaledWindowBorder(game,pos);
|
||||
}else{
|
||||
DrawTiledWindowBorder(game,pos);
|
||||
}
|
||||
|
||||
if(draggingComponent!=nullptr){
|
||||
game->SetDrawTarget(overlay.Sprite());
|
||||
Pixel::Mode prevMode=game->GetPixelMode();
|
||||
game->SetPixelMode(Pixel::MASK);
|
||||
game->Clear(BLANK);
|
||||
vf2d offsetPos=draggingComponent->rect.pos;
|
||||
if(!MOUSE_NAVIGATION){
|
||||
MenuComponent*selectedComponent=buttons[selection.y][selection.x];
|
||||
draggingComponent->Draw(game,pos+-offsetPos+selectedComponent->rect.pos+vi2d{1,-4},this==Menu::stack.back());
|
||||
draggingComponent->Draw(game,pos-offsetPos+selectedComponent->rect.pos+vi2d{1,-4},this==Menu::stack.back());
|
||||
}else{
|
||||
draggingComponent->Draw(game,-offsetPos+game->GetMousePos(),this==Menu::stack.back());
|
||||
}
|
||||
game->SetPixelMode(prevMode);
|
||||
game->SetDrawTarget(nullptr);
|
||||
overlay.Decal()->Update();
|
||||
game->DrawDecal({0,0},overlay.Decal());
|
||||
if(!MOUSE_NAVIGATION){
|
||||
MenuComponent*selectedComponent=buttons[selection.y][selection.x];
|
||||
draggingComponent->DrawDecal(game,-offsetPos+selectedComponent->rect.pos+vi2d{1,-4},this==Menu::stack.back());
|
||||
}else{
|
||||
draggingComponent->DrawDecal(game,-pos-offsetPos+game->GetMousePos(),this==Menu::stack.back());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -299,7 +335,7 @@ void Menu::KeyboardButtonNavigation(Crawler*game,vf2d menuPos){
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::DrawScaledWindow(Crawler*game,vf2d menuPos){
|
||||
void Menu::DrawScaledWindowBorder(Crawler*game,vf2d menuPos){
|
||||
vf2d patchSize={"Interface.9PatchSize"_f[0],"Interface.9PatchSize"_f[1]};
|
||||
|
||||
//Upper-Left
|
||||
@ -318,16 +354,9 @@ void Menu::DrawScaledWindow(Crawler*game,vf2d menuPos){
|
||||
game->DrawPartialDecal(menuPos+vf2d{size.x,0},vf2d{patchSize.x,size.y},GetPatchPart(2,1).Decal(),{patchSize.x*2,patchSize.y*1},patchSize,GetRenderColor());
|
||||
//Bottom
|
||||
game->DrawPartialDecal(menuPos+vf2d{0,size.y},vf2d{size.x,patchSize.y},GetPatchPart(1,2).Decal(),{patchSize.x*1,patchSize.y*2},patchSize,GetRenderColor());
|
||||
//Center
|
||||
if(GetCurrentTheme().HasBackground()){
|
||||
Decal*back=GetCurrentTheme().GetBackground();
|
||||
game->DrawPartialDecal(menuPos,size,back,{0,0},back->sprite->Size(),GetRenderColor());
|
||||
}else{
|
||||
game->DrawPartialDecal(menuPos,size,GetPatchPart(1,1).Decal(),{patchSize.x*1,patchSize.y*1},patchSize,GetRenderColor());
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::DrawTiledWindow(Crawler*game,vf2d menuPos){
|
||||
void Menu::DrawTiledWindowBorder(Crawler*game,vf2d menuPos){
|
||||
vf2d patchSize={"Interface.9PatchSize"_f[0],"Interface.9PatchSize"_f[1]};
|
||||
|
||||
//Upper-Left
|
||||
@ -346,6 +375,23 @@ void Menu::DrawTiledWindow(Crawler*game,vf2d menuPos){
|
||||
game->DrawPartialDecal(menuPos+vf2d{size.x,0},vf2d{patchSize.x,size.y},GetPatchPart(2,1).Decal(),{0,0},vf2d{patchSize.x,size.y},GetRenderColor());
|
||||
//Bottom
|
||||
game->DrawPartialDecal(menuPos+vf2d{0,size.y},vf2d{size.x,patchSize.y},GetPatchPart(1,2).Decal(),{0,0},vf2d{size.x,patchSize.y},GetRenderColor());
|
||||
}
|
||||
|
||||
void Menu::DrawScaledWindowBackground(Crawler*game,vf2d menuPos){
|
||||
vf2d patchSize={"Interface.9PatchSize"_f[0],"Interface.9PatchSize"_f[1]};
|
||||
|
||||
//Center
|
||||
if(GetCurrentTheme().HasBackground()){
|
||||
Decal*back=GetCurrentTheme().GetBackground();
|
||||
game->DrawPartialDecal(menuPos,size,back,{0,0},back->sprite->Size(),GetRenderColor());
|
||||
}else{
|
||||
game->DrawPartialDecal(menuPos,size,GetPatchPart(1,1).Decal(),{patchSize.x*1,patchSize.y*1},patchSize,GetRenderColor());
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::DrawTiledWindowBackground(Crawler*game,vf2d menuPos){
|
||||
vf2d patchSize={"Interface.9PatchSize"_f[0],"Interface.9PatchSize"_f[1]};
|
||||
|
||||
//Center
|
||||
if(GetCurrentTheme().HasBackground()){
|
||||
Decal*back=GetCurrentTheme().GetBackground();
|
||||
|
||||
@ -24,18 +24,15 @@ class Menu:IAttributable{
|
||||
friend class Crawler;
|
||||
friend class Player;
|
||||
static bool MOUSE_NAVIGATION;
|
||||
static std::map<MenuType,Menu*>menus;
|
||||
|
||||
float buttonHoldTime=0;
|
||||
std::map<int/*Y*/,std::vector<MenuComponent*>>buttons; //Buttons are stored in rows followed by their column order.
|
||||
std::map<int/*Y*/,std::vector<MenuComponent*>>newButtonArrangement; //The new setup that the buttons will be at if a drag operation completes.
|
||||
std::vector<MenuComponent*>displayComponents; //Components that are only for displaying purposes.
|
||||
vi2d selection={-1,-1};
|
||||
vf2d pos; //Specify the upper-left corner of the window. Using CENTERED will always put this where the upper-left corner would center the window.
|
||||
vf2d size; //Size in tiles (24x24), every menu will be tile-based
|
||||
|
||||
MenuComponent*draggingComponent=nullptr;
|
||||
Renderable r;
|
||||
Renderable r,overlay;
|
||||
public:
|
||||
Menu();
|
||||
Menu(vf2d pos,vf2d size);
|
||||
@ -49,6 +46,9 @@ public:
|
||||
static safeunorderedmap<std::string,Theme>themes;
|
||||
static const vf2d CENTERED;
|
||||
safemap<std::string,MenuComponent*>components; //A friendly way to interrogate any component we are interested in.
|
||||
static std::map<MenuType,Menu*>menus;
|
||||
vf2d pos; //Specify the upper-left corner of the window. Using CENTERED will always put this where the upper-left corner would center the window.
|
||||
vf2d size; //Size in tiles (24x24), every menu will be tile-based
|
||||
|
||||
private:
|
||||
void HoverMenuSelect(Crawler*game);
|
||||
@ -63,8 +63,10 @@ private:
|
||||
static Theme&GetCurrentTheme();
|
||||
|
||||
void KeyboardButtonNavigation(Crawler*game,vf2d menuPos);
|
||||
void DrawScaledWindow(Crawler*game,vf2d menuPos);
|
||||
void DrawTiledWindow(Crawler*game,vf2d menuPos);
|
||||
void DrawScaledWindowBackground(Crawler*game,vf2d menuPos);
|
||||
void DrawTiledWindowBackground(Crawler*game,vf2d menuPos);
|
||||
void DrawScaledWindowBorder(Crawler*game,vf2d menuPos);
|
||||
void DrawTiledWindowBorder(Crawler*game,vf2d menuPos);
|
||||
|
||||
Pixel GetRenderColor();
|
||||
};
|
||||
|
||||
@ -16,13 +16,15 @@ void MenuComponent::Update(Crawler*game){
|
||||
}
|
||||
|
||||
void MenuComponent::Draw(Crawler*game,vf2d parentPos,bool focused){
|
||||
game->FillRectDecal(rect.pos+parentPos,rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),hoverEffect/"ThemeGlobal.HighlightTime"_F)*(focused?1:"ThemeGlobal.MenuUnfocusedColorMult"_F));
|
||||
game->FillRect(rect.pos+parentPos,rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),hoverEffect/"ThemeGlobal.HighlightTime"_F)*(focused?1:"ThemeGlobal.MenuUnfocusedColorMult"_F));
|
||||
if(border){
|
||||
game->DrawRectDecal(rect.pos+parentPos,rect.size,focused?GREY:GREY*"ThemeGlobal.MenuUnfocusedColorMult"_F);
|
||||
game->DrawRect(rect.pos+parentPos,rect.size,focused?GREY:GREY*"ThemeGlobal.MenuUnfocusedColorMult"_F);
|
||||
}
|
||||
game->DrawStringPropDecal(rect.pos+parentPos+rect.size/2-game->GetTextSizeProp(label)/2,label,focused?WHITE:WHITE*"ThemeGlobal.MenuUnfocusedColorMult"_F);
|
||||
game->DrawStringProp(rect.pos+parentPos+rect.size/2-game->GetTextSizeProp(label)/2,label,focused?WHITE:WHITE*"ThemeGlobal.MenuUnfocusedColorMult"_F);
|
||||
}
|
||||
|
||||
void MenuComponent::DrawDecal(Crawler*game,vf2d parentPos,bool focused){}
|
||||
|
||||
MenuComponent*MenuComponent::PickUpDraggableItem(){
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ public:
|
||||
MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,bool selectable=true);
|
||||
virtual void Update(Crawler*game);
|
||||
virtual void Draw(Crawler*game,vf2d parentPos,bool focused);
|
||||
virtual void DrawDecal(Crawler*game,vf2d parentPos,bool focused);
|
||||
//We picked up a draggable component, we should make a copy and return it here. If a nullptr is returned here, the pickup is not allowed.
|
||||
//WARNING!!! This allocates a brand new component when successful!!! Be prepared to clear it!
|
||||
virtual MenuComponent*PickUpDraggableItem();
|
||||
|
||||
@ -18,7 +18,7 @@ protected:
|
||||
virtual inline void Draw(Crawler*game,vf2d parentPos,bool focused)override{
|
||||
MenuComponent::Draw(game,parentPos,focused);
|
||||
if(icon!=nullptr){
|
||||
game->DrawRotatedDecal(parentPos+rect.middle(),icon,0,icon->sprite->Size()/2,{1,1},focused?WHITE:WHITE*"ThemeGlobal.MenuUnfocusedColorMult"_F);
|
||||
game->DrawSprite(parentPos+rect.middle()-icon->sprite->Size()/2,icon->sprite,1,Sprite::Flip::NONE,[&](Pixel&in){return focused?in:in*"ThemeGlobal.MenuUnfocusedColorMult"_F;});
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -4,6 +4,7 @@
|
||||
#include "Crawler.h"
|
||||
#include "Item.h"
|
||||
#include "safemap.h"
|
||||
#include "olcPGEX_Graphics2D.h"
|
||||
|
||||
INCLUDE_game
|
||||
INCLUDE_ITEM_DATA
|
||||
@ -57,12 +58,12 @@ protected:
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual inline void Draw(Crawler*game,vf2d parentPos,bool focused)override{
|
||||
MenuIconButton::Draw(game,parentPos,focused);
|
||||
virtual inline void DrawDecal(Crawler*game,vf2d parentPos,bool focused)override{
|
||||
MenuIconButton::DrawDecal(game,parentPos,focused);
|
||||
if(valid){
|
||||
std::string quantityText="x"+std::to_string(Inventory::GetItemCount(invRef.at(inventoryIndex)));
|
||||
vf2d textSize=vf2d(game->GetTextSizeProp(quantityText))*0.5;
|
||||
game->DrawShadowStringDecal(parentPos+rect.pos+rect.size-textSize,quantityText,WHITE,BLACK,{0.5,0.5},0.5);
|
||||
game->DrawShadowStringDecal(Menu::menus[parentMenu]->pos+parentPos+rect.pos+rect.size-textSize,quantityText,WHITE,BLACK,{0.5,0.5},0.5);
|
||||
}
|
||||
}
|
||||
virtual inline MenuComponent*PickUpDraggableItem()override{
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include "MenuComponent.h"
|
||||
#include "DEFINES.h"
|
||||
#include "Crawler.h"
|
||||
#include "utils.h"
|
||||
|
||||
INCLUDE_game
|
||||
|
||||
@ -21,14 +22,15 @@ protected:
|
||||
MenuComponent::Update(game);
|
||||
}
|
||||
virtual void inline Draw(Crawler*game,vf2d parentPos,bool focused)override{
|
||||
vf2d drawPos=rect.pos+parentPos+rect.size/2-game->GetTextSizeProp(label)/2; //Assume centered.
|
||||
std::string wrappedText=util::WrapText(game,label,rect.size.x,true,{1,1});
|
||||
vf2d drawPos=parentPos+rect.middle()-game->GetTextSizeProp(wrappedText)/2; //Assume centered.
|
||||
if(!centered){
|
||||
drawPos=rect.pos+parentPos;
|
||||
}
|
||||
if(shadow){
|
||||
game->DrawShadowStringPropDecal(drawPos,label,focused?WHITE:WHITE*"ThemeGlobal.MenuUnfocusedColorMult"_F);
|
||||
game->DrawShadowStringProp(drawPos,wrappedText,focused?WHITE:WHITE*"ThemeGlobal.MenuUnfocusedColorMult"_F);
|
||||
}else{
|
||||
game->DrawStringPropDecal(drawPos,label,focused?WHITE:WHITE*"ThemeGlobal.MenuUnfocusedColorMult"_F);
|
||||
game->DrawStringProp(drawPos,wrappedText,focused?WHITE:WHITE*"ThemeGlobal.MenuUnfocusedColorMult"_F);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -2,7 +2,7 @@
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 2
|
||||
#define VERSION_PATCH 0
|
||||
#define VERSION_BUILD 1899
|
||||
#define VERSION_BUILD 1954
|
||||
|
||||
#define stringify(a) stringify_(a)
|
||||
#define stringify_(a) #a
|
||||
|
||||
313
Crawler/olcPGEX_Graphics2D.h
Normal file
313
Crawler/olcPGEX_Graphics2D.h
Normal file
@ -0,0 +1,313 @@
|
||||
/*
|
||||
olcPGEX_Graphics2D.h
|
||||
|
||||
+-------------------------------------------------------------+
|
||||
| OneLoneCoder Pixel Game Engine Extension |
|
||||
| Advanced 2D Rendering - v0.5 |
|
||||
+-------------------------------------------------------------+
|
||||
|
||||
What is this?
|
||||
~~~~~~~~~~~~~
|
||||
This is an extension to the olcPixelGameEngine, which provides
|
||||
advanced olc::Sprite manipulation and drawing routines. To use
|
||||
it, simply include this header file.
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018 - 2019 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2019
|
||||
*/
|
||||
|
||||
/*
|
||||
Matrices stored as [Column][Row] (i.e. x, y)
|
||||
|
||||
|C0R0 C1R0 C2R0| | x | | x'|
|
||||
|C0R1 C1R1 C2R1| * | y | = | y'|
|
||||
|C0R2 C1R2 C2R2| |1.0| | - |
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef OLC_PGEX_GFX2D
|
||||
#define OLC_PGEX_GFX2D
|
||||
|
||||
#include <algorithm>
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
namespace olc
|
||||
{
|
||||
// Container class for Advanced 2D Drawing functions
|
||||
class GFX2D : public olc::PGEX
|
||||
{
|
||||
// A representation of an affine transform, used to rotate, scale, offset & shear space
|
||||
public:
|
||||
class Transform2D
|
||||
{
|
||||
public:
|
||||
Transform2D();
|
||||
|
||||
public:
|
||||
// Set this transformation to unity
|
||||
void Reset();
|
||||
// Append a rotation of fTheta radians to this transform
|
||||
void Rotate(float fTheta);
|
||||
// Append a translation (ox, oy) to this transform
|
||||
void Translate(float ox, float oy);
|
||||
// Append a scaling operation (sx, sy) to this transform
|
||||
void Scale(float sx, float sy);
|
||||
// Append a shear operation (sx, sy) to this transform
|
||||
void Shear(float sx, float sy);
|
||||
|
||||
void Perspective(float ox, float oy);
|
||||
// Calculate the Forward Transformation of the coordinate (in_x, in_y) -> (out_x, out_y)
|
||||
void Forward(float in_x, float in_y, float &out_x, float &out_y);
|
||||
// Calculate the Inverse Transformation of the coordinate (in_x, in_y) -> (out_x, out_y)
|
||||
void Backward(float in_x, float in_y, float &out_x, float &out_y);
|
||||
// Regenerate the Inverse Transformation
|
||||
void Invert();
|
||||
|
||||
private:
|
||||
void Multiply();
|
||||
float matrix[4][3][3];
|
||||
int nTargetMatrix;
|
||||
int nSourceMatrix;
|
||||
bool bDirty;
|
||||
};
|
||||
|
||||
public:
|
||||
// Draws a sprite with the transform applied
|
||||
static void DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#ifdef OLC_PGEX_GRAPHICS2D
|
||||
#undef OLC_PGEX_GRAPHICS2D
|
||||
|
||||
namespace olc
|
||||
{
|
||||
void GFX2D::DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform)
|
||||
{
|
||||
if (sprite == nullptr)
|
||||
return;
|
||||
|
||||
// Work out bounding rectangle of sprite
|
||||
float ex, ey;
|
||||
float sx, sy;
|
||||
float px, py;
|
||||
|
||||
transform.Forward(0.0f, 0.0f, sx, sy);
|
||||
px = sx; py = sy;
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
transform.Forward((float)sprite->width, (float)sprite->height, px, py);
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
transform.Forward(0.0f, (float)sprite->height, px, py);
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
transform.Forward((float)sprite->width, 0.0f, px, py);
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
// Perform inversion of transform if required
|
||||
transform.Invert();
|
||||
|
||||
if (ex < sx)
|
||||
std::swap(ex, sx);
|
||||
if (ey < sy)
|
||||
std::swap(ey, sy);
|
||||
|
||||
// Iterate through render space, and sample Sprite from suitable texel location
|
||||
for (float i = sx; i < ex; i++)
|
||||
{
|
||||
for (float j = sy; j < ey; j++)
|
||||
{
|
||||
float ox, oy;
|
||||
transform.Backward(i, j, ox, oy);
|
||||
pge->Draw((int32_t)i, (int32_t)j, sprite->GetPixel((int32_t)(ox+0.5f), (int32_t)(oy+0.5f)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
olc::GFX2D::Transform2D::Transform2D()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Reset()
|
||||
{
|
||||
nTargetMatrix = 0;
|
||||
nSourceMatrix = 1;
|
||||
bDirty = true;
|
||||
|
||||
// Columns Then Rows
|
||||
|
||||
// Matrices 0 & 1 are used as swaps in Transform accumulation
|
||||
matrix[0][0][0] = 1.0f; matrix[0][1][0] = 0.0f; matrix[0][2][0] = 0.0f;
|
||||
matrix[0][0][1] = 0.0f; matrix[0][1][1] = 1.0f; matrix[0][2][1] = 0.0f;
|
||||
matrix[0][0][2] = 0.0f; matrix[0][1][2] = 0.0f; matrix[0][2][2] = 1.0f;
|
||||
|
||||
matrix[1][0][0] = 1.0f; matrix[1][1][0] = 0.0f; matrix[1][2][0] = 0.0f;
|
||||
matrix[1][0][1] = 0.0f; matrix[1][1][1] = 1.0f; matrix[1][2][1] = 0.0f;
|
||||
matrix[1][0][2] = 0.0f; matrix[1][1][2] = 0.0f; matrix[1][2][2] = 1.0f;
|
||||
|
||||
// Matrix 2 is a cache matrix to hold the immediate transform operation
|
||||
// Matrix 3 is a cache matrix to hold the inverted transform
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Multiply()
|
||||
{
|
||||
for (int c = 0; c < 3; c++)
|
||||
{
|
||||
for (int r = 0; r < 3; r++)
|
||||
{
|
||||
matrix[nTargetMatrix][c][r] = matrix[2][0][r] * matrix[nSourceMatrix][c][0] +
|
||||
matrix[2][1][r] * matrix[nSourceMatrix][c][1] +
|
||||
matrix[2][2][r] * matrix[nSourceMatrix][c][2];
|
||||
}
|
||||
}
|
||||
|
||||
std::swap(nTargetMatrix, nSourceMatrix);
|
||||
bDirty = true; // Any transform multiply dirties the inversion
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Rotate(float fTheta)
|
||||
{
|
||||
// Construct Rotation Matrix
|
||||
matrix[2][0][0] = cosf(fTheta); matrix[2][1][0] = sinf(fTheta); matrix[2][2][0] = 0.0f;
|
||||
matrix[2][0][1] = -sinf(fTheta); matrix[2][1][1] = cosf(fTheta); matrix[2][2][1] = 0.0f;
|
||||
matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
|
||||
Multiply();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Scale(float sx, float sy)
|
||||
{
|
||||
// Construct Scale Matrix
|
||||
matrix[2][0][0] = sx; matrix[2][1][0] = 0.0f; matrix[2][2][0] = 0.0f;
|
||||
matrix[2][0][1] = 0.0f; matrix[2][1][1] = sy; matrix[2][2][1] = 0.0f;
|
||||
matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
|
||||
Multiply();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Shear(float sx, float sy)
|
||||
{
|
||||
// Construct Shear Matrix
|
||||
matrix[2][0][0] = 1.0f; matrix[2][1][0] = sx; matrix[2][2][0] = 0.0f;
|
||||
matrix[2][0][1] = sy; matrix[2][1][1] = 1.0f; matrix[2][2][1] = 0.0f;
|
||||
matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
|
||||
Multiply();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Translate(float ox, float oy)
|
||||
{
|
||||
// Construct Translate Matrix
|
||||
matrix[2][0][0] = 1.0f; matrix[2][1][0] = 0.0f; matrix[2][2][0] = ox;
|
||||
matrix[2][0][1] = 0.0f; matrix[2][1][1] = 1.0f; matrix[2][2][1] = oy;
|
||||
matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
|
||||
Multiply();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Perspective(float ox, float oy)
|
||||
{
|
||||
// Construct Translate Matrix
|
||||
matrix[2][0][0] = 1.0f; matrix[2][1][0] = 0.0f; matrix[2][2][0] = 0.0f;
|
||||
matrix[2][0][1] = 0.0f; matrix[2][1][1] = 1.0f; matrix[2][2][1] = 0.0f;
|
||||
matrix[2][0][2] = ox; matrix[2][1][2] = oy; matrix[2][2][2] = 1.0f;
|
||||
Multiply();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Forward(float in_x, float in_y, float &out_x, float &out_y)
|
||||
{
|
||||
out_x = in_x * matrix[nSourceMatrix][0][0] + in_y * matrix[nSourceMatrix][1][0] + matrix[nSourceMatrix][2][0];
|
||||
out_y = in_x * matrix[nSourceMatrix][0][1] + in_y * matrix[nSourceMatrix][1][1] + matrix[nSourceMatrix][2][1];
|
||||
float out_z = in_x * matrix[nSourceMatrix][0][2] + in_y * matrix[nSourceMatrix][1][2] + matrix[nSourceMatrix][2][2];
|
||||
if (out_z != 0)
|
||||
{
|
||||
out_x /= out_z;
|
||||
out_y /= out_z;
|
||||
}
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Backward(float in_x, float in_y, float &out_x, float &out_y)
|
||||
{
|
||||
out_x = in_x * matrix[3][0][0] + in_y * matrix[3][1][0] + matrix[3][2][0];
|
||||
out_y = in_x * matrix[3][0][1] + in_y * matrix[3][1][1] + matrix[3][2][1];
|
||||
float out_z = in_x * matrix[3][0][2] + in_y * matrix[3][1][2] + matrix[3][2][2];
|
||||
if (out_z != 0)
|
||||
{
|
||||
out_x /= out_z;
|
||||
out_y /= out_z;
|
||||
}
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Invert()
|
||||
{
|
||||
if (bDirty) // Obviously costly so only do if needed
|
||||
{
|
||||
float det = matrix[nSourceMatrix][0][0] * (matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][1][2] * matrix[nSourceMatrix][2][1]) -
|
||||
matrix[nSourceMatrix][1][0] * (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][2][1] * matrix[nSourceMatrix][0][2]) +
|
||||
matrix[nSourceMatrix][2][0] * (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][0][2]);
|
||||
|
||||
float idet = 1.0f / det;
|
||||
matrix[3][0][0] = (matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][1][2] * matrix[nSourceMatrix][2][1]) * idet;
|
||||
matrix[3][1][0] = (matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][1][0] * matrix[nSourceMatrix][2][2]) * idet;
|
||||
matrix[3][2][0] = (matrix[nSourceMatrix][1][0] * matrix[nSourceMatrix][2][1] - matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][1][1]) * idet;
|
||||
matrix[3][0][1] = (matrix[nSourceMatrix][2][1] * matrix[nSourceMatrix][0][2] - matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][2]) * idet;
|
||||
matrix[3][1][1] = (matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][0][2]) * idet;
|
||||
matrix[3][2][1] = (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][0] - matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][2][1]) * idet;
|
||||
matrix[3][0][2] = (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][0][2] * matrix[nSourceMatrix][1][1]) * idet;
|
||||
matrix[3][1][2] = (matrix[nSourceMatrix][0][2] * matrix[nSourceMatrix][1][0] - matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][1][2]) * idet;
|
||||
matrix[3][2][2] = (matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][1][1] - matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][0]) * idet;
|
||||
bDirty = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@ -805,6 +805,7 @@ namespace olc
|
||||
|
||||
public:
|
||||
void SetSampleMode(olc::Sprite::Mode mode = olc::Sprite::Mode::NORMAL);
|
||||
void Resize(int32_t w, int32_t h);
|
||||
Pixel GetPixel(int32_t x, int32_t y) const;
|
||||
bool SetPixel(int32_t x, int32_t y, Pixel p);
|
||||
Pixel GetPixel(const olc::vi2d& a) const;
|
||||
@ -1093,20 +1094,21 @@ namespace olc
|
||||
void FillTexturedTriangle(const std::vector<olc::vf2d>& vPoints, std::vector<olc::vf2d> vTex, std::vector<olc::Pixel> vColour, olc::Sprite* sprTex);
|
||||
void FillTexturedPolygon(const std::vector<olc::vf2d>& vPoints, const std::vector<olc::vf2d>& vTex, const std::vector<olc::Pixel>& vColour, olc::Sprite* sprTex, olc::DecalStructure structure = olc::DecalStructure::LIST);
|
||||
// Draws an entire sprite at location (x,y)
|
||||
void DrawSprite(int32_t x, int32_t y, Sprite* sprite, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE);
|
||||
void DrawSprite(const olc::vi2d& pos, Sprite* sprite, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE);
|
||||
void DrawSprite(int32_t x, int32_t y, Sprite* sprite, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE, std::function<Pixel(Pixel&)>colorFunc=[](Pixel&in){return in;});
|
||||
void DrawSprite(const olc::vi2d& pos, Sprite* sprite, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE, std::function<Pixel(Pixel&)>colorFunc=[](Pixel&in){return in;});
|
||||
// Draws an area of a sprite at location (x,y), where the
|
||||
// selected area is (ox,oy) to (ox+w,oy+h)
|
||||
void DrawPartialSprite(int32_t x, int32_t y, Sprite* sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE);
|
||||
void DrawPartialSprite(const olc::vi2d& pos, Sprite* sprite, const olc::vi2d& sourcepos, const olc::vi2d& size, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE);
|
||||
// Draws a single line of text - traditional monospaced
|
||||
void DrawString(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
|
||||
void DrawString(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
|
||||
olc::vi2d GetTextSize(const std::string& s);
|
||||
// Draws a single line of text - non-monospaced
|
||||
void DrawStringProp(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
|
||||
void DrawStringProp(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
|
||||
void DrawShadowString(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float shadowSizeFactor=1);
|
||||
void DrawStringProp(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
|
||||
void DrawShadowStringProp(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float shadowSizeFactor=1);
|
||||
olc::vi2d GetTextSize(const std::string& s);
|
||||
olc::vi2d GetTextSizeProp(const std::string& s);
|
||||
void DrawString(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
|
||||
void DrawString(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
|
||||
|
||||
// Decal Quad functions
|
||||
void SetDecalMode(const olc::DecalMode& mode);
|
||||
@ -1597,6 +1599,13 @@ namespace olc
|
||||
Sprite::~Sprite()
|
||||
{ pColData.clear(); }
|
||||
|
||||
void Sprite::Resize(int32_t w, int32_t h)
|
||||
{
|
||||
width = w; height = h;
|
||||
pColData.resize(width * height);
|
||||
pColData.resize(width * height, nDefaultPixel);
|
||||
}
|
||||
|
||||
void Sprite::SetSampleMode(olc::Sprite::Mode mode)
|
||||
{ modeSample = mode; }
|
||||
|
||||
@ -2759,10 +2768,10 @@ namespace olc
|
||||
}
|
||||
|
||||
|
||||
void PixelGameEngine::DrawSprite(const olc::vi2d& pos, Sprite* sprite, uint32_t scale, uint8_t flip)
|
||||
void PixelGameEngine::DrawSprite(const olc::vi2d& pos, Sprite* sprite, uint32_t scale, uint8_t flip, std::function<Pixel(Pixel&)>colorFunc)
|
||||
{ DrawSprite(pos.x, pos.y, sprite, scale, flip); }
|
||||
|
||||
void PixelGameEngine::DrawSprite(int32_t x, int32_t y, Sprite* sprite, uint32_t scale, uint8_t flip)
|
||||
void PixelGameEngine::DrawSprite(int32_t x, int32_t y, Sprite* sprite, uint32_t scale, uint8_t flip, std::function<Pixel(Pixel&)>colorFunc)
|
||||
{
|
||||
if (sprite == nullptr)
|
||||
return;
|
||||
@ -3327,6 +3336,29 @@ namespace olc
|
||||
}
|
||||
DrawStringPropDecal(pos, sText, col,scale);
|
||||
}
|
||||
|
||||
void PixelGameEngine::DrawShadowString(const olc::vi2d& pos, const std::string& sText, Pixel col, const Pixel shadowCol, const olc::vf2d& scale,const float shadowSizeFactor){
|
||||
for(float y=-shadowSizeFactor;y<=shadowSizeFactor+0.1;y+=shadowSizeFactor/2){
|
||||
for(float x=-shadowSizeFactor;x<=shadowSizeFactor+0.1;x+=shadowSizeFactor/2){
|
||||
if(x!=0||y!=0){
|
||||
DrawString(pos.x+x,pos.y+y, sText, shadowCol,int(scale.x));
|
||||
}
|
||||
}
|
||||
}
|
||||
DrawString(pos.x,pos.y, sText, col,int(scale.x));
|
||||
}
|
||||
|
||||
void PixelGameEngine::DrawShadowStringProp(const olc::vi2d& pos, const std::string& sText, Pixel col, const Pixel shadowCol, const olc::vf2d& scale,const float shadowSizeFactor){
|
||||
for(float y=-shadowSizeFactor;y<=shadowSizeFactor+0.1;y+=shadowSizeFactor/2){
|
||||
for(float x=-shadowSizeFactor;x<=shadowSizeFactor+0.1;x+=shadowSizeFactor/2){
|
||||
if(x!=0||y!=0){
|
||||
DrawStringProp(pos.x+x,pos.y+y, sText, shadowCol,int(scale.x));
|
||||
}
|
||||
}
|
||||
}
|
||||
DrawStringProp(pos.x,pos.y, sText, col,int(scale.x));
|
||||
}
|
||||
|
||||
// Thanks Oso-Grande/Sopadeoso For these awesom and stupidly clever Text Rotation routines... duh XD
|
||||
void PixelGameEngine::DrawRotatedStringDecal(const olc::vf2d& pos, const std::string& sText, const float fAngle, const olc::vf2d& center, const Pixel col, const olc::vf2d& scale)
|
||||
{
|
||||
|
||||
@ -6,4 +6,6 @@
|
||||
#define TMX_PARSER_SETUP
|
||||
#include "TMXParser.h"
|
||||
#define TSX_PARSER_SETUP
|
||||
#include "TSXParser.h"
|
||||
#include "TSXParser.h"
|
||||
#define OLC_PGEX_GRAPHICS2D
|
||||
#include "olcPGEX_Graphics2D.h"
|
||||
@ -1,4 +1,5 @@
|
||||
#include "utils.h"
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
float util::random(float range){
|
||||
return float(rand())/RAND_MAX*range;
|
||||
@ -42,4 +43,28 @@ std::string util::timerStr(float time){
|
||||
timeStr+=std::to_string(seconds%60);
|
||||
|
||||
return timeStr;
|
||||
}
|
||||
|
||||
std::string util::WrapText(PixelGameEngine*pge,std::string str,int width,bool proportional,vd2d scale){
|
||||
std::string newStr;
|
||||
while (true) {
|
||||
std::string word;
|
||||
if (str.find(" ")==std::string::npos) {
|
||||
word=str;
|
||||
} else {
|
||||
word = str.substr(0,str.find(" "));
|
||||
}
|
||||
vi2d newSize = vd2d(proportional?pge->GetTextSizeProp(newStr+(newStr.size()>0?" ":"")+word):pge->GetTextSize(newStr+(newStr.size()>0?" ":"")+word))*scale;
|
||||
if (newSize.x>width) {
|
||||
newStr+="\n"+word;
|
||||
} else {
|
||||
newStr+=(newStr.size()>0?" ":"")+word;
|
||||
}
|
||||
if (str.find(" ")==std::string::npos) {
|
||||
break;
|
||||
} else {
|
||||
str.erase(0,str.find(" ")+1);
|
||||
}
|
||||
}
|
||||
return newStr;
|
||||
}
|
||||
@ -12,4 +12,5 @@ namespace util{
|
||||
float radToDeg(float rad);
|
||||
float lerp(float n1,float n2,double t);
|
||||
std::string timerStr(float time);
|
||||
std::string WrapText(PixelGameEngine*pge,std::string str,int width,bool proportional,vd2d scale);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user