Added scaling/tiling capabilities for themes. Safe maps have unordered version.

pull/28/head
sigonasr2 1 year ago
parent 999855c6e8
commit 10cfb009f7
  1. 2
      Crawler/Animation.cpp
  2. 32
      Crawler/Crawler.cpp
  3. 44
      Crawler/Menu.cpp
  4. 6
      Crawler/Menu.h
  5. 4
      Crawler/MenuComponent.cpp
  6. 2
      Crawler/Player.cpp
  7. 11
      Crawler/TestSubMenu.cpp
  8. 15
      Crawler/Theme.h
  9. 2
      Crawler/Version.h
  10. 3
      Crawler/assets/config/gfx/gfx.txt
  11. 42
      Crawler/assets/config/gfx/themes.txt
  12. BIN
      Crawler/assets/themes/9patch_3.png
  13. BIN
      Crawler/assets/themes/9patch_4.png
  14. BIN
      Crawler/assets/themes/testback.png
  15. BIN
      Crawler/assets/themes/testtiledback.png
  16. 5
      Crawler/olcUTIL_DataFile.h
  17. 63
      Crawler/safemap.h

@ -216,8 +216,6 @@ void sig::Animation::InitializeAnimations(){
if(!ANIMATION_DATA.count(imgFile)){
std::cout<<"WARNING! Animation data for "<<imgFile<<" not found! Auto-generating..."<<std::endl;
CreateStillAnimation(imgFile,GFX[imgFile].Sprite()->Size());
std::map<int,int>test;
test.begin();
}
}
}

