aboutsummaryrefslogtreecommitdiff
path: root/tests/main.c
blob: df68dd53fc95ad076cdba2baa435b5328a6dce12 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <mgl/mgl.h>
#include <mgl/window/window.h>
#include <mgl/window/event.h>
#include <mgl/graphics/texture.h>
#include <mgl/graphics/rectangle.h>
#include <mgl/graphics/sprite.h>
#include <mgl/graphics/font.h>
#include <mgl/graphics/text.h>
#include <mgl/graphics/vertex_buffer.h>
#include <mgl/graphics/shader.h>
#include <mgl/system/clock.h>
#include <mgl/system/fileutils.h>
#include <mgl/system/utf8.h>

#define require_equals(a, b) do { if((a) != (b)) { fprintf(stderr, "Assert failed on line %d: %s == %s\n", __LINE__, #a, #b); abort(); } } while(0)
#define require_not_equals(a, b) do { if((a) == (b)) { fprintf(stderr, "Assert failed on line %d: %s != %s\n", __LINE__, #a, #b); abort(); } } while(0)

typedef struct {
    mgl_texture *texture;
    mgl_font *font;
    mgl_font *cjk_font;
    mgl_vertex_buffer *vertex_buffer1;
    mgl_shader_program *shader_program;
    mgl_clock clock;
    int fps;
    int fps_counter;
} Userdata;

