Skip to content

Commit 93122bd

Browse files
committed
render: refactored blending, now works like on real HW
removed float operations from rasterizer
1 parent 6b89756 commit 93122bd

File tree

5 files changed

+74
-76
lines changed

5 files changed

+74
-76
lines changed

src/device/gpu/psx_color.h

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22
#include <cstdint>
33
#include <glm/glm.hpp>
4+
#include "semi_transparency.h"
45
#include "utils/macros.h"
56
#include "utils/math.h"
67

@@ -34,54 +35,61 @@ union PSXColor {
3435
INLINE uint16_t rev() const { return (r << 11) | (g << 6) | (b << 1) | k; }
3536

3637
PSXColor() : raw(0) {}
38+
39+
// 16bit word from VRAM
3740
PSXColor(uint16_t color) : raw(color) {}
41+
42+
// 8bit input values
3843
PSXColor(uint8_t r, uint8_t g, uint8_t b) {
3944
this->r = r >> 3;
4045
this->g = g >> 3;
4146
this->b = b >> 3;
4247
this->k = 0;
4348
}
4449

45-
PSXColor operator+(const PSXColor& rhs) {
46-
r = std::min(r + rhs.r, 31);
47-
g = std::min(g + rhs.g, 31);
48-
b = std::min(b + rhs.b, 31);
49-
return *this;
50-
}
51-
52-
PSXColor operator-(const PSXColor& rhs) {
53-
r = std::max<int>(r - rhs.r, 0);
54-
g = std::max<int>(g - rhs.g, 0);
55-
b = std::max<int>(b - rhs.b, 0);
56-
return *this;
57-
}
58-
59-
PSXColor operator*(const float& rhs) {
60-
r = (uint16_t)(r * rhs);
61-
g = (uint16_t)(g * rhs);
62-
b = (uint16_t)(b * rhs);
63-
return *this;
64-
}
65-
66-
PSXColor operator/(const int& rhs) {
67-
r = (uint16_t)(r / rhs);
68-
g = (uint16_t)(g / rhs);
69-
b = (uint16_t)(b / rhs);
70-
return *this;
71-
}
50+
// 5bit input values
51+
PSXColor(uint8_t r, uint8_t g, uint8_t b, uint8_t k) : r(r), g(g), b(b), k(k) {}
7252

73-
PSXColor operator>>(const int& sh) {
74-
r >>= sh;
75-
g >>= sh;
76-
b >>= sh;
77-
return *this;
53+
PSXColor operator*(const glm::ivec3& rhs) const {
54+
return PSXColor( //
55+
clamp_top<uint8_t>((rhs.r * r) >> 7, 31), //
56+
clamp_top<uint8_t>((rhs.g * g) >> 7, 31), //
57+
clamp_top<uint8_t>((rhs.b * b) >> 7, 31), //
58+
k //
59+
);
7860
}
7961

80-
PSXColor operator*(const glm::vec3& rhs) {
81-
r = std::min<uint16_t>((uint16_t)(rhs.r * r), 31);
82-
g = std::min<uint16_t>((uint16_t)(rhs.g * g), 31);
83-
b = std::min<uint16_t>((uint16_t)(rhs.b * b), 31);
84-
return *this;
62+
INLINE static PSXColor blend(const PSXColor& bg, const PSXColor& c, const gpu::SemiTransparency& transparency) {
63+
switch (transparency) {
64+
case gpu::SemiTransparency::Bby2plusFby2:
65+
return PSXColor( //
66+
clamp_top((bg.r + c.r) >> 1, 31), //
67+
clamp_top((bg.g + c.g) >> 1, 31), //
68+
clamp_top((bg.b + c.b) >> 1, 31), //
69+
0 //
70+
);
71+
case gpu::SemiTransparency::BplusF:
72+
return PSXColor( //
73+
clamp_top(bg.r + c.r, 31), //
74+
clamp_top(bg.g + c.g, 31), //
75+
clamp_top(bg.b + c.b, 31), //
76+
0 //
77+
);
78+
case gpu::SemiTransparency::BminusF:
79+
return PSXColor( //
80+
clamp_bottom(bg.r - c.r, 0), //
81+
clamp_bottom(bg.g - c.g, 0), //
82+
clamp_bottom(bg.b - c.b, 0), //
83+
0 //
84+
);
85+
case gpu::SemiTransparency::BplusFby4:
86+
return PSXColor( //
87+
clamp_top(bg.r + (c.r >> 2), 31), //
88+
clamp_top(bg.g + (c.g >> 2), 31), //
89+
clamp_top(bg.b + (c.b >> 2), 31), //
90+
0 //
91+
);
92+
}
8593
}
8694
};
8795

src/device/gpu/render/render_line.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#define VRAM ((uint16_t(*)[gpu::VRAM_WIDTH])gpu->vram.data())
88

99
void Render::drawLine(gpu::GPU* gpu, const primitive::Line& line) {
10-
using Transparency = gpu::SemiTransparency;
1110
const auto transparency = gpu->gp0_e1.semiTransparency;
1211
const bool checkMaskBeforeDraw = gpu->gp0_e6.checkMaskBeforeDraw;
1312
const bool setMaskWhileDrawing = gpu->gp0_e6.setMaskWhileDrawing;
@@ -73,14 +72,8 @@ void Render::drawLine(gpu::GPU* gpu, const primitive::Line& line) {
7372
c = PSXColor(col.r, col.g, col.b);
7473
}
7574

76-
// TODO: This code repeats 3 times, make it more generic
7775
if (line.isSemiTransparent) {
78-
switch (transparency) {
79-
case Transparency::Bby2plusFby2: c = (bg >> 1) + (c >> 1); break;
80-
case Transparency::BplusF: c = bg + c; break;
81-
case Transparency::BminusF: c = bg - c; break;
82-
case Transparency::BplusFby4: c = bg + (c >> 2); break;
83-
}
76+
c = PSXColor::blend(bg, c, transparency);
8477
}
8578

8679
c.k |= bg.k | setMaskWhileDrawing;

src/device/gpu/render/render_rectangle.cpp

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
#include "utils/macros.h"
55

66
using glm::ivec2;
7+
using glm::ivec3;
78
using glm::uvec2;
8-
using glm::vec3;
99
using gpu::GPU;
1010

1111
#undef VRAM
@@ -28,7 +28,6 @@ INLINE glm::uvec2 calculateTexel(glm::ivec2 tex, const gpu::GP0_E2 textureWindow
2828
template <ColorDepth bits>
2929
INLINE void rectangle(GPU* gpu, const primitive::Rect& rect) {
3030
// Extract common GPU state
31-
using Transparency = gpu::SemiTransparency;
3231
const auto transparency = gpu->gp0_e1.semiTransparency;
3332
const bool checkMaskBeforeDraw = gpu->gp0_e6.checkMaskBeforeDraw;
3433
const bool setMaskWhileDrawing = gpu->gp0_e6.setMaskWhileDrawing;
@@ -83,18 +82,12 @@ INLINE void rectangle(GPU* gpu, const primitive::Rect& rect) {
8382
if (c.raw == 0x0000) continue;
8483

8584
if (isBlended) {
86-
vec3 brightness = vec3(rect.color.r, rect.color.g, rect.color.b) / 255.f;
87-
c = c * (brightness * 2.f);
85+
c = c * ivec3(rect.color.r, rect.color.g, rect.color.b);
8886
}
8987
}
9088

9189
if (rect.isSemiTransparent && (!isTextured || c.k)) {
92-
switch (transparency) {
93-
case Transparency::Bby2plusFby2: c = (bg >> 1) + (c >> 1); break;
94-
case Transparency::BplusF: c = bg + c; break;
95-
case Transparency::BminusF: c = bg - c; break;
96-
case Transparency::BplusFby4: c = bg + (c >> 2); break;
97-
}
90+
c = PSXColor::blend(bg, c, transparency);
9891
}
9992

10093
c.k |= bg.k | setMaskWhileDrawing;

src/device/gpu/render/render_triangle.cpp

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
using glm::ivec2;
1010
using glm::ivec3;
1111
using glm::uvec2;
12-
using glm::vec3;
1312
using gpu::GPU;
1413
using gpu::Vertex;
1514

@@ -67,7 +66,6 @@ static bool isTopLeft(const ivec2 e) { return e.y < 0 || (e.y == 0 && e.x < 0);
6766
template <ColorDepth bits>
6867
void rasterizeTriangle(GPU* gpu, const primitive::Triangle& triangle) {
6968
// Extract common GPU state
70-
using Transparency = gpu::SemiTransparency;
7169
const auto transparency = triangle.transparency;
7270
const bool checkMaskBeforeDraw = gpu->gp0_e6.checkMaskBeforeDraw;
7371
const bool setMaskWhileDrawing = gpu->gp0_e6.setMaskWhileDrawing;
@@ -133,10 +131,8 @@ void rasterizeTriangle(GPU* gpu, const primitive::Triangle& triangle) {
133131
};
134132

135133
ivec3 COLOR[3];
136-
vec3 fcolor[3];
137134
for (int i = 0; i < 3; i++) {
138135
COLOR[i] = ivec3(triangle.v[i].color.r, triangle.v[i].color.g, triangle.v[i].color.b);
139-
fcolor[i] = vec3(COLOR[i]) / 255.f;
140136
}
141137

142138
ivec2 p;
@@ -163,32 +159,25 @@ void rasterizeTriangle(GPU* gpu, const primitive::Triangle& triangle) {
163159
if (c.raw == 0x0000) goto DONE;
164160

165161
if (isBlended) {
166-
vec3 brightness;
167-
162+
ivec3 brightness;
168163
if (isGouroudShaded) {
169-
// TODO: Get rid of float colors
170-
brightness = vec3( //
171-
(s.x * fcolor[0].r + s.y * fcolor[1].r + s.z * fcolor[2].r), //
172-
(s.x * fcolor[0].g + s.y * fcolor[1].g + s.z * fcolor[2].g), //
173-
(s.x * fcolor[0].b + s.y * fcolor[1].b + s.z * fcolor[2].b) //
164+
brightness = ivec3( //
165+
(s.x * COLOR[0].r + s.y * COLOR[1].r + s.z * COLOR[2].r), //
166+
(s.x * COLOR[0].g + s.y * COLOR[1].g + s.z * COLOR[2].g), //
167+
(s.x * COLOR[0].b + s.y * COLOR[1].b + s.z * COLOR[2].b) //
174168
);
175169
brightness /= area;
176170
} else { // Flat shading
177-
brightness = fcolor[0];
171+
brightness = COLOR[0];
178172
}
179173

180-
c = c * (brightness * 2.f);
174+
c = c * brightness;
181175
}
182176
// TODO: Textured polygons are not dithered
183177
}
184178

185179
if (isSemiTransparent && (!isTextured || c.k)) {
186-
switch (transparency) {
187-
case Transparency::Bby2plusFby2: c = (bg >> 1) + (c >> 1); break;
188-
case Transparency::BplusF: c = bg + c; break;
189-
case Transparency::BminusF: c = bg - c; break;
190-
case Transparency::BplusFby4: c = bg + (c >> 2); break;
191-
}
180+
c = PSXColor::blend(bg, c, transparency);
192181
}
193182

194183
c.k |= bg.k | setMaskWhileDrawing;

src/utils/math.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#pragma once
2-
#include <algorithm>
32

43
template <typename T>
54
T clamp(T number, size_t range) {
@@ -9,7 +8,23 @@ T clamp(T number, size_t range) {
98

109
template <typename T>
1110
T clamp(T v, T min, T max) {
12-
return std::min(std::max(v, min), max);
11+
if (v > max) {
12+
return max;
13+
} else if (v < min) {
14+
return min;
15+
} else {
16+
return v;
17+
}
18+
}
19+
20+
template <typename T>
21+
T clamp_top(T v, T top) {
22+
return v > top ? top : v;
23+
}
24+
25+
template <typename T>
26+
T clamp_bottom(T v, T bottom) {
27+
return v < bottom ? bottom : v;
1328
}
1429

1530
inline float lerp(float a, float b, float t) { return a + t * (b - a); }

0 commit comments

Comments
 (0)