# HG changeset patch # User Mike Becker # Date 1754433421 -7200 # Node ID 60014484121c98de2529deca1445e405cf449db9 # Parent 0e0a0bf4f7e4ce01c7f654390bc301f966e121c7 remove the asc_col4i datatype in favor of a unified asc_color type and also adds some min and max functions diff -r 0e0a0bf4f7e4 -r 60014484121c src/2d.c --- a/src/2d.c Tue Aug 05 20:38:11 2025 +0200 +++ b/src/2d.c Wed Aug 06 00:37:01 2025 +0200 @@ -109,13 +109,13 @@ asc_shader_upload_model_matrix(shader, node); if (filled) { - asc_shader_upload_col4f(rect_shader->color, rectangle->color); + asc_shader_upload_color(rect_shader->color, rectangle->color); } asc_shader_upload_vec2f(rect_shader->size, rectangle->size); if (border) { asc_shader_upload_float(rect_shader->thickness, rectangle->thickness); - asc_shader_upload_col4f(rect_shader->border_color, rectangle->border_color); + asc_shader_upload_color(rect_shader->border_color, rectangle->border_color); } if (round) { asc_shader_upload_float(rect_shader->radius, rectangle->radius); @@ -148,15 +148,15 @@ // use the main color args.border_color = args.color; } - rectangle->color = asc_col_itof(args.color); - rectangle->border_color = asc_col_itof(args.border_color); + rectangle->color = args.color; + rectangle->border_color = args.border_color; asc_ptr_cast(AscSceneNode, node, rectangle); asc_scene_node_init(node, ASC_SCENE_NODE_FUNCS(asc_rectangle), .pos2d = ASC_VEC2I(pos_x, pos_y), .origin2d = ASC_VEC2I(args.origin_x, args.origin_y), - .render_group = (args.filled && args.color.alpha < 255) || args.border_color.alpha < 255 + .render_group = (args.filled && args.color.alpha < 1) || args.border_color.alpha < 1 ? ASC_RENDER_GROUP_2D_BLEND : ASC_RENDER_GROUP_2D_OPAQUE ); @@ -254,13 +254,13 @@ asc_shader_upload_model_matrix(shader, node); if (filled) { - asc_shader_upload_col4f(ellipsis_shader->color, ellipsis->color); + asc_shader_upload_color(ellipsis_shader->color, ellipsis->color); } asc_shader_upload_vec2f(ellipsis_shader->radii, ellipsis->radii); if (border) { asc_shader_upload_float(ellipsis_shader->thickness, ellipsis->thickness); - asc_shader_upload_col4f(ellipsis_shader->border_color, ellipsis->border_color); + asc_shader_upload_color(ellipsis_shader->border_color, ellipsis->border_color); } // Draw mesh @@ -295,21 +295,21 @@ ellipsis->thickness = args.thickness; } - if (!args.filled && asc_memcmpz(&args.border_color, sizeof(args.border_color))) { + if (!args.filled && asc_memcmpz(&args.border_color, sizeof(asc_color))) { // convenience fallback: // when we are drawing an outline but have no explicit border color, // use the main color args.border_color = args.color; } - ellipsis->color = asc_col_itof(args.color); - ellipsis->border_color = asc_col_itof(args.border_color); + ellipsis->color = args.color; + ellipsis->border_color = args.border_color; asc_ptr_cast(AscSceneNode, node, ellipsis); asc_scene_node_init(node, ASC_SCENE_NODE_FUNCS(asc_ellipsis), .pos2d = ASC_VEC2I(pos_x, pos_y), .origin3d = ASC_VEC3F(ellipsis->radii.x, ellipsis->radii.y, 0), // use float to avoid cast - .render_group = (args.filled && args.color.alpha < 255) || args.border_color.alpha < 255 + .render_group = (args.filled && args.color.alpha < 1) || args.border_color.alpha < 1 ? ASC_RENDER_GROUP_2D_BLEND : ASC_RENDER_GROUP_2D_OPAQUE ); diff -r 0e0a0bf4f7e4 -r 60014484121c src/ascension/2d.h --- a/src/ascension/2d.h Tue Aug 05 20:38:11 2025 +0200 +++ b/src/ascension/2d.h Wed Aug 06 00:37:01 2025 +0200 @@ -34,8 +34,8 @@ typedef struct asc_rectangle_s { AscSceneNode node; AscMesh mesh; - asc_col4f color; - asc_col4f border_color; + asc_color color; + asc_color border_color; asc_vec2f size; float radius; float thickness; @@ -86,11 +86,11 @@ * If filled is true, this is the fill color. * If filled is false, and no border_color is specified, this is used as border color. */ - asc_col4i color; + asc_color color; /** * Border color to be used when thickness is larger than zero and filled is true. */ - asc_col4i border_color; + asc_color border_color; /** * If true, the rectangle will be filled with the specified color. * If the thickness is larger than zero, an outline border with that thickness is drawn @@ -117,8 +117,8 @@ typedef struct asc_ellipsis_s { AscSceneNode node; AscMesh mesh; - asc_col4f color; - asc_col4f border_color; + asc_color color; + asc_color border_color; asc_vec2f radii; float thickness; bool filled; @@ -166,11 +166,11 @@ * If filled is true, this is the fill color. * If filled is false, and no border_color is specified, this is used as border color. */ - asc_col4i color; + asc_color color; /** * Border color to be used when thickness is larger than zero and filled is true. */ - asc_col4i border_color; + asc_color border_color; /** * If true, the ellipsis will be filled with the specified color. * If the thickness is larger than zero, an outline border with that thickness is drawn diff -r 0e0a0bf4f7e4 -r 60014484121c src/ascension/camera.h --- a/src/ascension/camera.h Tue Aug 05 20:38:11 2025 +0200 +++ b/src/ascension/camera.h Wed Aug 06 00:37:01 2025 +0200 @@ -46,7 +46,7 @@ */ asc_camera_viewport_update_func viewport_update_func; asc_camera_projection_update_func projection_update_func; - asc_col4f clear_color; + asc_color clear_color; bool viewport_clear; }; @@ -72,7 +72,7 @@ * Indicates whether the viewport for this camera shall be cleared before rendering. * The active drawing color will be used as the clear color (can be changed in the camera struct, afterward). */ - asc_col4i clear_color; + asc_color clear_color; bool viewport_clear; }; diff -r 0e0a0bf4f7e4 -r 60014484121c src/ascension/datatypes.h --- a/src/ascension/datatypes.h Tue Aug 05 20:38:11 2025 +0200 +++ b/src/ascension/datatypes.h Wed Aug 06 00:37:01 2025 +0200 @@ -173,19 +173,14 @@ #define ASC_VEC4F_0 (asc_vec4f){{0.0f, 0.0f, 0.0f, 0.0f}} #define ASC_VEC4F_1 (asc_vec4f){{1.0f, 1.0f, 1.0f, 1.0f}} -typedef struct asc_col4i { - asc_ubyte red, green, blue, alpha; -} asc_col4i; - -typedef struct asc_col4f { +typedef struct asc_color { float red, green, blue, alpha; -} asc_col4f; +} asc_color; -// TODO: think about removing integer colors -#define ASC_RGB(r,g,b) (asc_col4i){(asc_ubyte)(r), (asc_ubyte)(g), (asc_ubyte)(b), 255u} -#define ASC_RGBA(r,g,b,a) (asc_col4i){(asc_ubyte)(r), (asc_ubyte)(g), (asc_ubyte)(b), (asc_ubyte)(a)} -#define ASC_RGB_F(r,g,b) (asc_col4f){r,g,b,1.f} -#define ASC_RGBA_F(r,g,b,a) (asc_col4f){r,g,b,a} +#define ASC_RGBi(r,g,b) asc_color_int(r,g,b,255) +#define ASC_RGBAi(r,g,b,a) asc_color_int(r,g,b,a) +#define ASC_RGB(r,g,b) (asc_color){r,g,b,1.f} +#define ASC_RGBA(r,g,b,a) (asc_color){r,g,b,a} typedef float asc_mat4f[16]; @@ -261,6 +256,84 @@ double: asc_clampd \ )(v, min, max) +static inline int asc_mini(int x, int y) { + if (x < y) return x; + return y; +} + +static inline long long int asc_minll(long long int x, long long int y) { + if (x < y) return x; + return y; +} + +static inline unsigned asc_minu(unsigned x, unsigned y) { + if (x < y) return x; + return y; +} + +static inline unsigned long long int asc_minull(unsigned long long int x, unsigned long long int y) { + if (x < y) return x; + return y; +} + +static inline float asc_minf(float x, float y) { + if (x < y) return x; + return y; +} + +static inline double asc_mind(double x, double y) { + if (x < y) return x; + return y; +} + +#define asc_min(x, y) _Generic((x), \ + int: asc_mini, \ + long long int: asc_minll, \ + unsigned: asc_minu, \ + unsigned long long int: asc_minull, \ + float: asc_minf, \ + double: asc_mind \ + )(x, y) + +static inline int asc_maxi(int x, int y) { + if (x > y) return x; + return y; +} + +static inline long long int asc_maxll(long long int x, long long int y) { + if (x > y) return x; + return y; +} + +static inline unsigned asc_maxu(unsigned x, unsigned y) { + if (x > y) return x; + return y; +} + +static inline unsigned long long int asc_maxull(unsigned long long int x, unsigned long long int y) { + if (x > y) return x; + return y; +} + +static inline float asc_maxf(float x, float y) { + if (x > y) return x; + return y; +} + +static inline double asc_maxd(double x, double y) { + if (x > y) return x; + return y; +} + +#define asc_max(x, y) _Generic((x), \ + int: asc_maxi, \ + long long int: asc_maxll, \ + unsigned: asc_maxu, \ + unsigned long long int: asc_maxull, \ + float: asc_maxf, \ + double: asc_maxd \ + )(x, y) + static inline asc_vec2i asc_rect_center(asc_rect rect) { return ASC_VEC2I(rect.pos.x + rect.size.width/2, rect.pos.y + rect.size.height/2); } @@ -318,41 +391,24 @@ return asc_fround_zero(sinf(x)); } -/** - * Converts a float color (0.0f to 1.0f) to an int color (0 to 255). - * - * This operation is quite expensive. When you need to use it often, it's - * quite obvious that you should change the data type. - * - * @param c the color using floats - * @return the same color using ints - */ -static inline asc_col4i asc_col_ftoi(asc_col4f c) { - unsigned red = (unsigned)(255*c.red); - unsigned green = (unsigned)(255*c.green); - unsigned blue = (unsigned)(255*c.blue); - unsigned alpha = (unsigned)(255*c.alpha); - asc_col4i r; - r.red = asc_clamp(red, 0, 255); - r.green = asc_clamp(green, 0, 255); - r.blue = asc_clamp(blue, 0, 255); - r.alpha = asc_clamp(alpha, 0, 255); - return r; -} - -static inline asc_col4f asc_col_itof(asc_col4i c) { +static inline asc_color asc_color_int(int r, int g, int b, int a) { // dividing by 256 is much more performant // because it compiles to multiplication instead of division const float f = 256.f / 255.f; - const float red = c.red * f / 256.f; - const float green = c.green * f / 256.f; - const float blue = c.blue * f / 256.f; - const float alpha = c.alpha * f / 256.f; - return (asc_col4f) {red, green, blue, alpha}; + const float red = r * f / 256.f; + const float green = g * f / 256.f; + const float blue = b * f / 256.f; + const float alpha = a * f / 256.f; + return (asc_color) {red, green, blue, alpha}; } -static inline SDL_Color asc_col_sdl(asc_col4i col) { - return (SDL_Color) {.r = col.red, .g = col.green, .b = col.blue, .a = col.alpha}; +static inline SDL_Color asc_color_sdl(asc_color color) { + return (SDL_Color){ + .r = asc_min((int)(color.red*255), 255), + .g = asc_min((int)(color.green*255), 255), + .b = asc_min((int)(color.blue*255), 255), + .a = asc_min((int)(color.alpha*255), 255), + }; } // -------------------------------------------------------------------------- diff -r 0e0a0bf4f7e4 -r 60014484121c src/ascension/mesh.h --- a/src/ascension/mesh.h Tue Aug 05 20:38:11 2025 +0200 +++ b/src/ascension/mesh.h Wed Aug 06 00:37:01 2025 +0200 @@ -55,7 +55,7 @@ typedef struct asc_vertex2d_col { asc_vec2f pos; asc_vec2f uv; - asc_col4f color; + asc_color color; } asc_vertex2d_col; typedef struct asc_vertex3d { @@ -66,7 +66,7 @@ typedef struct asc_vertex3d_col { asc_vec3f pos; asc_vec2f uv; - asc_col4f color; + asc_color color; } asc_vertex3d_col; diff -r 0e0a0bf4f7e4 -r 60014484121c src/ascension/shader.h --- a/src/ascension/shader.h Tue Aug 05 20:38:11 2025 +0200 +++ b/src/ascension/shader.h Wed Aug 06 00:37:01 2025 +0200 @@ -178,11 +178,7 @@ void asc_shader_upload_model_matrix(const AscShaderProgram *shader, const AscSceneNode *node); -void asc_shader_upload_col4f(int uniform_id, asc_col4f color); - -static inline void asc_shader_upload_col4i(int uniform_id, asc_col4i color) { - asc_shader_upload_col4f(uniform_id, asc_col_itof(color)); -} +void asc_shader_upload_color(int uniform_id, asc_color color); void asc_shader_upload_float(int uniform_id, float value); diff -r 0e0a0bf4f7e4 -r 60014484121c src/ascension/text.h --- a/src/ascension/text.h Tue Aug 05 20:38:11 2025 +0200 +++ b/src/ascension/text.h Wed Aug 06 00:37:01 2025 +0200 @@ -41,7 +41,7 @@ AscTexture *texture; cxmutstr text; AscFont font; - asc_col4i color; + asc_color color; unsigned short max_width; /** * The automatically calculated offset in case the text is centered. @@ -67,7 +67,7 @@ int y; const char *name; const char *text; - asc_col4i color; + asc_color color; enum asc_text_alignment alignment; unsigned short max_width; bool centered; diff -r 0e0a0bf4f7e4 -r 60014484121c src/camera.c --- a/src/camera.c Tue Aug 05 20:38:11 2025 +0200 +++ b/src/camera.c Wed Aug 06 00:37:01 2025 +0200 @@ -47,7 +47,7 @@ camera->viewport_update_func = args.viewport_update_func; camera->projection_update_func = args.projection_update_func; camera->viewport_clear = args.viewport_clear; - camera->clear_color = asc_col_itof(args.clear_color); + camera->clear_color = args.clear_color; } void asc_camera_ortho(AscCamera *camera, asc_rect rect) { diff -r 0e0a0bf4f7e4 -r 60014484121c src/scene.c --- a/src/scene.c Tue Aug 05 20:38:11 2025 +0200 +++ b/src/scene.c Wed Aug 06 00:37:01 2025 +0200 @@ -210,7 +210,7 @@ scene->camera.viewport.size.height ); glEnable(GL_SCISSOR_TEST); - const asc_col4f col = scene->camera.clear_color; + const asc_color col = scene->camera.clear_color; glClearColor(col.red, col.green, col.blue, col.alpha); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); diff -r 0e0a0bf4f7e4 -r 60014484121c src/shader.c --- a/src/shader.c Tue Aug 05 20:38:11 2025 +0200 +++ b/src/shader.c Wed Aug 06 00:37:01 2025 +0200 @@ -277,7 +277,7 @@ glUniformMatrix4fv(shader->model, 1,GL_FALSE, node->world_transform); } -void asc_shader_upload_col4f(int uniform_id, asc_col4f color) { +void asc_shader_upload_color(int uniform_id, asc_color color) { glUniform4f(uniform_id, color.red, color.green, color.blue, color.alpha); } diff -r 0e0a0bf4f7e4 -r 60014484121c src/text.c --- a/src/text.c Tue Aug 05 20:38:11 2025 +0200 +++ b/src/text.c Wed Aug 06 00:37:01 2025 +0200 @@ -74,7 +74,7 @@ TTF_SetFontWrapAlignment( font, alignments[text->base.flags & ASC_TEXT_ALIGNMENT_MASK]); SDL_Surface *surface = TTF_RenderText_Blended_Wrapped( - font, text->text.ptr, text->text.length, asc_col_sdl(text->color), text->max_width + font, text->text.ptr, text->text.length, asc_color_sdl(text->color), text->max_width ); if (surface == NULL) { asc_error("Rendering TTF surface failed: %s", SDL_GetError()); @@ -150,8 +150,8 @@ if (text->font.size == 0) { text->font.size = 12; } - if (asc_memcmpz(&args.color, sizeof(asc_col4i))) { - text->color = ASC_RGB(255, 255, 255); + if (asc_memcmpz(&args.color, sizeof(asc_color))) { + text->color = ASC_RGB(1, 1, 1); } else { text->color = args.color; } diff -r 0e0a0bf4f7e4 -r 60014484121c test/snake/snake.c --- a/test/snake/snake.c Tue Aug 05 20:38:11 2025 +0200 +++ b/test/snake/snake.c Wed Aug 06 00:37:01 2025 +0200 @@ -58,7 +58,7 @@ static asc_vec2i directions[4]; typedef struct { - asc_col4f color; + asc_color color; enum MoveDirection direction; enum MoveDirection target_direction; /** @@ -143,7 +143,7 @@ // also add a frame for the main scene // add this to the UI layer so that the border size does not scale - AscSceneNode *frame = asc_rectangle(.thickness = 2, .color = ASC_RGB(66, 142, 161)); + AscSceneNode *frame = asc_rectangle(.thickness = 2, .color = ASC_RGBi(66, 142, 161)); asc_behavior_add(frame, .func = main_scene_frame_scale); asc_ui_add_node(frame); } @@ -170,7 +170,7 @@ static void fps_counter_create(void) { AscSceneNode *node = asc_text( .name = "FPS Counter", - .color = ASC_RGB(255, 255, 255), + .color = ASC_RGB(1, 1, 1), .font = asc_font(ASC_FONT_REGULAR, 12), ); asc_behavior_add(node, .func = fps_counter_update, .interval = asc_seconds(1)); @@ -187,7 +187,7 @@ int old_owner = game_field->tile_data[x][y] & GAME_FIELD_TILE_OWNER_MASK; if (player == NULL) { asc_clear_flag(game_field->tile_data[x][y], GAME_FIELD_TILE_OWNER_MASK); - tile->color = asc_col_itof(ASC_RGB(16, 50, 160)); + tile->color = ASC_RGBi(16, 50, 160); } else { asc_set_flag_masked(game_field->tile_data[x][y], GAME_FIELD_TILE_OWNER_MASK, player->number); tile->color = player->color; @@ -205,8 +205,8 @@ AscSceneNode *tile = asc_rectangle( .x = x*GAME_FIELD_TILE_SIZE, .y = y*GAME_FIELD_TILE_SIZE, .filled = true, .thickness = 2, .width = GAME_FIELD_TILE_SIZE, .height = GAME_FIELD_TILE_SIZE, - .color = ASC_RGB(16, 50, 160), - .border_color = ASC_RGB(20, 84, 128), + .color = ASC_RGBi(16, 50, 160), + .border_color = ASC_RGBi(20, 84, 128), ); game_field->tile_data[x][y] = GAME_FIELD_TILE_EXISTS_FLAG; @@ -259,7 +259,7 @@ // Bind texture asc_texture_bind(TEXTURE_PLAYER, shader->map_albedo, 0); asc_texture_bind(TEXTURE_PLAYER_COLOR_MAP, shader->map_color, 1); - asc_shader_upload_col4f(shader->color, player->color); + asc_shader_upload_color(shader->color, player->color); asc_mesh_draw_triangle_strip(&sprite->mesh); } @@ -370,7 +370,7 @@ player_position(player, 12, 8); player->speed = 3.f; // start with 3 tiles/sec player->number = 1; - player->color = ASC_RGB_F(1, 0, 0); + player->color = ASC_RGB(1, 0, 0); player->trace = cxLinkedListCreateSimple(sizeof(asc_vec2i)); node->draw_func = player_draw; node->user_data_free_func = (cx_destructor_func2)player_destroy; @@ -452,7 +452,7 @@ (GAME_FIELD_SIZE+2)*GAME_FIELD_TILE_SIZE ), .viewport_clear = true, - .clear_color = ASC_RGB(0, 32, 16), + .clear_color = ASC_RGBi(0, 32, 16), .viewport_update_func = main_scene_viewport_update );