diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/meson.build | 1 | ||||
| -rw-r--r-- | tests/window.c | 313 |
2 files changed, 314 insertions, 0 deletions
diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000..c0da2d1 --- /dev/null +++ b/tests/meson.build @@ -0,0 +1 @@ +executable('window', ['window.c'], dependencies: stela, c_args: ['-DSTELA_FORCE_COMPATABILITY']) diff --git a/tests/window.c b/tests/window.c new file mode 100644 index 0000000..b185e6b --- /dev/null +++ b/tests/window.c @@ -0,0 +1,313 @@ +#ifdef STELA_API_NULL +#undef STELA_API_NULL +#endif +#ifndef STELA_API_OPENGL +#define STELA_API_OPENGL +#endif +#define AL_LOG_SECTION "test_window" +#include <al/log.h> +#include <al/types.h> +#include <al/array.h> +#include <al/str.h> +#include <stl/window.h> +#include <stl/gl.h> +#include <nnwt/common.h> +#define _USE_MATH_DEFINES +#include <math.h> + +#define DEFAULT_WIDTH 720 +#define DEFAULT_HEIGHT 480 + +static struct stl_window *window; +static s32 quit = 0; + +static bool dragging = false; +static f64 last_mouse_x = 0.0; +static f64 last_mouse_y = 0.0; + +static const GLfloat init_rotation[] = { -25.f, 35.f, 0.f }; +static GLfloat rotation[] = { init_rotation[0], init_rotation[1], init_rotation[2] }; +static GLfloat zoom = 0.5f; + +AL_IGNORE_WARNING("-Wunused-function") +static inline GLfloat degrees_to_radians(GLfloat degrees) +{ + return degrees * M_PI / 180.f; +} +AL_IGNORE_WARNING_END + +static bool pointer_pos_callback(void *userdata, f64 x, f64 y) +{ + (void)userdata; + + // There's probably a "standard" way to handle dragging here + // but this works well enough. + if (dragging) { + GLfloat dx = (GLfloat)x - (GLfloat)last_mouse_x; + GLfloat dy = (GLfloat)y - (GLfloat)last_mouse_y; + dx /= 2.f; + dy /= 2.f; + rotation[0] += dy; + rotation[1] += rotation[0] > 140.f && rotation[0] < 290.f ? -dx : dx; + if (rotation[0] > 360.f) rotation[0] -= 360.f; + else if (rotation[0] < 0.f) rotation[0] += 360.f; + if (rotation[1] > 360.f) rotation[1] -= 360.f; + else if (rotation[1] < 0.f) rotation[1] += 360.f; + if (rotation[2] > 360.f) rotation[2] -= 360.f; + else if (rotation[2] < 0.f) rotation[2] += 360.f; + } + + last_mouse_x = x; + last_mouse_y = y; + + return true; +} + +static bool scroll_callback(void *userdata, f64 y) +{ + (void)userdata; + zoom += y / -2500.f; + if (zoom < 0.1f) zoom = 0.1f; + return true; +} + +static bool mouse_button_callback(void *userdata, u8 state, u8 button) +{ + (void)userdata; + switch (button) { + case STELA_MOUSE1: + switch (state) { + case STELA_BUTTON_PRESSED: + dragging = true; + break; + case STELA_BUTTON_RELEASED: + dragging = false; + break; + } + break; + } + return false; +} + +static bool key_callback(void *userdata, u8 state, u16 button) +{ + (void)userdata; + switch (state) { + case STELA_BUTTON_PRESSED: + switch (button) { + case STELA_KEY_Q: + quit = 1; + break; + case STELA_KEY_R: + rotation[0] = init_rotation[0]; + rotation[1] = init_rotation[1]; + rotation[2] = init_rotation[2]; + return true; + } + break; + } + return false; +} + +static void key_immediate_callback(void *userdata, u8 state, u16 button) +{ + (void)userdata; + switch (state) { + case STELA_BUTTON_PRESSED: + switch (button) { + case STELA_KEY_F: + window->toggle_fullscreen(window); + break; + } + break; + } +} + +static void should_close_callback(void *userdata) +{ + (void)userdata; + quit = 1; +} + +#ifdef STELA_API_OPENGL +static GLfloat vertices[] = { + -1.f, -1.f, -1.f, + 1.f, -1.f, -1.f, + 1.f, 1.f, -1.f, + -1.f, 1.f, -1.f, + -1.f, -1.f, 1.f, + 1.f, -1.f, 1.f, + 1.f, 1.f, 1.f, + -1.f, 1.f, 1.f +}; + +#define EXPAND_RGB(c) \ + ((c >> 16) & 0xff) / 255.f, \ + ((c >> 8) & 0xff) / 255.f, \ + (c & 0xff) / 255.f + +static const u32 c0 = 0x2F3C7A; +static const GLfloat bg[3] = { EXPAND_RGB(c0) }; + +static const u32 c1 = 0x0F1B26; +static const GLfloat color1[3] = { EXPAND_RGB(c1) }; + +static const u32 c2 = 0xC3A46F; +static const GLfloat color2[3] = { EXPAND_RGB(c2) }; + +//static const u32 c3 = 0x111419; +static const GLfloat color3[3] = { EXPAND_RGB(c1) }; + +static GLfloat colors[] = { + color1[0], color1[1], color1[2], + color1[0], color1[1], color1[2], + color1[0], color1[1], color1[2], + color1[0], color1[1], color1[2], + color2[0], color2[1], color2[2], + color3[0], color3[1], color3[2], + color3[0], color3[1], color3[2], + color3[0], color3[1], color3[2] +}; + +static GLubyte indices[] = { + 0, 3, 2, 1, + 2, 3, 7, 6, + 0, 4, 7, 3, + 1, 2, 6, 5, + 4, 5, 6, 7, + 0, 1, 5, 4 +}; +#endif + +s32 window_system_main(u32 argc, str *argv, void *extra) +{ + (void)extra; + + window = stl_window_create(); + window->pointer_pos_callback = pointer_pos_callback; + window->scroll_callback = scroll_callback; + window->mouse_button_callback = mouse_button_callback; + window->key_callback = key_callback; + window->key_immediate_callback = key_immediate_callback; + window->should_close_callback = should_close_callback; + window->userdata = NULL; + + u32 flags = STELA_WINDOW_VSYNC; + if (!window->create_window(window, DEFAULT_WIDTH, DEFAULT_HEIGHT, "", "Stella", flags)) { + return EXIT_FAILURE; + } + +#ifdef STELA_API_OPENGL + if (!window->gl_loader_load(window)) { + log_error("Failed to load OpenGL."); + return EXIT_FAILURE; + } + if (!window->gl_make_current(window)) { + log_error("Failed to make thread current in OpenGL."); + } + const char *gl_version = (const char *)glGetString(GL_VERSION); + if (gl_version) { + log_info("GL context created: %s.", gl_version); + } + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glClearColor(1.f, 1.f, 1.f, 1.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + window->gl_swap_buffers(window); + if (argc > 1 && al_str_cmp(&argv[1], &al_str_c("w"), 0, 1) == 0) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } +#endif + + while (!quit) { + window->poll(window, true); + window->process_events(window); + if (window->should_refresh(window)) { +#ifdef STELA_API_OPENGL + glViewport(0, 0, window->width, window->height); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + f32 w = window->width; + f32 h = window->height; + const f32 frame_ratio = 4.f / 3.f; + const f32 ratio = w / h; + if (frame_ratio > ratio) { + h = w / frame_ratio; + } else { + w = h * frame_ratio; + } + u32 x_offset = (window->width - w) / 2u; + u32 y_offset = (window->height - h) / 2u; + + glScissor(x_offset, y_offset, (GLsizei)w, (GLsizei)h); + glEnable(GL_SCISSOR_TEST); + glClearColor(bg[0], bg[1], bg[2], 1.f); + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(1.f, 1.f, 1.f, 1.f); + glDisable(GL_SCISSOR_TEST); + + glViewport(x_offset, y_offset, (GLsizei)w, (GLsizei)h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-1.0, 1.0, -1.0, 1.0, -100.0, 100.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + if (frame_ratio > 1.f) { + glScalef(zoom / frame_ratio, zoom, zoom); + } else { + glScalef(zoom, zoom * frame_ratio, zoom); + } + glRotatef(rotation[0], 1.f, 0.f, 0.f); + glRotatef(rotation[1], 0.f, 1.f, 0.f); + glRotatef(rotation[2], 0.f, 0.f, 1.f); + + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, vertices); + glColorPointer(3, GL_FLOAT, 0, colors); + glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, indices); + + window->gl_swap_buffers(window); +#endif + } + } + +#ifdef STELA_API_OPENGL + window->gl_release_current(window); +#endif + + window->free(&window); + al_assert(!window); + + return EXIT_SUCCESS; +} + +s32 main(s32 argc, char *argv[]) +{ + if (!nn_common_init() || !stl_global_init(false)) { + return EXIT_FAILURE; + } + + array(str) args; + al_array_init(args); + al_array_reserve(args, argc); + for (s32 i = 0; i < argc; i++) { + str arg; + al_str_from(&arg, argv[i]); + al_array_push(args, arg); + } + + s32 ret = stl_swallow_main(args.count, args.data, window_system_main, NULL); + stl_global_close(); + + str *arg; + al_array_foreach_ptr(args, i, arg) { + al_str_free(arg); + } + al_array_free(args); + + nn_common_close(); + + return ret; +} |