static void draw(mgl_window *window, void *userdata) {
    mgl_context *context = mgl_get_context();
    Userdata *u = userdata;

    mgl_shader_program_set_uniform_vec2f(u->shader_program, "resolution", (mgl_vec2f){ u->texture->width, u->texture->height });

    static float rot = 0.0f;
    rot += 5.0f;

    mgl_sprite sprite;
    mgl_sprite_init(&sprite, u->texture);
    mgl_sprite_set_position(&sprite, (mgl_vec2f){ 100.0f - 10.0f + u->texture->width * 0.5f * 2.0f, u->texture->height * 0.5f * 2.0f });
    mgl_sprite_set_color(&sprite, (mgl_color){255, 255, 255, 128});
    mgl_sprite_set_rotation(&sprite, rot);
    mgl_sprite_set_origin(&sprite, (mgl_vec2f){ u->texture->width * 0.5f, u->texture->height * 0.5f });
    sprite.scale = (mgl_vec2f){ 2.0f, 2.0f };
    mgl_shader_program_use(u->shader_program);
    mgl_sprite_draw(context, &sprite);
    mgl_shader_program_use(NULL);

    ++u->fps_counter;
    if(mgl_clock_get_elapsed_time_seconds(&u->clock) >= 1.0) {
        mgl_clock_restart(&u->clock);
        u->fps = u->fps_counter;
        u->fps_counter = 0;
        fprintf(stderr, "fps: %d\n", u->fps);
    }
    char str[512];
    snprintf(str, sizeof(str), "|,.-_/1234567890½!\"#¤%%&/()=?¡@£$€¥{[]}\\'abcdefghijklmnopqrstuvwxyzáàäåãâíìîïúùũüûéèẽëêóòõôöABCDEFGHIJKLMNOPQRSTUVWXYZÁÀÄÅÃÂÍÌÎÏÚÙŨÜÛÉÈẼËÊÓÒÕÔÖ └> pacman -Q quickmedia-git");

    mgl_text text;
    mgl_text_init(&text, u->font, str, strlen(str));
    mgl_text_draw(context, &text);
    mgl_text_deinit(&text);

    const char *cjk_str = "饕餮  로 초성, 중성, 종성을 東京都と周辺7県で首都圏を構成\n"
        "【システマ流】誰でも出来る「不眠.ストレス」に打ち勝つ呼吸法(東京都・埼玉県・千葉県・神奈川県)の総人口は約 千葉県・神奈川日本の民間研究所が年に発表した「世界の都市総合力ランキング」では、ロンド\n"
        "ンとニューヨークに次ぐ世界3位と評価された年に首都圏整備法の施行に伴い廃止された。このように首都建設法の廃止により区部の東部には、隅田川、荒川、江戸川、中川などの河口部に沖積平野が広がっ日本国内におけ\n"
        "る気候区分では23区〜多摩東部および伊豆諸島は太平洋側気候、多摩西部などは中央高地式気候に属する。小笠原諸島は南日本気候である。特徴としては、四季の変化が明瞭であり、天気が日によって変化しやすい。夏季は\n"
        "高温・多雨となり、冬季は晴れて乾燥する東京都区部 - 気象庁露場のあった大手町付近の観測による最低気温が最も高くなることも珍しくなかった。しかし、夏場の最高気温自体はそれほど高くもない。一方、内陸寄りにあ\n"
        "る練馬区のアメダス観測[注 7][22]地域では冬日は珍しくなく、新宿区や渋谷区などの都心部でも冬日の観測はよく見られる。また、気象観測所のある千代田区内におい足立区、荒川区、板橋区、江戸川区、大田区、葛飾区、\n"
        "北区、江東区、品川区、渋谷区、新宿区、杉並区、墨田区、世田谷区、台東区、中央区、千代田区、豊島区、中野区、練馬区、文京区、港区、目黒区昭島市、あきる野市、稲城市、青梅市、清瀬市、国立市、小金井市、国分寺市、\n"
        "小平市、狛江市、立川市、多摩市、調布市、西東京市、八王子市、羽村市、東久留米市、東村山市、東大和市、日野市、府中市、福生市、町田市、三鷹市、武蔵野市、武蔵村山市";

    mgl_text cjk_text;
    mgl_text_init(&cjk_text, u->cjk_font, cjk_str, strlen(cjk_str));
    mgl_text_set_position(&cjk_text, (mgl_vec2f){ 0.0f, 500.0f });
    mgl_text_draw(context, &cjk_text);
    mgl_text_deinit(&cjk_text);

    mgl_view prev_view;
    mgl_window_get_view(window, &prev_view);

    mgl_vec2i view_size = {
        .x = 200,
        .y = 200
    };
    mgl_view new_view = {
        .position = { window->size.x/2 - view_size.x/2, window->size.y/2 - view_size.y/2 },
        .size = view_size
    };
    mgl_window_set_view(window, &new_view);

    mgl_vertex vertices[4] = {
        (mgl_vertex){
            .position = {-new_view.position.x + window->cursor_position.x, -new_view.position.y + window->cursor_position.y},
            .texcoords = {0.0f, 0.0f},
            .color = {255, 0, 0, 255}
        },
        (mgl_vertex){
            .position = {-new_view.position.x + window->cursor_position.x + 400.0f, -new_view.position.y + window->cursor_position.y},
            .texcoords = {0.0f, 0.0f},
            .color = {0, 255, 0, 255},
        },
        (mgl_vertex){
            .position = {-new_view.position.x + window->cursor_position.x + 400.0f, -new_view.position.y + window->cursor_position.y + 400.0f},
            .texcoords = {0.0f, 0.0f},
            .color = {0, 0, 255, 255},
        },
        (mgl_vertex){
            .position = {-new_view.position.x + window->cursor_position.x, -new_view.position.y + window->cursor_position.y + 400.0f},
            .texcoords = {0.0f, 0.0f},
            .color = {255, 255, 0, 255}
        }
    };

    mgl_vertices_draw(context, vertices, 4, MGL_PRIMITIVE_QUADS, (mgl_vec2f){ 0.0f, 0.0f });
    mgl_window_set_view(window, &prev_view);

    mgl_rectangle rect = {
        .position = { window->cursor_position.x, window->cursor_position.y },
        .size = { u->font->texture.width, u->font->texture.height },
        .color = { 255, 255, 255, 255 },
    };
    mgl_rectangle_draw(context, &rect);

    mgl_vertex vertices1[4] = {
        (mgl_vertex){
            .position = {0.0f, 0.0f},
            .texcoords = {0.0f, 0.0f},
            .color = {255, 0, 0, 100}
        },
        (mgl_vertex){
            .position = {u->font->texture.width, 0.0f},
            .texcoords = {u->font->texture.width, 0.0f},
            .color = {0, 255, 0, 100},
        },
        (mgl_vertex){
            .position = {u->font->texture.width, u->font->texture.height},
            .texcoords = {u->font->texture.width, u->font->texture.height},
            .color = {0, 0, 255, 100},
        },
        (mgl_vertex){
            .position = {0.0f, u->font->texture.height},
            .texcoords = {0.0f, u->font->texture.height},
            .color = {255, 0, 255, 100}
        }
    };

    mgl_vertex_buffer_update(u->vertex_buffer1, vertices1, 4, MGL_PRIMITIVE_QUADS, MGL_USAGE_STREAM);
    mgl_vertex_buffer_set_position(u->vertex_buffer1, (mgl_vec2f){ window->cursor_position.x, window->cursor_position.y });
    mgl_vertex_buffer_draw(context, u->vertex_buffer1, &u->font->texture);
}

