#define AL_LOG_SECTION "test_window" #include #include #include #include #include #include #include #include #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; 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 += (f32)stl_scale_scroll(y, 50.0); 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: dragging = state == STELA_BUTTON_PRESSED; 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 bool 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); return true; } break; } return false; } 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 // #EDEDF0 static const u32 cw = 0xEDEDF0; static const GLfloat winbg[3] = { EXPAND_RGB(cw) }; // #2F3C7A static const u32 c0 = 0x2F3C7A; static const GLfloat bg[3] = { EXPAND_RGB(c0) }; // #1F2947 static const u32 c1 = 0x1F2947; static const GLfloat color1[3] = { EXPAND_RGB(c1) }; // #C3A46F 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, flags, "", "Stella", "stela")) { 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(winbg[0], winbg[1], winbg[2], 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(winbg[0], winbg[1], winbg[2], 1.f); glClear(GL_COLOR_BUFFER_BIT); glClearColor(bg[0], bg[1], bg[2], 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("Stella_main")) return EXIT_FAILURE; if (!stl_global_init(false)) { nn_common_close(); 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; }