Prepare framework with Draw and DrawDecal split.

pull/28/head
sigonasr2 1 year ago
parent dd2ff24d85
commit e3d0283fcb
  1. 1
      Crawler/Crawler.vcxproj
  2. 3
      Crawler/Crawler.vcxproj.filters
  3. 8
      Crawler/InventoryWindow.cpp
  4. 78
      Crawler/Menu.cpp
  5. 14
      Crawler/Menu.h
  6. 8
      Crawler/MenuComponent.cpp
  7. 1
      Crawler/MenuComponent.h
  8. 2
      Crawler/MenuIconButton.h
  9. 7
      Crawler/MenuItemButton.h
  10. 8
      Crawler/MenuLabel.h
  11. 2
      Crawler/Version.h
  12. 313
      Crawler/olcPGEX_Graphics2D.h
  13. 50
      Crawler/olcPixelGameEngine.h
  14. 4
      Crawler/pixelGameEngine.cpp
  15. 25
      Crawler/utils.cpp
  16. 1
      Crawler/utils.h

@ -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,{0,0},this==Menu::stack.back());
}
}
for(auto&component:displayComponents){
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->Draw(game,pos,this==Menu::stack.back());
button->DrawDecal(game,{0,0},this==Menu::stack.back());
}
}
for(auto&component:displayComponents){
component->Draw(game,pos,this==Menu::stack.back());
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

@ -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…
Cancel
Save