Add Viewport PGEX back in for radar stuff.

sigonasr2 3 months ago
parent e37456f757
commit 6ee7e293d5
  1. BIN
      assets/radar.png
  2. BIN
      assets/radar.xcf
  3. 12
      src/HamsterGame.cpp
  4. 2
      src/HamsterGame.h
  5. 722
      src/olcPGEX_Viewport.h
  6. 2
      src/olcPixelGameEngine.cpp
  7. 3
      src/util.cpp
  8. 1
      src/util.h

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

@ -31,6 +31,13 @@ bool HamsterGame::OnUserCreate(){
border.ChangeBorder(Border::DEFAULT); border.ChangeBorder(Border::DEFAULT);
renderer.SetProjection(90.0f, (float)SCREEN_FRAME.size.x/(float)SCREEN_FRAME.size.y, 0.1f, 1000.0f, 0, SCREEN_FRAME.pos.y, 512, SCREEN_FRAME.size.y); renderer.SetProjection(90.0f, (float)SCREEN_FRAME.size.x/(float)SCREEN_FRAME.size.y, 0.1f, 1000.0f, 0, SCREEN_FRAME.pos.y, 512, SCREEN_FRAME.size.y);
std::vector<vf2d>radarCircle;
for(int i=360;i>=0;i-=4){
float angle=util::degToRad(float(i))-geom2d::pi/2;
if(i==360){radarCircle.push_back(vf2d{cos(angle),sin(angle)}*42+43);}
radarCircle.push_back(vf2d{cos(angle),sin(angle)}*43+vf2d{43,44});
}
radar=ViewPort{radarCircle,{5.f,8.f}};
return true; return true;
} }
@ -57,6 +64,7 @@ void HamsterGame::LoadGraphics(){
_LoadImage("fuelbar_outline.png"); _LoadImage("fuelbar_outline.png");
_LoadImage("speedometer.png"); _LoadImage("speedometer.png");
_LoadImage("speedometer_overlay.png"); _LoadImage("speedometer_overlay.png");
_LoadImage("radar.png");
UpdateMatrixTexture(); UpdateMatrixTexture();
} }
@ -190,7 +198,7 @@ void HamsterGame::DrawGame(){
for(int y:std::ranges::iota_view(0,4)){ for(int y:std::ranges::iota_view(0,4)){
for(int x:std::ranges::iota_view(0,2)){ for(int x:std::ranges::iota_view(0,2)){
const int powerupInd{y*2+x}; const int powerupInd{y*2+x};
const float drawX{x*32.f+20.f}; const float drawX{x*32.f+16.f};
const float drawY{y*32.f+12.f+96.f}; const float drawY{y*32.f+12.f+96.f};
const Powerup::PowerupType powerupType{Powerup::PowerupType(powerupInd)}; const Powerup::PowerupType powerupType{Powerup::PowerupType(powerupInd)};
const geom2d::rect<float>powerupSubimageRect{Powerup::GetPowerupSubimageRect(powerupType)}; const geom2d::rect<float>powerupSubimageRect{Powerup::GetPowerupSubimageRect(powerupType)};
@ -246,6 +254,8 @@ void HamsterGame::DrawGame(){
} }
} }
DrawStringDecal(SCREEN_FRAME.pos+SCREEN_FRAME.size-speedometerStrSize-vf2d{4.f,4.f},speedometerStr,speedometerCol); DrawStringDecal(SCREEN_FRAME.pos+SCREEN_FRAME.size-speedometerStrSize-vf2d{4.f,4.f},speedometerStr,speedometerCol);
radar.FillRectDecal({},{128,128},GREEN);
DrawDecal({2.f,4.f},GetGFX("radar.png").Decal());
} }
const Terrain::TerrainType HamsterGame::GetTerrainTypeAtPos(const vf2d pos)const{ const Terrain::TerrainType HamsterGame::GetTerrainTypeAtPos(const vf2d pos)const{

@ -48,6 +48,7 @@ All rights reserved.
#include "SpecialRenderable.h" #include "SpecialRenderable.h"
#include "olcPGEX_Graphics3D.h" #include "olcPGEX_Graphics3D.h"
#include "AnimationState.h" #include "AnimationState.h"
#include "olcPGEX_Viewport.h"
struct Letter{ struct Letter{
vf2d pos; vf2d pos;
@ -112,4 +113,5 @@ private:
vf2d cloudSpd{}; vf2d cloudSpd{};
vf2d cloudOffset{}; vf2d cloudOffset{};
float speedometerDisplayAmt{0.f}; float speedometerDisplayAmt{0.f};
ViewPort radar;
}; };

@ -0,0 +1,722 @@
#pragma once
#include "olcPixelGameEngine.h"
#include <algorithm>
#include <array>
#include <cmath>
#include <cstdint>
#include <iostream>
#include <vector>
// Declarations
namespace olc {
class ViewPort : public olc::PGEX {
public:
ViewPort();
//Define a set of vertices to construct this viewport with. Winding order is counter-clockwise.
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 &center = {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 &center,
const vf2d &source_pos,
const vf2d &source_size,
const vf2d &scale = {1.0f, 1.0f},
const Pixel &tint = WHITE) const;
void DrawRectDecal(const vf2d &pos,
const vf2d &size,
const Pixel col = 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;
private:
void drawClippedDecal(Decal *decal,
const vf2d *points,
const vf2d *uvs,
const Pixel *col,
uint32_t elements = 0) const;
void drawClippedPolygonDecal(Decal *decal,
const vf2d *points,
const vf2d *uvs,
const float *depth,
const Pixel tint,
uint32_t elements = 0) const;
static bool ccw(vf2d A,vf2d B,vf2d C);
static bool intersect(vf2d A,vf2d B,vf2d C,vf2d D);
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<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;
}
drawClippedPolygonDecal(decal, pos, uvs.data(), w.data(), tint, 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;
}
drawClippedPolygonDecal(decal, pos, uvs.data(), ws.data(), tint, 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 &center,
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 &center,
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::DrawRectDecal(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},
};
// Ideally we use the wireframe mode just like the PGE,
// however we can't save the current decal mode which
// can impact some applications so instead we draw 4
// lines.
DrawLineDecal(points[0],points[1],col);
DrawLineDecal(points[1],points[2],col);
DrawLineDecal(points[2],points[3],col);
DrawLineDecal(points[3],points[0],col);
}
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,
};
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> &depth,
const std::vector<vf2d> &uv,
const Pixel tint) const {
drawClippedPolygonDecal(decal, pos.data(), uv.data(), depth.data(), tint, pos.size());
}
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] - offset;
auto clipB = clipVertices[(i + 1) % clipVertices.size()] - offset;
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;
}
}
// Inside check. Draw a ray to the edge of the screen and count the times
// it intersects. When odd, we are inside a shape, when even we are outside
// of it.
vf2d leftEdgeA = {0.f,posA.y};
vf2d leftEdgeB = {0.f,posB.y};
int leftEdgeIntersectionsA = 0;
int leftEdgeIntersectionsB = 0;
for (auto i = 0u; i < clipVertices.size(); i++) {
auto clipA = clipVertices[i] - offset;
auto clipB = clipVertices[(i + 1) % clipVertices.size()] - offset;
auto leftEdgeIntersectA = intersect(clipA, clipB, leftEdgeA, posA);
auto leftEdgeIntersectB = intersect(clipA, clipB, leftEdgeB, posB);
if (leftEdgeIntersectA) {
leftEdgeIntersectionsA++;
}
if (leftEdgeIntersectB) {
leftEdgeIntersectionsB++;
}
}
// If we found an intersection, we are drawing this line.
//
// Otherwise, if either count is odd, one point is at
// least inside the shape, so render it.
if (leftEdgeIntersectionsA % 2 == 1 || leftEdgeIntersectionsB % 2 == 1) {
pge->DrawLineDecal(posA, posB, 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) % clipVertices.size()];
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());
}
void olc::ViewPort::drawClippedPolygonDecal(Decal *decal,
const vf2d *points,
const vf2d *uvs,
const float *depth,
const Pixel tint,
uint32_t elements) const {
std::vector<vf2d> outputList{points, points + elements};
std::vector<vf2d> outputUvs{uvs, uvs + elements};
std::vector<float> outputDepths{depth, depth + elements};
for (auto i = 0u; i < clipVertices.size(); i++) {
auto clipA = clipVertices[i];
auto clipB = clipVertices[(i + 1) % clipVertices.size()];
auto inputList{outputList};
auto inputUvs{outputUvs};
auto inputWs{outputDepths};
outputList.clear();
outputUvs.clear();
outputDepths.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 intersection =
lineSegmentIntersect(clipA, clipB, polygonA, polygonB);
auto intersectionPoint =
polygonA + (polygonB - polygonA) * intersection;
auto intersectionUv = uvA + (uvB - uvA) * intersection;
auto intersectionDepth = Wa + (Wb - Wa) * 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);
outputDepths.push_back(intersectionDepth);
}
outputList.push_back(polygonB);
outputUvs.push_back(uvB);
outputDepths.push_back(Wb);
} else if (aDirection <= 0) {
outputList.push_back(intersectionPoint);
outputUvs.push_back(intersectionUv);
outputDepths.push_back(intersectionDepth);
}
}
}
for (auto &point : outputList) {
point += offset;
}
pge->DrawPolygonDecal(decal,
outputList,
outputDepths,
outputUvs,
tint);
}
bool olc::ViewPort::ccw(vf2d A,vf2d B,vf2d C) {
return (C.y-A.y) * (B.x-A.x) > (B.y-A.y) * (C.x-A.x);
}
bool olc::ViewPort::intersect(vf2d A,vf2d B,vf2d C,vf2d D) {
return ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D);
}
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);
}
#endif

@ -9,3 +9,5 @@
#include "TSXParser.h" #include "TSXParser.h"
#define OLC_PGEX_GRAPHICS3D #define OLC_PGEX_GRAPHICS3D
#include "olcPGEX_Graphics3D.h" #include "olcPGEX_Graphics3D.h"
#define OLC_PGEX_VIEWPORT
#include "olcPGEX_Viewport.h"

@ -51,3 +51,6 @@ void olc::util::turn_towards_direction(float&angle,float target,float rate)
float olc::util::lerp(float n1,float n2,double t){ float olc::util::lerp(float n1,float n2,double t){
return float(n1*(1-t)+n2*t); return float(n1*(1-t)+n2*t);
} }
float olc::util::degToRad(float deg){
return deg*(geom2d::pi/180);
}

@ -48,4 +48,5 @@ namespace olc::util{
float angle_difference(float angle_1, float angle_2); float angle_difference(float angle_1, float angle_2);
void turn_towards_direction(float&angle,float target,float rate); void turn_towards_direction(float&angle,float target,float rate);
float lerp(float n1,float n2,double t); float lerp(float n1,float n2,double t);
float degToRad(float deg);
}; };
Loading…
Cancel
Save