parent
c11417d8a0
commit
4bab1397dc
@ -0,0 +1,775 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include "olcPixelGameEngine.h" |
||||||
|
#include "olcPGEX_TTF.h" |
||||||
|
|
||||||
|
#include <algorithm> |
||||||
|
#include <array> |
||||||
|
#include <cmath> |
||||||
|
#include <cstdint> |
||||||
|
#include <iostream> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
// Declarations
|
||||||
|
namespace olc { |
||||||
|
class ViewPort : public olc::PGEX { |
||||||
|
public: |
||||||
|
ViewPort(); |
||||||
|
ViewPort(std::vector<vf2d> 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<vf2d, 4> &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<vf2d, 4> &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<vf2d> &pos, |
||||||
|
const std::vector<vf2d> &uv, |
||||||
|
const Pixel tint = WHITE) const; |
||||||
|
void DrawPolygonDecal(Decal *decal, |
||||||
|
const std::vector<vf2d> &pos, |
||||||
|
const std::vector<float> &depth, |
||||||
|
const std::vector<vf2d> &uv, |
||||||
|
const Pixel tint = WHITE) const; |
||||||
|
void DrawPolygonDecal(Decal *decal, |
||||||
|
const std::vector<vf2d> &pos, |
||||||
|
const std::vector<vf2d> &uv, |
||||||
|
const std::vector<Pixel> &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<vf2d> 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<vf2d> 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<olc::vf2d> 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<vf2d> 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<vf2d> uvs{ |
||||||
|
{0, 0}, |
||||||
|
{0, 1}, |
||||||
|
{1, 1}, |
||||||
|
{1, 0}, |
||||||
|
}; |
||||||
|
std::vector<Pixel> cols{ |
||||||
|
tint, |
||||||
|
tint, |
||||||
|
tint, |
||||||
|
tint, |
||||||
|
}; |
||||||
|
|
||||||
|
drawClippedDecal(decal, pos, uvs.data(), cols.data(), 4); |
||||||
|
} |
||||||
|
void olc::ViewPort::DrawWarpedDecal(Decal *decal, |
||||||
|
const std::array<vf2d, 4> &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<float>(decal->sprite->width), |
||||||
|
static_cast<float>(decal->sprite->height)}; |
||||||
|
olc::vf2d sourceUvSize = |
||||||
|
source_size |
||||||
|
/ olc::vf2d{static_cast<float>(decal->sprite->width), |
||||||
|
static_cast<float>(decal->sprite->height)}; |
||||||
|
std::vector<vf2d> uvs{ |
||||||
|
sourceUvPos, |
||||||
|
{sourceUvPos.x, sourceUvPos.y + sourceUvSize.y}, |
||||||
|
sourceUvPos + sourceUvSize, |
||||||
|
{sourceUvPos.x + sourceUvSize.x, sourceUvPos.y}, |
||||||
|
}; |
||||||
|
std::vector<Pixel> cols{ |
||||||
|
tint, |
||||||
|
tint, |
||||||
|
tint, |
||||||
|
tint, |
||||||
|
}; |
||||||
|
|
||||||
|
drawClippedDecal(decal, pos, uvs.data(), cols.data(), 4); |
||||||
|
} |
||||||
|
|
||||||
|
void olc::ViewPort::DrawPartialWarpedDecal(Decal *decal, |
||||||
|
const std::array<vf2d, 4> &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<vf2d> 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<vf2d> 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<vf2d> points{ |
||||||
|
pos, |
||||||
|
{pos.x, pos.y + size.y}, |
||||||
|
pos + size, |
||||||
|
{pos.x + size.y, pos.y}, |
||||||
|
}; |
||||||
|
std::vector<vf2d> 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<vf2d> points{ |
||||||
|
pos, |
||||||
|
{pos.x, pos.y + size.y}, |
||||||
|
pos + size, |
||||||
|
{pos.x + size.y, pos.y}, |
||||||
|
}; |
||||||
|
|
||||||
|
std::vector<vf2d> uvs{ |
||||||
|
{0, 0}, |
||||||
|
{0, 1}, |
||||||
|
{1, 1}, |
||||||
|
{1, 0}, |
||||||
|
}; |
||||||
|
|
||||||
|
std::vector<Pixel> colors{ |
||||||
|
colTL, |
||||||
|
colBL, |
||||||
|
colBR, |
||||||
|
colTR, |
||||||
|
}; |
||||||
|
|
||||||
|
drawClippedDecal(nullptr, points.data(), uvs.data(), colors.data(), points.size()); |
||||||
|
} |
||||||
|
|
||||||
|
void olc::ViewPort::DrawPolygonDecal(Decal *decal, |
||||||
|
const std::vector<vf2d> &pos, |
||||||
|
const std::vector<vf2d> &uv, |
||||||
|
const Pixel tint) const { |
||||||
|
std::vector<Pixel> 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<vf2d> &pos, |
||||||
|
const std::vector<float> &, |
||||||
|
const std::vector<vf2d> &uv, |
||||||
|
const Pixel tint) const { |
||||||
|
DrawPolygonDecal(decal, pos, uv, tint); |
||||||
|
} |
||||||
|
|
||||||
|
void olc::ViewPort::DrawPolygonDecal(Decal *decal, |
||||||
|
const std::vector<vf2d> &pos, |
||||||
|
const std::vector<vf2d> &uv, |
||||||
|
const std::vector<Pixel> &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<vf2d> outputList{points, points + elements}; |
||||||
|
std::vector<vf2d> outputUvs{uvs, uvs + elements}; |
||||||
|
std::vector<Pixel> 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::map<std::u32string,DecalData>garbageCollector; |
||||||
|
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.expireTime<pge->GetRuntime()){ |
||||||
|
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::map<std::u32string,DecalData>garbageCollector; |
||||||
|
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.expireTime<pge->GetRuntime()){ |
||||||
|
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::map<std::u32string,DecalData>garbageCollector; |
||||||
|
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.expireTime<pge->GetRuntime()){ |
||||||
|
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 |
Loading…
Reference in new issue