summaryrefslogtreecommitdiff
path: root/graphics.c
diff options
context:
space:
mode:
Diffstat (limited to 'graphics.c')
-rwxr-xr-xgraphics.c285
1 files changed, 54 insertions, 231 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;
}