Skip to content
Permalink
Browse files

gpu: refactored polygon command to output valid struct

  • Loading branch information
JaCzekanski committed Aug 26, 2019
1 parent 8bfa8ad commit baaf19c32f055ecd9b7c513b19336f9ec2199f69
@@ -46,60 +46,32 @@ void GPU::reset() {
gp0_e6._reg = 0;
}

void GPU::drawPolygon(int16_t x[4], int16_t y[4], RGB c[4], TextureInfo t, bool isQuad, bool textured, int flags) {
int baseX = 0, baseY = 0, clutX = 0, clutY = 0, bitcount = 0;

for (int i = 0; i < (isQuad ? 4 : 3); i++) {
x[i] += drawingOffsetX;
y[i] += drawingOffsetY;
}

if (textured) {
clutX = t.getClutX();
clutY = t.getClutY();
baseX = t.getBaseX();
baseY = t.getBaseY();
bitcount = t.getBitcount();
flags |= ((int)t.semiTransparencyBlending()) << 5;
} else {
flags |= ((int)gp0_e1.semiTransparency) << 5;
void GPU::drawTriangle(const primitive::Triangle& triangle) {
if (hardwareRendering) {
int flags = 0;
if (triangle.isSemiTransparent) flags |= Vertex::Flags::SemiTransparency;
if (triangle.isRawTexture) flags |= Vertex::Flags::RawTexture;
if (gp0_e1.dither24to15) flags |= Vertex::Flags::Dithering;
if (triangle.gouroudShading) flags |= Vertex::Flags::GouroudShading;
flags |= static_cast<int>(triangle.transparency) << 5;

for (int i : {0, 1, 2}) {
auto& v = triangle.v[i];
vertices.push_back({Vertex::Type::Polygon,
{v.pos.x + drawingOffsetX, v.pos.y + drawingOffsetY},
{v.color.r, v.color.g, v.color.b},
{v.uv.x, v.uv.y},
triangle.bits,
{triangle.clut.x, triangle.clut.y},
{triangle.texpage.x, triangle.texpage.y},
flags,
gp0_e2,
gp0_e6});
}
}

Vertex v[3];
for (int i : {0, 1, 2}) {
v[i] = {Vertex::Type::Polygon,
{x[i], y[i]},
{c[i].r, c[i].g, c[i].b},
{t.uv[i].x, t.uv[i].y},
bitcount,
{clutX, clutY},
{baseX, baseY},
flags,
gp0_e2,
gp0_e6};
vertices.push_back(v[i]);
}
if (softwareRendering) {
Render::drawTriangle(this, v);
}

if (isQuad) {
for (int i : {1, 2, 3}) {
v[i - 1] = {Vertex::Type::Polygon,
{x[i], y[i]},
{c[i].r, c[i].g, c[i].b},
{t.uv[i].x, t.uv[i].y},
bitcount,
{clutX, clutY},
{baseX, baseY},
flags,
gp0_e2,
gp0_e6};
vertices.push_back(v[i - 1]);
}
if (softwareRendering) {
Render::drawTriangle(this, v);
}
Render::drawTriangle(this, triangle);
}
}

@@ -241,29 +213,53 @@ void GPU::cmdFillRectangle(uint8_t command) {

void GPU::cmdPolygon(PolygonArgs arg) {
int ptr = 1;
int16_t x[4], y[4];
RGB c[4] = {};

primitive::Triangle::Vertex v[4];
TextureInfo tex;

for (int i = 0; i < arg.getVertexCount(); i++) {
x[i] = extend_sign<10>(arguments[ptr] & 0xffff);
y[i] = extend_sign<10>((arguments[ptr++] & 0xffff0000) >> 16);
v[i].pos.x = extend_sign<10>(arguments[ptr] & 0xffff);
v[i].pos.y = extend_sign<10>((arguments[ptr++] & 0xffff0000) >> 16);

if (!arg.isRawTexture && (!arg.gouroudShading || i == 0)) c[i].raw = arguments[0] & 0xffffff;
if (!arg.isRawTexture && (!arg.gouroudShading || i == 0)) v[i].color.raw = arguments[0] & 0xffffff;
if (arg.isTextureMapped) {
if (i == 0) tex.palette = arguments[ptr];
if (i == 1) tex.texpage = arguments[ptr];
tex.uv[i].x = arguments[ptr] & 0xff;
tex.uv[i].y = (arguments[ptr] >> 8) & 0xff;
v[i].uv.x = arguments[ptr] & 0xff;
v[i].uv.y = (arguments[ptr] >> 8) & 0xff;
ptr++;
}
if (arg.gouroudShading && i < arg.getVertexCount() - 1) c[i + 1].raw = arguments[ptr++];
if (arg.gouroudShading && i < arg.getVertexCount() - 1) v[i + 1].color.raw = arguments[ptr++] & 0xffffff;
}

primitive::Triangle triangle;

for (int i : {0, 1, 2}) triangle.v[i] = v[i];

triangle.bits = 0;
triangle.isSemiTransparent = arg.semiTransparency;
triangle.transparency = gp0_e1.semiTransparency;
triangle.isRawTexture = arg.isRawTexture;
triangle.gouroudShading = arg.gouroudShading;

if (arg.isTextureMapped) {
triangle.bits = tex.getBitcount();
triangle.texpage.x = tex.getBaseX();
triangle.texpage.y = tex.getBaseY();
triangle.clut.x = tex.getClutX();
triangle.clut.y = tex.getClutY();
triangle.transparency = tex.semiTransparencyBlending();
}

triangle.assureCcw();
drawTriangle(triangle);

if (arg.isQuad) {
for (int i : {1, 2, 3}) triangle.v[i - 1] = v[i];

triangle.assureCcw();
drawTriangle(triangle);
}
int flags = 0;
if (arg.semiTransparency) flags |= Vertex::SemiTransparency;
if (arg.isRawTexture) flags |= Vertex::RawTexture;
if (arg.gouroudShading) flags |= Vertex::GouroudShading;
if (gp0_e1.dither24to15) flags |= Vertex::Dithering;
drawPolygon(x, y, c, tex, arg.isQuad, arg.isTextureMapped, flags);

cmd = Command::None;
}
@@ -106,7 +106,7 @@ class GPU {
void cmdVramToCpu(uint8_t command);
void cmdVramToVram(uint8_t command);

void drawPolygon(int16_t x[4], int16_t y[4], RGB c[4], TextureInfo t, bool isQuad = false, bool textured = false, int flags = 0);
void drawTriangle(const primitive::Triangle& triangle);
void drawLine(const primitive::Line& line);
void drawRectangle(const primitive::Rect& rect);

@@ -1,5 +1,7 @@
#pragma once
#include <glm/glm.hpp>
#include <utility>
#include "device/gpu/semi_transparency.h"
#include "psx_color.h"

namespace primitive {
@@ -27,4 +29,39 @@ struct Line {
bool isSemiTransparent;
bool gouroudShading;
};

struct Triangle {
struct Vertex {
glm::ivec2 pos;
RGB color; // Valid if bits == 0 or !isRawTexture
glm::ivec2 uv; // Valid if bits != 0
};
Vertex v[3];

// Flags
int bits = 0;
gpu::SemiTransparency transparency; // Valid if isSemiTransparent
bool isSemiTransparent = false;
bool isRawTexture = false;
bool gouroudShading = false;

// Texture, valid if bits != 0
glm::ivec2 texpage; // Texture page position in VRAM
glm::ivec2 clut; // Texture palette position in VRAM

void assureCcw() {
if (isCw()) {
std::swap(v[1], v[2]);
}
}

private:
bool isCw() const {
auto ab = v[1].pos - v[0].pos;
auto ac = v[2].pos - v[0].pos;
auto cross = ab.x * ac.y - ab.y * ac.x;

return cross < 0;
}
};
} // namespace primitive
@@ -4,6 +4,7 @@
#include "utils/macros.h"
#include "utils/math.h"

#undef RGB // Some header is adding this macro on Windows
// Union for storing 24bit color (used in GPU commands)
union RGB {
struct {
@@ -13,6 +14,8 @@ union RGB {
uint8_t _;
};
uint32_t raw;

RGB() : raw(0) {}
};

RGB operator*(const RGB& lhs, const float rhs);
@@ -1,5 +1,6 @@
#pragma once
#include "device/device.h"
#include "semi_transparency.h"

namespace gpu {

@@ -8,12 +9,6 @@ const int MAX_ARGS = 32;

// Draw Mode setting
union GP0_E1 {
enum class SemiTransparency : uint32_t {
Bby2plusFby2 = 0, // B/2+F/2
BplusF = 1, // B+F
BminusF = 2, // B-F
BplusFby4 = 3 // B+F/4
};
enum class TexturePageColors : uint32_t { bit4 = 0, bit8 = 1, bit15 = 2 };
enum class DrawingToDisplayArea : uint32_t { prohibited = 0, allowed = 1 };
struct {
@@ -248,12 +243,8 @@ struct TextureInfo {

int getClutX() const { return ((palette & 0x003f0000) >> 16) * 16; }
int getClutY() const { return ((palette & 0x7fc00000) >> 22); }
int getBaseX() const {
return ((texpage & 0x0f0000) >> 16) * 64; // N * 64
}
int getBaseY() const {
return ((texpage & 0x100000) >> 20) * 256; // N * 256
}
int getBaseX() const { return ((texpage & 0x0f0000) >> 16) * 64; } // N * 64
int getBaseY() const { return ((texpage & 0x100000) >> 20) * 256; } // N * 256
int getBitcount() const {
int depth = (texpage & 0x1800000) >> 23;
switch (depth) {
@@ -265,7 +256,7 @@ struct TextureInfo {
}
}

GP0_E1::SemiTransparency semiTransparencyBlending() const { return (GP0_E1::SemiTransparency)((texpage & 0x600000) >> 21); }
SemiTransparency semiTransparencyBlending() const { return (SemiTransparency)((texpage & 0x600000) >> 21); }
};

// Debug/rewind
@@ -4,6 +4,6 @@
class Render {
public:
static void drawLine(gpu::GPU* gpu, const primitive::Line& line);
static void drawTriangle(gpu::GPU* gpu, gpu::Vertex v[3]);
static void drawTriangle(gpu::GPU* gpu, const primitive::Triangle& triangle);
static void drawRectangle(gpu::GPU* gpu, const primitive::Rect& rect);
};
@@ -7,7 +7,7 @@
#define VRAM ((uint16_t(*)[gpu::VRAM_WIDTH])gpu->vram.data())

void Render::drawLine(gpu::GPU* gpu, const primitive::Line& line) {
using Transparency = gpu::GP0_E1::SemiTransparency;
using Transparency = gpu::SemiTransparency;
const auto transparency = gpu->gp0_e1.semiTransparency;
const bool checkMaskBeforeDraw = gpu->gp0_e6.checkMaskBeforeDraw;
const bool setMaskWhileDrawing = gpu->gp0_e6.setMaskWhileDrawing;

0 comments on commit baaf19c

Please sign in to comment.
You can’t perform that action at this time.