mirror of
https://github.com/whaison/psxact.git
synced 2024-05-16 19:10:33 -04:00
Implementing textured quads.
This commit is contained in:
parent
9eb540f12f
commit
d61e89cf71
|
@ -21,7 +21,7 @@ set(SOURCE_FILES
|
|||
src/bus.hpp
|
||||
src/psxact.cpp
|
||||
src/utility.cpp
|
||||
src/utility.hpp)
|
||||
src/utility.hpp src/gpu/gpu_draw_gouraud.cpp src/gpu/gpu_draw_texture.cpp)
|
||||
|
||||
add_executable(psxact ${SOURCE_FILES})
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ available, use one of them if you wish.
|
|||
## Current Status
|
||||
|
||||
Currently, the emulator hangs after drawing the Sony™ logo while trying
|
||||
to communicate with the CD-ROM drive. Textured primitives are not implemented,
|
||||
nor are they attempted.
|
||||
to communicate with the CD-ROM drive. Textured primitives are partially
|
||||
implemented.
|
||||
|
||||
![Current status](images/current.png)
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 22 KiB |
|
@ -1,7 +1,5 @@
|
|||
#include "gpu_core.hpp"
|
||||
#include "../utility.hpp"
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
|
||||
static gpu::state_t state;
|
||||
|
||||
|
@ -30,6 +28,14 @@ static int gp0_command_size[256] = {
|
|||
|
||||
gpu::vram_t gpu::vram;
|
||||
|
||||
uint16_t gpu::read_vram(int x, int y) {
|
||||
return vram.h[(y * 1024) + x];
|
||||
}
|
||||
|
||||
void gpu::write_vram(int x, int y, uint16_t color) {
|
||||
vram.h[(y * 1024) + x] = color;
|
||||
}
|
||||
|
||||
// --=============--
|
||||
// I/O Functions
|
||||
// --=============--
|
||||
|
@ -57,13 +63,29 @@ static inline uint32_t read_stat() {
|
|||
(1 << 28);
|
||||
}
|
||||
|
||||
static gpu::point_t gp0_to_point(const uint32_t &vertex, const uint32_t &color) {
|
||||
gpu::point_t p;
|
||||
p.x = int(vertex & 0xffff);
|
||||
p.y = int(vertex >> 16);
|
||||
p.r = (color >> 0) & 0xff;
|
||||
p.g = (color >> 8) & 0xff;
|
||||
p.b = (color >> 16) & 0xff;
|
||||
static gpu::gouraud::pixel_t gp0_to_gouraud_pixel(uint32_t vertex, uint32_t color) {
|
||||
gpu::gouraud::pixel_t p;
|
||||
p.point.x = int(vertex & 0xffff);
|
||||
p.point.y = int(vertex >> 16);
|
||||
|
||||
p.color.r = (color >> 0) & 0xff;
|
||||
p.color.g = (color >> 8) & 0xff;
|
||||
p.color.b = (color >> 16) & 0xff;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static gpu::texture::pixel_t gp0_to_texture_pixel(uint32_t vertex, uint32_t color, uint32_t texcoord) {
|
||||
gpu::texture::pixel_t p;
|
||||
p.point.x = int(vertex & 0xffff);
|
||||
p.point.y = int(vertex >> 16);
|
||||
|
||||
p.color.r = (color >> 0) & 0xff;
|
||||
p.color.g = (color >> 8) & 0xff;
|
||||
p.color.b = (color >> 16) & 0xff;
|
||||
|
||||
p.u = (texcoord >> 0) & 0xff;
|
||||
p.v = (texcoord >> 8) & 0xff;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
@ -119,12 +141,12 @@ static inline void write_gp0(uint32_t data) {
|
|||
auto vertex3 = get_gp0_data();
|
||||
auto vertex4 = get_gp0_data();
|
||||
|
||||
auto v0 = gp0_to_point(vertex1, color);
|
||||
auto v1 = gp0_to_point(vertex2, color);
|
||||
auto v2 = gp0_to_point(vertex3, color);
|
||||
auto v3 = gp0_to_point(vertex4, color);
|
||||
auto v0 = gp0_to_gouraud_pixel(vertex1, color);
|
||||
auto v1 = gp0_to_gouraud_pixel(vertex2, color);
|
||||
auto v2 = gp0_to_gouraud_pixel(vertex3, color);
|
||||
auto v3 = gp0_to_gouraud_pixel(vertex4, color);
|
||||
|
||||
gpu::draw_poly4(v0, v1, v2, v3);
|
||||
gpu::gouraud::draw_poly4({v0, v1, v2, v3});
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -139,12 +161,18 @@ static inline void write_gp0(uint32_t data) {
|
|||
auto vertex4 = get_gp0_data();
|
||||
auto tcoord4 = get_gp0_data();
|
||||
|
||||
auto v0 = gp0_to_point(vertex1, color);
|
||||
auto v1 = gp0_to_point(vertex2, color);
|
||||
auto v2 = gp0_to_point(vertex3, color);
|
||||
auto v3 = gp0_to_point(vertex4, color);
|
||||
gpu::texture::poly4_t p;
|
||||
|
||||
gpu::draw_poly4(v0, v1, v2, v3);
|
||||
p.v0 = gp0_to_texture_pixel(vertex1, color, tcoord1);
|
||||
p.v1 = gp0_to_texture_pixel(vertex2, color, tcoord2);
|
||||
p.v2 = gp0_to_texture_pixel(vertex3, color, tcoord3);
|
||||
p.v3 = gp0_to_texture_pixel(vertex4, color, tcoord4);
|
||||
p.clut_x = ((tcoord1 >> 16) & 0x03f) * 16;
|
||||
p.clut_y = ((tcoord1 >> 22) & 0x1ff) * 1;
|
||||
p.base_u = ((tcoord2 >> 16) & 0x00f) * 64;
|
||||
p.base_v = ((tcoord2 >> 20) & 0x001) * 256;
|
||||
|
||||
gpu::texture::draw_poly4(p);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -156,11 +184,11 @@ static inline void write_gp0(uint32_t data) {
|
|||
auto color3 = get_gp0_data();
|
||||
auto vertex3 = get_gp0_data();
|
||||
|
||||
auto v0 = gp0_to_point(vertex1, color1);
|
||||
auto v1 = gp0_to_point(vertex2, color2);
|
||||
auto v2 = gp0_to_point(vertex3, color3);
|
||||
auto v0 = gp0_to_gouraud_pixel(vertex1, color1);
|
||||
auto v1 = gp0_to_gouraud_pixel(vertex2, color2);
|
||||
auto v2 = gp0_to_gouraud_pixel(vertex3, color3);
|
||||
|
||||
gpu::draw_poly3(v0, v1, v2);
|
||||
gpu::gouraud::draw_poly3({v0, v1, v2});
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -174,12 +202,12 @@ static inline void write_gp0(uint32_t data) {
|
|||
auto color4 = get_gp0_data();
|
||||
auto vertex4 = get_gp0_data();
|
||||
|
||||
auto v0 = gp0_to_point(vertex1, color1);
|
||||
auto v1 = gp0_to_point(vertex2, color2);
|
||||
auto v2 = gp0_to_point(vertex3, color3);
|
||||
auto v3 = gp0_to_point(vertex4, color4);
|
||||
auto v0 = gp0_to_gouraud_pixel(vertex1, color1);
|
||||
auto v1 = gp0_to_gouraud_pixel(vertex2, color2);
|
||||
auto v2 = gp0_to_gouraud_pixel(vertex3, color3);
|
||||
auto v3 = gp0_to_gouraud_pixel(vertex4, color4);
|
||||
|
||||
gpu::draw_poly4(v0, v1, v2, v3);
|
||||
gpu::gouraud::draw_poly4({v0, v1, v2, v3});
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,28 +57,75 @@ namespace gpu {
|
|||
|
||||
void write(int size, uint32_t address, uint32_t data);
|
||||
|
||||
struct point_t {
|
||||
int x;
|
||||
int y;
|
||||
uint16_t read_vram(int x, int y);
|
||||
|
||||
void write_vram(int x, int y, uint16_t color);
|
||||
|
||||
struct color_t {
|
||||
int r;
|
||||
int g;
|
||||
int b;
|
||||
};
|
||||
|
||||
struct triangle_t {
|
||||
point_t v[3];
|
||||
struct point_t {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
struct quad_t {
|
||||
point_t v0;
|
||||
point_t v1;
|
||||
point_t v2;
|
||||
point_t v3;
|
||||
};
|
||||
void draw_point(int x, int y, int r, int g, int b);
|
||||
|
||||
void draw_poly3(const gpu::point_t &v0, const gpu::point_t &v1, const gpu::point_t &v2);
|
||||
namespace gouraud {
|
||||
struct pixel_t {
|
||||
point_t point;
|
||||
color_t color;
|
||||
};
|
||||
|
||||
void draw_poly4(const gpu::point_t &v0, const gpu::point_t &v1, const gpu::point_t &v2, const gpu::point_t &v3);
|
||||
struct poly3_t {
|
||||
pixel_t v[3];
|
||||
};
|
||||
|
||||
struct poly4_t {
|
||||
pixel_t v[4];
|
||||
};
|
||||
|
||||
void draw_poly3(const gpu::gouraud::poly3_t &p);
|
||||
|
||||
void draw_poly4(const gpu::gouraud::poly4_t &p);
|
||||
}
|
||||
|
||||
namespace texture {
|
||||
struct pixel_t {
|
||||
point_t point;
|
||||
color_t color;
|
||||
int u;
|
||||
int v;
|
||||
};
|
||||
|
||||
struct poly3_t {
|
||||
pixel_t v0;
|
||||
pixel_t v1;
|
||||
pixel_t v2;
|
||||
int clut_x;
|
||||
int clut_y;
|
||||
int base_u;
|
||||
int base_v;
|
||||
};
|
||||
|
||||
struct poly4_t {
|
||||
pixel_t v0;
|
||||
pixel_t v1;
|
||||
pixel_t v2;
|
||||
pixel_t v3;
|
||||
int clut_x;
|
||||
int clut_y;
|
||||
int base_u;
|
||||
int base_v;
|
||||
};
|
||||
|
||||
void draw_poly3(const poly3_t &p);
|
||||
|
||||
void draw_poly4(const poly4_t &p);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //PSXACT_GPU_CORE_HPP
|
||||
|
|
|
@ -14,109 +14,19 @@ static int dither_lut[4][4] = {
|
|||
{ 3, -1, 2, -2 }
|
||||
};
|
||||
|
||||
void draw_point(const int &x, const int &y, const int &r, const int &g, const int &b) {
|
||||
void gpu::draw_point(int x, int y, int r, int g, int b) {
|
||||
auto address = (y << 10) + x;
|
||||
|
||||
auto dither = dither_lut[y & 3][x & 3];
|
||||
|
||||
auto r_ = clip<0, 255>(r + dither);
|
||||
auto g_ = clip<0, 255>(g + dither);
|
||||
auto b_ = clip<0, 255>(b + dither);
|
||||
r = clip<0, 255>(r + dither);
|
||||
g = clip<0, 255>(g + dither);
|
||||
b = clip<0, 255>(b + dither);
|
||||
|
||||
auto color =
|
||||
(((r_ >> 3) & 0x1f) << 0) |
|
||||
(((g_ >> 3) & 0x1f) << 5) |
|
||||
(((b_ >> 3) & 0x1f) << 10);
|
||||
(((r >> 3) & 0x1f) << 0) |
|
||||
(((g >> 3) & 0x1f) << 5) |
|
||||
(((b >> 3) & 0x1f) << 10);
|
||||
|
||||
gpu::vram.h[address] = uint16_t(color);
|
||||
}
|
||||
|
||||
static int min3(int a, int b, int c) {
|
||||
if (a <= b && a <= c) return a;
|
||||
if (b <= a && b <= c) return b;
|
||||
return c;
|
||||
}
|
||||
|
||||
static int max3(int a, int b, int c) {
|
||||
if (a >= b && a >= c) return a;
|
||||
if (b >= a && b >= c) return b;
|
||||
return c;
|
||||
}
|
||||
|
||||
static int edge(const gpu::point_t& a, const gpu::point_t& b, const gpu::point_t& c) {
|
||||
return ((b.x - a.x) * (c.y - a.y)) - ((b.y - a.y) * (c.x - a.x));
|
||||
}
|
||||
|
||||
static bool is_top_left(const gpu::point_t &a, const gpu::point_t &b) {
|
||||
return (b.y == a.y && b.x > a.x) || b.y < a.y;
|
||||
}
|
||||
|
||||
static void draw_poly3_(const gpu::point_t &v0, const gpu::point_t &v1, const gpu::point_t &v2) {
|
||||
int min_x = min3(v0.x, v1.x, v2.x);
|
||||
int min_y = min3(v0.y, v1.y, v2.y);
|
||||
int max_x = max3(v0.x, v1.x, v2.x);
|
||||
int max_y = max3(v0.y, v1.y, v2.y);
|
||||
|
||||
bool is_top_left_12 = is_top_left(v1, v2);
|
||||
bool is_top_left_20 = is_top_left(v2, v0);
|
||||
bool is_top_left_01 = is_top_left(v0, v1);
|
||||
|
||||
int A01 = v0.y - v1.y, B01 = v1.x - v0.x;
|
||||
int A12 = v1.y - v2.y, B12 = v2.x - v1.x;
|
||||
int A20 = v2.y - v0.y, B20 = v0.x - v2.x;
|
||||
|
||||
gpu::point_t p = { min_x, min_y };
|
||||
int w0_row = edge(v1, v2, p);
|
||||
int w1_row = edge(v2, v0, p);
|
||||
int w2_row = edge(v0, v1, p);
|
||||
|
||||
for (p.y = min_y; p.y <= max_y; p.y++) {
|
||||
int w0 = w0_row;
|
||||
int w1 = w1_row;
|
||||
int w2 = w2_row;
|
||||
|
||||
for (p.x = min_x; p.x <= max_x; p.x++) {
|
||||
bool draw =
|
||||
(w0 > 0 || (w0 == 0 && is_top_left_12)) &&
|
||||
(w1 > 0 || (w1 == 0 && is_top_left_20)) &&
|
||||
(w2 > 0 || (w2 == 0 && is_top_left_01));
|
||||
|
||||
if (draw) {
|
||||
auto r = ((v0.r * w0) + (v1.r * w1) + (v2.r * w2)) / (w0 + w1 + w2);
|
||||
auto g = ((v0.g * w0) + (v1.g * w1) + (v2.g * w2)) / (w0 + w1 + w2);
|
||||
auto b = ((v0.b * w0) + (v1.b * w1) + (v2.b * w2)) / (w0 + w1 + w2);
|
||||
|
||||
draw_point(p.x, p.y, r, g, b);
|
||||
}
|
||||
|
||||
w0 += A12;
|
||||
w1 += A20;
|
||||
w2 += A01;
|
||||
}
|
||||
|
||||
w0_row += B12;
|
||||
w1_row += B20;
|
||||
w2_row += B01;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int double_area(const gpu::point_t &v0, const gpu::point_t &v1, const gpu::point_t &v2) {
|
||||
auto e0 = (v1.x - v0.x) * (v1.y + v0.y);
|
||||
auto e1 = (v2.x - v1.x) * (v2.y + v1.y);
|
||||
auto e2 = (v0.x - v2.x) * (v0.y + v2.y);
|
||||
|
||||
return e0 + e1 + e2;
|
||||
}
|
||||
|
||||
void gpu::draw_poly3(const gpu::point_t &v0, const gpu::point_t &v1, const gpu::point_t &v2) {
|
||||
if (double_area(v0, v1, v2) < 0) {
|
||||
draw_poly3_(v0, v1, v2);
|
||||
} else {
|
||||
draw_poly3_(v0, v2, v1);
|
||||
}
|
||||
}
|
||||
|
||||
void gpu::draw_poly4(const gpu::point_t &v0, const gpu::point_t &v1, const gpu::point_t &v2, const gpu::point_t &v3) {
|
||||
gpu::draw_poly3(v0, v1, v2);
|
||||
gpu::draw_poly3(v1, v2, v3);
|
||||
}
|
||||
|
|
109
src/gpu/gpu_draw_gouraud.cpp
Normal file
109
src/gpu/gpu_draw_gouraud.cpp
Normal file
|
@ -0,0 +1,109 @@
|
|||
#include "gpu_core.hpp"
|
||||
|
||||
void fill_gouraud(const gpu::gouraud::pixel_t &v0, const int &w0,
|
||||
const gpu::gouraud::pixel_t &v1, const int &w1,
|
||||
const gpu::gouraud::pixel_t &v2, const int &w2, int x, int y) {
|
||||
int area = w0 + w1 + w2;
|
||||
|
||||
int r = ((v0.color.r * w0) + (v1.color.r * w1) + (v2.color.r * w2)) / area;
|
||||
int g = ((v0.color.g * w0) + (v1.color.g * w1) + (v2.color.g * w2)) / area;
|
||||
int b = ((v0.color.b * w0) + (v1.color.b * w1) + (v2.color.b * w2)) / area;
|
||||
|
||||
gpu::draw_point(x, y, r, g, b);
|
||||
}
|
||||
|
||||
static int min3(int a, int b, int c) {
|
||||
if (a <= b && a <= c) return a;
|
||||
if (b <= a && b <= c) return b;
|
||||
return c;
|
||||
}
|
||||
|
||||
static int max3(int a, int b, int c) {
|
||||
if (a >= b && a >= c) return a;
|
||||
if (b >= a && b >= c) return b;
|
||||
return c;
|
||||
}
|
||||
|
||||
static int edge(const gpu::point_t& a, const gpu::point_t& b, const gpu::point_t& c) {
|
||||
return ((b.x - a.x) * (c.y - a.y)) - ((b.y - a.y) * (c.x - a.x));
|
||||
}
|
||||
|
||||
static bool is_top_left(const gpu::point_t &a, const gpu::point_t &b) {
|
||||
return (b.y == a.y && b.x > a.x) || b.y < a.y;
|
||||
}
|
||||
|
||||
static void fill_poly3_gouraud(const gpu::gouraud::pixel_t &v0, const gpu::gouraud::pixel_t &v1, const gpu::gouraud::pixel_t &v2) {
|
||||
int min_x = min3(v0.point.x, v1.point.x, v2.point.x);
|
||||
int min_y = min3(v0.point.y, v1.point.y, v2.point.y);
|
||||
int max_x = max3(v0.point.x, v1.point.x, v2.point.x);
|
||||
int max_y = max3(v0.point.y, v1.point.y, v2.point.y);
|
||||
|
||||
bool is_top_left_12 = is_top_left(v1.point, v2.point);
|
||||
bool is_top_left_20 = is_top_left(v2.point, v0.point);
|
||||
bool is_top_left_01 = is_top_left(v0.point, v1.point);
|
||||
|
||||
int x01 = v0.point.y - v1.point.y, y01 = v1.point.x - v0.point.x;
|
||||
int x12 = v1.point.y - v2.point.y, y12 = v2.point.x - v1.point.x;
|
||||
int x20 = v2.point.y - v0.point.y, y20 = v0.point.x - v2.point.x;
|
||||
|
||||
gpu::point_t p = { min_x, min_y };
|
||||
|
||||
int w0_row = edge(v1.point, v2.point, p);
|
||||
int w1_row = edge(v2.point, v0.point, p);
|
||||
int w2_row = edge(v0.point, v1.point, p);
|
||||
|
||||
for (p.y = min_y; p.y <= max_y; p.y++) {
|
||||
int w0 = w0_row;
|
||||
int w1 = w1_row;
|
||||
int w2 = w2_row;
|
||||
|
||||
for (p.x = min_x; p.x <= max_x; p.x++) {
|
||||
bool draw =
|
||||
(w0 > 0 || (w0 == 0 && is_top_left_12)) &&
|
||||
(w1 > 0 || (w1 == 0 && is_top_left_20)) &&
|
||||
(w2 > 0 || (w2 == 0 && is_top_left_01));
|
||||
|
||||
if (draw) {
|
||||
fill_gouraud(v0, w0, v1, w1, v2, w2, p.x, p.y);
|
||||
}
|
||||
|
||||
w0 += x12;
|
||||
w1 += x20;
|
||||
w2 += x01;
|
||||
}
|
||||
|
||||
w0_row += y12;
|
||||
w1_row += y20;
|
||||
w2_row += y01;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int double_area(const gpu::point_t &v0, const gpu::point_t &v1, const gpu::point_t &v2) {
|
||||
auto e0 = (v1.x - v0.x) * (v1.y + v0.y);
|
||||
auto e1 = (v2.x - v1.x) * (v2.y + v1.y);
|
||||
auto e2 = (v0.x - v2.x) * (v0.y + v2.y);
|
||||
|
||||
return e0 + e1 + e2;
|
||||
}
|
||||
|
||||
void gpu::gouraud::draw_poly3(const poly3_t &p) {
|
||||
const auto &p0 = p.v[0];
|
||||
const auto &p1 = p.v[1];
|
||||
const auto &p2 = p.v[2];
|
||||
|
||||
if (double_area(p0.point, p1.point, p2.point) < 0) {
|
||||
fill_poly3_gouraud(p0, p1, p2);
|
||||
} else {
|
||||
fill_poly3_gouraud(p0, p2, p1);
|
||||
}
|
||||
}
|
||||
|
||||
void gpu::gouraud::draw_poly4(const poly4_t &p) {
|
||||
auto &v0 = p.v[0];
|
||||
auto &v1 = p.v[1];
|
||||
auto &v2 = p.v[2];
|
||||
auto &v3 = p.v[3];
|
||||
|
||||
draw_poly3({ v0, v1, v2 });
|
||||
draw_poly3({ v1, v2, v3 });
|
||||
}
|
124
src/gpu/gpu_draw_texture.cpp
Normal file
124
src/gpu/gpu_draw_texture.cpp
Normal file
|
@ -0,0 +1,124 @@
|
|||
#include "gpu_core.hpp"
|
||||
|
||||
void fill_texture(const gpu::texture::poly3_t &p,
|
||||
const int &w0,
|
||||
const int &w1,
|
||||
const int &w2, int x, int y) {
|
||||
int area = w0 + w1 + w2;
|
||||
|
||||
int u = ((p.v0.u * w0) + (p.v1.u * w1) + (p.v2.u * w2)) / area;
|
||||
int v = ((p.v0.v * w0) + (p.v1.v * w1) + (p.v2.v * w2)) / area;
|
||||
|
||||
auto texel = gpu::read_vram(p.base_u + (u / 4), p.base_v + v);
|
||||
int index = 0;
|
||||
|
||||
switch (u & 3) {
|
||||
case 0: index = (texel >> 0) & 0xf; break;
|
||||
case 1: index = (texel >> 4) & 0xf; break;
|
||||
case 2: index = (texel >> 8) & 0xf; break;
|
||||
case 3: index = (texel >> 12) & 0xf; break;
|
||||
}
|
||||
|
||||
auto color = gpu::read_vram(p.clut_x + index, p.clut_y);
|
||||
if (color == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpu::write_vram(x, y, color);
|
||||
}
|
||||
|
||||
static int min3(int a, int b, int c) {
|
||||
if (a <= b && a <= c) return a;
|
||||
if (b <= a && b <= c) return b;
|
||||
return c;
|
||||
}
|
||||
|
||||
static int max3(int a, int b, int c) {
|
||||
if (a >= b && a >= c) return a;
|
||||
if (b >= a && b >= c) return b;
|
||||
return c;
|
||||
}
|
||||
|
||||
static int edge(const gpu::point_t& a, const gpu::point_t& b, const gpu::point_t& c) {
|
||||
return ((b.x - a.x) * (c.y - a.y)) - ((b.y - a.y) * (c.x - a.x));
|
||||
}
|
||||
|
||||
static bool is_top_left(const gpu::point_t &a, const gpu::point_t &b) {
|
||||
return (b.y == a.y && b.x > a.x) || b.y < a.y;
|
||||
}
|
||||
|
||||
static void fill_poly3_texture(const gpu::texture::poly3_t &t) {
|
||||
int min_x = min3(t.v0.point.x, t.v1.point.x, t.v2.point.x);
|
||||
int min_y = min3(t.v0.point.y, t.v1.point.y, t.v2.point.y);
|
||||
int max_x = max3(t.v0.point.x, t.v1.point.x, t.v2.point.x);
|
||||
int max_y = max3(t.v0.point.y, t.v1.point.y, t.v2.point.y);
|
||||
|
||||
bool is_top_left_12 = is_top_left(t.v1.point, t.v2.point);
|
||||
bool is_top_left_20 = is_top_left(t.v2.point, t.v0.point);
|
||||
bool is_top_left_01 = is_top_left(t.v0.point, t.v1.point);
|
||||
|
||||
int x01 = t.v0.point.y - t.v1.point.y, y01 = t.v1.point.x - t.v0.point.x;
|
||||
int x12 = t.v1.point.y - t.v2.point.y, y12 = t.v2.point.x - t.v1.point.x;
|
||||
int x20 = t.v2.point.y - t.v0.point.y, y20 = t.v0.point.x - t.v2.point.x;
|
||||
|
||||
gpu::point_t p = { min_x, min_y };
|
||||
|
||||
int w0_row = edge(t.v1.point, t.v2.point, p);
|
||||
int w1_row = edge(t.v2.point, t.v0.point, p);
|
||||
int w2_row = edge(t.v0.point, t.v1.point, p);
|
||||
|
||||
for (p.y = min_y; p.y <= max_y; p.y++) {
|
||||
int w0 = w0_row;
|
||||
int w1 = w1_row;
|
||||
int w2 = w2_row;
|
||||
|
||||
for (p.x = min_x; p.x <= max_x; p.x++) {
|
||||
bool draw =
|
||||
(w0 > 0 || (w0 == 0 && is_top_left_12)) &&
|
||||
(w1 > 0 || (w1 == 0 && is_top_left_20)) &&
|
||||
(w2 > 0 || (w2 == 0 && is_top_left_01));
|
||||
|
||||
if (draw) {
|
||||
fill_texture(t, w0, w1, w2, p.x, p.y);
|
||||
}
|
||||
|
||||
w0 += x12;
|
||||
w1 += x20;
|
||||
w2 += x01;
|
||||
}
|
||||
|
||||
w0_row += y12;
|
||||
w1_row += y20;
|
||||
w2_row += y01;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int double_area(const gpu::point_t &v0, const gpu::point_t &v1, const gpu::point_t &v2) {
|
||||
auto e0 = (v1.x - v0.x) * (v1.y + v0.y);
|
||||
auto e1 = (v2.x - v1.x) * (v2.y + v1.y);
|
||||
auto e2 = (v0.x - v2.x) * (v0.y + v2.y);
|
||||
|
||||
return e0 + e1 + e2;
|
||||
}
|
||||
|
||||
void gpu::texture::draw_poly3(const gpu::texture::poly3_t &p) {
|
||||
auto &v0 = p.v0;
|
||||
auto &v1 = p.v1;
|
||||
auto &v2 = p.v2;
|
||||
|
||||
if (double_area(v0.point, v1.point, v2.point) < 0) {
|
||||
fill_poly3_texture({v0, v1, v2, p.clut_x, p.clut_y, p.base_u, p.base_v});
|
||||
} else {
|
||||
fill_poly3_texture({v0, v2, v1, p.clut_x, p.clut_y, p.base_u, p.base_v});
|
||||
}
|
||||
}
|
||||
|
||||
void gpu::texture::draw_poly4(const gpu::texture::poly4_t &p) {
|
||||
auto &v0 = p.v0;
|
||||
auto &v1 = p.v1;
|
||||
auto &v2 = p.v2;
|
||||
auto &v3 = p.v3;
|
||||
|
||||
gpu::texture::draw_poly3({v0, v1, v2, p.clut_x, p.clut_y, p.base_u, p.base_v});
|
||||
gpu::texture::draw_poly3({v1, v2, v3, p.clut_x, p.clut_y, p.base_u, p.base_v});
|
||||
}
|
Loading…
Reference in a new issue