summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xgraphics.c285
-rwxr-xr-xreduced_system_layer.c323
2 files changed, 270 insertions, 338 deletions
diff --git a/graphics.c b/graphics.c
index 670610b..a14bedd 100755
--- a/graphics.c
+++ b/graphics.c
@@ -56,10 +56,6 @@ exit $STATUS # */
#define EPSILON (1e-9)
#endif
-#ifndef ANTIALIASING_SCALE
-#define ANTIALIASING_SCALE 3
-#endif
-
#ifndef GRAPHICS_CACHE_DEPTH
#define GRAPHICS_CACHE_DEPTH 4
#endif
@@ -68,18 +64,6 @@ exit $STATUS # */
#define GRAPHICS_CACHE_SIZE (128 * GRAPHICS_CACHE_DEPTH)
#endif
-#ifndef GRAPHICS_FRAME_BUDGET
-#define GRAPHICS_FRAME_BUDGET (100.0)
-#endif
-
-#ifndef GRAPHICS_RENDER_COST
-#define GRAPHICS_RENDER_COST (0.1)
-#endif
-
-#ifndef GRAPHICS_DOWNSCALE_COST
-#define GRAPHICS_DOWNSCALE_COST (0.1)
-#endif
-
// ================================================================
//
// Vector math
@@ -298,32 +282,17 @@ static b8 same_sign_(f64 a, f64 b) {
return 1;
}
-static f64 gamma_(f64 x) {
- if (x >= 0.0031308)
- return 1.055 * pow(x, 1.0 / 2.4) - 0.055;
- return 12.92 * x;
-}
-
-static f64 gamma_re_(f64 x) {
- if (x >= 0.04045)
- return pow((x + 0.055) / 1.055, 2.4);
- return x / 12.92;
-}
-
-static void put_pixel_(Pixel_Buffer dst, vec4_f32 color, i64 x, i64 y) {
- i64 n = y * dst.stride + x;
-
+static void put_pixel_(vec4_f32 *dst, vec4_f32 color) {
if (color.w == 1.f)
- dst.pixels[n] = color;
+ *dst = color;
else {
- vec4_f32 dst_color = dst.pixels[n];
- f32 dst_amount = 1. - color.w;
-
- dst.pixels[n] = (vec4_f32) {
- .x = dst_color.x * dst_amount + color.x * color.w,
- .y = dst_color.y * dst_amount + color.y * color.w,
- .z = dst_color.z * dst_amount + color.z * color.w,
- .w = max2_f32_(dst_color.w, color.w),
+ f32 dst_amount = 1. - color.w;
+
+ *dst = (vec4_f32) {
+ .x = dst->x * dst_amount + color.x * color.w,
+ .y = dst->y * dst_amount + color.y * color.w,
+ .z = dst->z * dst_amount + color.z * color.w,
+ .w = max2_f32_(dst->w, color.w),
};
}
}
@@ -342,43 +311,28 @@ void draw_pixels_to_buffer(Pixel_Buffer dst, Box area, Pixel_Buffer src) {
if (j0 < 0) j0 = 0;
if (j1 > dst.height) j1 = dst.height;
- f64 w_inv = 1. / area.width;
- f64 h_inv = 1. / area.height;
+ f64 w_coeff = src.width / area.width;
+ f64 h_coeff = src.height / area.height;
for (i64 j = j0; j < j1; ++j) {
- i64 src_j = (i64) floor(((j - area.y + .5) * src.height) * h_inv);
+ i64 src_j = (i64) floor((j - area.y + .5) * h_coeff);
if (src_j < 0 || src_j >= src.height) continue;
vec4_f32 *q = src.pixels + src_j * src.stride;
vec4_f32 *p = dst.pixels + j * dst.stride + i0;
for (i64 i = i0; i < i1; ++i) {
- i64 src_i = (i64) floor(((i - area.x + .5) * src.width) * w_inv);
+ i64 src_i = (i64) floor((i - area.x + .5) * w_coeff);
if (src_i < 0 || src_i >= src.width) continue;
- vec4_f32 color = q[src_i];
- if (color.w == 1.f)
- *p = color;
- else {
- vec4_f32 dst_color = *p;
- f32 dst_amount = 1. - color.w;
- *p = (vec4_f32) {
- .x = dst_color.x * dst_amount + color.x * color.w,
- .y = dst_color.y * dst_amount + color.y * color.w,
- .z = dst_color.z * dst_amount + color.z * color.w,
- .w = max2_f32_(dst_color.w, color.w),
- };
- }
+ put_pixel_(p, q[src_i]);
++p;
}
}
}
void fill_rectangle_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area) {
- f64 x1 = area.x + area.width;
- f64 y1 = area.y + area.height;
-
- i64 i0 = (i64) ceil (area.x);
- i64 i1 = (i64) floor(x1);
- i64 j0 = (i64) ceil (area.y);
- i64 j1 = (i64) floor(y1);
+ i64 i0 = (i64) floor(area.x);
+ i64 i1 = (i64) floor(area.x + area.width);
+ i64 j0 = (i64) floor(area.y);
+ i64 j1 = (i64) floor(area.y + area.height);
i64 i00 = i0;
i64 j00 = j0;
@@ -390,73 +344,11 @@ void fill_rectangle_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area) {
if (j0 < 0) j0 = 0;
if (j1 > dst.height) j1 = dst.height;
- f64 kx0 = i00 - area.x;
- f64 kx1 = x1 - i10;
- f64 ky0 = j00 - area.y;
- f64 ky1 = y1 - j10;
-
- for (i64 j = j0; j < j1; ++j)
- for (i64 i = i0; i < i1; ++i)
- put_pixel_(dst, color, i, j);
-
- if (i00 > i10) {
- kx0 *= kx1;
- kx1 = 0.;
- }
-
- if (j00 > j10) {
- ky0 *= ky1;
- ky1 = 0.;
- }
-
- f64 alpha = color.w;
-
- if (i00 - 1 >= 0 && i00 - 1 < dst.width) {
- color.w = gamma_(gamma_re_(alpha) * kx0);
- for (i64 j = j0; j < j1; ++j)
- put_pixel_(dst, color, i00 - 1, j);
- }
-
- if (i10 >= 0 && i10 < dst.width) {
- color.w = gamma_(gamma_re_(alpha) * kx1);
- for (i64 j = j0; j < j1; ++j)
- put_pixel_(dst, color, i10, j);
- }
-
- if (j00 - 1 >= 0 && j00 - 1 < dst.height) {
- color.w = gamma_(gamma_re_(alpha) * ky0);
- for (i64 i = i0; i < i1; ++i)
- put_pixel_(dst, color, i, j00 - 1);
- }
-
- if (j10 >= 0 && j10 < dst.height) {
- color.w = gamma_(gamma_re_(alpha) * ky1);
- for (i64 i = i0; i < i1; ++i)
- put_pixel_(dst, color, i, j10);
- }
-
- if ( i00 - 1 >= 0 && i00 - 1 < dst.width
- && j00 - 1 >= 0 && j00 - 1 < dst.height) {
- color.w = gamma_(gamma_re_(alpha) * kx0 * ky0);
- put_pixel_(dst, color, i00 - 1, j00 - 1);
- }
-
- if ( i10 >= 0 && i10 < dst.width
- && j00 - 1 >= 0 && j00 - 1 < dst.height) {
- color.w = gamma_(gamma_re_(alpha) * kx1 * ky0);
- put_pixel_(dst, color, i10, j00 - 1);
- }
-
- if ( i00 - 1 >= 0 && i00 - 1 < dst.width
- && j10 >= 0 && j10 < dst.height) {
- color.w = gamma_(gamma_re_(alpha) * kx0 * ky1);
- put_pixel_(dst, color, i00 - 1, j10);
- }
-
- if ( i10 >= 0 && i10 < dst.width
- && j10 >= 0 && j10 < dst.height) {
- color.w = gamma_(gamma_re_(alpha) * kx1 * ky1);
- put_pixel_(dst, color, i10, j10);
+ for (i64 j = j0; j < j1; ++j) {
+ vec4_f32 *p = dst.pixels + j * dst.stride + i0;
+ vec4_f32 *p_end = dst.pixels + j * dst.stride + i1;
+ for (; p < p_end; ++p)
+ put_pixel_(p, color);
}
}
@@ -496,8 +388,10 @@ void fill_triangle_to_buffer(Pixel_Buffer dst, vec4_f32 color, vec2 vertices[3])
break;
}
- for (i64 i = left; i <= right; ++i)
- put_pixel_(dst, color, i, j);
+ vec4_f32 *p = dst.pixels + j * dst.stride + left;
+ vec4_f32 *p_end = dst.pixels + j * dst.stride + right + 1;
+ for (; p < p_end; ++p)
+ put_pixel_(p, color);
}
}
@@ -539,8 +433,10 @@ void fill_quad_to_buffer(Pixel_Buffer dst, vec4_f32 color, vec2 vertices[4]) {
break;
}
- for (i64 i = left; i <= right; ++i)
- put_pixel_(dst, color, i, j);
+ vec4_f32 *p = dst.pixels + j * dst.stride + left;
+ vec4_f32 *p_end = dst.pixels + j * dst.stride + right + 1;
+ for (; p < p_end; ++p)
+ put_pixel_(p, color);
}
}
@@ -576,8 +472,10 @@ void fill_ellipse_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area) {
if (left < 0) left = 0;
if (right >= dst.width) right = dst.width - 1;
- for (i64 i = left; i <= right; ++i)
- put_pixel_(dst, color, i, j);
+ vec4_f32 *p = dst.pixels + j * dst.stride + left;
+ vec4_f32 *p_end = dst.pixels + j * dst.stride + right + 1;
+ for (; p < p_end; ++p)
+ put_pixel_(p, color);
}
}
@@ -810,13 +708,13 @@ static void draw_text_(Pixel_Buffer dst, vec4_f32 color, f64 x0, f64 y0, f64 sca
f64 h_inv = 1. / h;
for (i64 i = i0; i <= i1; ++i) {
- i64 column = (i64) floor(((i - x) * num_cols) * w_inv + .5);
+ i64 column = (i64) floor(((i - x + .5) * num_cols) * w_inv);
i64 offset = char_column_offset_(text[n], column);
for (i64 j = j0; j <= j1; ++j) {
- i64 row = (i64) floor(((j - y) * CHAR_NUM_BITS_Y_) * h_inv + .5);
+ i64 row = (i64) floor(((j - y + .5) * CHAR_NUM_BITS_Y_) * h_inv);
if (char_bit_(offset, row))
- put_pixel_(dst, color, i, j);
+ put_pixel_(dst.pixels + j * dst.stride + i, color);
}
}
}
@@ -1433,33 +1331,17 @@ typedef union {
typedef struct {
b8 occupied;
- b8 done_rendering;
- b8 done_downscaling;
Graphics_Request_Id_ id;
Graphics_Request req;
i64 width;
i64 height;
i64 buffer_len;
vec4_f32 * buffer;
- i64 upscaled_buffer_len;
- vec4_f32 * upscaled_buffer;
} Graphics_Cache_Slot_;
static Graphics_Cache_Slot_ _graphics_cache[GRAPHICS_CACHE_SIZE] = {0};
-static i64 _graphics_cache_gc_index = 0;
-static f64 _graphics_rendering_budget = .0;
-
-static f64 _graphics_costs[] = {
- [GRAPHICS_DRAW_PIXELS] = 2.,
- [GRAPHICS_FILL_RECTANGLE] = 1.,
- [GRAPHICS_FILL_TRIANGLE] = 2.,
- [GRAPHICS_FILL_QUAD] = 2.,
- [GRAPHICS_FILL_ELLIPSE] = 2.,
- [GRAPHICS_FILL_LINE] = 3.,
- [GRAPHICS_DRAW_TEXT_AREA] = 2.,
- [GRAPHICS_DRAW_TEXT_CURSOR] = 2.,
-};
+static i64 _graphics_cache_gc_index = 0;
static void graphics_request_hash_(Blake2b_State *S, Graphics_Request req) {
switch (req.op) {
@@ -1817,41 +1699,14 @@ static b8 mem_eq_(i64 size, void *x, void *y) {
static void copy_pixels_quick_(Pixel_Buffer dst, i64 x, i64 y, Pixel_Buffer src) {
for (i64 j = 0; j < src.height; ++j) {
- i64 src_n = j * src.stride;
- i64 src_n1 = src_n + src.width;
- i64 dst_n = (y + j) * dst.stride + x;
-
- while (src_n < src_n1) {
- vec4_f32 *d = dst.pixels + dst_n;
- vec4_f32 *s = src.pixels + src_n;
+ vec4_f32 *s = src.pixels + j * src.stride;
+ vec4_f32 *d = dst.pixels + (y + j) * dst.stride + x;
+ vec4_f32 *d_end = d + src.width;
+ for (; d < d_end; ++d, ++s) {
d->x = d->x * (1.f - s->w) + s->x * s->w;
d->y = d->y * (1.f - s->w) + s->y * s->w;
d->z = d->z * (1.f - s->w) + s->z * s->w;
-
- ++dst_n;
- ++src_n;
- }
- }
-}
-
-static void downscale_pixels_(vec4_f32 *dst, i64 width, i64 height, vec4_f32 *src) {
- f32 k = 1.f / (ANTIALIASING_SCALE * ANTIALIASING_SCALE);
- for (i64 j = 0; j < height; ++j) {
- for (i64 i = 0; i < width; ++i) {
- vec4_f32 color = {0};
- for (i64 jj = 0; jj < ANTIALIASING_SCALE; ++jj)
- for (i64 ii = 0; ii < ANTIALIASING_SCALE; ++ii) {
- i64 n = (j * ANTIALIASING_SCALE + jj) * width + (i * ANTIALIASING_SCALE + ii);
- color.x += gamma_re_(src[n].x);
- color.y += gamma_re_(src[n].y);
- color.z += gamma_re_(src[n].z);
- color.w += gamma_re_(src[n].w);
- }
- dst[j * width + i].x = gamma_(color.x * k);
- dst[j * width + i].y = gamma_(color.y * k);
- dst[j * width + i].z = gamma_(color.z * k);
- dst[j * width + i].w = gamma_(color.w * k);
}
}
}
@@ -1891,14 +1746,10 @@ static void perform_graphics_request_cached_(Pixel_Buffer dst, Graphics_Request
Graphics_Cache_Slot_ *s = _graphics_cache + slot;
- i64 num_pixels = norm.width * norm.height;
- i64 upscaled_len = num_pixels * (ANTIALIASING_SCALE * ANTIALIASING_SCALE);
-
+ i64 num_pixels = norm.width * norm.height;
if (reset_slot) {
s->occupied = 1;
- s->done_rendering = 0;
- s->done_downscaling = 0;
s->id = id;
s->req = norm.req;
s->width = norm.width;
@@ -1907,44 +1758,21 @@ static void perform_graphics_request_cached_(Pixel_Buffer dst, Graphics_Request
if (num_pixels > s->buffer_len)
resize_dynamic_array_exact(&s->buffer_len, (void **) &s->buffer, sizeof *s->buffer, num_pixels);
- if (upscaled_len > s->upscaled_buffer_len)
- resize_dynamic_array_exact(&s->upscaled_buffer_len, (void **) &s->upscaled_buffer, sizeof *s->upscaled_buffer, upscaled_len);
-
- if (s->buffer_len < num_pixels || s->upscaled_buffer_len < upscaled_len)
+ if (s->buffer_len < num_pixels)
// Out of memory
s->occupied = 0;
- }
- if (_graphics_rendering_budget > 0 && !s->done_rendering) {
- if (s->upscaled_buffer_len >= upscaled_len) {
- Pixel_Buffer dst = {
- .width = s->width * ANTIALIASING_SCALE,
- .height = s->height * ANTIALIASING_SCALE,
- .stride = s->width * ANTIALIASING_SCALE,
- .pixels = s->upscaled_buffer,
- };
- Graphics_Request upscaled = graphics_request_scaled_(s->req, (vec2) { ANTIALIASING_SCALE, ANTIALIASING_SCALE });
- perform_graphics_request_to_buffer_(dst, upscaled);
- s->done_rendering = 1;
- _graphics_rendering_budget -= num_pixels * GRAPHICS_RENDER_COST * _graphics_costs[req.op];
- } else {
- LOG_ERROR("Sanity");
- s->occupied = 0;
- }
- }
+ Pixel_Buffer dst = {
+ .width = s->width,
+ .height = s->height,
+ .stride = s->width,
+ .pixels = s->buffer,
+ };
- if (_graphics_rendering_budget > 0 && s->done_rendering && !s->done_downscaling) {
- if (s->buffer_len >= num_pixels && s->upscaled_buffer_len >= upscaled_len) {
- downscale_pixels_(s->buffer, s->width, s->height, s->upscaled_buffer);
- s->done_downscaling = 1;
- _graphics_rendering_budget -= num_pixels * GRAPHICS_DOWNSCALE_COST;
- } else {
- LOG_ERROR("Sanity");
- s->occupied = 0;
- }
+ perform_graphics_request_to_buffer_(dst, s->req);
}
- if (s->done_downscaling)
+ if (s->occupied)
copy_pixels_quick_(dst, norm.x, norm.y, (Pixel_Buffer) {
.width = s->width,
.height = s->height,
@@ -1990,17 +1818,12 @@ void perform_graphics_request(Graphics_Context context, Graphics_Request req) {
}
void graphics_refresh_frame(void) {
- _graphics_rendering_budget = GRAPHICS_FRAME_BUDGET;
-
Graphics_Cache_Slot_ *s = _graphics_cache + _graphics_cache_gc_index;
- i64 required_len = !s->occupied ? 0 : s->width * s->height;
- i64 required_upscaled_len = !s->occupied ? 0 : required_len * (ANTIALIASING_SCALE * ANTIALIASING_SCALE);
+ i64 required_len = !s->occupied ? 0 : s->width * s->height;
if (s->buffer_len > required_len)
resize_dynamic_array_exact(&s->buffer_len, (void **) &s->buffer, sizeof *s->buffer, required_len);
- if (s->upscaled_buffer_len > required_upscaled_len)
- resize_dynamic_array_exact(&s->upscaled_buffer_len, (void **) &s->upscaled_buffer, sizeof *s->buffer, required_upscaled_len);
_graphics_cache_gc_index = (_graphics_cache_gc_index + 1) % GRAPHICS_CACHE_SIZE;
}
diff --git a/reduced_system_layer.c b/reduced_system_layer.c
index 1ca54e5..5079f4d 100755
--- a/reduced_system_layer.c
+++ b/reduced_system_layer.c
@@ -52,6 +52,7 @@
#/ + [x] Memory buffer allocator
#/ + [x] Blake2 hash
#/ + [x] Requests cache
+#/ + [x] Global anti-aliasing
#/ - Examples
#/ - Conway's Game of Life
#/ - Julia Set
@@ -259,12 +260,16 @@ i32 main(i32 argc, c8 **argv);
#define MEMORY_CHUNK_SIZE 1024
#endif
+#ifndef DEFAULT_ANTIALIASING_SCALE
+#define DEFAULT_ANTIALIASING_SCALE 4
+#endif
+
#ifndef MIN_PIXEL_SIZE
#define MIN_PIXEL_SIZE (1.0)
#endif
#ifndef MAX_PIXEL_SIZE
-#define MAX_PIXEL_SIZE (16.0)
+#define MAX_PIXEL_SIZE (40.0)
#endif
#ifndef DEFAULT_PIXEL_SIZE
@@ -593,13 +598,14 @@ typedef struct {
u8 v4_address[4];
u8 v6_address[16];
};
-} IP_Address;
+} Network_Address;
typedef struct {
c8 *title;
i32 frame_width;
i32 frame_height;
f64 pixel_size;
+ i32 antialiasing_scale; // TODO: Global anti-aliasing.
b8 exact_resolution : 1;
b8 graceful_shutdown : 1;
@@ -651,6 +657,7 @@ i8 utf8_write(c32 c, c8 *buffer);
// Time and sleep
i64 current_utc_time_in_milliseconds(void);
+void current_utc_time_in_sec_and_nsec(i64 *seconds, i64 *nanoseconds);
void yield_thread_execution(void);
void suspend_thread_for_milliseconds(i64 duration);
@@ -676,8 +683,8 @@ void handle_primary_sound(void);
void queue_primary_sound(i64 delay_in_samples, i64 num_samples, f32 *frames);
// Networking
-i64 network_recv(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port, IP_Address *remote_address);
-i64 network_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port);
+i64 network_recv(u16 slot, Network_Address address, i64 size, u8 *data, u16 *local_port, Network_Address *remote_address);
+i64 network_send(u16 slot, Network_Address address, i64 size, u8 *data, u16 *local_port);
// NOTE: This will shutdown main window, networking and audio.
// If g_platform.graceful_shutdown is 0, this does nothing.
@@ -890,6 +897,9 @@ void resize_dynamic_array_exact(i64 *num, void **data, i64 element_size, i64 new
return;
}
+ if (*num == new_num)
+ return;
+
void *new_data = memory_buffer_allocate(
new_num * element_size,
element_size,
@@ -911,6 +921,9 @@ void resize_dynamic_array_capacity(i64 *num, i64 *capacity, void **data, i64 ele
return;
}
+ if (*num == new_num)
+ return;
+
if (new_num > *capacity)
resize_dynamic_array_exact(capacity, data, element_size, new_num);
@@ -1357,6 +1370,17 @@ static vec3_f32 rgb_f32_from_u32_(u32 c) {
};
}
+// ================================================================
+//
+// Platform
+//
+// ================================================================
+
+static i64 _internal_pixels_len = 0;
+static i32 _internal_width = 0;
+static i32 _internal_height = 0;
+static u32 *_internal_pixels = NULL;
+
static i64 average_frame_duration_(i64 duration) {
_frame_duration[_frame_index] = duration;
_frame_index = (_frame_index + 1) % NUM_FRAMES_AVERAGED;
@@ -1455,20 +1479,24 @@ static void drop_files_set_data_(i64 index, i64 data_size) {
resize_dynamic_array_exact(&f->data_size, (void **) &f->data, 1, data_size);
}
+static i32 min2_i32_(i32 x, i32 y) {
+ return x < y ? x : y;
+}
+
+static i32 max2_i32_(i32 x, i32 y) {
+ return x > y ? x : y;
+}
+
static i8 pixel_size_update_(i32 real_width, i32 real_height) {
i8 size_changed = 0;
- i32 width = real_width;
- i32 height = real_height;
+ if (g_platform.antialiasing_scale <= 0) g_platform.antialiasing_scale = DEFAULT_ANTIALIASING_SCALE;
+ if (g_platform.pixel_size <= .0) g_platform.pixel_size = DEFAULT_PIXEL_SIZE;
+ if (g_platform.pixel_size < MIN_PIXEL_SIZE) g_platform.pixel_size = MIN_PIXEL_SIZE;
+ if (g_platform.pixel_size > MAX_PIXEL_SIZE) g_platform.pixel_size = MAX_PIXEL_SIZE;
- if (g_platform.pixel_size <= 0.) g_platform.pixel_size = DEFAULT_PIXEL_SIZE;
- if (g_platform.pixel_size < MIN_PIXEL_SIZE) g_platform.pixel_size = MIN_PIXEL_SIZE;
- if (g_platform.pixel_size > MAX_PIXEL_SIZE) g_platform.pixel_size = MAX_PIXEL_SIZE;
-
- if (g_platform.pixel_size > 1.) {
- width = (i32) floor(((f64) real_width) / g_platform.pixel_size + .5);
- height = (i32) floor(((f64) real_height) / g_platform.pixel_size + .5);
- }
+ i32 width = (i32) floor(((f64) real_width) / g_platform.pixel_size + .5) * g_platform.antialiasing_scale;
+ i32 height = (i32) floor(((f64) real_height) / g_platform.pixel_size + .5) * g_platform.antialiasing_scale;
if (g_platform.real_width != real_width || g_platform.real_height != real_height) {
size_changed = 1;
@@ -1476,16 +1504,125 @@ static i8 pixel_size_update_(i32 real_width, i32 real_height) {
g_platform.real_height = real_height;
}
+ resize_dynamic_array_exact(&g_platform.num_pixels, (void **) &g_platform.pixels, sizeof *g_platform.pixels, width * height);
+ height = g_platform.num_pixels / width;
+
if (g_platform.frame_width != width || g_platform.frame_height != height) {
size_changed = 1;
g_platform.frame_width = width;
g_platform.frame_height = height;
}
+ i32 internal_width = max2_i32_(real_width, width / g_platform.antialiasing_scale);
+ i32 internal_height = max2_i32_(real_height, height / g_platform.antialiasing_scale);
+
+ resize_dynamic_array_exact(&_internal_pixels_len, (void **) &_internal_pixels, sizeof *_internal_pixels, internal_width * internal_height);
+ _internal_width = real_width;
+ _internal_height = min2_i32_(_internal_pixels_len / real_width, real_height);
+
return size_changed;
}
-static void pixel_size_calubrate_(i64 current_frame_duration) {
+static f64 gamma_(f64 x) {
+ if (x >= 0.0031308)
+ return 1.055 * pow(x, 1.0 / 2.4) - 0.055;
+ return 12.92 * x;
+}
+
+static f64 gamma_re_(f64 x) {
+ if (x >= 0.04045)
+ return pow((x + 0.055) / 1.055, 2.4);
+ return x / 12.92;
+}
+
+static void convert_pixels_for_window_(void) {
+ i32 aa_scale = g_platform.antialiasing_scale;
+
+ if (aa_scale <= 0) {
+ LOG_ERROR("Sanity");
+ return;
+ }
+
+ // Downscale pixels from vec4_f32 pixel buffer to internal u32 pixel buffer.
+ {
+ i64 dst_width = g_platform.frame_width / aa_scale;
+ i64 dst_height = g_platform.frame_height / aa_scale;
+ i64 src_width = g_platform.frame_width;
+ i64 src_stride = g_platform.frame_width * aa_scale;
+
+ if (g_platform.num_pixels < src_width * g_platform.frame_height) {
+ LOG_ERROR("Sanity");
+ return;
+ }
+
+ if (_internal_pixels_len < dst_width * dst_height) {
+ LOG_ERROR("Sanity");
+ return;
+ }
+
+ f32 k = 1.f / (aa_scale * aa_scale);
+
+ for (i64 j = 0; j < dst_width; ++j) {
+ vec4_f32 *s = g_platform.pixels + j * src_stride;
+ u32 *d = _internal_pixels + j * dst_width;
+ u32 *d_end = d + dst_width;
+
+ for (; d < d_end; ++d, s += aa_scale) {
+ vec3_f32 color = {0};
+
+ for (i32 jj = 0; jj < aa_scale; ++jj) {
+ vec4_f32 *ss = s + jj * src_width;
+ vec4_f32 *ss_end = ss + aa_scale;
+
+ for (; ss < ss_end; ++ss) {
+ color.x += gamma_re_(ss->z);
+ color.y += gamma_re_(ss->y);
+ color.z += gamma_re_(ss->x);
+ }
+ }
+
+ color.x = gamma_(color.x * k);
+ color.y = gamma_(color.y * k);
+ color.z = gamma_(color.z * k);
+
+ *d = rgb_u32_from_f32_(color) | 0xff000000;
+ }
+ }
+ }
+
+ // Resize internal pixel buffer in-place.
+ {
+ i64 src_width = g_platform.frame_width / aa_scale;
+ i64 src_height = g_platform.frame_height / aa_scale;
+ i64 src_len = src_width * src_height;
+ i64 dst_width = _internal_width;
+ i64 dst_height = _internal_height;
+ i64 dst_len = dst_width * dst_height;
+
+ if (_internal_pixels_len < src_len) {
+ LOG_ERROR("Sanity");
+ return;
+ }
+
+ if (_internal_pixels_len < dst_len) {
+ LOG_ERROR("Sanity");
+ return;
+ }
+
+ i64 half_w = dst_width / 2;
+ i64 half_h = dst_height / 2;
+
+ // FIXME, PERF: Use pointers, check if src_len is less than dst_len.
+ for (i64 j = dst_height - 1; j >= 0; --j)
+ for (i64 i = dst_width - 1; i >= 0; --i) {
+ i64 n = j * dst_width + i;
+ i64 nn = ((j * src_height) / dst_height) * src_width + (i * src_width) / dst_width;
+ _internal_pixels[n] = _internal_pixels[nn];
+ }
+ }
+}
+
+static void pixel_size_calibrate_(i64 current_frame_duration) {
if (g_platform.exact_resolution)
return;
@@ -1499,6 +1636,11 @@ static void pixel_size_calubrate_(i64 current_frame_duration) {
g_platform.pixel_size -= PIXEL_SIZE_DELTA * (MIN_FRAME_DURATION - frame_duration);
}
+static void cleanup_pixel_buffers_(void) {
+ resize_dynamic_array_exact(&_internal_pixels_len, (void **) &_internal_pixels, sizeof *_internal_pixels, 0);
+ resize_dynamic_array_exact(&g_platform.num_pixels, (void **) &g_platform.pixels, sizeof *g_platform.pixels, 0);
+}
+
// ================================================================
//
// Unix
@@ -1511,6 +1653,13 @@ static void pixel_size_calubrate_(i64 current_frame_duration) {
#include <sched.h>
#include <unistd.h>
+void current_utc_time_in_sec_and_nsec(i64 *seconds, i64 *nanoseconds) {
+ struct timespec t;
+ timespec_get(&t, TIME_UTC);
+ if (seconds != NULL) *seconds = t.tv_sec;
+ if (nanoseconds != NULL) *nanoseconds = t.tv_nsec;
+}
+
i64 current_utc_time_in_milliseconds(void) {
struct timespec t;
timespec_get(&t, TIME_UTC);
@@ -1553,10 +1702,10 @@ void suspend_thread_for_milliseconds(i64 duration) {
#include <sys/socket.h>
typedef struct {
- b8 ready;
- i32 socket;
- u16 local_port;
- IP_Address address;
+ b8 ready;
+ i32 socket;
+ u16 local_port;
+ Network_Address address;
} Socket_Slot;
static b8 _network_ready = 0;
@@ -1588,7 +1737,7 @@ static void network_cleanup_(void) {
resize_dynamic_array_exact(&_num_sockets, (void **) &_sockets, sizeof *_sockets, 0);
}
-static b8 network_open_(u16 slot, IP_Address address, u16 *local_port) {
+static b8 network_open_(u16 slot, Network_Address address, u16 *local_port) {
network_init_(slot);
b8 change_address =
@@ -1664,9 +1813,9 @@ static b8 network_open_(u16 slot, IP_Address address, u16 *local_port) {
return 1;
}
-i64 network_recv(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port, IP_Address *remote_address) {
+i64 network_recv(u16 slot, Network_Address address, i64 size, u8 *data, u16 *local_port, Network_Address *remote_address) {
if (address.protocol != IPv4_UDP && address.protocol != IPv6_UDP) {
- LOG_ERROR("Invalid address protocol %d.", (i32) (u32) address.protocol);
+ LOG_ERROR("Invalid address protocol: %d", (i32) (u32) address.protocol);
return 0;
}
@@ -1722,13 +1871,13 @@ i64 network_recv(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_po
return received;
}
-i64 network_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port) {
+i64 network_send(u16 slot, Network_Address address, i64 size, u8 *data, u16 *local_port) {
if (address.protocol != IPv4_UDP && address.protocol != IPv6_UDP) {
- LOG_ERROR("Invalid address protocol %d.", (i32) (u32) address.protocol);
+ LOG_ERROR("Invalid address protocol: %d", (i32) (u32) address.protocol);
return 0;
}
- IP_Address local_address = address;
+ Network_Address local_address = address;
local_address.port = 0;
if (!network_open_(slot, local_address, local_port))
@@ -2545,11 +2694,6 @@ static Atom _text_uri_list = 0;
static Window _dnd_source = 0;
static b8 _mapped = 0;
static b8 _requested_clipboard = 0;
-// TODO: Use the same buffer for both scaled and non-scaled images.
-static i64 _pixels_scaled_len = 0;
-static u32 * _pixels_scaled = NULL;
-static i64 _pixels_internal_len = 0;
-static u32 * _pixels_internal = NULL;
static i16 _key_table [MAX_NUM_KEYS] = {0};
static b8 _key_repeat [MAX_NUM_KEYS] = {0};
@@ -2568,17 +2712,12 @@ static i32 x11_error_handler_(Display *display, XErrorEvent *event) {
return 0;
}
-void update_main_window_frame_(void) {
- i64 num_pixels = g_platform.frame_width * g_platform.frame_height;
-
- if (g_platform.num_pixels < num_pixels)
- resize_dynamic_array_exact(&g_platform.num_pixels, (void **) &g_platform.pixels, sizeof *g_platform.pixels, num_pixels);
- if (_pixels_scaled_len < num_pixels)
- resize_dynamic_array_exact(&_pixels_scaled_len, (void **) &_pixels_scaled, sizeof *_pixels_scaled, num_pixels);
- if (_pixels_internal_len < num_pixels)
- resize_dynamic_array_exact(&_pixels_internal_len, (void **) &_pixels_internal, sizeof *_pixels_internal, num_pixels);
+void put_image_to_main_window_(void) {
+ if (_image.width <= 0 || _image.height <= 0)
+ return;
- _image.data = (c8 *) _pixels_internal;
+ XPutImage(_display, _window, _gc, &_image, 0, 0, 0, 0, _image.width, _image.height);
+ XFlush(_display);
}
void init_main_window(void) {
@@ -2752,13 +2891,16 @@ void init_main_window(void) {
if (_ic == NULL) {
LOG_ERROR("XCreateIC failed.");
return;
- }
+ }
+
+ pixel_size_update_(g_platform.frame_width, g_platform.frame_height);
_image = (XImage) {
- .width = g_platform.frame_width,
- .height = g_platform.frame_height,
+ .width = _internal_width,
+ .height = _internal_height,
.depth = depth,
.format = ZPixmap,
+ .data = (c8 *) _internal_pixels,
.byte_order = LSBFirst,
.bitmap_unit = 32,
.bitmap_bit_order = LSBFirst,
@@ -2770,8 +2912,6 @@ void init_main_window(void) {
.blue_mask = 0x0000ff,
};
- update_main_window_frame_();
-
XInitImage(&_image);
_wm_delete_window = XInternAtom(_display, "WM_DELETE_WINDOW", False);
@@ -2802,10 +2942,6 @@ void init_main_window(void) {
XChangeProperty(_display, _window, _dnd_aware, 4, 32, PropModeReplace, &(u8) {5}, 1);
- // FIXME: Check if _image.data is successfully allocated.
- XPutImage(_display, _window, _gc, &_image, 0, 0, 0, 0, _image.width, _image.height);
- XFlush(_display);
-
_mapped = 0;
}
@@ -2824,16 +2960,13 @@ void shutdown_all_systems(void) {
_display = NULL;
drop_files_clean_();
- g_platform.input_len = 0;
-
- resize_dynamic_array_exact(&_pixels_scaled_len, (void **) &_pixels_scaled, sizeof *_pixels_scaled, 0);
- resize_dynamic_array_exact(&_pixels_internal_len, (void **) &_pixels_internal, sizeof *_pixels_internal, 0);
- resize_dynamic_array_exact(&g_platform.num_pixels, (void **) &g_platform.pixels, sizeof *g_platform.pixels, 0);
- resize_dynamic_array_exact(&g_platform.input_capacity, (void **) &g_platform.input, sizeof *g_platform.input, 0);
- resize_dynamic_array_exact(&g_platform.clipboard_text_len, (void **) &g_platform.clipboard_text, 1, 0);
-
+ cleanup_pixel_buffers_();
network_cleanup_();
sound_cleanup_();
+
+ g_platform.input_len = 0;
+ resize_dynamic_array_exact(&g_platform.input_capacity, (void **) &g_platform.input, sizeof *g_platform.input, 0);
+ resize_dynamic_array_exact(&g_platform.clipboard_text_len, (void **) &g_platform.clipboard_text, 1, 0);
}
i32 handle_main_window_events(void) {
@@ -2980,7 +3113,7 @@ i32 handle_main_window_events(void) {
g_platform.cursor_y = ev.xkey.y;
g_platform.key_down[k] = 0;
- _key_repeat[k] = 1;
+ _key_repeat[k] = 1;
g_platform.key_down[MOD_CTRL] = !!(ev.xkey.state & ControlMask);
g_platform.key_down[MOD_SHIFT] = !!(ev.xkey.state & ShiftMask);
@@ -3350,13 +3483,13 @@ i32 handle_main_window_events(void) {
XWindowAttributes attrs;
XGetWindowAttributes(_display, _window, &attrs);
- if (attrs.width > 0 && attrs.height > 0) {
- _image.width = attrs.width;
- _image.height = attrs.height;
- _image.bytes_per_line = _image.width * 4;
- }
+ num_events += pixel_size_update_(attrs.width, attrs.height);
- num_events += pixel_size_update_(_image.width, _image.height);
+ _image.width = _internal_width;
+ _image.height = _internal_height;
+ _image.data = (c8 *) _internal_pixels;
+
+ _image.bytes_per_line = _image.width * 4;
return num_events;
}
@@ -3383,41 +3516,11 @@ void render_main_window_frame(void) {
_mapped = 1;
}
- update_main_window_frame_();
-
- i64 size = g_platform.frame_width * g_platform.frame_height;
- if (size > g_platform.num_pixels)
- size = g_platform.num_pixels;
-
- if (g_platform.frame_width == _image.width && g_platform.frame_height == _image.height) {
- if (size > _pixels_internal_len)
- size = _pixels_internal_len;
- for (i64 i = 0; i < size; ++i)
- _pixels_internal[i] = rgb_u32_from_f32_((vec3_f32) { g_platform.pixels[i].x, g_platform.pixels[i].y, g_platform.pixels[i].z });
- } else {
- if (size > _pixels_scaled_len)
- size = _pixels_scaled_len;
- for (i64 i = 0; i < size; ++i)
- _pixels_scaled[i] = rgb_u32_from_f32_((vec3_f32) { g_platform.pixels[i].x, g_platform.pixels[i].y, g_platform.pixels[i].z });
-
- for (i64 j = 0; j < _image.height; ++j) {
- if ((j + 1) * _image.width > _pixels_internal_len)
- break;
- i64 j0 = (j * g_platform.frame_height) / _image.height;
- if ((j0 + 1) * g_platform.frame_width > _pixels_scaled_len)
- break;
- for (i64 i = 0; i < _image.width; ++i) {
- i64 i0 = (i * g_platform.frame_width) / _image.width;
- _pixels_internal[j * _image.width + i] = _pixels_scaled[j0 * g_platform.frame_width + i0];
- }
- }
- }
+ convert_pixels_for_window_();
- // FIXME: Check if _image.data is successfully allocated.
- XPutImage(_display, _window, _gc, &_image, 0, 0, 0, 0, _image.width, _image.height);
- XFlush(_display);
+ put_image_to_main_window_();
- pixel_size_calubrate_(current_utc_time_in_milliseconds() - _frame_time);
+ pixel_size_calibrate_(current_utc_time_in_milliseconds() - _frame_time);
}
void write_clipboard_text(i64 size, c8 *data) {
@@ -3647,7 +3750,7 @@ static b8 _files_dropped = 0;
static c8 _href [4096] = {0};
static u32 _pixels_scaled [MAX_NUM_PIXELS] = {0};
-static u32 _pixels_internal [MAX_NUM_PIXELS] = {0};
+static u32 _internal_pixels [MAX_NUM_PIXELS] = {0};
static b8 _key_pressed [MAX_NUM_KEYS] = {0};
static f32 _sound_buffer [MAX_NUM_PRIMARY_SOUND_FRAMES] = {0};
static u8 _drop_buffer [DROP_FILES_BUFFER_SIZE] = {0};
@@ -3656,18 +3759,24 @@ void shutdown_all_systems(void) {
g_platform.done = 1;
}
-i64 network_recv(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port, IP_Address *remote_address) {
+i64 network_recv(u16 slot, Network_Address address, i64 size, u8 *data, u16 *local_port, Network_Address *remote_address) {
LOG_ERROR("Web sockets are not implemented.");
return 0;
}
-i64 network_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port) {
+i64 network_send(u16 slot, Network_Address address, i64 size, u8 *data, u16 *local_port) {
LOG_ERROR("Web sockets are not implemented.");
return 0;
}
i64 current_utc_time_in_milliseconds(void);
+void current_utc_time_in_sec_and_nsec(i64 *seconds, i64 *nanoseconds) {
+ i64 time = current_utc_time_in_milliseconds();
+ if (seconds != NULL) *seconds = time / 1000ll;
+ if (nanoseconds != NULL) *nanoseconds = 1000000ll * (time % 1000ll);
+}
+
void yield_thread_execution(void) {
// Do nothing
}
@@ -3741,11 +3850,11 @@ void render_main_window_frame(void) {
i64 size = g_platform.frame_width * g_platform.frame_height;
if (size > g_platform.num_pixels)
size = g_platform.num_pixels;
- if (size > _pixels_internal_len)
- size = _pixels_internal_len;
+ if (size > _internal_pixels_len)
+ size = _internal_pixels_len;
for (i64 i = 0; i < size; ++i)
- _pixels_internal[i] = 0xff000000u | rgb_u32_from_f32_((vec3_f32) { g_platform.pixels[i].z, g_platform.pixels[i].y, g_platform.pixels[i].x });
+ _internal_pixels[i] = 0xff000000u | rgb_u32_from_f32_((vec3_f32) { g_platform.pixels[i].z, g_platform.pixels[i].y, g_platform.pixels[i].x });
} else {
i64 size = g_platform.frame_width * g_platform.frame_height;
if (size > g_platform.num_pixels)
@@ -3758,12 +3867,12 @@ void render_main_window_frame(void) {
for (i64 j = 0; j < _frame_height; ++j) {
i64 j0 = (j * g_platform.frame_height) / _frame_height;
- if ((j0 + 1) * _frame_width > _pixels_internal_len) break;
+ if ((j0 + 1) * _frame_width > _internal_pixels_len) break;
for (i64 i = 0; i < _frame_width; ++i) {
i64 i0 = (i * g_platform.frame_width) / _frame_width;
i64 n0 = j0 * g_platform.frame_width + i0;
if (n0 > _pixels_scaled_len) break;
- _pixels_internal[j * _frame_width + i] = 0xff000000u | _pixels_scaled[n0];
+ _internal_pixels[j * _frame_width + i] = 0xff000000u | _pixels_scaled[n0];
}
}
}
@@ -3859,7 +3968,7 @@ __attribute__((export_name("js_title"))) void *js_title(void) {
}
__attribute__((export_name("js_pixels"))) void *js_pixels(void) {
- return _pixels_internal;
+ return _internal_pixels;
}
__attribute__((export_name("js_frame"))) void js_frame(i32 frame_width, i32 frame_height, i32 num_samples) {
@@ -3892,7 +4001,7 @@ __attribute__((export_name("js_frame"))) void js_frame(i32 frame_width, i32 fram
_sound_read = (_sound_read + num_samples * NUM_PRIMARY_SOUND_CHANNELS) % MAX_NUM_PRIMARY_SOUND_FRAMES;
if (do_render)
- pixel_size_calubrate_(current_utc_time_in_milliseconds() - frame_time);
+ pixel_size_calibrate_(current_utc_time_in_milliseconds() - frame_time);
}
__attribute__((export_name("js_mousemove"))) void js_mousemove(i32 x, i32 y) {