mirror of
https://github.com/k4zmu2a/SpaceCadetPinball.git
synced 2024-12-18 10:37:53 +01:00
Added debug overlay v1.
It features various collision info perspective projected and overlayed on the table.
This commit is contained in:
parent
0cb75ecf7f
commit
5461483bb5
15 changed files with 388 additions and 29 deletions
|
@ -170,6 +170,8 @@ set(SOURCE_FILES
|
||||||
SpaceCadetPinball/imstb_textedit.h
|
SpaceCadetPinball/imstb_textedit.h
|
||||||
SpaceCadetPinball/imstb_rectpack.h
|
SpaceCadetPinball/imstb_rectpack.h
|
||||||
SpaceCadetPinball/imstb_truetype.h
|
SpaceCadetPinball/imstb_truetype.h
|
||||||
|
SpaceCadetPinball/DebugOverlay.cpp
|
||||||
|
SpaceCadetPinball/DebugOverlay.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# On Windows, include resource file with the icon
|
# On Windows, include resource file with the icon
|
||||||
|
|
255
SpaceCadetPinball/DebugOverlay.cpp
Normal file
255
SpaceCadetPinball/DebugOverlay.cpp
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
#include "pch.h"
|
||||||
|
#include "DebugOverlay.h"
|
||||||
|
|
||||||
|
#include "maths.h"
|
||||||
|
#include "proj.h"
|
||||||
|
#include "winmain.h"
|
||||||
|
#include "TFlipperEdge.h"
|
||||||
|
#include "TFlipper.h"
|
||||||
|
#include "pb.h"
|
||||||
|
#include "TLine.h"
|
||||||
|
#include "TCircle.h"
|
||||||
|
#include "TPinballTable.h"
|
||||||
|
#include "TEdgeBox.h"
|
||||||
|
#include "TTableLayer.h"
|
||||||
|
#include "TBall.h"
|
||||||
|
#include "render.h"
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
|
||||||
|
gdrv_bitmap8* DebugOverlay::dbScreen = nullptr;
|
||||||
|
|
||||||
|
int SDL_RenderDrawCircle(SDL_Renderer* renderer, int x, int y, int radius)
|
||||||
|
{
|
||||||
|
int offsetx, offsety, d;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
offsetx = 0;
|
||||||
|
offsety = radius;
|
||||||
|
d = radius - 1;
|
||||||
|
status = 0;
|
||||||
|
|
||||||
|
while (offsety >= offsetx) {
|
||||||
|
status += SDL_RenderDrawPoint(renderer, x + offsetx, y + offsety);
|
||||||
|
status += SDL_RenderDrawPoint(renderer, x + offsety, y + offsetx);
|
||||||
|
status += SDL_RenderDrawPoint(renderer, x - offsetx, y + offsety);
|
||||||
|
status += SDL_RenderDrawPoint(renderer, x - offsety, y + offsetx);
|
||||||
|
status += SDL_RenderDrawPoint(renderer, x + offsetx, y - offsety);
|
||||||
|
status += SDL_RenderDrawPoint(renderer, x + offsety, y - offsetx);
|
||||||
|
status += SDL_RenderDrawPoint(renderer, x - offsetx, y - offsety);
|
||||||
|
status += SDL_RenderDrawPoint(renderer, x - offsety, y - offsetx);
|
||||||
|
|
||||||
|
if (status < 0) {
|
||||||
|
status = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d >= 2 * offsetx) {
|
||||||
|
d -= 2 * offsetx + 1;
|
||||||
|
offsetx += 1;
|
||||||
|
}
|
||||||
|
else if (d < 2 * (radius - offsety)) {
|
||||||
|
d += 2 * offsety - 1;
|
||||||
|
offsety -= 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d += 2 * (offsety - offsetx - 1);
|
||||||
|
offsety -= 1;
|
||||||
|
offsetx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugOverlay::UnInit()
|
||||||
|
{
|
||||||
|
delete dbScreen;
|
||||||
|
dbScreen = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugOverlay::DrawOverlay()
|
||||||
|
{
|
||||||
|
if (dbScreen == nullptr)
|
||||||
|
{
|
||||||
|
dbScreen = new gdrv_bitmap8(render::vscreen->Width, render::vscreen->Height, false, false);
|
||||||
|
dbScreen->CreateTexture("nearest", SDL_TEXTUREACCESS_TARGET);
|
||||||
|
SDL_SetTextureBlendMode(dbScreen->Texture, SDL_BLENDMODE_BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup overlay rendering
|
||||||
|
Uint8 initialR, initialG, initialB, initialA;
|
||||||
|
auto initialRenderTarget = SDL_GetRenderTarget(winmain::Renderer);
|
||||||
|
SDL_GetRenderDrawColor(winmain::Renderer, &initialR, &initialG, &initialB, &initialA);
|
||||||
|
SDL_SetRenderTarget(winmain::Renderer, dbScreen->Texture);
|
||||||
|
SDL_SetRenderDrawColor(winmain::Renderer, 0, 0, 0, 0);
|
||||||
|
SDL_RenderClear(winmain::Renderer);
|
||||||
|
|
||||||
|
// Draw EdgeManager box grid
|
||||||
|
if (options::Options.DebugOverlayGrid)
|
||||||
|
DrawBoxGrid();
|
||||||
|
|
||||||
|
// Draw all edges registered in TCollisionComponent.EdgeList + flippers
|
||||||
|
if (options::Options.DebugOverlayAllEdges)
|
||||||
|
DrawAllEdges();
|
||||||
|
|
||||||
|
// Draw ball collision
|
||||||
|
if (options::Options.DebugOverlayBallPosition || options::Options.DebugOverlayBallEdges)
|
||||||
|
DrawBallInfo();
|
||||||
|
|
||||||
|
// Restore render target
|
||||||
|
SDL_SetRenderTarget(winmain::Renderer, initialRenderTarget);
|
||||||
|
SDL_SetRenderDrawColor(winmain::Renderer,
|
||||||
|
initialR, initialG, initialB, initialA);
|
||||||
|
|
||||||
|
// Copy overlay with alpha blending
|
||||||
|
SDL_BlendMode blendMode;
|
||||||
|
SDL_GetRenderDrawBlendMode(winmain::Renderer, &blendMode);
|
||||||
|
SDL_SetRenderDrawBlendMode(winmain::Renderer, SDL_BLENDMODE_BLEND);
|
||||||
|
SDL_RenderCopy(winmain::Renderer, dbScreen->Texture, nullptr, &render::DestinationRect);
|
||||||
|
SDL_SetRenderDrawBlendMode(winmain::Renderer, blendMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugOverlay::DrawBoxGrid()
|
||||||
|
{
|
||||||
|
auto& edgeMan = *TTableLayer::edge_manager;
|
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(winmain::Renderer, 0, 255, 0, 255);
|
||||||
|
for (int x = 0; x <= edgeMan.MaxBoxX; x++)
|
||||||
|
{
|
||||||
|
vector2 boxPt{ x * edgeMan.AdvanceX + edgeMan.X , edgeMan.Y };
|
||||||
|
auto pt1 = proj::xform_to_2d(boxPt);
|
||||||
|
boxPt.Y = edgeMan.MaxBoxY * edgeMan.AdvanceY + edgeMan.Y;
|
||||||
|
auto pt2 = proj::xform_to_2d(boxPt);
|
||||||
|
|
||||||
|
SDL_RenderDrawLine(winmain::Renderer, pt1.X, pt1.Y, pt2.X, pt2.Y);
|
||||||
|
}
|
||||||
|
for (int y = 0; y <= edgeMan.MaxBoxY; y++)
|
||||||
|
{
|
||||||
|
vector2 boxPt{ edgeMan.X, y * edgeMan.AdvanceY + edgeMan.Y };
|
||||||
|
auto pt1 = proj::xform_to_2d(boxPt);
|
||||||
|
boxPt.X = edgeMan.MaxBoxX * edgeMan.AdvanceX + edgeMan.X;
|
||||||
|
auto pt2 = proj::xform_to_2d(boxPt);
|
||||||
|
|
||||||
|
SDL_RenderDrawLine(winmain::Renderer, pt1.X, pt1.Y, pt2.X, pt2.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugOverlay::DrawAllEdges()
|
||||||
|
{
|
||||||
|
SDL_SetRenderDrawColor(winmain::Renderer, 0, 200, 200, 255);
|
||||||
|
for (auto cmp : pb::MainTable->ComponentList)
|
||||||
|
{
|
||||||
|
auto collCmp = dynamic_cast<TCollisionComponent*>(cmp);
|
||||||
|
if (collCmp)
|
||||||
|
{
|
||||||
|
for (auto edge : collCmp->EdgeList)
|
||||||
|
{
|
||||||
|
DrawEdge(edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto flip = dynamic_cast<TFlipper*>(cmp);
|
||||||
|
if (flip)
|
||||||
|
{
|
||||||
|
DrawEdge(flip->FlipperEdge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugOverlay::DrawBallInfo()
|
||||||
|
{
|
||||||
|
auto& edgeMan = *TTableLayer::edge_manager;
|
||||||
|
for (auto ball : pb::MainTable->BallList)
|
||||||
|
{
|
||||||
|
if (ball->ActiveFlag)
|
||||||
|
{
|
||||||
|
vector2 ballPosition = { ball->Position.X, ball->Position.Y };
|
||||||
|
|
||||||
|
if (options::Options.DebugOverlayBallEdges)
|
||||||
|
{
|
||||||
|
SDL_SetRenderDrawColor(winmain::Renderer, 255, 0, 0, 255);
|
||||||
|
auto x = edgeMan.box_x(ballPosition.X), y = edgeMan.box_y(ballPosition.Y);
|
||||||
|
auto& box = edgeMan.BoxArray[x + y * edgeMan.MaxBoxX];
|
||||||
|
for (auto edge : box.EdgeList)
|
||||||
|
{
|
||||||
|
DrawEdge(edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options::Options.DebugOverlayBallPosition)
|
||||||
|
{
|
||||||
|
SDL_SetRenderDrawColor(winmain::Renderer, 0, 0, 255, 255);
|
||||||
|
|
||||||
|
auto pt1 = proj::xform_to_2d(ballPosition);
|
||||||
|
SDL_RenderDrawCircle(winmain::Renderer, pt1.X, pt1.Y, 10);
|
||||||
|
|
||||||
|
auto nextPos = ballPosition;
|
||||||
|
maths::vector_add(nextPos, maths::vector_mul(ball->Acceleration, ball->Speed / 10.0f));
|
||||||
|
auto pt2 = proj::xform_to_2d(nextPos);
|
||||||
|
SDL_RenderDrawLine(winmain::Renderer, pt1.X, pt1.Y, pt2.X, pt2.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugOverlay::DrawCicleType(circle_type& circle)
|
||||||
|
{
|
||||||
|
vector2 linePt{ circle.Center.X + sqrt(circle.RadiusSq), circle.Center.Y };
|
||||||
|
auto pt1 = proj::xform_to_2d(circle.Center);
|
||||||
|
auto pt2 = proj::xform_to_2d(linePt);
|
||||||
|
auto radius = abs(pt2.X - pt1.X);
|
||||||
|
|
||||||
|
SDL_RenderDrawCircle(winmain::Renderer, pt1.X, pt1.Y, radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugOverlay::DrawLineType(line_type& line)
|
||||||
|
{
|
||||||
|
auto pt1 = proj::xform_to_2d(line.Origin);
|
||||||
|
auto pt2 = proj::xform_to_2d(line.End);
|
||||||
|
|
||||||
|
SDL_RenderDrawLine(winmain::Renderer, pt1.X, pt1.Y, pt2.X, pt2.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugOverlay::DrawEdge(TEdgeSegment* edge)
|
||||||
|
{
|
||||||
|
if (options::Options.DebugOverlayCollisionMask)
|
||||||
|
{
|
||||||
|
TBall* refBall = nullptr;
|
||||||
|
for (auto ball : pb::MainTable->BallList)
|
||||||
|
{
|
||||||
|
if (ball->ActiveFlag)
|
||||||
|
{
|
||||||
|
refBall = ball;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (refBall != nullptr && (refBall->FieldFlag & edge->CollisionGroup) == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto line = dynamic_cast<TLine*>(edge);
|
||||||
|
if (line)
|
||||||
|
{
|
||||||
|
DrawLineType(line->Line);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto circle = dynamic_cast<TCircle*>(edge);
|
||||||
|
if (circle)
|
||||||
|
{
|
||||||
|
DrawCicleType(circle->Circle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto flip = dynamic_cast<TFlipperEdge*>(edge);
|
||||||
|
if (flip)
|
||||||
|
{
|
||||||
|
flip->set_control_points(pb::time_now);
|
||||||
|
flip->build_edges_in_motion();
|
||||||
|
|
||||||
|
DrawLineType(TFlipperEdge::lineA);
|
||||||
|
DrawLineType(TFlipperEdge::lineB);
|
||||||
|
DrawCicleType(TFlipperEdge::circlebase);
|
||||||
|
DrawCicleType(TFlipperEdge::circleT1);
|
||||||
|
}
|
||||||
|
}
|
22
SpaceCadetPinball/DebugOverlay.h
Normal file
22
SpaceCadetPinball/DebugOverlay.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct gdrv_bitmap8;
|
||||||
|
struct circle_type;
|
||||||
|
struct line_type;
|
||||||
|
class TEdgeSegment;
|
||||||
|
|
||||||
|
class DebugOverlay
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void UnInit();
|
||||||
|
static void DrawOverlay();
|
||||||
|
private:
|
||||||
|
static gdrv_bitmap8* dbScreen;
|
||||||
|
|
||||||
|
static void DrawCicleType(circle_type& circle);
|
||||||
|
static void DrawLineType(line_type& line);
|
||||||
|
static void DrawEdge(TEdgeSegment* edge);
|
||||||
|
static void DrawBoxGrid();
|
||||||
|
static void DrawAllEdges();
|
||||||
|
static void DrawBallInfo();
|
||||||
|
};
|
|
@ -47,7 +47,7 @@ void GroupData::AddEntry(EntryData* entry)
|
||||||
if (srcBmp->BitmapType == BitmapTypes::Spliced)
|
if (srcBmp->BitmapType == BitmapTypes::Spliced)
|
||||||
{
|
{
|
||||||
// Get rid of spliced bitmap early on, to simplify render pipeline
|
// Get rid of spliced bitmap early on, to simplify render pipeline
|
||||||
auto bmp = new gdrv_bitmap8(srcBmp->Width, srcBmp->Height, srcBmp->Width);
|
auto bmp = new gdrv_bitmap8(srcBmp->Width, srcBmp->Height, true);
|
||||||
auto zMap = new zmap_header_type(srcBmp->Width, srcBmp->Height, srcBmp->Width);
|
auto zMap = new zmap_header_type(srcBmp->Width, srcBmp->Height, srcBmp->Width);
|
||||||
SplitSplicedBitmap(*srcBmp, *bmp, *zMap);
|
SplitSplicedBitmap(*srcBmp, *bmp, *zMap);
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ TBall::TBall(TPinballTable* table) : TPinballComponent(table, -1, false)
|
||||||
if (ListBitmap)
|
if (ListBitmap)
|
||||||
ListBitmap->push_back(visual.Bitmap);
|
ListBitmap->push_back(visual.Bitmap);
|
||||||
auto visVec = reinterpret_cast<vector3*>(loader::query_float_attribute(groupIndex, index, 501));
|
auto visVec = reinterpret_cast<vector3*>(loader::query_float_attribute(groupIndex, index, 501));
|
||||||
auto zDepth = proj::z_distance(visVec);
|
auto zDepth = proj::z_distance(*visVec);
|
||||||
VisualZArray[index] = zDepth;
|
VisualZArray[index] = zDepth;
|
||||||
}
|
}
|
||||||
RenderSprite = render::create_sprite(VisualTypes::Ball, nullptr, nullptr, 0, 0, nullptr);
|
RenderSprite = render::create_sprite(VisualTypes::Ball, nullptr, nullptr, 0, 0, nullptr);
|
||||||
|
@ -60,8 +60,6 @@ TBall::TBall(TPinballTable* table) : TPinballComponent(table, -1, false)
|
||||||
|
|
||||||
void TBall::Repaint()
|
void TBall::Repaint()
|
||||||
{
|
{
|
||||||
int pos2D[2];
|
|
||||||
|
|
||||||
if (CollisionFlag)
|
if (CollisionFlag)
|
||||||
{
|
{
|
||||||
Position.Z =
|
Position.Z =
|
||||||
|
@ -70,8 +68,8 @@ void TBall::Repaint()
|
||||||
Offset + CollisionOffset.Z;
|
Offset + CollisionOffset.Z;
|
||||||
}
|
}
|
||||||
|
|
||||||
proj::xform_to_2d(&Position, pos2D);
|
auto pos2D = proj::xform_to_2d(Position);
|
||||||
auto zDepth = proj::z_distance(&Position);
|
auto zDepth = proj::z_distance(Position);
|
||||||
|
|
||||||
auto zArrPtr = VisualZArray;
|
auto zArrPtr = VisualZArray;
|
||||||
auto index = 0u;
|
auto index = 0u;
|
||||||
|
@ -85,8 +83,8 @@ void TBall::Repaint()
|
||||||
RenderSprite,
|
RenderSprite,
|
||||||
bmp,
|
bmp,
|
||||||
zDepth,
|
zDepth,
|
||||||
pos2D[0] - bmp->Width / 2,
|
pos2D.X - bmp->Width / 2,
|
||||||
pos2D[1] - bmp->Height / 2);
|
pos2D.Y - bmp->Height / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TBall::not_again(TEdgeSegment* edge)
|
void TBall::not_again(TEdgeSegment* edge)
|
||||||
|
|
|
@ -9,7 +9,15 @@
|
||||||
|
|
||||||
ColorRgba gdrv::current_palette[256]{};
|
ColorRgba gdrv::current_palette[256]{};
|
||||||
|
|
||||||
gdrv_bitmap8::gdrv_bitmap8(int width, int height, bool indexed)
|
gdrv_bitmap8::gdrv_bitmap8(int width, int height) : gdrv_bitmap8(width, height, true, true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
gdrv_bitmap8::gdrv_bitmap8(int width, int height, bool indexed) : gdrv_bitmap8(width, height, indexed, true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
gdrv_bitmap8::gdrv_bitmap8(int width, int height, bool indexed, bool bmpBuff)
|
||||||
{
|
{
|
||||||
assertm(width >= 0 && height >= 0, "Negative bitmap8 dimensions");
|
assertm(width >= 0 && height >= 0, "Negative bitmap8 dimensions");
|
||||||
|
|
||||||
|
@ -20,13 +28,15 @@ gdrv_bitmap8::gdrv_bitmap8(int width, int height, bool indexed)
|
||||||
BitmapType = BitmapTypes::DibBitmap;
|
BitmapType = BitmapTypes::DibBitmap;
|
||||||
Texture = nullptr;
|
Texture = nullptr;
|
||||||
IndexedBmpPtr = nullptr;
|
IndexedBmpPtr = nullptr;
|
||||||
|
BmpBufPtr1 = nullptr;
|
||||||
XPosition = 0;
|
XPosition = 0;
|
||||||
YPosition = 0;
|
YPosition = 0;
|
||||||
Resolution = 0;
|
Resolution = 0;
|
||||||
|
|
||||||
if (indexed)
|
if (indexed)
|
||||||
IndexedBmpPtr = new char[Height * IndexedStride];
|
IndexedBmpPtr = new char[Height * IndexedStride];
|
||||||
BmpBufPtr1 = new ColorRgba[Height * Stride];
|
if (bmpBuff)
|
||||||
|
BmpBufPtr1 = new ColorRgba[Height * Stride];
|
||||||
}
|
}
|
||||||
|
|
||||||
gdrv_bitmap8::gdrv_bitmap8(const dat8BitBmpHeader& header)
|
gdrv_bitmap8::gdrv_bitmap8(const dat8BitBmpHeader& header)
|
||||||
|
|
|
@ -47,7 +47,9 @@ static_assert(sizeof(ColorRgba) == 4, "Wrong size of RGBA color");
|
||||||
|
|
||||||
struct gdrv_bitmap8
|
struct gdrv_bitmap8
|
||||||
{
|
{
|
||||||
|
gdrv_bitmap8(int width, int height);
|
||||||
gdrv_bitmap8(int width, int height, bool indexed);
|
gdrv_bitmap8(int width, int height, bool indexed);
|
||||||
|
gdrv_bitmap8(int width, int height, bool indexed, bool bmpBuff);
|
||||||
gdrv_bitmap8(const struct dat8BitBmpHeader& header);
|
gdrv_bitmap8(const struct dat8BitBmpHeader& header);
|
||||||
~gdrv_bitmap8();
|
~gdrv_bitmap8();
|
||||||
void ScaleIndexed(float scaleX, float scaleY);
|
void ScaleIndexed(float scaleX, float scaleY);
|
||||||
|
|
|
@ -132,6 +132,7 @@ float maths::normalize_2d(vector2& vec)
|
||||||
void maths::line_init(line_type& line, float x0, float y0, float x1, float y1)
|
void maths::line_init(line_type& line, float x0, float y0, float x1, float y1)
|
||||||
{
|
{
|
||||||
line.Origin = { x0, y0 };
|
line.Origin = { x0, y0 };
|
||||||
|
line.End = { x1, y1 };
|
||||||
line.Direction.X = x1 - x0;
|
line.Direction.X = x1 - x0;
|
||||||
line.Direction.Y = y1 - y0;
|
line.Direction.Y = y1 - y0;
|
||||||
normalize_2d(line.Direction);
|
normalize_2d(line.Direction);
|
||||||
|
@ -219,6 +220,11 @@ vector2 maths::vector_sub(const vector2& vec1, const vector2& vec2)
|
||||||
return { vec1.X - vec2.X, vec1.Y - vec2.Y };
|
return { vec1.X - vec2.X, vec1.Y - vec2.Y };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector2 maths::vector_mul(const vector2& vec1, float val)
|
||||||
|
{
|
||||||
|
return { vec1.X * val, vec1.Y * val };
|
||||||
|
}
|
||||||
|
|
||||||
float maths::basic_collision(TBall* ball, vector2* nextPosition, vector2* direction, float elasticity, float smoothness,
|
float maths::basic_collision(TBall* ball, vector2* nextPosition, vector2* direction, float elasticity, float smoothness,
|
||||||
float threshold, float boost)
|
float threshold, float boost)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,9 +19,18 @@ struct vector2
|
||||||
|
|
||||||
struct vector3 :vector2
|
struct vector3 :vector2
|
||||||
{
|
{
|
||||||
|
vector3() = default;
|
||||||
|
vector3(float x, float y) : vector3{ x, y, 0 } {}
|
||||||
|
vector3(float x, float y, float z) : vector2{ x, y }, Z(z) {}
|
||||||
float Z;
|
float Z;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct vector2i
|
||||||
|
{
|
||||||
|
int X;
|
||||||
|
int Y;
|
||||||
|
};
|
||||||
|
|
||||||
struct rectangle_type
|
struct rectangle_type
|
||||||
{
|
{
|
||||||
int XPosition;
|
int XPosition;
|
||||||
|
@ -52,6 +61,7 @@ struct line_type
|
||||||
vector2 PerpendicularC;
|
vector2 PerpendicularC;
|
||||||
vector2 Direction;
|
vector2 Direction;
|
||||||
vector2 Origin;
|
vector2 Origin;
|
||||||
|
vector2 End;
|
||||||
float MinCoord;
|
float MinCoord;
|
||||||
float MaxCoord;
|
float MaxCoord;
|
||||||
vector2 RayIntersect;
|
vector2 RayIntersect;
|
||||||
|
@ -98,6 +108,7 @@ public:
|
||||||
static float magnitude(const vector3& vec);
|
static float magnitude(const vector3& vec);
|
||||||
static void vector_add(vector2& vec1Dst, const vector2& vec2);
|
static void vector_add(vector2& vec1Dst, const vector2& vec2);
|
||||||
static vector2 vector_sub(const vector2& vec1, const vector2& vec2);
|
static vector2 vector_sub(const vector2& vec1, const vector2& vec2);
|
||||||
|
static vector2 vector_mul(const vector2& vec1, float val);
|
||||||
static float basic_collision(TBall* ball, vector2* nextPosition, vector2* direction, float elasticity,
|
static float basic_collision(TBall* ball, vector2* nextPosition, vector2* direction, float elasticity,
|
||||||
float smoothness,
|
float smoothness,
|
||||||
float threshold, float boost);
|
float threshold, float boost);
|
||||||
|
|
|
@ -104,6 +104,12 @@ void options::InitPrimary()
|
||||||
Options.IntegerScaling = get_int("Integer Scaling", false);
|
Options.IntegerScaling = get_int("Integer Scaling", false);
|
||||||
Options.SoundVolume = Clamp(get_int("Sound Volume", DefVolume), MinVolume, MaxVolume);
|
Options.SoundVolume = Clamp(get_int("Sound Volume", DefVolume), MinVolume, MaxVolume);
|
||||||
Options.MusicVolume = Clamp(get_int("Music Volume", DefVolume), MinVolume, MaxVolume);
|
Options.MusicVolume = Clamp(get_int("Music Volume", DefVolume), MinVolume, MaxVolume);
|
||||||
|
Options.DebugOverlay = get_int("Debug Overlay", false);
|
||||||
|
Options.DebugOverlayGrid = get_int("Debug Overlay Grid", true);
|
||||||
|
Options.DebugOverlayAllEdges = get_int("Debug Overlay All Edges", true);
|
||||||
|
Options.DebugOverlayBallPosition = get_int("Debug Overlay Ball Position", true);
|
||||||
|
Options.DebugOverlayBallEdges = get_int("Debug Overlay Ball Edges", true);
|
||||||
|
Options.DebugOverlayCollisionMask = get_int("Debug Overlay Collision Mask", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void options::InitSecondary()
|
void options::InitSecondary()
|
||||||
|
@ -143,6 +149,12 @@ void options::uninit()
|
||||||
set_int("Integer Scaling", Options.IntegerScaling);
|
set_int("Integer Scaling", Options.IntegerScaling);
|
||||||
set_int("Sound Volume", Options.SoundVolume);
|
set_int("Sound Volume", Options.SoundVolume);
|
||||||
set_int("Music Volume", Options.MusicVolume);
|
set_int("Music Volume", Options.MusicVolume);
|
||||||
|
set_int("Debug Overlay", Options.DebugOverlay);
|
||||||
|
set_int("Debug Overlay Grid", Options.DebugOverlayGrid);
|
||||||
|
set_int("Debug Overlay All Edges", Options.DebugOverlayAllEdges);
|
||||||
|
set_int("Debug Overlay Ball Position", Options.DebugOverlayBallPosition);
|
||||||
|
set_int("Debug Overlay Ball Edges", Options.DebugOverlayBallEdges);
|
||||||
|
set_int("Debug Overlay Collision Mask", Options.DebugOverlayCollisionMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,12 @@ struct optionsStruct
|
||||||
bool IntegerScaling;
|
bool IntegerScaling;
|
||||||
int SoundVolume;
|
int SoundVolume;
|
||||||
int MusicVolume;
|
int MusicVolume;
|
||||||
|
bool DebugOverlay;
|
||||||
|
bool DebugOverlayGrid;
|
||||||
|
bool DebugOverlayAllEdges;
|
||||||
|
bool DebugOverlayBallPosition;
|
||||||
|
bool DebugOverlayBallEdges;
|
||||||
|
bool DebugOverlayCollisionMask;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ControlRef
|
struct ControlRef
|
||||||
|
|
|
@ -26,33 +26,42 @@ void proj::init(float* mat4x3, float d, float centerX, float centerY)
|
||||||
centery = centerY;
|
centery = centerY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void proj::matrix_vector_multiply(mat4_row_major* mat, vector3* vec, vector3* dstVec)
|
vector3 proj::matrix_vector_multiply(const mat4_row_major& mat, const vector3& vec)
|
||||||
{
|
{
|
||||||
const float x = vec->X, y = vec->Y, z = vec->Z;
|
vector3 dstVec;
|
||||||
dstVec->X = z * mat->Row0.Z + y * mat->Row0.Y + x * mat->Row0.X + mat->Row0.W;
|
const float x = vec.X, y = vec.Y, z = vec.Z;
|
||||||
dstVec->Y = z * mat->Row1.Z + y * mat->Row1.Y + x * mat->Row1.X + mat->Row1.W;
|
dstVec.X = z * mat.Row0.Z + y * mat.Row0.Y + x * mat.Row0.X + mat.Row0.W;
|
||||||
dstVec->Z = z * mat->Row2.Z + y * mat->Row2.Y + x * mat->Row2.X + mat->Row2.W;
|
dstVec.Y = z * mat.Row1.Z + y * mat.Row1.Y + x * mat.Row1.X + mat.Row1.W;
|
||||||
|
dstVec.Z = z * mat.Row2.Z + y * mat.Row2.Y + x * mat.Row2.X + mat.Row2.W;
|
||||||
|
return dstVec;
|
||||||
}
|
}
|
||||||
|
|
||||||
float proj::z_distance(vector3* vec)
|
float proj::z_distance(const vector3& vec)
|
||||||
{
|
{
|
||||||
vector3 dstVec{};
|
auto projVec = matrix_vector_multiply(matrix, vec);
|
||||||
matrix_vector_multiply(&matrix, vec, &dstVec);
|
return maths::magnitude(projVec);
|
||||||
return maths::magnitude(dstVec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void proj::xform_to_2d(vector3* vec, int* dst)
|
vector2i proj::xform_to_2d(const vector2& vec)
|
||||||
|
{
|
||||||
|
vector3 vec3{ vec.X, vec.Y, 0 };
|
||||||
|
return xform_to_2d(vec3);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector2i proj::xform_to_2d(const vector3& vec)
|
||||||
{
|
{
|
||||||
float projCoef;
|
float projCoef;
|
||||||
vector3 dstVec2{};
|
|
||||||
|
|
||||||
matrix_vector_multiply(&matrix, vec, &dstVec2);
|
auto projVec = matrix_vector_multiply(matrix, vec);
|
||||||
if (dstVec2.Z == 0.0f)
|
if (projVec.Z == 0.0f)
|
||||||
projCoef = 999999.88f;
|
projCoef = 999999.88f;
|
||||||
else
|
else
|
||||||
projCoef = d_ / dstVec2.Z;
|
projCoef = d_ / projVec.Z;
|
||||||
dst[0] = static_cast<int>(dstVec2.X * projCoef + centerx);
|
return
|
||||||
dst[1] = static_cast<int>(dstVec2.Y * projCoef + centery);
|
{
|
||||||
|
static_cast<int>(projVec.X * projCoef + centerx),
|
||||||
|
static_cast<int>(projVec.Y * projCoef + centery)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void proj::recenter(float centerX, float centerY)
|
void proj::recenter(float centerX, float centerY)
|
||||||
|
|
|
@ -22,9 +22,10 @@ class proj
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void init(float* mat4x3, float d, float centerX, float centerY);
|
static void init(float* mat4x3, float d, float centerX, float centerY);
|
||||||
static void matrix_vector_multiply(mat4_row_major* mat, vector3* vec, vector3* dstVec);
|
static vector3 matrix_vector_multiply(const mat4_row_major& mat, const vector3& vec);
|
||||||
static float z_distance(vector3* vec);
|
static float z_distance(const vector3& vec);
|
||||||
static void xform_to_2d(vector3* vec, int* dst);
|
static vector2i xform_to_2d(const vector3& vec);
|
||||||
|
static vector2i xform_to_2d(const vector2& vec);
|
||||||
static void recenter(float centerX, float centerY);
|
static void recenter(float centerX, float centerY);
|
||||||
private:
|
private:
|
||||||
static mat4_row_major matrix;
|
static mat4_row_major matrix;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "score.h"
|
#include "score.h"
|
||||||
#include "TPinballTable.h"
|
#include "TPinballTable.h"
|
||||||
#include "winmain.h"
|
#include "winmain.h"
|
||||||
|
#include "DebugOverlay.h"
|
||||||
|
|
||||||
std::vector<render_sprite_type_struct*> render::dirty_list, render::sprite_list, render::ball_list;
|
std::vector<render_sprite_type_struct*> render::dirty_list, render::sprite_list, render::ball_list;
|
||||||
zmap_header_type* render::background_zmap;
|
zmap_header_type* render::background_zmap;
|
||||||
|
@ -57,6 +58,7 @@ void render::uninit()
|
||||||
ball_list.clear();
|
ball_list.clear();
|
||||||
dirty_list.clear();
|
dirty_list.clear();
|
||||||
sprite_list.clear();
|
sprite_list.clear();
|
||||||
|
DebugOverlay::UnInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void render::recreate_screen_texture()
|
void render::recreate_screen_texture()
|
||||||
|
@ -585,4 +587,9 @@ void render::PresentVScreen()
|
||||||
SDL_RenderCopy(winmain::Renderer, vscreen->Texture, &srcSidebarRect, &dstSidebarRect);
|
SDL_RenderCopy(winmain::Renderer, vscreen->Texture, &srcSidebarRect, &dstSidebarRect);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options::Options.DebugOverlay)
|
||||||
|
{
|
||||||
|
DebugOverlay::DrawOverlay();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -577,6 +577,24 @@ void winmain::RenderUi()
|
||||||
{
|
{
|
||||||
DispGRhistory ^= true;
|
DispGRhistory ^= true;
|
||||||
}
|
}
|
||||||
|
if (ImGui::MenuItem("Debug Overlay", nullptr, Options.DebugOverlay))
|
||||||
|
{
|
||||||
|
Options.DebugOverlay ^= true;
|
||||||
|
}
|
||||||
|
if (Options.DebugOverlay && ImGui::BeginMenu("Overlay Options"))
|
||||||
|
{
|
||||||
|
if (ImGui::MenuItem("Box Grid", nullptr, Options.DebugOverlayGrid))
|
||||||
|
Options.DebugOverlayGrid ^= true;
|
||||||
|
if (ImGui::MenuItem("All Edges", nullptr, Options.DebugOverlayAllEdges))
|
||||||
|
Options.DebugOverlayAllEdges ^= true;
|
||||||
|
if (ImGui::MenuItem("Ball Position", nullptr, Options.DebugOverlayBallPosition))
|
||||||
|
Options.DebugOverlayBallPosition ^= true;
|
||||||
|
if (ImGui::MenuItem("Ball Box Edges", nullptr, Options.DebugOverlayBallEdges))
|
||||||
|
Options.DebugOverlayBallEdges ^= true;
|
||||||
|
if (ImGui::MenuItem("Apply Collision Mask", nullptr, Options.DebugOverlayCollisionMask))
|
||||||
|
Options.DebugOverlayCollisionMask ^= true;
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
if (ImGui::BeginMenu("Cheats"))
|
if (ImGui::BeginMenu("Cheats"))
|
||||||
{
|
{
|
||||||
if (ImGui::MenuItem("hidden test", nullptr, pb::cheat_mode))
|
if (ImGui::MenuItem("hidden test", nullptr, pb::cheat_mode))
|
||||||
|
|
Loading…
Reference in a new issue