quicksort implementation

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 {
81         tcase_add_test(test, test_dynarray_extend);
82         suite_add_tcase(suite, test);
83     }
84+    {
85+        TCase* test = tcase_create("test_dynarray_sort");
86+        tcase_add_test(test, test_dynarray_sort);
87+        suite_add_tcase(suite, test);
88+    }
89 
90     SRunner* runner = srunner_create(suite);
91