static void test_hash_map_get_insert(mgl_font_char_map *char_map, uint32_t unicode, bool exists) {
    mgl_font_glyph font_glyph;
    font_glyph.advance = 5.0f;
    if(exists) {
        require_not_equals(mgl_font_char_map_get(char_map, unicode), NULL);
    } else {
        require_equals(mgl_font_char_map_get(char_map, unicode), NULL);
        require_equals(mgl_font_char_map_insert(char_map, unicode, &font_glyph, NULL), 0);
    }
}

static void test_hash_map() {
    mgl_font_char_map char_map;
    mgl_font_char_map_init(&char_map);

    test_hash_map_get_insert(&char_map, 'h', false);
    test_hash_map_get_insert(&char_map, 'e', false);
    test_hash_map_get_insert(&char_map, 'l', false);
    test_hash_map_get_insert(&char_map, 'l', true);
    test_hash_map_get_insert(&char_map, 'o', false);
    test_hash_map_get_insert(&char_map, ' ', false);
    test_hash_map_get_insert(&char_map, 'f', false);
    test_hash_map_get_insert(&char_map, 'p', false);
    test_hash_map_get_insert(&char_map, 's', false);

    require_not_equals(mgl_font_char_map_get(&char_map, 'h'), NULL);
    require_not_equals(mgl_font_char_map_get(&char_map, 'e'), NULL);
    require_not_equals(mgl_font_char_map_get(&char_map, 'l'), NULL);
    require_not_equals(mgl_font_char_map_get(&char_map, 'o'), NULL);
    require_not_equals(mgl_font_char_map_get(&char_map, ' '), NULL);
    require_not_equals(mgl_font_char_map_get(&char_map, 'f'), NULL);
    require_not_equals(mgl_font_char_map_get(&char_map, 'p'), NULL);
    require_not_equals(mgl_font_char_map_get(&char_map, 's'), NULL);

    mgl_font_char_map_deinit(&char_map);
}

static void test_utf8() {
    uint32_t codepoint = 0;
    size_t codepoint_length = 0;

    require_equals(mgl_utf8_decode("a", 1, &codepoint, &codepoint_length), true);
    require_equals(codepoint, 0x61);
    require_equals(codepoint_length, 1);

    require_equals(mgl_utf8_decode("á", 2, &codepoint, &codepoint_length), true);
    require_equals(codepoint, 0xE1);
    require_equals(codepoint_length, 2);

    require_equals(mgl_utf8_decode("‡", 3, &codepoint, &codepoint_length), true);
    require_equals(codepoint, 0x2021);
    require_equals(codepoint_length, 3);

    require_equals(mgl_utf8_decode("𒀀", 4, &codepoint, &codepoint_length), true);
    require_equals(codepoint, 0x12000);
    require_equals(codepoint_length, 4);

    require_equals(mgl_utf8_get_start_of_codepoint("abc", 3, 0), 0);
    require_equals(mgl_utf8_get_start_of_codepoint("abc", 3, 2), 2);
    require_equals(mgl_utf8_get_start_of_codepoint("abö", 3, 4), 2);
}

