Testing, fixing premultiplied alpha, UI work, resizing plots
This commit is contained in:
@@ -75,6 +75,7 @@ box. In this box every pixel gets tested to see if it's in the triangle. In this
|
|||||||
the box is clipped to the image metrics - 0, 0, width, height.
|
the box is clipped to the image metrics - 0, 0, width, height.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Resources that helped me build the rasterizer (Might be helpful to you too):
|
### Resources that helped me build the rasterizer (Might be helpful to you too):
|
||||||
|
|
||||||
* Algorithm I used for triangle rasterization by Juan Pineda: https://www.cs.drexel.edu/~david/Classes/Papers/comp175-06-pineda.pdf
|
* Algorithm I used for triangle rasterization by Juan Pineda: https://www.cs.drexel.edu/~david/Classes/Papers/comp175-06-pineda.pdf
|
||||||
|
|||||||
165
main.cpp
165
main.cpp
@@ -96,8 +96,7 @@ struct R_Render {
|
|||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
GLOBAL bool draw_rects = 0;
|
GLOBAL B32 draw_rects = 0;
|
||||||
GLOBAL bool draw_wireframe = 0;
|
|
||||||
|
|
||||||
FUNCTION
|
FUNCTION
|
||||||
Vec4 srgb_to_almost_linear(Vec4 a) {
|
Vec4 srgb_to_almost_linear(Vec4 a) {
|
||||||
@@ -111,6 +110,16 @@ FUNCTION
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FUNCTION
|
||||||
|
Vec4 premultiplied_alpha(Vec4 dst, Vec4 src) {
|
||||||
|
Vec4 result;
|
||||||
|
result.r = src.r + ((1-src.a) * dst.r);
|
||||||
|
result.g = src.g + ((1-src.a) * dst.g);
|
||||||
|
result.b = src.b + ((1-src.a) * dst.b);
|
||||||
|
result.a = src.a + dst.a - src.a*dst.a;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
FUNCTION
|
FUNCTION
|
||||||
void r_draw_rect(Bitmap* dst, F32 X, F32 Y, F32 w, F32 h, Vec4 color) {
|
void r_draw_rect(Bitmap* dst, F32 X, F32 Y, F32 w, F32 h, Vec4 color) {
|
||||||
int max_x = (int)(MIN(X + w, dst->x) + 0.5f);
|
int max_x = (int)(MIN(X + w, dst->x) + 0.5f);
|
||||||
@@ -118,26 +127,25 @@ void r_draw_rect(Bitmap* dst, F32 X, F32 Y, F32 w, F32 h, Vec4 color) {
|
|||||||
int min_x = (int)(MAX(0, X) + 0.5f);
|
int min_x = (int)(MAX(0, X) + 0.5f);
|
||||||
int min_y = (int)(MAX(0, Y) + 0.5f);
|
int min_y = (int)(MAX(0, Y) + 0.5f);
|
||||||
|
|
||||||
|
color.rgb *= color.a;
|
||||||
color = srgb_to_almost_linear(color);
|
color = srgb_to_almost_linear(color);
|
||||||
for (int y = min_y; y < max_y; y++) {
|
for (int y = min_y; y < max_y; y++) {
|
||||||
for (int x = min_x; x < max_x; x++) {
|
for (int x = min_x; x < max_x; x++) {
|
||||||
U32 *dst_pixel = dst->pixels + (x + y * dst->x);
|
U32 *dst_pixel = dst->pixels + (x + y * dst->x);
|
||||||
Vec4 dst_color = srgb_to_almost_linear(vec4abgr(*dst_pixel));
|
Vec4 dstc = srgb_to_almost_linear(vec4abgr(*dst_pixel));
|
||||||
|
dstc = premultiplied_alpha(dstc, color);
|
||||||
color.r = color.r + (1-color.a) * dst_color.r;
|
U32 color32 = vec4_to_u32abgr(almost_linear_to_srgb(dstc));
|
||||||
color.g = color.g + (1-color.a) * dst_color.g;
|
|
||||||
color.b = color.b + (1-color.a) * dst_color.b;
|
|
||||||
color.a = color.a + dst_color.a - color.a*dst_color.a;
|
|
||||||
U32 color32 = vec4_to_u32abgr(almost_linear_to_srgb(color));
|
|
||||||
*dst_pixel = color32;
|
*dst_pixel = color32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION
|
FUNCTION
|
||||||
void r_draw_bitmap(Bitmap* dst, Bitmap* src, Vec2 pos) {
|
void r_draw_bitmap(Bitmap* dst, Bitmap* src, Vec2 pos, Vec2 size=vec2(F32MAX, F32MAX)) {
|
||||||
I64 minx = (I64)(pos.x + 0.5);
|
I64 minx = (I64)(pos.x + 0.5);
|
||||||
I64 miny = (I64)(pos.y + 0.5);
|
I64 miny = (I64)(pos.y + 0.5);
|
||||||
|
|
||||||
|
if (size.x == F32MAX || size.y == F32MAX) {
|
||||||
I64 maxx = minx + src->x;
|
I64 maxx = minx + src->x;
|
||||||
I64 maxy = miny + src->y;
|
I64 maxy = miny + src->y;
|
||||||
I64 offsetx = 0;
|
I64 offsetx = 0;
|
||||||
@@ -157,7 +165,6 @@ void r_draw_bitmap(Bitmap* dst, Bitmap* src, Vec2 pos) {
|
|||||||
offsety = -miny;
|
offsety = -miny;
|
||||||
miny = 0;
|
miny = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (I64 y = miny; y < maxy; y++) {
|
for (I64 y = miny; y < maxy; y++) {
|
||||||
for (I64 x = minx; x < maxx; x++) {
|
for (I64 x = minx; x < maxx; x++) {
|
||||||
I64 tx = x - minx + offsetx;
|
I64 tx = x - minx + offsetx;
|
||||||
@@ -166,16 +173,54 @@ void r_draw_bitmap(Bitmap* dst, Bitmap* src, Vec2 pos) {
|
|||||||
U32 *pixel = src->pixels + (tx + ty * src->x);
|
U32 *pixel = src->pixels + (tx + ty * src->x);
|
||||||
Vec4 result_color = srgb_to_almost_linear(vec4abgr(*pixel));
|
Vec4 result_color = srgb_to_almost_linear(vec4abgr(*pixel));
|
||||||
Vec4 dst_color = srgb_to_almost_linear(vec4abgr(*dst_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 = premultiplied_alpha(dst_color, result_color);
|
||||||
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);
|
result_color = almost_linear_to_srgb(result_color);
|
||||||
U32 color32 = vec4_to_u32abgr(result_color);
|
U32 color32 = vec4_to_u32abgr(result_color);
|
||||||
*dst_pixel = color32;
|
*dst_pixel = color32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
I64 maxx = minx + (I64)(size.x + 0.5f);
|
||||||
|
I64 maxy = miny + (I64)(size.y + 0.5f);
|
||||||
|
I64 offsetx = 0;
|
||||||
|
I64 offsety = 0;
|
||||||
|
|
||||||
|
if (maxx > dst->x) {
|
||||||
|
maxx = dst->x;
|
||||||
|
}
|
||||||
|
if (maxy > dst->y) {
|
||||||
|
maxy = dst->y;
|
||||||
|
}
|
||||||
|
if (minx < 0) {
|
||||||
|
offsetx = -minx;
|
||||||
|
minx = 0;
|
||||||
|
}
|
||||||
|
if (miny < 0) {
|
||||||
|
offsety = -miny;
|
||||||
|
miny = 0;
|
||||||
|
}
|
||||||
|
F32 distx = (F32)(maxx - minx);
|
||||||
|
F32 disty = (F32)(maxy - miny);
|
||||||
|
for (I64 y = miny; y < maxy; y++) {
|
||||||
|
for (I64 x = minx; x < maxx; x++) {
|
||||||
|
F32 u = (F32)(x - minx) / distx;
|
||||||
|
F32 v = (F32)(y - miny) / disty;
|
||||||
|
I64 tx = (I64)(u * src->x + 0.5f);
|
||||||
|
I64 ty = (I64)(v * src->y + 0.5f);
|
||||||
|
U32 *dst_pixel = dst->pixels + (x + y * dst->x);
|
||||||
|
U32 *pixel = src->pixels + (tx + ty * src->x);
|
||||||
|
Vec4 result_color = srgb_to_almost_linear(vec4abgr(*pixel));
|
||||||
|
Vec4 dst_color = srgb_to_almost_linear(vec4abgr(*dst_pixel));
|
||||||
|
result_color = premultiplied_alpha(dst_color, result_color);
|
||||||
|
result_color = almost_linear_to_srgb(result_color);
|
||||||
|
U32 color32 = vec4_to_u32abgr(result_color);
|
||||||
|
*dst_pixel = color32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
FN Vec4 r_base_string(Bitmap *dst, Font *font, S8 word, Vec2 pos, B32 draw) {
|
FN Vec4 r_base_string(Bitmap *dst, Font *font, S8 word, Vec2 pos, B32 draw) {
|
||||||
Vec2 og_position = pos;
|
Vec2 og_position = pos;
|
||||||
@@ -267,10 +312,7 @@ void draw_triangle_nearest(Bitmap* dst, F32 *depth_buffer, Bitmap *src, F32 ligh
|
|||||||
result_color.r *= light;
|
result_color.r *= light;
|
||||||
result_color.g *= light;
|
result_color.g *= light;
|
||||||
result_color.b *= light;
|
result_color.b *= light;
|
||||||
result_color.r = result_color.r + (1-result_color.a) * dst_color.r;
|
result_color = premultiplied_alpha(dst_color, result_color);
|
||||||
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);
|
result_color = almost_linear_to_srgb(result_color);
|
||||||
U32 color32 = vec4_to_u32abgr(result_color);
|
U32 color32 = vec4_to_u32abgr(result_color);
|
||||||
#else
|
#else
|
||||||
@@ -352,10 +394,7 @@ FUNCTION
|
|||||||
#if PREMULTIPLIED_ALPHA_BLENDING
|
#if PREMULTIPLIED_ALPHA_BLENDING
|
||||||
Vec4 dst_color = vec4abgr(*dst_pixel);
|
Vec4 dst_color = vec4abgr(*dst_pixel);
|
||||||
dst_color = srgb_to_almost_linear(dst_color);
|
dst_color = srgb_to_almost_linear(dst_color);
|
||||||
result_color.r = result_color.r + (1-result_color.a) * dst_color.r;
|
result_color = premultiplied_alpha(dst_color, result_color);
|
||||||
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;
|
|
||||||
#endif // PREMULTIPLIED_ALPHA_BLENDING
|
#endif // PREMULTIPLIED_ALPHA_BLENDING
|
||||||
result_color = almost_linear_to_srgb(result_color);
|
result_color = almost_linear_to_srgb(result_color);
|
||||||
U32 color32 = vec4_to_u32abgr(result_color);
|
U32 color32 = vec4_to_u32abgr(result_color);
|
||||||
@@ -372,24 +411,6 @@ FUNCTION
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION
|
|
||||||
void draw_line(Bitmap *dst, F32 x0, F32 y0, F32 x1, F32 y1) {
|
|
||||||
F32 delta_x = (x1 - x0);
|
|
||||||
F32 delta_y = (y1 - y0);
|
|
||||||
F32 longest_side_length = (ABS(delta_x) >= ABS(delta_y)) ? ABS(delta_x) : ABS(delta_y);
|
|
||||||
F32 x_inc = delta_x / (F32)longest_side_length;
|
|
||||||
F32 y_inc = delta_y / (F32)longest_side_length;
|
|
||||||
F32 current_x = (F32)x0;
|
|
||||||
F32 current_y = (F32)y0;
|
|
||||||
for (int i = 0; i <= longest_side_length; i++) {
|
|
||||||
int x = (int)(current_x + 0.5f);
|
|
||||||
int y = (int)(current_y + 0.5f);
|
|
||||||
dst->pixels[x + y * dst->x] = 0xffffffff;
|
|
||||||
current_x += x_inc;
|
|
||||||
current_y += y_inc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNCTION
|
FUNCTION
|
||||||
Bitmap load_image(const char* path) {
|
Bitmap load_image(const char* path) {
|
||||||
int x, y, n;
|
int x, y, n;
|
||||||
@@ -411,7 +432,7 @@ Bitmap load_image(const char* path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FN void r_scatter_plot(Bitmap *dst, F64 *data, I64 data_len) {
|
FN void r_scatter_plot(Bitmap *dst, F64 *data, I64 data_len) {
|
||||||
F64 min = FLT_MAX;
|
F64 min = F32MAX;
|
||||||
F64 max = FLT_MIN;
|
F64 max = FLT_MIN;
|
||||||
F64 step = dst->x / (F64)data_len;
|
F64 step = dst->x / (F64)data_len;
|
||||||
for (U32 i = 0; i < data_len; i++) {
|
for (U32 i = 0; i < data_len; i++) {
|
||||||
@@ -466,6 +487,7 @@ FN void r_draw_mesh(R_Render *r, ObjMesh *mesh, Vec3 *vertices, Vec2 *tex_coords
|
|||||||
Vec3 light_direction = mat4_rotation_y(45) * vec3(0, 0, 1);
|
Vec3 light_direction = mat4_rotation_y(45) * vec3(0, 0, 1);
|
||||||
F32 light = -dot(normal, light_direction);
|
F32 light = -dot(normal, light_direction);
|
||||||
light = CLAMP(0.05f, light, 1.f);
|
light = CLAMP(0.05f, light, 1.f);
|
||||||
|
light = 1;
|
||||||
if (dot(normal, p0_to_camera) > 0) { //@Note: Backface culling
|
if (dot(normal, p0_to_camera) > 0) { //@Note: Backface culling
|
||||||
/// ## Clipping
|
/// ## Clipping
|
||||||
///
|
///
|
||||||
@@ -569,14 +591,10 @@ FN void r_draw_mesh(R_Render *r, ObjMesh *mesh, Vec3 *vertices, Vec2 *tex_coords
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (draw_wireframe) {
|
|
||||||
draw_line(&r->screen320, vert[0].pos.x, vert[0].pos.y, vert[1].pos.x, vert[1].pos.y);
|
|
||||||
draw_line(&r->screen320, vert[1].pos.x, vert[1].pos.y, vert[2].pos.x, vert[2].pos.y);
|
|
||||||
draw_line(&r->screen320, vert[2].pos.x, vert[2].pos.y, vert[0].pos.x, vert[0].pos.y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#include "ui.cpp"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
os.window_size.x = 1280;
|
os.window_size.x = 1280;
|
||||||
@@ -601,6 +619,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scenario_name = LIT("assets/f22.obj");
|
scenario_name = LIT("assets/f22.obj");
|
||||||
|
//scenario_name = LIT("assets/cube.obj");
|
||||||
//scenario_name = LIT("assets/AnyConv.com__White.obj");
|
//scenario_name = LIT("assets/AnyConv.com__White.obj");
|
||||||
//scenario_name = LIT("assets/sponza/sponza.obj");
|
//scenario_name = LIT("assets/sponza/sponza.obj");
|
||||||
Obj obj = load_obj(scenario_name);
|
Obj obj = load_obj(scenario_name);
|
||||||
@@ -619,15 +638,46 @@ int main() {
|
|||||||
r.screen320 = {(U32 *)PUSH_SIZE(os.perm_arena, screen_x*screen_y*sizeof(U32)), screen_x, screen_y};
|
r.screen320 = {(U32 *)PUSH_SIZE(os.perm_arena, screen_x*screen_y*sizeof(U32)), screen_x, screen_y};
|
||||||
r.plot = {(U32 *)PUSH_SIZE(os.perm_arena, 1280*720*sizeof(U32)), 1280, 720};
|
r.plot = {(U32 *)PUSH_SIZE(os.perm_arena, 1280*720*sizeof(U32)), 1280, 720};
|
||||||
r.depth320 = (F32 *)PUSH_SIZE(os.perm_arena, sizeof(F32) * screen_x * screen_y);
|
r.depth320 = (F32 *)PUSH_SIZE(os.perm_arena, sizeof(F32) * screen_x * screen_y);
|
||||||
r.img = load_image("assets/bricksx64.png");
|
r.img = load_image("assets/cat.png");
|
||||||
|
|
||||||
|
/* @Note: Transparent texture */ {
|
||||||
|
#if 0
|
||||||
|
Vec4 testc = vec4(1, 1, 1, 0.5f);
|
||||||
|
testc.rgb *= testc.a;
|
||||||
|
U32 testc32 = vec4_to_u32abgr(testc);
|
||||||
|
U32 a[] = {
|
||||||
|
testc32, testc32, testc32, testc32,
|
||||||
|
testc32, testc32, testc32, testc32,
|
||||||
|
testc32, testc32, testc32, testc32,
|
||||||
|
testc32, testc32, testc32, testc32,
|
||||||
|
};
|
||||||
|
r.img.pixels = a;
|
||||||
|
r.img.x = 4;
|
||||||
|
r.img.y = 4;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
S8 frame_data = {};
|
||||||
|
UISetup setup[] = {
|
||||||
|
UI_BOOL(LIT("Draw rectangles:"), &draw_rects),
|
||||||
|
UI_IMAGE(&r.plot),
|
||||||
|
UI_LABEL(&frame_data),
|
||||||
|
};
|
||||||
|
UI ui = ui_make(os.perm_arena, setup, ARRAY_CAP(setup));
|
||||||
|
B32 ui_mouse_lock = true;
|
||||||
|
|
||||||
while (os_game_loop()) {
|
while (os_game_loop()) {
|
||||||
r.camera_yaw.x += os.delta_mouse_pos.x * 0.05f;
|
if (ui_mouse_lock == false) {
|
||||||
r.camera_yaw.y -= os.delta_mouse_pos.y * 0.05f;
|
r.camera_yaw.x += os.delta_mouse_pos.x * 0.01f;
|
||||||
|
r.camera_yaw.y -= os.delta_mouse_pos.y * 0.01f;
|
||||||
|
}
|
||||||
if (os.key[Key_Escape].pressed) os_quit();
|
if (os.key[Key_Escape].pressed) os_quit();
|
||||||
if (os.key[Key_O].down) rotation += 0.05f;
|
if (os.key[Key_O].down) rotation += 0.05f;
|
||||||
if (os.key[Key_P].down) rotation -= 0.05f;
|
if (os.key[Key_P].down) rotation -= 0.05f;
|
||||||
if (os.key[Key_F1].pressed) draw_rects = !draw_rects;
|
if (os.key[Key_F1].pressed) draw_rects = !draw_rects;
|
||||||
if (os.key[Key_F2].pressed) draw_wireframe = !draw_wireframe;
|
if (os.key[Key_F2].pressed) ui_mouse_lock = !ui_mouse_lock;
|
||||||
if (os.key[Key_A].down) r.camera_pos.x -= speed * (F32)os.delta_time;
|
if (os.key[Key_A].down) r.camera_pos.x -= speed * (F32)os.delta_time;
|
||||||
if (os.key[Key_D].down) r.camera_pos.x += speed * (F32)os.delta_time;
|
if (os.key[Key_D].down) r.camera_pos.x += speed * (F32)os.delta_time;
|
||||||
if (os.key[Key_W].down) {
|
if (os.key[Key_W].down) {
|
||||||
@@ -643,16 +693,17 @@ int main() {
|
|||||||
U32* p = r.screen320.pixels;
|
U32* p = r.screen320.pixels;
|
||||||
for (int y = 0; y < r.screen320.y; y++) {
|
for (int y = 0; y < r.screen320.y; y++) {
|
||||||
for (int x = 0; x < r.screen320.x; x++) {
|
for (int x = 0; x < r.screen320.x; x++) {
|
||||||
*p++ = 0x00333333;
|
*p++ = 0x33333333;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
F32* dp = r.depth320;
|
F32* dp = r.depth320;
|
||||||
for (int y = 0; y < r.screen320.y; y++) {
|
for (int y = 0; y < r.screen320.y; y++) {
|
||||||
for (int x = 0; x < r.screen320.x; x++) {
|
for (int x = 0; x < r.screen320.x; x++) {
|
||||||
*dp++ = -FLT_MAX;
|
*dp++ = -F32MAX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Mat4 camera_rotation = mat4_rotation_y(r.camera_yaw.x) * mat4_rotation_x(r.camera_yaw.y);
|
Mat4 camera_rotation = mat4_rotation_y(r.camera_yaw.x) * mat4_rotation_x(r.camera_yaw.y);
|
||||||
r.camera_direction = (camera_rotation * vec4(0,0,1,1)).xyz;
|
r.camera_direction = (camera_rotation * vec4(0,0,1,1)).xyz;
|
||||||
Vec3 target = r.camera_pos + r.camera_direction;
|
Vec3 target = r.camera_pos + r.camera_direction;
|
||||||
@@ -676,12 +727,14 @@ int main() {
|
|||||||
*ptr++ = r.screen320.pixels[tx + ty * (r.screen320.x)];
|
*ptr++ = r.screen320.pixels[tx + ty * (r.screen320.x)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
S8 print_string = string_format(os.frame_arena, "FPS:%f dt:%f frame:%u", os.fps, os.delta_time, os.frame);
|
ui_end_frame(os.screen, &ui, &font);
|
||||||
r_draw_string(os.screen, &font, print_string, vec2(0, os.screen->y - font.height));
|
frame_data = string_format(os.frame_arena, "FPS:%f dt:%f frame:%u", os.fps, os.delta_time, os.frame);
|
||||||
if (r.plot_ready) r_draw_bitmap(os.screen, &r.plot, { 0, 0 });
|
/*r_draw_string(os.screen, &font, print_string, vec2(0, os.screen->y - font.height));
|
||||||
|
if (r.plot_ready) r_draw_bitmap(os.screen, &r.plot, { 0, 0 });*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
/// ### Resources that helped me build the rasterizer (Might be helpful to you too):
|
/// ### Resources that helped me build the rasterizer (Might be helpful to you too):
|
||||||
///
|
///
|
||||||
/// * Algorithm I used for triangle rasterization by Juan Pineda: https://www.cs.drexel.edu/~david/Classes/Papers/comp175-06-pineda.pdf
|
/// * Algorithm I used for triangle rasterization by Juan Pineda: https://www.cs.drexel.edu/~david/Classes/Papers/comp175-06-pineda.pdf
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ FN void save_profile_data(ProfileScope *scope, S8 scenario_name, S8 scope_name)
|
|||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
{
|
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
scenario_name = string_chop_last_period(scenario_name);
|
scenario_name = string_chop_last_period(scenario_name);
|
||||||
scenario_name = string_skip_to_last_slash(scenario_name);
|
scenario_name = string_skip_to_last_slash(scenario_name);
|
||||||
@@ -51,4 +50,3 @@ FN void save_profile_data(ProfileScope *scope, S8 scenario_name, S8 scope_name)
|
|||||||
S8 name = string_format(scratch, "stats/%s_%s_%s_%u_%u_%u_%u_%u_%u.txt", scope_name, build_name, scenario_name, date.year, date.month, date.day, date.hour, date.minute, date.second);
|
S8 name = string_format(scratch, "stats/%s_%s_%s_%u_%u_%u_%u_%u_%u.txt", scope_name, build_name, scenario_name, date.year, date.month, date.day, date.hour, date.minute, date.second);
|
||||||
os_append_file(name, data);
|
os_append_file(name, data);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
176
ui.cpp
Normal file
176
ui.cpp
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
enum UIWidgetKind {
|
||||||
|
UIWidgetKind_None,
|
||||||
|
UIWidgetKind_Boolean,
|
||||||
|
UIWidgetKind_Image,
|
||||||
|
UIWidgetKind_Label,
|
||||||
|
UIWidgetKind_Group,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UISetup {
|
||||||
|
UIWidgetKind kind;
|
||||||
|
S8 text;
|
||||||
|
union {
|
||||||
|
void *v;
|
||||||
|
Bitmap *image;
|
||||||
|
B32 *b32;
|
||||||
|
S8 *label;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
#define UI_BOOL(text, x) {UIWidgetKind_Boolean,text,(void*)(x)}
|
||||||
|
#define UI_IMAGE(x) {UIWidgetKind_Image,string_null,(void*)(x)}
|
||||||
|
#define UI_LABEL(x) {UIWidgetKind_Label,string_null,(void*)(x)}
|
||||||
|
|
||||||
|
struct UIWidget {
|
||||||
|
UIWidgetKind kind;
|
||||||
|
UIWidget *next;
|
||||||
|
UIWidget *prev;
|
||||||
|
UIWidget *first_child;
|
||||||
|
UIWidget *last_child;
|
||||||
|
|
||||||
|
S8 text;
|
||||||
|
Vec2 size;
|
||||||
|
union {
|
||||||
|
Bitmap *image;
|
||||||
|
B32 *b32;
|
||||||
|
S8 *label;
|
||||||
|
} ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UI : UIWidget {
|
||||||
|
Arena arena;
|
||||||
|
|
||||||
|
UIWidget *hot;
|
||||||
|
UIWidget *active;
|
||||||
|
};
|
||||||
|
|
||||||
|
FUNCTION UIWidget *ui_new_widget(Arena *arena, UIWidgetKind kind) {
|
||||||
|
UIWidget *result = PUSH_STRUCT(arena, UIWidget);
|
||||||
|
result->kind = kind;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION void ui_push_child(UIWidget *widget, UIWidget *child) {
|
||||||
|
DLL_QUEUE_PUSH(widget->first_child, widget->last_child, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION UIWidget *ui_push_child(Arena *arena, UIWidget *widget, UIWidgetKind kind) {
|
||||||
|
UIWidget *result = ui_new_widget(arena, kind);
|
||||||
|
ui_push_child(widget, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION UIWidget *ui_push_image(Arena *arena, UIWidget *widget, Bitmap *img) {
|
||||||
|
UIWidget *result = ui_push_child(arena, widget, UIWidgetKind_Image);
|
||||||
|
result->ptr.image = img;
|
||||||
|
|
||||||
|
F32 ratio = (F32)result->ptr.image->x / (F32)result->ptr.image->y;
|
||||||
|
result->size.y = 64;
|
||||||
|
result->size.x = 64 * ratio;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION UIWidget *ui_push_bool(Arena *arena, UIWidget *widget, B32 *b32) {
|
||||||
|
UIWidget *result = ui_push_child(arena, widget, UIWidgetKind_Boolean);
|
||||||
|
result->ptr.b32 = b32;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION UIWidget *ui_push_string(Arena *arena, UIWidget *widget, S8 *string) {
|
||||||
|
UIWidget *result = ui_push_child(arena, widget, UIWidgetKind_Label);
|
||||||
|
result->ptr.label = string;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION UI ui_make(Arena *arena, UISetup *setup, U64 len) {
|
||||||
|
UI result = {};
|
||||||
|
result.arena = arena_sub(arena, MiB(16));
|
||||||
|
UIWidget *parent = &result;
|
||||||
|
for (UISetup *s = setup; s != (setup+len); s++) {
|
||||||
|
switch (s->kind) {
|
||||||
|
case UIWidgetKind_Image: {
|
||||||
|
ui_push_image(&result.arena, parent, s->image);
|
||||||
|
} break;
|
||||||
|
case UIWidgetKind_Boolean: {
|
||||||
|
ui_push_bool(&result.arena, parent, s->b32)->text = s->text;
|
||||||
|
} break;
|
||||||
|
case UIWidgetKind_Label: {
|
||||||
|
ui_push_string(&result.arena, parent, s->label);
|
||||||
|
} break;
|
||||||
|
INVALID_DEFAULT_CASE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION B32 ui_mouse_test(UI *ui, UIWidget *w, Vec4 rect) {
|
||||||
|
B32 result = false;
|
||||||
|
if (os.mouse_pos.x > rect.x && os.mouse_pos.x < rect.x + rect.width &&
|
||||||
|
os.mouse_pos.y > rect.y && os.mouse_pos.y < rect.y + rect.height) {
|
||||||
|
ui->hot = w;
|
||||||
|
if (os.key[Key_MouseLeft].down) {
|
||||||
|
ui->active = w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (w == ui->hot) {
|
||||||
|
ui->hot = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (os.key[Key_MouseLeft].released) {
|
||||||
|
if (ui->active == w) {
|
||||||
|
if (ui->hot == w)
|
||||||
|
result = true;
|
||||||
|
ui->active = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION void ui_end_frame(Bitmap *dst, UI *ui, Font *font) {
|
||||||
|
Scratch scratch;
|
||||||
|
Vec2 pos = vec2(0, (F32)dst->y);
|
||||||
|
for (UIWidget *w = ui->first_child; w; w = w->next) {
|
||||||
|
Vec4 rect = {};
|
||||||
|
switch (w->kind) {
|
||||||
|
case UIWidgetKind_Image: {
|
||||||
|
pos.y -= w->size.y;
|
||||||
|
rect = vec4(pos, w->size);
|
||||||
|
ui_mouse_test(ui, w, rect);
|
||||||
|
S8 string = string_format(scratch, "%d %d", w->ptr.image->x, w->ptr.image->y);
|
||||||
|
r_draw_string(dst, font, string, pos);
|
||||||
|
r_draw_bitmap(dst, w->ptr.image, pos, w->size);
|
||||||
|
if (ui->active == w) {
|
||||||
|
F32 ratio = (F32)w->ptr.image->y / (F32)w->ptr.image->x;
|
||||||
|
w->size.x -= os.delta_mouse_pos.x;
|
||||||
|
w->size.y = w->size.x * ratio;
|
||||||
|
}
|
||||||
|
if (ui->hot == w) {
|
||||||
|
r_draw_rect(dst, rect.x, rect.y, rect.width, rect.height, vec4(1, 1, 1, 0.1f));
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case UIWidgetKind_Boolean: {
|
||||||
|
pos.y -= font->height;
|
||||||
|
Vec4 color = vec4(0, 0, 0, 1);
|
||||||
|
S8 string = string_format(scratch, "%s %d", w->text, *w->ptr.b32);
|
||||||
|
rect = r_get_string_rect(font, string, pos);
|
||||||
|
B32 clicked = ui_mouse_test(ui, w, rect);
|
||||||
|
if (clicked) *w->ptr.b32 = !*w->ptr.b32;
|
||||||
|
if (ui->hot == w) {
|
||||||
|
color = vec4(0.4f, 0.4f, 0.4f, 1.f);
|
||||||
|
}
|
||||||
|
rect.y = rect.y-font->line_advance / 5;
|
||||||
|
r_draw_rect(dst, rect.x, rect.y, rect.width, rect.height, color);
|
||||||
|
rect = r_draw_string(dst, font, string, pos);
|
||||||
|
pos.y -= rect.height - font->height;
|
||||||
|
} break;
|
||||||
|
case UIWidgetKind_Label: {
|
||||||
|
pos.y -= font->height;
|
||||||
|
rect = r_draw_string(dst, font, *w->ptr.label, pos);
|
||||||
|
pos.y -= rect.height - font->height;
|
||||||
|
} break;
|
||||||
|
INVALID_DEFAULT_CASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user