@ -78,6 +78,7 @@ Crawler::Crawler()
utils::datafile::Read(DATA,CONFIG_PATH + "class_directory"_S + cl + ".txt");
}
utils::datafile::DEBUG_ACCESS_OPTIONS="debug_access_options"_I;
utils::datafile::INITIAL_SETUP_COMPLETE=true;
}
bool Crawler::OnUserCreate(){
@ -1682,7 +1683,7 @@ void Crawler::InitializeGraphics(){
std::string key=val.first;
std::string imgFile=DATA["Images"][key].GetString();
std::cout<<"Loading image "+imgFile+"..."<<std::endl;
if(GFX[imgFile].Load("GFX_Prefix"_S+imgFile,nullptr,false,false)!=rcode::OK){
if(!GFX.count(imgFile)&&GFX[imgFile].Load("GFX_Prefix"_S+imgFile,nullptr,false,false)!=rcode::OK){
std::cout<<" WARNING! Failed to load "+imgFile+"!";
throw;
}
@ -1692,23 +1693,38 @@ void Crawler::InitializeGraphics(){
for(auto&key:DATA["Themes"].GetKeys()){
std::string themeName=key.first;
std::string imgPath=DATA["Themes"][themeName]["Name"].GetString();
Renderable&patchImg=GFX["theme_img_directory"_S+imgPath+".png"];
Renderable&img=GFX["theme_img_directory"_S+imgPath+".png"];
img.Load("GFX_Prefix"_S+"theme_img_directory"_S+imgPath+".png");
Renderable&sourceImg=img;
Pixel::Mode prevMode=GetPixelMode();
SetPixelMode(Pixel::Mode::MASK);
for(int x=0;x<3;x++){
for(int y=0;y<3;y++){
std::string patchKey=imgPath+"_"+std::to_string(x)+std::to_string(y)+".png";
GFX[patchKey].Create("Interface.9PatchSize"_i[0],"Interface.9PatchSize"_i[1],false,false);
SetDrawTarget(GFX[patchKey].Sprite());
std::string patchKey=themeName+"_"+std::to_string(x)+std::to_string(y)+".png";
Renderable&patchImg=GFX[patchKey];
patchImg.Create("Interface.9PatchSize"_i[0],"Interface.9PatchSize"_i[1],false,false);
SetDrawTarget(patchImg.Sprite());
Clear(BLANK);
DrawPartialSprite({0,0},patchImg.Sprite(),{x*"Interface.9PatchSize"_i[0],y*"Interface.9PatchSize"_i[1]},{"Interface.9PatchSize"_i[0],"Interface.9PatchSize"_i[1]});
GFX[patchKey].Decal()->Update();
DrawPartialSprite({0,0},sourceImg.Sprite(),{x*"Interface.9PatchSize"_i[0],y*"Interface.9PatchSize"_i[1]},{"Interface.9PatchSize"_i[0],"Interface.9PatchSize"_i[1]});
patchImg.Decal()->Update();
SetDrawTarget(nullptr);
}
}
SetPixelMode(prevMode);
Menu::themes[imgPath]=Theme{themeName,imgPath,DATA["Themes"][themeName]["ButtonColor"].GetPixel(),DATA["Themes"][themeName]["HighlightColor"].GetPixel()};
std::cout<<"Theme "<<themeName<<" Loaded."<<std::endl;
if(DATA["Themes"][themeName].HasProperty("CustomBack")){
std::string backPath=DATA["Themes"][themeName]["CustomBack"].GetString();
std::cout<<" Custom background detected, Loading "<<backPath<<"..."<<std::endl;
if(!GFX.count(backPath)){
Renderable&background=GFX[backPath];
background.Load("GFX_Prefix"_S+backPath,nullptr,false,false);
}
Menu::themes[themeName]=Theme{themeName,imgPath,bool(DATA["Themes"][themeName]["Tiled"].GetInt()),DATA["Themes"][themeName]["ButtonColor"].GetPixel(),DATA["Themes"][themeName]["HighlightColor"].GetPixel(),GFX.at(backPath).Decal()};
}else{
Menu::themes[themeName]=Theme{themeName,imgPath,bool(DATA["Themes"][themeName]["Tiled"].GetInt()),DATA["Themes"][themeName]["ButtonColor"].GetPixel(),DATA["Themes"][themeName]["HighlightColor"].GetPixel()};
}
}
Menu::themes.SetInitialized();

@ -6,8 +6,8 @@
bool Menu::MOUSE_NAVIGATION=true;
std::vector<Menu*>Menu::stack;
std::map<MenuType,Menu>Menu::menus;
std::string Menu::themeSelection="9patch";
safemap<std::string,Theme>Menu::themes;
std::string Menu::themeSelection="BlueDefault";
safeunorderedmap<std::string,Theme>Menu::themes;
INCLUDE_GFX
@ -90,7 +90,7 @@ void Menu::Update(Crawler*game){
void Menu::Draw(Crawler*game){
vf2d upperLeftPos=game->GetScreenSize()/2-size/2;
if(scaled){
if(GetCurrentTheme().IsScaled()){
DrawScaledWindow(game,upperLeftPos);
}else{
DrawTiledWindow(game,upperLeftPos);
@ -239,31 +239,32 @@ void Menu::KeyboardButtonNavigation(Crawler*game,vf2d menuPos){
}
}
void Menu::SetScaledPatchBorder(bool scaled){
this->scaled=scaled;
}
void Menu::DrawScaledWindow(Crawler*game,vf2d menuPos){
vf2d patchSize={"Interface.9PatchSize"_f[0],"Interface.9PatchSize"_f[1]};
//Upper-Left
game->DrawPartialDecal(menuPos-patchSize,patchSize,GFX["9patch.png"].Decal(),{patchSize.x*0,patchSize.y*0},patchSize);
game->DrawPartialDecal(menuPos-patchSize,patchSize,GetPatchPart(0,0).Decal(),{patchSize.x*0,patchSize.y*0},patchSize);
//Upper-Right
game->DrawPartialDecal(menuPos+vf2d{size.x,-patchSize.y},patchSize,GFX["9patch.png"].Decal(),{patchSize.x*2,patchSize.y*0},patchSize);
game->DrawPartialDecal(menuPos+vf2d{size.x,-patchSize.y},patchSize,GetPatchPart(2,0).Decal(),{patchSize.x*2,patchSize.y*0},patchSize);
//Bottom-Left
game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,size.y},patchSize,GFX["9patch.png"].Decal(),{patchSize.x*0,patchSize.y*2},patchSize);
game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,size.y},patchSize,GetPatchPart(0,2).Decal(),{patchSize.x*0,patchSize.y*2},patchSize);
//Bottom-Right
game->DrawPartialDecal(menuPos+vf2d{size.x,size.y},patchSize,GFX["9patch.png"].Decal(),{patchSize.x*2,patchSize.y*2},patchSize);
game->DrawPartialDecal(menuPos+vf2d{size.x,size.y},patchSize,GetPatchPart(2,2).Decal(),{patchSize.x*2,patchSize.y*2},patchSize);
//Top
game->DrawPartialDecal(menuPos+vf2d{0,-patchSize.y},vf2d{size.x,patchSize.y},GFX["9patch.png"].Decal(),{patchSize.x*1,patchSize.y*0},patchSize);
game->DrawPartialDecal(menuPos+vf2d{0,-patchSize.y},vf2d{size.x,patchSize.y},GetPatchPart(1,0).Decal(),{patchSize.x*1,patchSize.y*0},patchSize);
//Left
game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,0},vf2d{patchSize.x,size.y},GFX["9patch.png"].Decal(),{patchSize.x*0,patchSize.y*1},patchSize);
game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,0},vf2d{patchSize.x,size.y},GetPatchPart(0,1).Decal(),{patchSize.x*0,patchSize.y*1},patchSize);
//Right
game->DrawPartialDecal(menuPos+vf2d{size.x,0},vf2d{patchSize.x,size.y},GFX["9patch.png"].Decal(),{patchSize.x*2,patchSize.y*1},patchSize);
game->DrawPartialDecal(menuPos+vf2d{size.x,0},vf2d{patchSize.x,size.y},GetPatchPart(2,1).Decal(),{patchSize.x*2,patchSize.y*1},patchSize);
//Bottom
game->DrawPartialDecal(menuPos+vf2d{0,size.y},vf2d{size.x,patchSize.y},GFX["9patch.png"].Decal(),{patchSize.x*1,patchSize.y*2},patchSize);
game->DrawPartialDecal(menuPos+vf2d{0,size.y},vf2d{size.x,patchSize.y},GetPatchPart(1,2).Decal(),{patchSize.x*1,patchSize.y*2},patchSize);
//Center
game->DrawPartialDecal(menuPos,size,GFX["9patch.png"].Decal(),{patchSize.x*1,patchSize.y*1},patchSize);
if(GetCurrentTheme().HasBackground()){
Decal*back=GetCurrentTheme().GetBackground();
game->DrawPartialDecal(menuPos,size,back,{0,0},back->sprite->Size());
}else{
game->DrawPartialDecal(menuPos,size,GetPatchPart(1,1).Decal(),{patchSize.x*1,patchSize.y*1},patchSize);
}
}
void Menu::DrawTiledWindow(Crawler*game,vf2d menuPos){
@ -286,9 +287,18 @@ void Menu::DrawTiledWindow(Crawler*game,vf2d menuPos){
//Bottom
game->DrawPartialDecal(menuPos+vf2d{0,size.y},vf2d{size.x,patchSize.y},GetPatchPart(1,2).Decal(),{0,0},vf2d{size.x,patchSize.y});
//Center
game->DrawPartialDecal(menuPos,size,GetPatchPart(1,1).Decal(),{0,0},patchSize);
if(GetCurrentTheme().HasBackground()){
Decal*back=GetCurrentTheme().GetBackground();
game->DrawPartialDecal(menuPos,size,back,{0,0},size);
}else{
game->DrawPartialDecal(menuPos,size,GetPatchPart(1,1).Decal(),{0,0},patchSize);
}
}
Renderable&Menu::GetPatchPart(int x,int y){
return GFX[themeSelection+"_"+std::to_string(x)+std::to_string(y)+".png"];
}
Theme&Menu::GetCurrentTheme(){
return themes[themeSelection];
}

@ -19,19 +19,17 @@ class Menu:IAttributable{
safemap<std::string,MenuComponent*>components; //A friendly way to interrogate any component we are interested in.
vi2d selection={-1,-1};
vf2d size; //Size in tiles (24x24), every menu will be tile-based
bool scaled=false; //Whether or not the patch border is supposed to be scaled or tiled.
public:
Menu();
Menu(vf2d size);
void AddComponent(std::string key,MenuComponent*button);
void Update(Crawler*game);
void Draw(Crawler*game);
void SetScaledPatchBorder(bool scaled);
static void InitializeMenus();
static void OpenMenu(MenuType menu);
static std::vector<Menu*>stack;
static std::string themeSelection;
static safemap<std::string,Theme>themes;
static safeunorderedmap<std::string,Theme>themes;
private:
void MenuSelect(Crawler*game);
static const Menu InitializeTestMenu();
@ -39,6 +37,8 @@ private:
//X (0-3), Y (0-2) for specific 9-patch tile (tiled version).
static Renderable&GetPatchPart(int x,int y);
static Theme&GetCurrentTheme();
void KeyboardButtonNavigation(Crawler*game,vf2d menuPos);
void DrawScaledWindow(Crawler*game,vf2d menuPos);
void DrawTiledWindow(Crawler*game,vf2d menuPos);

@ -9,14 +9,14 @@ MenuComponent::MenuComponent(geom2d::rect<float>rect,std::string label,MenuType
void MenuComponent::Update(Crawler*game){
if(hovered){
hoverEffect=std::min(1.f,hoverEffect+game->GetElapsedTime());
hoverEffect=std::min("ThemeGlobal.HighlightTime"_F,hoverEffect+game->GetElapsedTime());
}else{
hoverEffect=std::max(0.f,hoverEffect-game->GetElapsedTime());
}
}
void MenuComponent::Draw(Crawler*game,vf2d parentPos){
game->FillRectDecal(rect.pos+parentPos,rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),hoverEffect));
game->FillRectDecal(rect.pos+parentPos,rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),hoverEffect/"ThemeGlobal.HighlightTime"_F));
if(border){
game->DrawRectDecal(rect.pos+parentPos,rect.size,GREY);
}

