nearest neighbour blending and gamma
This commit is contained in:
17
main.cpp
17
main.cpp
@@ -231,7 +231,14 @@ void draw_triangle(Image* dst, float *depth_buffer, Image *src,
|
|||||||
#endif // GAMMA_CORRECT_BLENDING
|
#endif // GAMMA_CORRECT_BLENDING
|
||||||
U32 color32 = color_to_u32abgr(result_color);
|
U32 color32 = color_to_u32abgr(result_color);
|
||||||
#else // BILINEAR_BLEND
|
#else // BILINEAR_BLEND
|
||||||
U32 color32 = *pixel;
|
Vec4 result_color = srgb_to_almost_linear(vec4abgr(*pixel));
|
||||||
|
Vec4 dst_color = srgb_to_almost_linear(vec4abgr(*dst_pixel));
|
||||||
|
result_color.r = result_color.r + (1-result_color.a) * dst_color.r;
|
||||||
|
result_color.g = result_color.g + (1-result_color.a) * dst_color.g;
|
||||||
|
result_color.b = result_color.b + (1-result_color.a) * dst_color.b;
|
||||||
|
result_color.a = result_color.a + dst_color.a - result_color.a*dst_color.a;
|
||||||
|
result_color = almost_linear_to_srgb(result_color);
|
||||||
|
U32 color32 = color_to_u32abgr(result_color);
|
||||||
#endif // BILINEAR_BLEND
|
#endif // BILINEAR_BLEND
|
||||||
|
|
||||||
*dst_pixel = color32;
|
*dst_pixel = color32;
|
||||||
@@ -306,16 +313,16 @@ int main() {
|
|||||||
float rotation = 0;
|
float rotation = 0;
|
||||||
Vec3 camera_pos = {0,0,-5};
|
Vec3 camera_pos = {0,0,-5};
|
||||||
|
|
||||||
Obj obj = load_obj("assets/f22.obj");
|
Obj obj = load_obj("assets/cube.obj");
|
||||||
Vec3* vertices = (Vec3 *)obj.vertices;
|
Vec3* vertices = (Vec3 *)obj.vertices;
|
||||||
Vec2* tex_coords = (Vec2*)obj.texture;
|
Vec2* tex_coords = (Vec2*)obj.texture;
|
||||||
FaceA* faces = (FaceA*)obj.indices;
|
FaceA* faces = (FaceA*)obj.indices;
|
||||||
I64 face_count = obj.indices_count;
|
I64 face_count = obj.indices_count;
|
||||||
|
|
||||||
|
|
||||||
Image img = load_image("assets/bricksx64.png");
|
Image img = load_image("assets/cat.png");
|
||||||
int screen_x = 320;
|
int screen_x = 160;
|
||||||
int screen_y = 60;
|
int screen_y = 90;
|
||||||
Image screen320 = {(U32 *)malloc(screen_x*screen_y*sizeof(U32)), screen_x, screen_y};
|
Image screen320 = {(U32 *)malloc(screen_x*screen_y*sizeof(U32)), screen_x, screen_y};
|
||||||
float* depth320 = (float *)malloc(sizeof(float) * screen_x * screen_y);
|
float* depth320 = (float *)malloc(sizeof(float) * screen_x * screen_y);
|
||||||
while (os.game_loop()) {
|
while (os.game_loop()) {
|
||||||
|
|||||||
@@ -1,265 +0,0 @@
|
|||||||
|
|
||||||
FUNCTION void draw_triangle_PERSPECTIVE_CORRECT_INTERPOLATION_off_BILINEAR_BLEND_off (Image* dst, float *depth_buffer, Image *src,
|
|
||||||
|
|
||||||
Vec4 p0, Vec4 p1, Vec4 p2,
|
|
||||||
|
|
||||||
Vec2 tex0, Vec2 tex1, Vec2 tex2) {
|
|
||||||
|
|
||||||
float min_x1 = (float)(MIN(p0.x, MIN(p1.x, p2.x)));
|
|
||||||
|
|
||||||
float min_y1 = (float)(MIN(p0.y, MIN(p1.y, p2.y)));
|
|
||||||
|
|
||||||
float max_x1 = (float)(MAX(p0.x, MAX(p1.x, p2.x)));
|
|
||||||
|
|
||||||
float max_y1 = (float)(MAX(p0.y, MAX(p1.y, p2.y)));
|
|
||||||
|
|
||||||
I64 min_x = (I64)MAX(0, floor(min_x1));
|
|
||||||
|
|
||||||
I64 min_y = (I64)MAX(0, floor(min_y1));
|
|
||||||
|
|
||||||
I64 max_x = (I64)MIN(dst->x, ceil(max_x1));
|
|
||||||
|
|
||||||
I64 max_y = (I64)MIN(dst->y, ceil(max_y1));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
float area = edge_function(p0, p1, p2);
|
|
||||||
|
|
||||||
for (I64 y = min_y; y < max_y; y++) {
|
|
||||||
|
|
||||||
for (I64 x = min_x; x < max_x; x++) {
|
|
||||||
|
|
||||||
float edge1 = edge_function(p0, p1, { (float)x,(float)y });
|
|
||||||
|
|
||||||
float edge2 = edge_function(p1, p2, { (float)x,(float)y });
|
|
||||||
|
|
||||||
float edge3 = edge_function(p2, p0, { (float)x,(float)y });
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (edge1 >= 0 && edge2 >= 0 && edge3 >= 0) {
|
|
||||||
|
|
||||||
float w1 = edge2 / area;
|
|
||||||
|
|
||||||
float w2 = edge3 / area;
|
|
||||||
|
|
||||||
float w3 = edge1 / area;
|
|
||||||
|
|
||||||
float interpolated_z = (1.f / p0.w) * w1 + (1.f / p1.w) * w2 + (1.f / p2.w) * w3;
|
|
||||||
|
|
||||||
// PERSPECTIVE_CORRECT_INTERPOLATION
|
|
||||||
|
|
||||||
float u = tex0.x * w1 + tex1.x * w2 + tex2.x * w3;
|
|
||||||
|
|
||||||
float v = tex0.y * w1 + tex1.y * w2 + tex2.y * w3;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// @Note: We could do: interpolated_z = 1.f / interpolated_z to get proper depth
|
|
||||||
|
|
||||||
// but why waste an instruction, the smaller the depth value the farther the object
|
|
||||||
|
|
||||||
float* depth = depth_buffer + (x + y * dst->x);
|
|
||||||
|
|
||||||
if (*depth < interpolated_z) {
|
|
||||||
|
|
||||||
*depth = interpolated_z;
|
|
||||||
|
|
||||||
u = u * (src->x - 2);
|
|
||||||
|
|
||||||
v = v * (src->y - 2);
|
|
||||||
|
|
||||||
I64 ui = (I64)(u);
|
|
||||||
|
|
||||||
I64 vi = (I64)(v);
|
|
||||||
|
|
||||||
float udiff = u - (float)ui;
|
|
||||||
|
|
||||||
float vdiff = v - (float)vi;
|
|
||||||
|
|
||||||
// Origin UV (0,0) is in bottom left
|
|
||||||
|
|
||||||
U32* pixel = src->pixels + (ui + (src->y - 1ll - vi) * src->x);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// BILINEAR_BLEND
|
|
||||||
|
|
||||||
U32 color32 = *pixel;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dst->pixels[x + y * dst->x] = color32;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (draw_rects) {
|
|
||||||
|
|
||||||
draw_rect(dst, p0.x-4, p0.y-4, 8,8, 0x00ff0000);
|
|
||||||
|
|
||||||
draw_rect(dst, p1.x-4, p1.y-4, 8,8, 0x0000ff00);
|
|
||||||
|
|
||||||
draw_rect(dst, p2.x-4, p2.y-4, 8,8, 0x000000ff);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
FUNCTION void draw_triangle_PERSPECTIVE_CORRECT_INTERPOLATION_on_BILINEAR_BLEND_on (Image* dst, float *depth_buffer, Image *src,
|
|
||||||
|
|
||||||
Vec4 p0, Vec4 p1, Vec4 p2,
|
|
||||||
|
|
||||||
Vec2 tex0, Vec2 tex1, Vec2 tex2) {
|
|
||||||
|
|
||||||
float min_x1 = (float)(MIN(p0.x, MIN(p1.x, p2.x)));
|
|
||||||
|
|
||||||
float min_y1 = (float)(MIN(p0.y, MIN(p1.y, p2.y)));
|
|
||||||
|
|
||||||
float max_x1 = (float)(MAX(p0.x, MAX(p1.x, p2.x)));
|
|
||||||
|
|
||||||
float max_y1 = (float)(MAX(p0.y, MAX(p1.y, p2.y)));
|
|
||||||
|
|
||||||
I64 min_x = (I64)MAX(0, floor(min_x1));
|
|
||||||
|
|
||||||
I64 min_y = (I64)MAX(0, floor(min_y1));
|
|
||||||
|
|
||||||
I64 max_x = (I64)MIN(dst->x, ceil(max_x1));
|
|
||||||
|
|
||||||
I64 max_y = (I64)MIN(dst->y, ceil(max_y1));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
float area = edge_function(p0, p1, p2);
|
|
||||||
|
|
||||||
for (I64 y = min_y; y < max_y; y++) {
|
|
||||||
|
|
||||||
for (I64 x = min_x; x < max_x; x++) {
|
|
||||||
|
|
||||||
float edge1 = edge_function(p0, p1, { (float)x,(float)y });
|
|
||||||
|
|
||||||
float edge2 = edge_function(p1, p2, { (float)x,(float)y });
|
|
||||||
|
|
||||||
float edge3 = edge_function(p2, p0, { (float)x,(float)y });
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (edge1 >= 0 && edge2 >= 0 && edge3 >= 0) {
|
|
||||||
|
|
||||||
float w1 = edge2 / area;
|
|
||||||
|
|
||||||
float w2 = edge3 / area;
|
|
||||||
|
|
||||||
float w3 = edge1 / area;
|
|
||||||
|
|
||||||
float interpolated_z = (1.f / p0.w) * w1 + (1.f / p1.w) * w2 + (1.f / p2.w) * w3;
|
|
||||||
|
|
||||||
// PERSPECTIVE_CORRECT_INTERPOLATION
|
|
||||||
|
|
||||||
float u = tex0.x * (w1 / p0.w) + tex1.x * (w2 / p1.w) + tex2.x * (w3 / p2.w);
|
|
||||||
|
|
||||||
float v = tex0.y * (w1 / p0.w) + tex1.y * (w2 / p1.w) + tex2.y * (w3 / p2.w);
|
|
||||||
|
|
||||||
u /= interpolated_z;
|
|
||||||
|
|
||||||
v /= interpolated_z;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// @Note: We could do: interpolated_z = 1.f / interpolated_z to get proper depth
|
|
||||||
|
|
||||||
// but why waste an instruction, the smaller the depth value the farther the object
|
|
||||||
|
|
||||||
float* depth = depth_buffer + (x + y * dst->x);
|
|
||||||
|
|
||||||
if (*depth < interpolated_z) {
|
|
||||||
|
|
||||||
*depth = interpolated_z;
|
|
||||||
|
|
||||||
u = u * (src->x - 2);
|
|
||||||
|
|
||||||
v = v * (src->y - 2);
|
|
||||||
|
|
||||||
I64 ui = (I64)(u);
|
|
||||||
|
|
||||||
I64 vi = (I64)(v);
|
|
||||||
|
|
||||||
float udiff = u - (float)ui;
|
|
||||||
|
|
||||||
float vdiff = v - (float)vi;
|
|
||||||
|
|
||||||
// Origin UV (0,0) is in bottom left
|
|
||||||
|
|
||||||
U32* pixel = src->pixels + (ui + (src->y - 1ll - vi) * src->x);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// BILINEAR_BLEND
|
|
||||||
|
|
||||||
Vec4 pixelx1y1 = v4abgr(*pixel);
|
|
||||||
|
|
||||||
if (pixelx1y1.a < 0.2) continue;
|
|
||||||
|
|
||||||
Vec4 pixelx2y1 = v4abgr(*(pixel + 1));
|
|
||||||
|
|
||||||
Vec4 pixelx1y2 = v4abgr(*(pixel - src->x));
|
|
||||||
|
|
||||||
Vec4 pixelx2y2 = v4abgr(*(pixel + 1 - src->x));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pixelx1y1 = srgb_to_almost_linear(pixelx1y1);
|
|
||||||
|
|
||||||
pixelx2y1 = srgb_to_almost_linear(pixelx2y1);
|
|
||||||
|
|
||||||
pixelx1y2 = srgb_to_almost_linear(pixelx1y2);
|
|
||||||
|
|
||||||
pixelx2y2 = srgb_to_almost_linear(pixelx2y2);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Vec4 blendx1 = lerp(pixelx1y1, pixelx2y1, udiff);
|
|
||||||
|
|
||||||
Vec4 blendx2 = lerp(pixelx1y2, pixelx2y2, udiff);
|
|
||||||
|
|
||||||
Vec4 result_color = lerp(blendx1, blendx2, vdiff);
|
|
||||||
|
|
||||||
result_color = almost_linear_to_srgb(result_color);
|
|
||||||
|
|
||||||
ASSERT(result_color.r <= 1 && result_color.g <= 1 && result_color.b <= 1);
|
|
||||||
|
|
||||||
U32 color32 = color_to_u32abgr(result_color);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dst->pixels[x + y * dst->x] = color32;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (draw_rects) {
|
|
||||||
|
|
||||||
draw_rect(dst, p0.x-4, p0.y-4, 8,8, 0x00ff0000);
|
|
||||||
|
|
||||||
draw_rect(dst, p1.x-4, p1.y-4, 8,8, 0x0000ff00);
|
|
||||||
|
|
||||||
draw_rect(dst, p2.x-4, p2.y-4, 8,8, 0x000000ff);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
FUNCTION void draw_triangle_PERSPECTIVE_CORRECT_INTERPOLATION_off_BILINEAR_BLEND_on (Image* dst, float *depth_buffer, Image *src,
|
|
||||||
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
struct Token {
|
|
||||||
char* s;
|
|
||||||
int len;
|
|
||||||
};
|
|
||||||
|
|
||||||
FUNCTION bool is_alphabetic(char w) {
|
|
||||||
bool result = (w >= 'a' && w <= 'z') || (w >= 'A' && w <= 'Z');
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNCTION bool is_number(char w) {
|
|
||||||
bool result = w >= '0' && w <= '9';
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNCTION bool is_whitespace(char w) {
|
|
||||||
bool result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r';
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNCTION int string_len(char* a) {
|
|
||||||
int result = 0;
|
|
||||||
while (*a++ != 0) result++;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNCTION bool equals(Token a, const char* b) {
|
|
||||||
int len = string_len((char*)b);
|
|
||||||
if (a.len != len) return false;
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
if (a.s[i] != b[i]) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool combinations[64][8] = { { 0, 0 }, { 1, 1 }, { 0, 1 }, { 1, 0 } };
|
|
||||||
int combinations_to_make = 4;
|
|
||||||
|
|
||||||
struct Lexer {
|
|
||||||
char* stream;
|
|
||||||
char* data;
|
|
||||||
char output[10000];
|
|
||||||
|
|
||||||
Token next() {
|
|
||||||
while (is_whitespace(*stream)) stream++;
|
|
||||||
Token result = {};
|
|
||||||
result.s = stream++;
|
|
||||||
if (is_alphabetic(*result.s)) {
|
|
||||||
while (is_alphabetic(*stream) || *stream == '_') stream++;
|
|
||||||
}
|
|
||||||
result.len = (int)(stream - result.s);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool match(const char* str, Token* out = 0) {
|
|
||||||
Lexer l = *this;
|
|
||||||
Token token = next();
|
|
||||||
if (out) *out = token;
|
|
||||||
if (equals(token, str)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
*this = l;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Section {
|
|
||||||
char* begin, * end;
|
|
||||||
char* name, * name_end;
|
|
||||||
int if_clause_i;
|
|
||||||
bool is_else;
|
|
||||||
};
|
|
||||||
|
|
||||||
FUNCTION void generate_stuff() {
|
|
||||||
char* data = os.read_file("main.cpp");
|
|
||||||
FILE* f = fopen("raster_functions.cpp", "w");
|
|
||||||
ASSERT(f);
|
|
||||||
Section sections[100] = {};
|
|
||||||
int sections_count = 0;
|
|
||||||
int if_clause_count = 0;
|
|
||||||
Lexer lexer = { data, data };
|
|
||||||
for (;;) {
|
|
||||||
Token token = lexer.next();
|
|
||||||
if (*token.s == 0) break;
|
|
||||||
|
|
||||||
if (equals(token, "FUNCTION") &&
|
|
||||||
lexer.match("void") &&
|
|
||||||
lexer.match("draw_triangle", &token)) {
|
|
||||||
Section* section = sections + sections_count++;
|
|
||||||
section->begin = token.s + token.len;
|
|
||||||
int indent = 1;
|
|
||||||
while (lexer.next().s[0] != '{');
|
|
||||||
for (; ; ) {
|
|
||||||
token = lexer.next();
|
|
||||||
if (token.s[0] == '{') indent++;
|
|
||||||
else if (token.s[0] == '}') indent--;
|
|
||||||
else if (token.s[0] == '#') {
|
|
||||||
if (lexer.match("if")) {
|
|
||||||
section->end = token.s;
|
|
||||||
|
|
||||||
if_clause_count++;
|
|
||||||
token = lexer.next();
|
|
||||||
section = sections + sections_count++;
|
|
||||||
section->if_clause_i = if_clause_count;
|
|
||||||
section->is_else = false;
|
|
||||||
section->name = token.s;
|
|
||||||
section->name_end = token.s + token.len;
|
|
||||||
section->begin = section->name_end;
|
|
||||||
}
|
|
||||||
else if (lexer.match("else")) {
|
|
||||||
section->end = token.s;
|
|
||||||
char* name = section->name;
|
|
||||||
char* name_end = section->name_end;
|
|
||||||
|
|
||||||
section = sections + sections_count++;
|
|
||||||
section->is_else = true;
|
|
||||||
section->if_clause_i = if_clause_count;
|
|
||||||
section->name = name;
|
|
||||||
section->name_end = name_end;
|
|
||||||
section->begin = token.s + 5;
|
|
||||||
}
|
|
||||||
else if (lexer.match("endif")) {
|
|
||||||
section->end = token.s;
|
|
||||||
section = sections + sections_count++;
|
|
||||||
section->begin = token.s + 6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (indent == 0) {
|
|
||||||
section->end = token.s + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int ci = 0; ci < combinations_to_make; ci++) {
|
|
||||||
// @Note: Figure out function name
|
|
||||||
fprintf(f, "\nFUNCTION void draw_triangle");
|
|
||||||
for (int i = 0; i < sections_count; i++) {
|
|
||||||
section = sections + i;
|
|
||||||
if (section->name && section->is_else == !combinations[ci][section->if_clause_i - 1]) {
|
|
||||||
fprintf(f, "_%.*s_", (int)(section->name_end - section->name), section->name);
|
|
||||||
fprintf(f, "%s", section->is_else ? "off" : "on");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// @Note: Figure out function content
|
|
||||||
for (int i = 0; i < sections_count; i++) {
|
|
||||||
section = sections + i;
|
|
||||||
if (!section->name) {
|
|
||||||
fprintf(f, "%.*s %.*s", (int)(section->name_end - section->name), section->name, (int)(section->end - section->begin), section->begin);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (section->is_else == !combinations[ci][section->if_clause_i - 1]) {
|
|
||||||
fprintf(f, "// %.*s %.*s", (int)(section->name_end - section->name), section->name, (int)(section->end - section->begin), section->begin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
249
test.txt
249
test.txt
@@ -1,249 +0,0 @@
|
|||||||
|
|
||||||
FUNCTION void draw_triangle_PERSPECTIVE_CORRECT_INTERPOLATION_off_BILINEAR_BLEND_off (Image* dst, float *depth_buffer, Image *src,
|
|
||||||
|
|
||||||
Vec4 p0, Vec4 p1, Vec4 p2,
|
|
||||||
|
|
||||||
Vec2 tex0, Vec2 tex1, Vec2 tex2) {
|
|
||||||
|
|
||||||
float min_x1 = (float)(MIN(p0.x, MIN(p1.x, p2.x)));
|
|
||||||
|
|
||||||
float min_y1 = (float)(MIN(p0.y, MIN(p1.y, p2.y)));
|
|
||||||
|
|
||||||
float max_x1 = (float)(MAX(p0.x, MAX(p1.x, p2.x)));
|
|
||||||
|
|
||||||
float max_y1 = (float)(MAX(p0.y, MAX(p1.y, p2.y)));
|
|
||||||
|
|
||||||
I64 min_x = (I64)MAX(0, floor(min_x1));
|
|
||||||
|
|
||||||
I64 min_y = (I64)MAX(0, floor(min_y1));
|
|
||||||
|
|
||||||
I64 max_x = (I64)MIN(dst->x, ceil(max_x1));
|
|
||||||
|
|
||||||
I64 max_y = (I64)MIN(dst->y, ceil(max_y1));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
float area = edge_function(p0, p1, p2);
|
|
||||||
|
|
||||||
for (I64 y = min_y; y < max_y; y++) {
|
|
||||||
|
|
||||||
for (I64 x = min_x; x < max_x; x++) {
|
|
||||||
|
|
||||||
float edge1 = edge_function(p0, p1, { (float)x,(float)y });
|
|
||||||
|
|
||||||
float edge2 = edge_function(p1, p2, { (float)x,(float)y });
|
|
||||||
|
|
||||||
float edge3 = edge_function(p2, p0, { (float)x,(float)y });
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (edge1 >= 0 && edge2 >= 0 && edge3 >= 0) {
|
|
||||||
|
|
||||||
float w1 = edge2 / area;
|
|
||||||
|
|
||||||
float w2 = edge3 / area;
|
|
||||||
|
|
||||||
float w3 = edge1 / area;
|
|
||||||
|
|
||||||
float interpolated_z = (1.f / p0.w) * w1 + (1.f / p1.w) * w2 + (1.f / p2.w) * w3;
|
|
||||||
|
|
||||||
// PERSPECTIVE_CORRECT_INTERPOLATION
|
|
||||||
|
|
||||||
float u = tex0.x * w1 + tex1.x * w2 + tex2.x * w3;
|
|
||||||
|
|
||||||
float v = tex0.y * w1 + tex1.y * w2 + tex2.y * w3;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// @Note: We could do: interpolated_z = 1.f / interpolated_z to get proper depth
|
|
||||||
|
|
||||||
// but why waste an instruction, the smaller the depth value the farther the object
|
|
||||||
|
|
||||||
float* depth = depth_buffer + (x + y * dst->x);
|
|
||||||
|
|
||||||
if (*depth < interpolated_z) {
|
|
||||||
|
|
||||||
*depth = interpolated_z;
|
|
||||||
|
|
||||||
u = u * (src->x - 2);
|
|
||||||
|
|
||||||
v = v * (src->y - 2);
|
|
||||||
|
|
||||||
I64 ui = (I64)(u);
|
|
||||||
|
|
||||||
I64 vi = (I64)(v);
|
|
||||||
|
|
||||||
float udiff = u - (float)ui;
|
|
||||||
|
|
||||||
float vdiff = v - (float)vi;
|
|
||||||
|
|
||||||
// Origin UV (0,0) is in bottom left
|
|
||||||
|
|
||||||
U32* pixel = src->pixels + (ui + (src->y - 1ll - vi) * src->x);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// BILINEAR_BLEND
|
|
||||||
|
|
||||||
U32 color32 = *pixel;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dst->pixels[x + y * dst->x] = color32;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (draw_rects) {
|
|
||||||
|
|
||||||
draw_rect(dst, p0.x-4, p0.y-4, 8,8, 0x00ff0000);
|
|
||||||
|
|
||||||
draw_rect(dst, p1.x-4, p1.y-4, 8,8, 0x0000ff00);
|
|
||||||
|
|
||||||
draw_rect(dst, p2.x-4, p2.y-4, 8,8, 0x000000ff);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
FUNCTION void draw_triangle_PERSPECTIVE_CORRECT_INTERPOLATION_on_BILINEAR_BLEND_on (Image* dst, float *depth_buffer, Image *src,
|
|
||||||
|
|
||||||
Vec4 p0, Vec4 p1, Vec4 p2,
|
|
||||||
|
|
||||||
Vec2 tex0, Vec2 tex1, Vec2 tex2) {
|
|
||||||
|
|
||||||
float min_x1 = (float)(MIN(p0.x, MIN(p1.x, p2.x)));
|
|
||||||
|
|
||||||
float min_y1 = (float)(MIN(p0.y, MIN(p1.y, p2.y)));
|
|
||||||
|
|
||||||
float max_x1 = (float)(MAX(p0.x, MAX(p1.x, p2.x)));
|
|
||||||
|
|
||||||
float max_y1 = (float)(MAX(p0.y, MAX(p1.y, p2.y)));
|
|
||||||
|
|
||||||
I64 min_x = (I64)MAX(0, floor(min_x1));
|
|
||||||
|
|
||||||
I64 min_y = (I64)MAX(0, floor(min_y1));
|
|
||||||
|
|
||||||
I64 max_x = (I64)MIN(dst->x, ceil(max_x1));
|
|
||||||
|
|
||||||
I64 max_y = (I64)MIN(dst->y, ceil(max_y1));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
float area = edge_function(p0, p1, p2);
|
|
||||||
|
|
||||||
for (I64 y = min_y; y < max_y; y++) {
|
|
||||||
|
|
||||||
for (I64 x = min_x; x < max_x; x++) {
|
|
||||||
|
|
||||||
float edge1 = edge_function(p0, p1, { (float)x,(float)y });
|
|
||||||
|
|
||||||
float edge2 = edge_function(p1, p2, { (float)x,(float)y });
|
|
||||||
|
|
||||||
float edge3 = edge_function(p2, p0, { (float)x,(float)y });
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (edge1 >= 0 && edge2 >= 0 && edge3 >= 0) {
|
|
||||||
|
|
||||||
float w1 = edge2 / area;
|
|
||||||
|
|
||||||
float w2 = edge3 / area;
|
|
||||||
|
|
||||||
float w3 = edge1 / area;
|
|
||||||
|
|
||||||
float interpolated_z = (1.f / p0.w) * w1 + (1.f / p1.w) * w2 + (1.f / p2.w) * w3;
|
|
||||||
|
|
||||||
// PERSPECTIVE_CORRECT_INTERPOLATION
|
|
||||||
|
|
||||||
float u = tex0.x * (w1 / p0.w) + tex1.x * (w2 / p1.w) + tex2.x * (w3 / p2.w);
|
|
||||||
|
|
||||||
float v = tex0.y * (w1 / p0.w) + tex1.y * (w2 / p1.w) + tex2.y * (w3 / p2.w);
|
|
||||||
|
|
||||||
u /= interpolated_z;
|
|
||||||
|
|
||||||
v /= interpolated_z;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// @Note: We could do: interpolated_z = 1.f / interpolated_z to get proper depth
|
|
||||||
|
|
||||||
// but why waste an instruction, the smaller the depth value the farther the object
|
|
||||||
|
|
||||||
float* depth = depth_buffer + (x + y * dst->x);
|
|
||||||
|
|
||||||
if (*depth < interpolated_z) {
|
|
||||||
|
|
||||||
*depth = interpolated_z;
|
|
||||||
|
|
||||||
u = u * (src->x - 2);
|
|
||||||
|
|
||||||
v = v * (src->y - 2);
|
|
||||||
|
|
||||||
I64 ui = (I64)(u);
|
|
||||||
|
|
||||||
I64 vi = (I64)(v);
|
|
||||||
|
|
||||||
float udiff = u - (float)ui;
|
|
||||||
|
|
||||||
float vdiff = v - (float)vi;
|
|
||||||
|
|
||||||
// Origin UV (0,0) is in bottom left
|
|
||||||
|
|
||||||
U32* pixel = src->pixels + (ui + (src->y - 1ll - vi) * src->x);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// BILINEAR_BLEND
|
|
||||||
|
|
||||||
Vec4 pixelx1y1 = v4abgr(*pixel);
|
|
||||||
|
|
||||||
Vec4 pixelx2y1 = v4abgr(*(pixel + 1));
|
|
||||||
|
|
||||||
Vec4 pixelx1y2 = v4abgr(*(pixel - src->x));
|
|
||||||
|
|
||||||
Vec4 pixelx2y2 = v4abgr(*(pixel + 1 - src->x));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Vec4 blendx1 = lerp(pixelx1y1, pixelx2y1, udiff);
|
|
||||||
|
|
||||||
Vec4 blendx2 = lerp(pixelx1y2, pixelx2y2, udiff);
|
|
||||||
|
|
||||||
Vec4 result_color = lerp(blendx1, blendx2, vdiff);
|
|
||||||
|
|
||||||
U32 color32 = color_to_u32abgr(result_color);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dst->pixels[x + y * dst->x] = color32;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (draw_rects) {
|
|
||||||
|
|
||||||
draw_rect(dst, p0.x-4, p0.y-4, 8,8, 0x00ff0000);
|
|
||||||
|
|
||||||
draw_rect(dst, p1.x-4, p1.y-4, 8,8, 0x0000ff00);
|
|
||||||
|
|
||||||
draw_rect(dst, p2.x-4, p2.y-4, 8,8, 0x000000ff);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
FUNCTION void draw_triangle_PERSPECTIVE_CORRECT_INTERPOLATION_off_BILINEAR_BLEND_on (Image* dst, float *depth_buffer, Image *src,
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user