quicksort implementation
Francesco Pasa 10 months ago
Francesco Pasa 10 months ago
examples/text.c M +1 -1
8 options.clear_color.b = 0.02;
9 AlbaWindow* window = create_window(&options);
10
11- draw_text(window, 0, 0, 3, "bla");
12+ draw_text(window, 0, 0, 0, "7 lm ß 🍔");
13
14 while (!window_should_close(window))
15 {
include/alba.h M +1
21 void dynarray_extend(DynArray* array, uint64_t size, const void* data);
22 void dynarray_release(const DynArray* array);
23 void dynarray_clear(DynArray* array);
24+void dynarray_sort(const DynArray* array, uint32_t (*smaller_than_pivot)(void* pivot, void* elem));
25
26 // Misc
27 typedef struct
src/atlas.c M +19 -3
4 {
5 uint32_t character;
6 FT_Long glyph_index;
7+ FT_Bitmap bitmap;
8 } Glyph;
9
10 uint64_t hash_glyph(const void* item, const uint64_t seed0, const uint64_t seed1)
37
38 void atlas_append(Atlas* atlas, const FT_Face face, const uint32_t character)
39 {
40- const FT_Long glyph_index = FT_Load_Char(face, character, FT_LOAD_DEFAULT);
41+ const FT_Long glyph_index = FT_Load_Char(face, character, FT_LOAD_RENDER);
42
43- const Glyph glyph = {.glyph_index = glyph_index};
44+ const Glyph glyph = {
45+ .character = character,
46+ .glyph_index = glyph_index,
47+ .bitmap = face->glyph->bitmap,
48+ };
49 const uint32_t hash = hash_glyph(&glyph, 0, 0); // Execute hash only once
50 if (hashmap_get_with_hash(atlas->glyphs, &glyph, hash) == NULL)
51 {
52 }
53 }
54
55-void atlas_generate_image(const Atlas* atlas)
56+void atlas_generate_image(Atlas* atlas)
57 {
58 if (atlas->dirty == 0) return;
59
60 size_t iter = 0;
61 Glyph* glyph;
62+ DynArray glyphs = dynarray_new(sizeof(Glyph), hashmap_count(atlas->glyphs));
63 while (hashmap_iter(atlas->glyphs, &iter, (void**)&glyph))
64 {
65+ dynarray_append(&glyphs, glyph);
66 }
67+ dynarray_sort(&glyphs, compare_glyph);
68+
69+ atlas->width = 1024;
70+ atlas->height = 1024;
71+ atlas->image = reallocarray(atlas->image, atlas->width * atlas->height * 4, sizeof(uint8_t));
72 }
73
74 void atlas_release(const Atlas* atlas)
75 {
76 hashmap_free(atlas->glyphs);
77 dynarray_release(&atlas->glyph_sizes);
78+ if (atlas->image != NULL)
79+ {
80+ free(atlas->image);
81+ }
82 }
src/dynarray.c M +50
48 {
49 array->length = 0;
50 }
51+
52+static void swap(const uint64_t element_size, void* a, void* b, void* temp)
53+{
54+ memcpy(temp, a, element_size);
55+ memcpy(a, b, element_size);
56+ memcpy(b, temp, element_size);
57+}
58+
59+static void quicksort(
60+ const uint64_t element_size, const uint64_t length, void* data,
61+ uint32_t (*smaller_than_pivot)(void* pivot, void* elem), void* temp
62+)
63+{
64+ if (length < 2) return;
65+
66+ void* pivot = data + (length - 1) * element_size;
67+ void* larger = NULL;
68+ for (uint64_t i = 0; i < length; i++)
69+ {
70+ void* current = data + i * element_size;
71+ if (smaller_than_pivot(pivot, current))
72+ {
73+ if (larger == NULL) continue;
74+ swap(element_size, larger, current, temp);
75+ larger += element_size;
76+ }
77+ else if (larger == NULL)
78+ {
79+ larger = current;
80+ }
81+ }
82+
83+ if (larger != NULL)
84+ {
85+ swap(element_size, larger, pivot, temp);
86+ pivot = larger;
87+ }
88+
89+ const uint64_t size_before = (pivot - data);
90+ const uint64_t num_elem_before = size_before / element_size;
91+ quicksort(element_size, num_elem_before, data, smaller_than_pivot, temp);
92+ quicksort(element_size, length - num_elem_before - 1, data + size_before + element_size, smaller_than_pivot, temp);
93+}
94+
95+void dynarray_sort(const DynArray* array, uint32_t (*smaller_than_pivot)(void* pivot, void* elem))
96+{
97+ void* temp = malloc(array->element_size);
98+ quicksort(array->element_size, array->length, array->data, smaller_than_pivot, temp);
99+ free(temp);
100+}
src/internal.h M +4 -1
10 struct hashmap* glyphs;
11 int dirty;
12 DynArray glyph_sizes; // in w, h order
13+ uint32_t width;
14+ uint32_t height;
15+ uint8_t* image;
16 } Atlas;
17
18 Atlas atlas_new(uint32_t capacity);
19 void atlas_reserve(Atlas* atlas, uint32_t capacity);
20 void atlas_append(Atlas* atlas, FT_Face face, uint32_t character);
21-void atlas_generate_image(const Atlas* atlas);
22+void atlas_generate_image(Atlas* atlas);
23 void atlas_release(const Atlas* atlas);
24
25 #endif // INTERNAL_H
src/text.c M +32 -19
49 pthread_mutex_unlock(&freetype_mutex);
50 }
51
52+WGPUTexture create_texture(const AlbaWindow* window, const uint64_t width, const uint64_t height, const void* data)
53+{
54+ WGPUTextureDescriptor texture_options = {0};
55+ texture_options.usage = WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst;
56+ texture_options.format = WGPUTextureFormat_RGBA8UnormSrgb;
57+ texture_options.dimension = WGPUTextureDimension_2D;
58+ texture_options.size.width = width;
59+ texture_options.size.height = height;
60+ texture_options.size.depthOrArrayLayers = 1;
61+ texture_options.sampleCount = 1;
62+ texture_options.mipLevelCount = 1;
63+ const WGPUTexture texture = wgpuDeviceCreateTexture(window->device, &texture_options);
64+
65+ WGPUImageCopyTexture destination = {0};
66+ destination.texture = texture;
67+ destination.aspect = WGPUTextureAspect_All;
68+ WGPUTextureDataLayout source = {0};
69+ source.bytesPerRow = 4 * width;
70+ source.rowsPerImage = height;
71+ wgpuQueueWriteTexture(window->queue, &destination, data, width * height * 4, &source, &texture_options.size);
72+
73+ return texture;
74+}
75+
76 void draw_text(AlbaWindow* window, const float x, const float y, uint64_t length, const char* text)
77 {
78 initialize_freetype();
85 pthread_mutex_lock(&freetype_mutex);
86 for (uint64_t i = 0; i < length; i++)
87 {
88- const FT_Long glyph_index = FT_Get_Char_Index(roboto, text[i]); // TODO: unicode
89- atlas_append(&atlas, roboto, glyph_index);
90+ atlas_append(&atlas, roboto, text[i]); // TODO: unicode
91 }
92 pthread_mutex_unlock(&freetype_mutex);
93
94+ // FT_Error error = FT_Load_Char(roboto, '7', FT_LOAD_RENDER);
95+ // printf("%d\n", roboto->glyph->bitmap.width);
96+ // error = FT_Load_Char(roboto, 'l', FT_LOAD_RENDER);
97+ // printf("%d\n", roboto->glyph->bitmap.width);
98+ // error = FT_Load_Char(roboto, 'm', FT_LOAD_RENDER);
99+ // printf("%d\n", roboto->glyph->bitmap.width);
100
101- FT_Error error = FT_Load_Char(roboto, '7', FT_LOAD_RENDER);
102- printf("%d\n", roboto->glyph->bitmap.width);
103- error = FT_Load_Char(roboto, 'l', FT_LOAD_RENDER);
104- printf("%d\n", roboto->glyph->bitmap.width);
105- error = FT_Load_Char(roboto, 'm', FT_LOAD_RENDER);
106- printf("%d\n", roboto->glyph->bitmap.width);
107-
108- WGPUTextureDescriptor texture_options = {0};
109- texture_options.usage = WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst;
110- texture_options.format = WGPUTextureFormat_BGRA8UnormSrgb;
111- texture_options.dimension = WGPUTextureDimension_2D;
112- texture_options.size.width = window->width;
113- texture_options.size.height = window->height;
114- texture_options.size.depthOrArrayLayers = 1;
115- texture_options.sampleCount = 1;
116- texture_options.mipLevelCount = 1;
117- const WGPUTexture render_target = wgpuDeviceCreateTexture(window->device, &texture_options);
118+ atlas_generate_image(&atlas);
119 }
tests/test_dynarray.c M +37
34
35 END_TEST
36
37+uint32_t compare_floats(void* vpivot, void* velem)
38+{
39+ const float pivot = *(float*)vpivot;
40+ const float elem = *(float*)velem;
41+ return elem < pivot;
42+}
43+
44+START_TEST(test_dynarray_sort)
45+{
46+ DynArray array = dynarray_new(sizeof(float), 0);
47+ const float values[] = {7, 2.3, 5, 6, 2, 3, 4, 9, 1, 4};
48+ dynarray_extend(&array, 10, values);
49+
50+ ck_assert_int_eq(array.element_size, sizeof(float));
51+ ck_assert_int_eq(array.length, 10);
52+ ck_assert_int_eq(array.capacity, 16);
53+
54+ dynarray_sort(&array, compare_floats);
55+
56+ ck_assert_float_eq(((float*)array.data) [0], 1);
57+ ck_assert_float_eq(((float*)array.data) [1], 2);
58+ ck_assert_float_eq(((float*)array.data) [2], 2.3);
59+ ck_assert_float_eq(((float*)array.data) [3], 3);
60+ ck_assert_float_eq(((float*)array.data) [4], 4);
61+ ck_assert_float_eq(((float*)array.data) [5], 4);
62+ ck_assert_float_eq(((float*)array.data) [6], 5);
63+ ck_assert_float_eq(((float*)array.data) [7], 6);
64+ ck_assert_float_eq(((float*)array.data) [8], 7);
65+ ck_assert_float_eq(((float*)array.data) [9], 9);
66+}
67+
68+END_TEST
69
70 int main(void)
71 {