//------------------------------------------------------------------------------ // Take flight //------------------------------------------------------------------------------ #define SOKOL_IMPL #define SOKOL_D3D11 #include "sokol_gfx.h" #include "sokol_gp.h" #include "sokol_app.h" #include "sokol_glue.h" #define MAX_BOXES 32 #define BOX_SIZE 0.5f #define TIMESTEP 1.0f / 60.0f struct Body { sgp_point position; sgp_point old_position; sgp_vec2 acceleration; }; struct GameState { struct Player { struct Body body; } player; int num_boxes; struct Box { struct Body body; } boxes[MAX_BOXES]; }; struct GameState gs = {0}; bool mouse_down = false; bool keydown[SAPP_KEYCODE_MENU] = {0}; float funval = 0.0f; // easy to play with value controlled by left mouse button when held down @BeforeShip remove on release builds void init(void) { // @BeforeShip make all fprintf into logging to file, warning dialog boxes on failure instead of exit(-1), replace the macros in sokol with this as well, like assert sg_desc sgdesc = {.context = sapp_sgcontext()}; sg_setup(&sgdesc); if (!sg_isvalid()) { fprintf(stderr, "Failed to create Sokol GFX context!\n"); exit(-1); } gs.boxes[0] = (struct Box){ .body = (struct Body){ .position = (sgp_point){.x = 0.75f, .y = 0.0}}, }; gs.boxes[0].body.old_position = gs.boxes[0].body.position; gs.boxes[1] = (struct Box){ .body = (struct Body){ .position = (sgp_point){.x = 0.75f, .y = 0.5f}}, }; gs.boxes[1].body.old_position = gs.boxes[1].body.position; gs.num_boxes = 2; sgp_desc sgpdesc = {0}; sgp_setup(&sgpdesc); if (!sgp_is_valid()) { fprintf(stderr, "Failed to create Sokol GP context: %s\n", sgp_get_error_message(sgp_get_last_error())); exit(-1); } } sgp_vec2 v2add(sgp_vec2 a, sgp_vec2 b) { return (sgp_vec2){ .x = a.x + b.x, .y = a.y + b.y, }; } sgp_vec2 v2scale(sgp_vec2 a, float f) { return (sgp_vec2){ .x = a.x * f, .y = a.y * f, }; } sgp_vec2 v2sub(sgp_vec2 a, sgp_vec2 b) { return (sgp_vec2){ .x = a.x - b.x, .y = a.y - b.y, }; } void process_body(struct Body *body) { sgp_vec2 current = body->position; body->position = v2add(body->position, v2sub(current, body->old_position)); body->position = v2add(body->position, v2scale(body->acceleration, TIMESTEP*TIMESTEP)); body->old_position = current; } void frame(void) { int width = sapp_width(), height = sapp_height(); float ratio = width / (float)height; float time = sapp_frame_count() * sapp_frame_duration(); // gameplay { sgp_vec2 input = (sgp_vec2){ .x = (float)keydown[SAPP_KEYCODE_D] - (float)keydown[SAPP_KEYCODE_A], .y = (float)keydown[SAPP_KEYCODE_S] - (float)keydown[SAPP_KEYCODE_W], }; gs.player.body.acceleration = v2scale(input, 5.0f); process_body(&gs.player.body); for(int i = 0; i < gs.num_boxes; i++) { process_body(&gs.boxes[i].body); } } // drawing { sgp_begin(width, height); sgp_viewport(0, 0, width, height); // sgp_project(-ratio, ratio, 1.0f, -1.0f); sgp_project(0.0f, width, 0.0f, height); // Draw background color sgp_set_color(0.1f, 0.1f, 0.1f, 1.0f); sgp_clear(); // Drawing in world space now sgp_translate(width / 2, height / 2); sgp_scale_at(300.0f + funval, 300.0f + funval, 0.0f, 0.0f); sgp_translate(-gs.player.body.position.x, -gs.player.body.position.y); sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); sgp_draw_filled_rect(100.0f, 100.0f, 400.0f, 400.0f); // stars const int num = 50; for (int x = -num; x < num; x++) { for (int y = -num; y < num; y++) { sgp_draw_point((float)x * 0.1f, (float)y * 0.1f); } } float halfbox = BOX_SIZE / 2.0f; // player { sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); sgp_draw_filled_rect(gs.player.body.position.x - halfbox, gs.player.body.position.y - halfbox, BOX_SIZE, BOX_SIZE); } // boxes { sgp_set_color(0.5f, 0.5f, 0.5f, 1.0f); for (int i = 0; i < gs.num_boxes; i++) { sgp_draw_filled_rect(gs.boxes[i].body.position.x - halfbox, gs.boxes[i].body.position.y - halfbox, BOX_SIZE, BOX_SIZE); } } // sgp_draw_line(5.0f, 5.0f, 5.0f, 10.0f); // sgp_draw_line() // sgp_rotate_at(time, 0.0f, 0.0f); // Begin a render pass. sg_pass_action pass_action = {0}; sg_begin_default_pass(&pass_action, width, height); sgp_flush(); sgp_end(); sg_end_pass(); sg_commit(); } } void cleanup(void) { sgp_shutdown(); sg_shutdown(); } void event(const sapp_event *e) { switch (e->type) { case SAPP_EVENTTYPE_KEY_DOWN: keydown[e->key_code] = true; break; case SAPP_EVENTTYPE_KEY_UP: keydown[e->key_code] = false; break; case SAPP_EVENTTYPE_MOUSE_DOWN: if (e->mouse_button == SAPP_MOUSEBUTTON_LEFT) mouse_down = true; break; case SAPP_EVENTTYPE_MOUSE_UP: if (e->mouse_button == SAPP_MOUSEBUTTON_LEFT) mouse_down = false; break; case SAPP_EVENTTYPE_MOUSE_MOVE: if (mouse_down) { funval += e->mouse_dx; printf("Funval %f\n", funval); } break; } } sapp_desc sokol_main(int argc, char *argv[]) { (void)argc; (void)argv; return (sapp_desc){ .init_cb = init, .frame_cb = frame, .cleanup_cb = cleanup, .width = 640, .height = 480, .gl_force_gles2 = true, .window_title = "Flight", .icon.sokol_default = true, .event_cb = event, .win32_console_attach = true, .sample_count = 4, // anti aliasing }; }