@ -536,7 +536,7 @@ bool Player::Hurt(int damage,bool onUpperLevel,float z){
}
void Player::AddAnimation(std::string state){
animation.AddState(state,ANIMATION_DATA[state]);
animation.AddState(state,ANIMATION_DATA.at(state));
}
void Player::UpdateAnimation(std::string animState,int specificClass){

@ -17,8 +17,15 @@ const Menu Menu::InitializeTestSubMenu(){
};
testSubMenu.AddComponent("BACK",new MenuComponent({{24*1,24*1},{24*2,24*1}},"Go Back",goBack));
testSubMenu.I(A::INDEXED_THEME)=0;
int index=0;
for(auto&theme:Menu::themes){
if(theme.first==Menu::themeSelection){
testSubMenu.I(A::INDEXED_THEME)=index;
break;
}
index++;
}
MenuFunc themePrev=[](Menu&menu,Crawler*game){
bool found=false;

@ -5,11 +5,13 @@ class Theme{
std::string displayName;
std::string imgPath;
bool tiled=true;
Pixel buttonCol,highlightCol;
Decal*background;
public:
inline Theme(){}
inline Theme(std::string displayName,std::string imgPath,Pixel buttonCol,Pixel highlightCol)
:displayName(displayName),imgPath(imgPath),buttonCol(buttonCol),highlightCol(highlightCol){}
inline Theme(std::string displayName,std::string imgPath,bool tiled,Pixel buttonCol,Pixel highlightCol,Decal*background=nullptr)
:displayName(displayName),imgPath(imgPath),tiled(tiled),buttonCol(buttonCol),highlightCol(highlightCol),background(background){}
inline Pixel GetButtonCol(){
return buttonCol;
}
@ -19,4 +21,13 @@ public:
inline std::string GetThemeName(){
return displayName;
}
inline bool IsScaled(){
return !tiled;
}
inline bool HasBackground(){
return background!=nullptr;
}
inline Decal*GetBackground(){
return background;
}
};

@ -2,7 +2,7 @@
#define VERSION_MAJOR 0
#define VERSION_MINOR 2
#define VERSION_PATCH 0
#define VERSION_BUILD 1676
#define VERSION_BUILD 1704
#define stringify(a) stringify_(a)
#define stringify_(a) #a

@ -39,9 +39,6 @@ Images
GFX_SkillOverlayIcon = skill_overlay_icon.png
GFX_SkillOverlayIconOverlay = skill_overlay_icon_overlay.png
GFX_9Patch = themes/9patch.png
GFX_9Patch2 = themes/9patch_2.png
# Ability Icons
GFX_Warrior_BattleCry_Icon = Ability Icons/battlecry.png
GFX_Warrior_Block_Icon = Ability Icons/block.png

@ -1,25 +1,63 @@
ThemeGlobal
{
# How long it takes for the fade-in/fade-out effect to occur.
HighlightTime = 0.6
}
Themes
{
# Provide the patch image names without the .png extensions.
BlueDefault
{
Name = "9patch"
Name = 9patch
ButtonColor = 0,0,64,255
HighlightColor = 0,200,200,255
# If set to 0, stretches the edges and center instead of tiling it.
Tiled = 1
# Specifying a custom background from the assets directory uses that instead.
#CustomBack = image.png
}
Purple
{
Name = "9patch_2"
Name = 9patch_2
ButtonColor = 40,16,71,255
HighlightColor = 192,128,238,255
# If set to 0, stretches the edges and center instead of tiling it.
Tiled = 1
# Specifying a custom background from the assets directory uses that instead.
#CustomBack = themes/testback.png
}
NicoPink
{
Name = 9patch_3
ButtonColor = 208,73,182,255
HighlightColor = 255,239,232,255
# If set to 0, stretches the edges and center instead of tiling it.
Tiled = 0
# Specifying a custom background from the assets directory uses that instead.
CustomBack = themes/testback.png
}
NicoPinkTiled
{
Name = 9patch_4
ButtonColor = 208,73,182,255
HighlightColor = 255,239,232,255
# If set to 0, stretches the edges and center instead of tiling it.
Tiled = 1
# Specifying a custom background from the assets directory uses that instead.
CustomBack = themes/testtiledback.png
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

@ -71,6 +71,7 @@ namespace olc::utils
public:
inline datafile() = default;
inline static bool DEBUG_ACCESS_OPTIONS=false;
inline static bool INITIAL_SETUP_COMPLETE=false;
public:
// Sets the String Value of a Property (for a given index)
@ -444,6 +445,10 @@ namespace olc::utils
// Check if this "node"'s map already contains an object with this name...
if (m_mapObjects.count(name) == 0)
{
if(INITIAL_SETUP_COMPLETE){
std::cout<<"WARNING! Key "<<name<<" does not exist in datafile!"<<std::endl; //We're not going to allow manual creation of nodes.
throw;
}
// ...it did not! So create this object in the map. First get a vector id
// and link it with the name in the unordered_map
m_mapObjects[name] = m_vecObjects.size();

@ -12,7 +12,68 @@ public:
std::cout<<"WARNING! Trying to get non-existent key "<<key<<"!"<<std::endl;
throw;
}
return map[key];
if(!initialized){
size_t originalSize=map.size();
O&val=map[key];
if(originalSize==map.size()){
std::cout<<"WARNING! A previously set value has been overwritten! Key: "<<key<<std::endl;
throw;
}
return val;
}else{
return map[key];
}
}
O&at(T key){
return map.at(key);
}
size_t count(T key){
return map.count(key);
}
void SetInitialized(){
initialized=true;
}
size_t size(){
return map.size();
}
//Clears the entire map and unlocks the map so items can be added to it again.
void Reset(){
initialized=false;
map.clear();
}
auto begin()const{
return map.begin();
}
auto end()const{
return map.end();
}
};
//A class that has an initialization lock so that when the lock is activated, any further gets that are missing items in it will report themselves for easier debugging detection.
template<typename T,typename O>
class safeunorderedmap{
std::unordered_map<T,O>map;
bool initialized=false;
public:
O&operator[](T key){
if(initialized&&map.count(key)==0){
std::cout<<"WARNING! Trying to get non-existent key "<<key<<"!"<<std::endl;
throw;
}
if(!initialized){
size_t originalSize=map.size();
O&val=map[key];
if(originalSize==map.size()){
std::cout<<"WARNING! A previously set value has been overwritten! Key: "<<key<<std::endl;
throw;
}
return val;
}else{
return map[key];
}
}
O&at(T key){
return map.at(key);
}
size_t count(T key){
return map.count(key);

Loading…
Cancel
Save