|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "olcPixelGameEngine.h"
|
|
|
|
#include "olcPGEX_TTF.h"
|
|
|
|
#include "olcUTIL_Geometry2D.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <array>
|
|
|
|
#include <cmath>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <iostream>
|
|
|
|
#include <vector>
|
|
|
|
#include <limits>
|
|
|
|
|
|
|
|
// Declarations
|
|
|
|
namespace olc {
|
|
|
|
class ViewPort : public olc::PGEX {
|
|
|
|
public:
|
|
|
|
ViewPort();
|
|
|
|
ViewPort(std::vector<vf2d> vertices, vf2d offset = {0, 0});
|
|
|
|
geom2d::rect<float>rect;
|
|
|
|
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 DrawRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col=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,
|
|
|
|
const float *ws,
|
|
|
|
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, std::string_view sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f },const float width=std::numeric_limits<float>::max(),const bool disableDynamicScaling=false);
|
|
|
|
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, std::string_view sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }, const float width=std::numeric_limits<float>::max(),const bool disableDynamicScaling=false);
|
|
|
|
void DrawShadowStringDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float width=std::numeric_limits<float>::max(),const float shadowSizeFactor=1);
|
|
|
|
void DrawShadowStringPropDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float width=std::numeric_limits<float>::max(),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,
|
|
|
|
const float *ws,
|
|
|
|
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) {
|
|
|
|
olc::ViewPort newPort={{
|
|
|
|
topLeft,
|
|
|
|
{topLeft.x, topLeft.y + size.y},
|
|
|
|
topLeft + size,
|
|
|
|
{topLeft.x + size.x, topLeft.y},
|
|
|
|
},
|
|
|
|
offset};
|
|
|
|
newPort.rect={topLeft,size};
|
|
|
|
return newPort;
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
const float *ws,
|
|
|
|
uint32_t elements) const {
|
|
|
|
drawClippedDecal(decal, pos, uv, col, ws, 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<float> w{ 1, 1, 1, 1 };
|
|
|
|
std::vector<olc::vf2d> newPos;
|
|
|
|
newPos.resize(4);
|
|
|
|
std::vector<vf2d> uvs{
|
|
|
|
{0, 0},
|
|
|
|
{0, 1},
|
|
|
|
{1, 1},
|
|
|
|
{1, 0},
|
|
|
|
};
|
|
|
|
std::vector<Pixel> cols{
|
|
|
|
tint,
|
|
|
|
tint,
|
|
|
|
tint,
|
|
|
|
tint,
|
|
|
|
};
|
|
|
|
|
|
|
|
olc::vf2d vInvScreenSize={ 1.0f / pge->GetScreenSize().x, 1.0f / pge->GetScreenSize().y };
|
|
|
|
|
|
|
|
olc::vf2d center;
|
|
|
|
float rd = ((pos[2].x - pos[0].x) * (pos[3].y - pos[1].y) - (pos[3].x - pos[1].x) * (pos[2].y - pos[0].y));
|
|
|
|
if (rd != 0)
|
|
|
|
{
|
|
|
|
rd = 1.0f / rd;
|
|
|
|
float rn = ((pos[3].x - pos[1].x) * (pos[0].y - pos[1].y) - (pos[3].y - pos[1].y) * (pos[0].x - pos[1].x)) * rd;
|
|
|
|
float sn = ((pos[2].x - pos[0].x) * (pos[0].y - pos[1].y) - (pos[2].y - pos[0].y) * (pos[0].x - pos[1].x)) * rd;
|
|
|
|
if (!(rn < 0.f || rn > 1.f || sn < 0.f || sn > 1.f)) center = pos[0] + rn * (pos[2] - pos[0]);
|
|
|
|
float d[4]; for (int i = 0; i < 4; i++) d[i] = (pos[i] - center).mag();
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
float q = d[i] == 0.0f ? 1.0f : (d[i] + d[(i + 2) & 3]) / d[(i + 2) & 3];
|
|
|
|
uvs[i] *= q; w[i] *= q;
|
|
|
|
}
|
|
|
|
|
|
|
|
drawClippedDecal(decal, pos, uvs.data(), cols.data(), w.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,
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<float>ws{1,1,1,1};
|
|
|
|
|
|
|
|
olc::vf2d center;
|
|
|
|
float rd = ((pos[2].x - pos[0].x) * (pos[3].y - pos[1].y) - (pos[3].x - pos[1].x) * (pos[2].y - pos[0].y));
|
|
|
|
if (rd != 0)
|
|
|
|
{
|
|
|
|
rd = 1.0f / rd;
|
|
|
|
float rn = ((pos[3].x - pos[1].x) * (pos[0].y - pos[1].y) - (pos[3].y - pos[1].y) * (pos[0].x - pos[1].x)) * rd;
|
|
|
|
float sn = ((pos[2].x - pos[0].x) * (pos[0].y - pos[1].y) - (pos[2].y - pos[0].y) * (pos[0].x - pos[1].x)) * rd;
|
|
|
|
if (!(rn < 0.f || rn > 1.f || sn < 0.f || sn > 1.f)) center = pos[0] + rn * (pos[2] - pos[0]);
|
|
|
|
float d[4]; for (int i = 0; i < 4; i++) d[i] = (pos[i] - center).mag();
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
float q = d[i] == 0.0f ? 1.0f : (d[i] + d[(i + 2) & 3]) / d[(i + 2) & 3];
|
|
|
|
uvs[i] *= q; ws[i] *= q;
|
|
|
|
}
|
|
|
|
|
|
|
|
drawClippedDecal(decal, pos, uvs.data(), cols.data(), ws.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.x, 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.x, pos.y},
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<vf2d> uvs{
|
|
|
|
{0, 0},
|
|
|
|
{0, 1},
|
|
|
|
{1, 1},
|
|
|
|
{1, 0},
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<Pixel> colors{
|
|
|
|
colTL,
|
|
|
|
colBL,
|
|
|
|
colBR,
|
|
|
|
colTR,
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<float>w{1,1,1,1};
|
|
|
|
|
|
|
|
drawClippedDecal(nullptr, points.data(), uvs.data(), colors.data(), w.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;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<float>w{1,1,1,1};
|
|
|
|
|
|
|
|
drawClippedDecal(decal, pos.data(), uv.data(), colors.data(), w.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 {
|
|
|
|
std::vector<float>w{1,1,1,1};
|
|
|
|
drawClippedDecal(decal, pos.data(), uv.data(), tint.data(), w.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,
|
|
|
|
const float *ws,
|
|
|
|
uint32_t elements) const {
|
|
|
|
std::vector<vf2d> outputList{points, points + elements};
|
|
|
|
std::vector<vf2d> outputUvs{uvs, uvs + elements};
|
|
|
|
std::vector<float> outputWs{ws, ws + elements};
|
|
|
|
std::vector<Pixel> outputCols{col, col + elements};
|
|
|
|
|
|
|
|
vf2d min={std::numeric_limits<float>::max(),std::numeric_limits<float>::max()},max;
|
|
|
|
bool pointsOutside=false;
|
|
|
|
for(vf2d&points:outputList){
|
|
|
|
if(!geom2d::contains(rect,points)){
|
|
|
|
pointsOutside=true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!pointsOutside)goto render;
|
|
|
|
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 inputWs{outputWs};
|
|
|
|
auto inputCols{outputCols};
|
|
|
|
outputList.clear();
|
|
|
|
outputUvs.clear();
|
|
|
|
outputWs.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 Wa = inputWs[i];
|
|
|
|
auto Wb = inputWs[(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 intersectionW = Wa + (Wb - Wa) * 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);
|
|
|
|
outputWs.push_back(intersectionW);
|
|
|
|
outputCols.push_back(intersectionCol);
|
|
|
|
}
|
|
|
|
outputList.push_back(polygonB);
|
|
|
|
outputUvs.push_back(uvB);
|
|
|
|
outputWs.push_back(Wb);
|
|
|
|
outputCols.push_back(colB);
|
|
|
|
} else if (aDirection <= 0) {
|
|
|
|
outputList.push_back(intersectionPoint);
|
|
|
|
outputUvs.push_back(intersectionUv);
|
|
|
|
outputWs.push_back(intersectionW);
|
|
|
|
outputCols.push_back(intersectionCol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (outputList.size() == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
render:
|
|
|
|
|
|
|
|
for (auto &point : outputList) {
|
|
|
|
point += offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
pge->DrawExplicitDecal(decal,
|
|
|
|
outputList.data(),
|
|
|
|
outputUvs.data(),
|
|
|
|
outputCols.data(),
|
|
|
|
outputWs.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, std::string_view sText, const Pixel col, const olc::vf2d& scale, const float width,const bool disableDynamicScaling){
|
|
|
|
struct DecalData{
|
|
|
|
Decal*decal;
|
|
|
|
float expireTime=0.0f;
|
|
|
|
};
|
|
|
|
if(sText.length()==0)return;
|
|
|
|
static std::map<std::string,DecalData>garbageCollector;
|
|
|
|
std::string key{sText};
|
|
|
|
if(!disableDynamicScaling){
|
|
|
|
key+=scale.str();
|
|
|
|
}
|
|
|
|
if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time.
|
|
|
|
vi2d imageSize=pge->GetWrappedTextSize(sText,width,scale);
|
|
|
|
Decal*newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x));
|
|
|
|
garbageCollector[key].decal=newDecal;
|
|
|
|
pge->SetDrawTarget(newDecal->sprite);
|
|
|
|
pge->Clear(BLANK);
|
|
|
|
pge->DrawString({0,0},sText,WHITE,1U,width/scale.x);
|
|
|
|
pge->SetDrawTarget(nullptr);
|
|
|
|
newDecal->Update();
|
|
|
|
}
|
|
|
|
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,col);
|
|
|
|
}
|
|
|
|
|
|
|
|
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, std::string_view sText, const Pixel col, const olc::vf2d& scale,const float width,const bool disableDynamicScaling){
|
|
|
|
struct DecalData{
|
|
|
|
Decal*decal;
|
|
|
|
float expireTime=0.0f;
|
|
|
|
};
|
|
|
|
if(sText.length()==0)return;
|
|
|
|
static std::map<std::string,DecalData>garbageCollector;
|
|
|
|
std::string key{sText};
|
|
|
|
if(!disableDynamicScaling){
|
|
|
|
key+=scale.str();
|
|
|
|
}
|
|
|
|
if(!garbageCollector.count(key)){ //If the text key already exists, don't have to recreate the decal, just update the expire time.
|
|
|
|
vi2d imageSize=pge->GetWrappedTextSizeProp(sText,width,scale);
|
|
|
|
Decal*newDecal=new Decal(new Sprite(imageSize.x/scale.x,imageSize.y/scale.x));
|
|
|
|
garbageCollector[key].decal=newDecal;
|
|
|
|
pge->SetDrawTarget(newDecal->sprite);
|
|
|
|
pge->Clear(BLANK);
|
|
|
|
pge->DrawStringProp({0,0},sText,WHITE,1U,width/scale.x);
|
|
|
|
pge->SetDrawTarget(nullptr);
|
|
|
|
newDecal->Update();
|
|
|
|
}
|
|
|
|
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,col);
|
|
|
|
}
|
|
|
|
|
|
|
|
void olc::ViewPort::DrawShadowStringDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col, const Pixel shadowCol, const olc::vf2d& scale,const float width,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){
|
|
|
|
DrawStringDecal(pos+vf2d{x,y}, sText, shadowCol,scale,width);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DrawStringDecal(pos, sText, col,scale,width);
|
|
|
|
}
|
|
|
|
|
|
|
|
void olc::ViewPort::DrawShadowStringPropDecal(const olc::vf2d& pos, std::string_view sText, const Pixel col, const Pixel shadowCol, const olc::vf2d& scale,const float width,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){
|
|
|
|
DrawStringPropDecal(pos+vf2d{x,y}, sText, shadowCol,scale,width);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DrawStringPropDecal(pos, sText, col,scale,width);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void olc::ViewPort::DrawRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col)const{
|
|
|
|
FillRectDecal(pos,{size.x+1,1},col);
|
|
|
|
FillRectDecal(pos+vf2d{0,size.y-1+1},{size.x+1,1},col);
|
|
|
|
FillRectDecal(pos+vf2d{0,1},{1,size.y-1*2+1},col);
|
|
|
|
FillRectDecal(pos+vf2d{size.x-1+1,1},{1,size.y-1*2+1},col);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|