diff --git a/Crawler/Crawler.vcxproj b/Crawler/Crawler.vcxproj index a9d906a2..896a2b93 100644 --- a/Crawler/Crawler.vcxproj +++ b/Crawler/Crawler.vcxproj @@ -344,6 +344,7 @@ + diff --git a/Crawler/Crawler.vcxproj.filters b/Crawler/Crawler.vcxproj.filters index f2629c11..8005006a 100644 --- a/Crawler/Crawler.vcxproj.filters +++ b/Crawler/Crawler.vcxproj.filters @@ -297,6 +297,9 @@ Header Files\Interface + + Header Files + diff --git a/Crawler/MenuComponent.cpp b/Crawler/MenuComponent.cpp index f49758d3..be1e789f 100644 --- a/Crawler/MenuComponent.cpp +++ b/Crawler/MenuComponent.cpp @@ -197,6 +197,14 @@ bool MenuComponent::PointWithinParent(MenuComponent*child,vi2d drawPos){ } } +bool MenuComponent::PointWithinParent(MenuComponent*child,geom2d::rect drawRect){ + if(parentComponent!=nullptr){ + return parentComponent->PointWithinParent(child,drawRect); + }else{ + return true; + } +} + bool MenuComponent::HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton){ return false; }; diff --git a/Crawler/MenuComponent.h b/Crawler/MenuComponent.h index de209676..595c0302 100644 --- a/Crawler/MenuComponent.h +++ b/Crawler/MenuComponent.h @@ -103,7 +103,9 @@ protected: virtual bool GetHoverState(Crawler*game,MenuComponent*child); virtual void AfterCreate(); //Called after the creation of all menus finish. //CALL THIS FOR A PARENT to check a child's DrawDecal validity! - virtual bool PointWithinParent(MenuComponent*child,vi2d drawPos); + virtual bool PointWithinParent(MenuComponent*child,vi2d drawPos); + //CALL THIS FOR A PARENT to check a child's DrawDecal validity! + virtual bool PointWithinParent(MenuComponent*child,geom2d::rect drawRect); public: MenuType parentMenu=MenuType::ENUM_END; MenuComponent*parentComponent=nullptr; diff --git a/Crawler/MenuItemButton.h b/Crawler/MenuItemButton.h index f292e7d8..192c793c 100644 --- a/Crawler/MenuItemButton.h +++ b/Crawler/MenuItemButton.h @@ -157,7 +157,8 @@ protected: vf2d quantityTextScale=rect.size/48.f; vf2d textSize=vf2d(game->GetTextSizeProp(quantityText))*quantityTextScale; vf2d drawPos=parentPos+rect.pos+rect.size-textSize; - if(PointWithinParent(this,drawPos)){ + geom2d::rectboundingBox={drawPos,textSize}; + if(PointWithinParent(this,boundingBox)){ game->DrawShadowStringDecal(drawPos,quantityText,WHITE,BLACK,quantityTextScale,quantityTextScale.x); } } diff --git a/Crawler/MenuItemItemButton.h b/Crawler/MenuItemItemButton.h index 1a70605d..5149d680 100644 --- a/Crawler/MenuItemItemButton.h +++ b/Crawler/MenuItemItemButton.h @@ -141,7 +141,8 @@ protected: vf2d quantityTextScale=rect.size/48.f; vf2d textSize=vf2d(game->GetTextSizeProp(quantityText))*quantityTextScale; vf2d drawPos=Menu::menus[parentMenu]->pos+parentPos+rect.pos+rect.size-textSize; - if(PointWithinParent(this,drawPos)){ + geom2d::rectboundingBox={drawPos,textSize}; + if(PointWithinParent(this,boundingBox)){ game->DrawShadowStringDecal(drawPos,quantityText,WHITE,BLACK,quantityTextScale,quantityTextScale.x); } } diff --git a/Crawler/ScrollableWindowComponent.h b/Crawler/ScrollableWindowComponent.h index 231c9e53..6cdb32d1 100644 --- a/Crawler/ScrollableWindowComponent.h +++ b/Crawler/ScrollableWindowComponent.h @@ -260,6 +260,9 @@ public: virtual inline bool PointWithinParent(MenuComponent*child,vi2d drawPos)override{ return geom2d::overlaps(geom2d::rect{Menu::menus[parentMenu]->pos+rect.pos,rect.size},drawPos); } + virtual inline bool PointWithinParent(MenuComponent*child,geom2d::rect drawRect)override{ + return geom2d::overlaps(geom2d::rect{Menu::menus[parentMenu]->pos+rect.pos,rect.size},drawRect); + } virtual inline bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton)override{ //Set the offset so the center is highlighted by this button. V(A::SCROLL_OFFSET).y=-(disabledButton->rect.pos.y-disabledButton->rect.size.y/2); diff --git a/Crawler/State_GameRun.cpp b/Crawler/State_GameRun.cpp index c5d6171f..938a014e 100644 --- a/Crawler/State_GameRun.cpp +++ b/Crawler/State_GameRun.cpp @@ -50,6 +50,7 @@ void State_GameRun::OnStateChange(GameState*prevState){ Menu::CloseAllMenus(); } game->GetPlayer()->SetState(State::NORMAL); + port=ViewPort::rectViewPort({0,0},{72,100},{75,100}); } void State_GameRun::OnUserUpdate(Crawler*game){ game->bossDisplayTimer=std::max(0.f,game->bossDisplayTimer-game->GetElapsedTime()); @@ -79,16 +80,16 @@ void State_GameRun::Draw(Crawler*game){ } void State_GameRun::FontTest(){ - game->DrawStringDecal({8,8},"#000000This is a #000066test of hex"); - game->DrawStringDecal({8,16},"#FF0000This is a #BFA6F9test of hex"); - game->DrawStringDecal({8,24},"#00FF00This is a #E9A6F9test of hex"); - game->DrawStringDecal({8,32},"#0000FFThis is a #F9E8A6test of hex"); - game->DrawShadowStringDecal({8,40},"#000000This is a #000066test of hex"); - game->DrawShadowStringDecal({8,48},"#FF0000This is a #BFA6F9test of hex"); - game->DrawShadowStringDecal({8,56},"#00FF00This is a #E9A6F9test of hex"); - game->DrawShadowStringDecal({8,64},"#0000FFThis is a #F9E8A6test of hex"); - game->DrawShadowStringDecal(VisualNovel::font,{8,72},U"#000000This is a #000066test of hex"); - game->DrawShadowStringDecal(VisualNovel::font,{8,80},U"#FF0000This is a #BFA6F9test of hex"); - game->DrawShadowStringDecal(VisualNovel::font,{8,88},U"#00FF00This is a #E9A6F9test of hex"); - game->DrawShadowStringDecal(VisualNovel::font,{8,96},U"#0000FFThis is a #F9E8A6test of hex"); + port.DrawStringDecal({8,8},"#FFFFFFThis is a #000066test of hex"); + port.DrawStringDecal({8,16},"#FF0000This is a #BFA6F9test of hex"); + port.DrawStringDecal({8,24},"#00FF00This is a #E9A6F9test of hex"); + port.DrawStringDecal({8,32},"#0000FFThis is a #F9E8A6test of hex"); + port.DrawShadowStringDecal({8,40},"#FFFFFFThis is a #000066test of hex"); + port.DrawShadowStringDecal({8,48},"#FF0000This is a #BFA6F9test of hex"); + port.DrawShadowStringDecal({8,56},"#00FF00This is a #E9A6F9test of hex"); + port.DrawShadowStringDecal({8,64},"#0000FFThis is a #F9E8A6test of hex"); + port.DrawShadowStringDecal(VisualNovel::font,{8,72},U"#FFFFFFThis is a #000066test of hex"); + port.DrawShadowStringDecal(VisualNovel::font,{8,80},U"#FF0000This is a #BFA6F9test of hex"); + port.DrawShadowStringDecal(VisualNovel::font,{8,88},U"#00FF00This is a #E9A6F9test of hex"); + port.DrawShadowStringDecal(VisualNovel::font,{8,96},U"#0000FFThis is a #F9E8A6test of hex"); } \ No newline at end of file diff --git a/Crawler/State_GameRun.h b/Crawler/State_GameRun.h index a8931edb..90c9bf13 100644 --- a/Crawler/State_GameRun.h +++ b/Crawler/State_GameRun.h @@ -37,8 +37,10 @@ All rights reserved. #pragma endregion #pragma once #include "GameState.h" +#include "olcPGEX_ViewPort.h" class State_GameRun:public GameState{ + ViewPort port; virtual void OnStateChange(GameState*prevState)override final; virtual void OnUserUpdate(Crawler*game)override final; virtual void Draw(Crawler*game)override final; diff --git a/Crawler/State_OverworldMap.cpp b/Crawler/State_OverworldMap.cpp index 1724a4ec..ec52dc26 100644 --- a/Crawler/State_OverworldMap.cpp +++ b/Crawler/State_OverworldMap.cpp @@ -35,7 +35,6 @@ Project (www.freetype.org). Please see LICENSE_FT.txt for more information. All rights reserved. */ #pragma endregion -#include "State_OverworldMap.h" #include "Crawler.h" #include "DEFINES.h" #include "Menu.h" @@ -46,6 +45,7 @@ All rights reserved. #include "MenuLabel.h" #include "EncountersSpawnListScrollableWindowComponent.h" #include "VisualNovel.h" +#include "State_OverworldMap.h" INCLUDE_MONSTER_LIST INCLUDE_game diff --git a/Crawler/State_OverworldMap.h b/Crawler/State_OverworldMap.h index b1a69756..4f65deb8 100644 --- a/Crawler/State_OverworldMap.h +++ b/Crawler/State_OverworldMap.h @@ -38,6 +38,7 @@ All rights reserved. #pragma once #include "GameState.h" #include "ConnectionPoint.h" +#include "olcPGEX_ViewPort.h" class State_OverworldMap:public GameState{ friend class Crawler; diff --git a/Crawler/Version.h b/Crawler/Version.h index 8b582ff8..f208064c 100644 --- a/Crawler/Version.h +++ b/Crawler/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 0 #define VERSION_MINOR 2 #define VERSION_PATCH 1 -#define VERSION_BUILD 3827 +#define VERSION_BUILD 3862 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Crawler/olcPGEX_ViewPort.h b/Crawler/olcPGEX_ViewPort.h new file mode 100644 index 00000000..7a4893e2 --- /dev/null +++ b/Crawler/olcPGEX_ViewPort.h @@ -0,0 +1,775 @@ +#pragma once + +#include "olcPixelGameEngine.h" +#include "olcPGEX_TTF.h" + +#include +#include +#include +#include +#include +#include + +// Declarations +namespace olc { + class ViewPort : public olc::PGEX { + public: + ViewPort(); + ViewPort(std::vector vertices, vf2d offset = {0, 0}); + virtual ~ViewPort(); + void addPoint(vf2d point); + void clear(); + void drawEdges(); + void setOffset(vf2d offset); + + static ViewPort rectViewPort(vf2d topLeft, + vf2d size, + olc::vf2d offset = {0, 0}); + + void DrawDecal(const olc::vf2d &pos, + olc::Decal *decal, + const olc::vf2d &scale = {1.0f, 1.0f}, + const olc::Pixel &tint = olc::WHITE) const; + void DrawPartialDecal(const olc::vf2d &pos, + olc::Decal *decal, + const olc::vf2d &source_pos, + const olc::vf2d &source_size, + const olc::vf2d &scale = {1.0f, 1.0f}, + const olc::Pixel &tint = olc::WHITE) const; + void DrawPartialDecal(const vf2d &pos, + const vf2d &size, + Decal *decal, + const vf2d source_pos, + const vf2d &source_size, + const Pixel &tint = olc::WHITE) const; + void DrawExplicitDecal(olc::Decal *decal, + const olc::vf2d *pos, + const olc::vf2d *uv, + const olc::Pixel *col, + uint32_t elements = 4) const; + void DrawWarpedDecal(Decal *decal, + const vf2d (&pos)[4], + const Pixel &tint = WHITE) const; + void DrawWarpedDecal(Decal *decal, + const vf2d *pos, + const Pixel &tint = WHITE) const; + void DrawWarpedDecal(Decal *decal, + const std::array &pos, + const Pixel &tint = WHITE) const; + void DrawPartialWarpedDecal(Decal *decal, + const vf2d (&pos)[4], + const vf2d &source_pos, + const vf2d &source_size, + const Pixel &tint = WHITE) const; + void DrawPartialWarpedDecal(Decal *decal, + const vf2d *pos, + const vf2d &source_pos, + const vf2d &source_size, + const Pixel &tint = WHITE) const; + void DrawPartialWarpedDecal(Decal *decal, + const std::array &pos, + const vf2d &source_pos, + const vf2d &source_size, + const Pixel &tint = WHITE) const; + void DrawRotatedDecal(const vf2d &pos, + Decal *decal, + const float fAngle, + const vf2d ¢er = {0.0f, 0.0f}, + const vf2d &scale = {1.0f, 1.0f}, + const Pixel &tint = WHITE) const; + void DrawPartialRotatedDecal(const vf2d &pos, + Decal *decal, + const float fAngle, + const vf2d ¢er, + const vf2d &source_pos, + const vf2d &source_size, + const vf2d &scale = {1.0f, 1.0f}, + const Pixel &tint = WHITE) const; + void FillRectDecal(const vf2d &pos, + const vf2d &size, + const Pixel col = WHITE) const; + void GradientFillRectDecal(const vf2d &pos, + const vf2d &size, + const Pixel colTL, + const Pixel colBL, + const Pixel colBR, + const Pixel colTR) const; + void DrawPolygonDecal(Decal *decal, + const std::vector &pos, + const std::vector &uv, + const Pixel tint = WHITE) const; + void DrawPolygonDecal(Decal *decal, + const std::vector &pos, + const std::vector &depth, + const std::vector &uv, + const Pixel tint = WHITE) const; + void DrawPolygonDecal(Decal *decal, + const std::vector &pos, + const std::vector &uv, + const std::vector &tint) const; + void DrawLineDecal(const vf2d &pos1, + const vf2d &pos2, + Pixel p = WHITE) const; + // Draws a multiline string as a decal, with tinting and scaling + void DrawStringDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); + void DrawStringDecal(Font&font, const olc::vf2d& pos, const std::u32string& sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); + void DrawStringPropDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); + void DrawShadowStringDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float shadowSizeFactor=1); + void DrawShadowStringPropDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float shadowSizeFactor=1); + void DrawShadowStringDecal(Font&font, const olc::vf2d& pos, const std::u32string& sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float shadowSizeFactor=1); + void DrawDropShadowStringDecal(Font&font, const olc::vf2d& pos, const std::u32string& sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f }); + + private: + void drawClippedDecal(Decal *decal, + const vf2d *points, + const vf2d *uvs, + const Pixel *col, + uint32_t elements = 0) const; + + static float lineSegmentIntersect(vf2d lineA, + vf2d lineB, + vf2d segmentA, + vf2d segmentB); + static float directionFromLine(vf2d lineA, vf2d lineB, vf2d point); + + std::vector clipVertices; + olc::vf2d offset; + }; +} // namespace olc + +// Definitions + +#ifdef OLC_PGEX_VIEWPORT +#undef OLC_PGEX_VIEWPORT + +olc::ViewPort::ViewPort() { +} +olc::ViewPort::~ViewPort() { +} + +olc::ViewPort::ViewPort(std::vector vertices, olc::vf2d offset) + : clipVertices{vertices}, + offset{offset} { +} + +void olc::ViewPort::addPoint(vf2d point) { + clipVertices.push_back(point); +} + +void olc::ViewPort::clear() { + clipVertices.clear(); +} + +void olc::ViewPort::drawEdges() { + for (auto i = 0u; i < clipVertices.size(); i++) { + auto current = clipVertices[i] + offset; + auto next = clipVertices[(i + 1) % clipVertices.size()] + offset; + + pge->DrawLineDecal(current, next, olc::RED); + } +} + +void olc::ViewPort::setOffset(vf2d offset) { + this->offset = offset; +} + +olc::ViewPort + olc::ViewPort::rectViewPort(vf2d topLeft, vf2d size, olc::vf2d offset) { + return {{ + topLeft, + {topLeft.x, topLeft.y + size.y}, + topLeft + size, + {topLeft.x + size.x, topLeft.y}, + }, + offset}; +} + +void olc::ViewPort::DrawDecal(const olc::vf2d &pos, + olc::Decal *decal, + const olc::vf2d &scale, + const olc::Pixel &tint) const { + std::vector points{ + pos, + {pos.x, pos.y + decal->sprite->height * scale.y}, + {pos.x + decal->sprite->width * scale.x, + pos.y + decal->sprite->height * scale.y}, + {pos.x + decal->sprite->width * scale.x, pos.y}, + }; + DrawWarpedDecal(decal, points.data(), tint); +} + +void olc::ViewPort::DrawPartialDecal(const olc::vf2d &pos, + olc::Decal *decal, + const olc::vf2d &source_pos, + const olc::vf2d &source_size, + const olc::vf2d &scale, + const olc::Pixel &tint) const { + DrawPartialDecal(pos, source_size * scale, decal, source_pos, source_size, tint); +} + +void olc::ViewPort::DrawPartialDecal(const vf2d &pos, + const vf2d &size, + Decal *decal, + const vf2d source_pos, + const vf2d &source_size, + const Pixel &tint) const { + std::vector points{ + pos, + {pos.x, pos.y + size.y}, + pos + size, + {pos.x + size.x, pos.y}, + }; + DrawPartialWarpedDecal(decal, points.data(), source_pos, source_size, tint); +} + +void olc::ViewPort::DrawExplicitDecal(olc::Decal *decal, + const olc::vf2d *pos, + const olc::vf2d *uv, + const olc::Pixel *col, + uint32_t elements) const { + drawClippedDecal(decal, pos, uv, col, elements); +} + +void olc::ViewPort::DrawWarpedDecal(Decal *decal, + const vf2d (&pos)[4], + const Pixel &tint) const { + DrawWarpedDecal(decal, (const vf2d *)pos, tint); +} +void olc::ViewPort::DrawWarpedDecal(Decal *decal, + const vf2d *pos, + const Pixel &tint) const { + std::vector uvs{ + {0, 0}, + {0, 1}, + {1, 1}, + {1, 0}, + }; + std::vector cols{ + tint, + tint, + tint, + tint, + }; + + drawClippedDecal(decal, pos, uvs.data(), cols.data(), 4); +} +void olc::ViewPort::DrawWarpedDecal(Decal *decal, + const std::array &pos, + const Pixel &tint) const { + DrawWarpedDecal(decal, pos.data(), tint); +} + +void olc::ViewPort::DrawPartialWarpedDecal(Decal *decal, + const vf2d (&pos)[4], + const vf2d &source_pos, + const vf2d &source_size, + const Pixel &tint) const { + DrawPartialWarpedDecal(decal, + (const vf2d *)pos, + source_pos, + source_size, + tint); +} + +void olc::ViewPort::DrawPartialWarpedDecal(Decal *decal, + const vf2d *pos, + const vf2d &source_pos, + const vf2d &source_size, + const Pixel &tint) const { + olc::vf2d sourceUvPos = + source_pos + / olc::vf2d{static_cast(decal->sprite->width), + static_cast(decal->sprite->height)}; + olc::vf2d sourceUvSize = + source_size + / olc::vf2d{static_cast(decal->sprite->width), + static_cast(decal->sprite->height)}; + std::vector uvs{ + sourceUvPos, + {sourceUvPos.x, sourceUvPos.y + sourceUvSize.y}, + sourceUvPos + sourceUvSize, + {sourceUvPos.x + sourceUvSize.x, sourceUvPos.y}, + }; + std::vector cols{ + tint, + tint, + tint, + tint, + }; + + drawClippedDecal(decal, pos, uvs.data(), cols.data(), 4); +} + +void olc::ViewPort::DrawPartialWarpedDecal(Decal *decal, + const std::array &pos, + const vf2d &source_pos, + const vf2d &source_size, + const Pixel &tint) const { + DrawPartialWarpedDecal(decal, pos.data(), source_pos, source_size, tint); +} + +void olc::ViewPort::DrawRotatedDecal(const vf2d &pos, + Decal *decal, + const float fAngle, + const vf2d ¢er, + const vf2d &scale, + const Pixel &tint) const { + auto sin = std::sin(fAngle); + auto cos = std::cos(fAngle); + + std::vector points{ + -center * scale, + olc::vf2d{-center.x, decal->sprite->height - center.y} * scale, + olc::vf2d{decal->sprite->width - center.x, + decal->sprite->height - center.y} + * scale, + olc::vf2d{decal->sprite->width - center.x, -center.y} * scale, + }; + + for (auto i = 0u; i < points.size(); i++) { + points[i] = pos + + olc::vf2d{points[i].x * cos - points[i].y * sin, + points[i].x * sin + points[i].y * cos}; + } + + DrawWarpedDecal(decal, points.data(), tint); +} + +void olc::ViewPort::DrawPartialRotatedDecal(const vf2d &pos, + Decal *decal, + const float fAngle, + const vf2d ¢er, + const vf2d &source_pos, + const vf2d &source_size, + const vf2d &scale, + const Pixel &tint) const { + auto sin = std::sin(fAngle); + auto cos = std::cos(fAngle); + + std::vector points{ + -center * scale, + olc::vf2d{-center.x, source_size.y - center.y} * scale, + (source_size - center) * scale, + olc::vf2d{source_size.x - center.x, -center.y} * scale, + }; + + for (auto i = 0u; i < points.size(); i++) { + points[i] = pos + + olc::vf2d{points[i].x * cos - points[i].y * sin, + points[i].x * sin + points[i].y * cos}; + } + + DrawPartialWarpedDecal(decal, points.data(), source_pos, source_size, tint); +} + +void olc::ViewPort::FillRectDecal(const vf2d &pos, + const vf2d &size, + const Pixel col) const { + std::vector points{ + pos, + {pos.x, pos.y + size.y}, + pos + size, + {pos.x + size.y, pos.y}, + }; + std::vector uvs{ + {0, 0}, + {0, 1}, + {1, 1}, + {1, 0}, + }; + + DrawPolygonDecal(nullptr, points, uvs, col); +} + +void olc::ViewPort::GradientFillRectDecal(const vf2d &pos, + const vf2d &size, + const Pixel colTL, + const Pixel colBL, + const Pixel colBR, + const Pixel colTR) const { + std::vector points{ + pos, + {pos.x, pos.y + size.y}, + pos + size, + {pos.x + size.y, pos.y}, + }; + + std::vector uvs{ + {0, 0}, + {0, 1}, + {1, 1}, + {1, 0}, + }; + + std::vector colors{ + colTL, + colBL, + colBR, + colTR, + }; + + drawClippedDecal(nullptr, points.data(), uvs.data(), colors.data(), points.size()); +} + +void olc::ViewPort::DrawPolygonDecal(Decal *decal, + const std::vector &pos, + const std::vector &uv, + const Pixel tint) const { + std::vector colors; + colors.resize(pos.size()); + for (auto i = 0u; i < colors.size(); i++) { + colors[i] = tint; + } + + drawClippedDecal(decal, pos.data(), uv.data(), colors.data(), pos.size()); +} + +void olc::ViewPort::DrawPolygonDecal(Decal *decal, + const std::vector &pos, + const std::vector &, + const std::vector &uv, + const Pixel tint) const { + DrawPolygonDecal(decal, pos, uv, tint); +} + +void olc::ViewPort::DrawPolygonDecal(Decal *decal, + const std::vector &pos, + const std::vector &uv, + const std::vector &tint) const { + drawClippedDecal(decal, pos.data(), uv.data(), tint.data(), pos.size()); +} + +void olc::ViewPort::DrawLineDecal(const vf2d &pos1, + const vf2d &pos2, + Pixel p) const { + vf2d posA = pos1; + vf2d posB = pos2; + + for (auto i = 0u; i < clipVertices.size(); i++) { + auto clipA = clipVertices[i]; + auto clipB = clipVertices[(i + 1) % clipVertices.size()]; + + auto intersection = lineSegmentIntersect(clipA, clipB, posA, posB); + if (intersection < 0 || intersection > 1) { + continue; + } + + auto clipDirection = directionFromLine(clipA, clipB, posA); + auto intersectionPoint = posA + (posB - posA) * intersection; + + if (clipDirection >= 0) { + posA = intersectionPoint; + } else { + posB = intersectionPoint; + } + } + + pge->DrawLineDecal(posA + offset, posB + offset, p); +} + +void olc::ViewPort::drawClippedDecal(Decal *decal, + const vf2d *points, + const vf2d *uvs, + const Pixel *col, + uint32_t elements) const { + std::vector outputList{points, points + elements}; + std::vector outputUvs{uvs, uvs + elements}; + std::vector outputCols{col, col + elements}; + + for (auto i = 0u; i < clipVertices.size(); i++) { + auto clipA = clipVertices[i]; + auto clipB = clipVertices[(i + 1) % 4]; + + auto inputList{outputList}; + auto inputUvs{outputUvs}; + auto inputCols{outputCols}; + outputList.clear(); + outputUvs.clear(); + outputCols.clear(); + + for (auto i = 0u; i < inputList.size(); i++) { + auto polygonA = inputList[i]; + auto polygonB = inputList[(i + 1) % inputList.size()]; + auto uvA = inputUvs[i]; + auto uvB = inputUvs[(i + 1) % inputList.size()]; + auto colA = inputCols[i]; + auto colB = inputCols[(i + 1) % inputList.size()]; + + auto intersection = + lineSegmentIntersect(clipA, clipB, polygonA, polygonB); + auto intersectionPoint = + polygonA + (polygonB - polygonA) * intersection; + auto intersectionUv = uvA + (uvB - uvA) * intersection; + auto intersectionCol = PixelLerp(colA, colB, intersection); + + float aDirection = directionFromLine(clipA, clipB, polygonA); + float bDirection = directionFromLine(clipA, clipB, polygonB); + + if (bDirection <= 0) { + if (aDirection > 0) { + outputList.push_back(intersectionPoint); + outputUvs.push_back(intersectionUv); + outputCols.push_back(intersectionCol); + } + outputList.push_back(polygonB); + outputUvs.push_back(uvB); + outputCols.push_back(colB); + } else if (aDirection <= 0) { + outputList.push_back(intersectionPoint); + outputUvs.push_back(intersectionUv); + outputCols.push_back(intersectionCol); + } + } + } + + if (outputList.size() == 0) { + return; + } + + for (auto &point : outputList) { + point += offset; + } + + pge->DrawExplicitDecal(decal, + outputList.data(), + outputUvs.data(), + outputCols.data(), + outputList.size()); +} + +float olc::ViewPort::lineSegmentIntersect(vf2d lineA, + vf2d lineB, + vf2d segmentA, + vf2d segmentB) { + return ((lineA.x - segmentA.x) * (lineA.y - lineB.y) + - (lineA.y - segmentA.y) * (lineA.x - lineB.x)) + / ((lineA.x - lineB.x) * (segmentA.y - segmentB.y) + - (lineA.y - lineB.y) * (segmentA.x - segmentB.x)); +} + +float olc::ViewPort::directionFromLine(vf2d lineA, vf2d lineB, vf2d point) { + return (lineB.x - lineA.x) * (point.y - lineA.y) + - (point.x - lineA.x) * (lineB.y - lineA.y); +} + +void olc::ViewPort::DrawStringDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col, const olc::vf2d& scale){ + olc::vf2d spos = { 0.0f, 0.0f }; + Pixel textCol=col; + const auto hexToNumber=[](char c){ + if(c<='9')return c-'0'; + return (c-'A')+10; + }; + for (int skip=0,index=-1;auto c : sText) + { + index++; + if(skip){ + skip--; + continue; + } + if(c=='\r')continue; //Ignore carriage returns. Stupid Linux. + if (c == '\n') + { + spos.x = 0; spos.y += 8.0f * scale.y; + } + else if (c == '\t') + { + spos.x += 8.0f * float(nTabSizeInSpaces) * scale.x; + } + else if (c>=-128&&c<-105) + { + textCol={PixelGameEngine::charToColor[c].r,PixelGameEngine::charToColor[c].g,PixelGameEngine::charToColor[c].b,col.a}; + } + else if (c=='#') + { + skip=6; + textCol=BLACK; + for(int i=1;i<7;i++){ + if(i<3){ + textCol.r*=16; + textCol.r+=hexToNumber(sText[index+i]); + }else + if(i<5){ + textCol.g*=16; + textCol.g+=hexToNumber(sText[index+i]); + }else{ + textCol.b*=16; + textCol.b+=hexToNumber(sText[index+i]); + } + } + } + else + { + int32_t ox = (c - 32) % 16; + int32_t oy = (c - 32) / 16; + DrawPartialDecal(pos + spos, pge->GetFontDecal(), {float(ox) * 8.0f, float(oy) * 8.0f}, {8.0f, 8.0f}, scale, textCol); + spos.x += 8.0f * scale.x; + } + } +} + +void olc::ViewPort::DrawStringDecal(Font&font, const olc::vf2d& pos, const std::u32string& sText, const Pixel col, const olc::vf2d& scale){ + struct DecalData{ + Decal*decal; + float expireTime=0.0f; + }; + if(sText.length()==0)return; + static std::mapgarbageCollector; + std::u32string key=font.GetFontName()+U"_"+sText; + if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + garbageCollector[key].decal=font.RenderStringToDecal(sText,WHITE); + } + garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; + std::erase_if(garbageCollector,[&](auto&key){ + if(key.second.expireTimeGetRuntime()){ + delete key.second.decal; + return true; + } + return false; + }); + DrawDecal(pos,garbageCollector[key].decal,scale/4,col); +} + +void olc::ViewPort::DrawStringPropDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col, const olc::vf2d& scale){ + olc::vf2d spos = { 0.0f, 0.0f }; + Pixel textCol=col; + const auto hexToNumber=[](char c){ + if(c<='9')return c-'0'; + return (c-'A')+10; + }; + for (int skip=0,index=-1;auto c : sText) + { + index++; + if(skip){ + skip--; + continue; + } + if(c=='\r')continue; //Ignore carriage returns. Stupid Linux. + if (c == '\n') + { + spos.x = 0; spos.y += 8.0f * scale.y; + } + else if (c == '\t') + { + spos.x += 8.0f * float(nTabSizeInSpaces) * scale.x; + } + else if (c>=-128&&c<-105) + { + textCol={PixelGameEngine::charToColor[c].r,PixelGameEngine::charToColor[c].g,PixelGameEngine::charToColor[c].b,col.a}; + } + else if (c==PixelGameEngine::Reset[0]) + { + textCol=col; + } + else if (c=='#') + { + skip=6; + textCol=BLACK; + for(int i=1;i<7;i++){ + if(i<3){ + textCol.r*=16; + textCol.r+=hexToNumber(sText[index+i]); + }else + if(i<5){ + textCol.g*=16; + textCol.g+=hexToNumber(sText[index+i]); + }else{ + textCol.b*=16; + textCol.b+=hexToNumber(sText[index+i]); + } + } + } + else + { + int32_t ox = (c - 32) % 16; + int32_t oy = (c - 32) / 16; + DrawPartialDecal(pos + spos, pge->GetFontDecal(), { float(ox) * 8.0f + float(pge->vFontSpacing[c - 32].x), float(oy) * 8.0f }, { float(pge->vFontSpacing[c - 32].y), 8.0f }, scale, textCol); + spos.x += float(pge->vFontSpacing[c - 32].y) * scale.x; + } + } +} + +void olc::ViewPort::DrawShadowStringDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col, const Pixel shadowCol, const olc::vf2d& scale,const float shadowSizeFactor){ + std::string strippedText=sText; + std::erase_if(strippedText,[](char chr){return chr<0;}); + int skip=0; + std::erase_if(strippedText,[&](char chr){if(skip>0){skip--;return true;}if(chr=='#'){skip=6;return true;}return false;}); + 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){ + DrawStringDecal(pos+vf2d{x,y}, strippedText, shadowCol,scale); + } + } + } + DrawStringDecal(pos, sText, col,scale); +} + +void olc::ViewPort::DrawShadowStringPropDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col, const Pixel shadowCol, const olc::vf2d& scale,const float shadowSizeFactor){ + std::string strippedText=sText; + std::erase_if(strippedText,[](char chr){return chr<0;}); + int skip=0; + std::erase_if(strippedText,[&](char chr){if(skip>0){skip--;return true;}if(chr=='#'){skip=6;return true;}return false;}); + 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){ + DrawStringPropDecal(pos+vf2d{x,y}, strippedText, shadowCol,scale); + } + } + } + DrawStringPropDecal(pos, sText, col,scale); +} + +void olc::ViewPort::DrawShadowStringDecal(Font&font, const olc::vf2d& pos, const std::u32string& sText, const Pixel col, const Pixel shadowCol, const olc::vf2d& scale,const float shadowSizeFactor){ + struct DecalData{ + Decal*decal; + float expireTime=0.0f; + }; + if(sText.length()==0)return; + static std::mapgarbageCollector; + std::u32string key=font.GetFontName()+U"_"+sText; + if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + garbageCollector[key].decal=font.RenderStringToDecal(sText,WHITE); + } + garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; + std::erase_if(garbageCollector,[&](auto&key){ + if(key.second.expireTimeGetRuntime()){ + delete key.second.decal; + return true; + } + return false; + }); + 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){ + DrawDecal(pos+vf2d{x,y},garbageCollector[key].decal,scale/4,shadowCol); + } + } + } + DrawDecal(pos,garbageCollector[key].decal,scale/4,col); +} + +void olc::ViewPort::DrawDropShadowStringDecal(Font&font, const olc::vf2d& pos, const std::u32string& sText, const Pixel col, const Pixel shadowCol, const olc::vf2d& scale){ + struct DecalData{ + Decal*decal; + float expireTime=0.0f; + }; + if(sText.length()==0)return; + static std::mapgarbageCollector; + std::u32string key=font.GetFontName()+U"_"+sText; + if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time. + garbageCollector[key].decal=font.RenderStringToDecal(sText,WHITE); + } + garbageCollector[key].expireTime=pge->GetRuntime()+120.0f; + std::erase_if(garbageCollector,[&](auto&key){ + if(key.second.expireTimeGetRuntime()){ + delete key.second.decal; + return true; + } + return false; + }); + DrawDecal(pos+vf2d{0,0.5f},garbageCollector[key].decal,scale/4,shadowCol); + DrawDecal(pos+vf2d{0.5f,0},garbageCollector[key].decal,scale/4,shadowCol); + DrawDecal(pos+vf2d{0.5f,0.5f},garbageCollector[key].decal,scale/4,shadowCol); + DrawDecal(pos,garbageCollector[key].decal,scale/4,col); +} + +#endif \ No newline at end of file diff --git a/Crawler/olcPixelGameEngine.h b/Crawler/olcPixelGameEngine.h index da2d031d..d9b24053 100644 --- a/Crawler/olcPixelGameEngine.h +++ b/Crawler/olcPixelGameEngine.h @@ -1171,6 +1171,8 @@ namespace olc void ClearBuffer(Pixel p, bool bDepth = true); // Returns the font image olc::Sprite* GetFontSprite(); + // Returns the font image + olc::Decal* GetFontDecal(); // Clip a line segment to visible area bool ClipLineToScreen(olc::vi2d& in_p1, olc::vi2d& in_p2); @@ -1254,6 +1256,8 @@ namespace olc public: // Branding std::string sAppName; + friend class ViewPort; + private: // Inner mysterious workings olc::Sprite* pDrawTarget = nullptr; Pixel::Mode nPixelMode = Pixel::NORMAL; @@ -2461,6 +2465,8 @@ namespace olc olc::Sprite* PixelGameEngine::GetFontSprite() { return fontRenderable.Sprite(); } + olc::Decal* PixelGameEngine::GetFontDecal() + { return fontRenderable.Decal(); } bool PixelGameEngine::ClipLineToScreen(olc::vi2d& in_p1, olc::vi2d& in_p2) { diff --git a/Crawler/pixelGameEngine.cpp b/Crawler/pixelGameEngine.cpp index dc93023c..a6680bf1 100644 --- a/Crawler/pixelGameEngine.cpp +++ b/Crawler/pixelGameEngine.cpp @@ -39,6 +39,8 @@ All rights reserved. //#define OLC_PGE_HEADLESS #define OLC_PGEX_TTF #include "olcPGEX_TTF.h" +#define OLC_PGEX_VIEWPORT +#include "olcPGEX_ViewPort.h" #define OLC_PGE_APPLICATION #include "olcPixelGameEngine.h" #define OLC_PGEX_TRANSFORMEDVIEW