nearest neighbour blending and gamma

This commit is contained in:
Krzosa Karol
2022-02-20 20:02:33 +01:00
parent a5b111d24a
commit 03777764b7
4 changed files with 12 additions and 684 deletions

View File

@@ -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()) {

View File

@@ -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,

View File

@@ -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
View File

@@ -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,