int main(int argc, char **argv) {
    test_hash_map();
    test_utf8();

    if(mgl_init() != 0)
        return 1;

    mgl_texture texture;
    mgl_memory_mapped_file font_file;
    mgl_memory_mapped_file cjk_font_file;
    mgl_font font;
    mgl_font cjk_font;
    mgl_vertex_buffer vertex_buffer1;
    mgl_shader_program shader_program;

    Userdata userdata;
    userdata.texture = &texture;
    userdata.font = &font;
    userdata.cjk_font = &cjk_font;
    userdata.vertex_buffer1 = &vertex_buffer1;
    userdata.shader_program = &shader_program;
    userdata.fps = 0;
    userdata.fps_counter = 0;
    mgl_clock_init(&userdata.clock);

    mgl_window window;
    if(mgl_window_create(&window, "mgl", &(mgl_window_create_params){ .size = {1280, 720}, .min_size = { 1000, 1000 } }) != 0)
        return 1;

    if(mgl_texture_init(&texture) != 0)
        return 1;

    if(mgl_texture_load_from_file(&texture, "tests/X11.jpg", &(mgl_texture_load_options){ false, false }) != 0)
        return 1;

    if(mgl_mapped_file_load("/usr/share/fonts/TTF/Hack-Regular.ttf", &font_file, &(mgl_memory_mapped_file_load_options){ .readable = true, .writable = false }) != 0)
        return 1;

    if(mgl_mapped_file_load("/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc", &cjk_font_file, &(mgl_memory_mapped_file_load_options){ .readable = true, .writable = false }) != 0)
        return 1;

    if(mgl_font_load_from_file(&font, &font_file, 26) != 0)
        return 1;

    if(mgl_font_load_from_file(&cjk_font, &cjk_font_file, 26) != 0)
        return 1;

    if(mgl_shader_program_init(&shader_program) != 0)
        return 1;

    if(mgl_shader_program_add_shader_from_file(&shader_program, "tests/circle_mask.glsl", MGL_SHADER_FRAGMENT) != 0)
        return 1;

    if(mgl_shader_program_finalize(&shader_program) != 0)
        return 1;

    mgl_vertex_buffer_init(&vertex_buffer1);

    mgl_event event;
    while(mgl_window_is_open(&window)) {
        while(mgl_window_poll_event(&window, &event)) {
            switch(event.type) {
                case MGL_EVENT_TEXT_ENTERED: {
                    fprintf(stderr, "text event, codepoint: %u, str: %s\n", event.text.codepoint, event.text.str);
                    break;
                }
                case MGL_EVENT_KEY_PRESSED: {
                    if(event.key.code == MGL_KEY_C) {
                        const char *str = "東京都, Tōkyō-to";
                        mgl_window_set_clipboard(&window, str, strlen(str));
                        fprintf(stderr, "Copied '%s' to the clipboard\n", str);
                    } else if(event.key.code == MGL_KEY_V) {
                        char *str;
                        size_t size;
                        if(mgl_window_get_clipboard(&window, &str, &size)) {
                            fprintf(stderr, "Copied '%s' from the clipboard\n", str);
                            free(str);
                        }
                    }
                    fprintf(stderr, "key press event, code: %u\n", event.key.code);
                    break;
                }
                case MGL_EVENT_KEY_RELEASED: {
                    fprintf(stderr, "key release event, code: %u\n", event.key.code);
                    break;
                }
            }
        }

        mgl_window_clear(&window, (mgl_color){0, 0, 0, 0});
        draw(&window, &userdata);
        mgl_window_display(&window);
    }

    mgl_vertex_buffer_deinit(&vertex_buffer1);
    mgl_shader_program_deinit(&shader_program);
    mgl_font_unload(&cjk_font);
    mgl_font_unload(&font);
    mgl_mapped_file_unload(&cjk_font_file);
    mgl_mapped_file_unload(&font_file);
    mgl_texture_unload(&texture);
    mgl_window_deinit(&window);
    mgl_deinit();
    return 0;
}