summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/meson.build1
-rw-r--r--tests/window.c313
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;
+}