void init(void) { CORE->palette.colors[PC_TRANSPARENT] = color_make(0x00, 0x00, 0x00, 0x00); CORE->palette.colors[PC_TRUE_BLACK] = color_make(0x00, 0x00, 0x00, 0xff); set_palette_set(PS_WHITE); // IMPORTANT NOTE(bill): This must be white as the spritesheet is white CORE->palette.colors_count = PC_COUNT; canvas_clear(1); bitmap_load_resource(&spritesheet, "spritesheet.png"); bitmap_load_resource(&title_screen, "title_screen.png"); bitmap_load_resource(&font.bitmap, "font.png"); font.char_width = 4; font.char_height = 7; CORE->font = &font; init_game(); #if 0 set_palette_set(PS_WHITE); #endif }
void step() { canvas_clear(1); if (key_down(KEY_ESCAPE)) { CORE->running = 0; } if (key_pressed(KEY_RETURN)) { window_fullscreen_toggle(); } player_step(&GAME->player, key_down(KEY_LEFT), key_down(KEY_RIGHT), key_pressed(KEY_UP)); tilemap_draw(GAME->scene.tilemap); char buf[256]; sprintf(buf, "%.3fms %.3f", CORE->perf_step * 1e3, CORE->time_delta); text_draw(buf, 0, 0, 2); }
int32_t main(int32_t argc, char *argv[]) { printf("<<watchlist//>>\n"); if( init_sdl2() ) { return 1; } uint32_t width = 1280; uint32_t height = 720; SDL_Window* window; sdl2_window("test-canvas", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, &window); SDL_GLContext* context; sdl2_glcontext(3, 2, window, &context); if( init_shader() ) { return 1; } if( init_canvas() ) { return 1; } printf("sizeof(struct Canvas): %zu\n", sizeof(struct Canvas)); printf("MAX_OGL_PRIMITIVES: %d\n", MAX_OGL_PRIMITIVES); struct Arcball arcball = {0}; arcball_create(width, height, (Vec4f){1.0,2.0,8.0,1.0}, (Vec4f){0.0,0.0,0.0,1.0}, 0.01, 1000.0, &arcball); struct Character symbols[256] = {0}; default_font_create(symbols); struct Shader shader = {0}; shader_create(&shader); shader_attach(&shader, GL_VERTEX_SHADER, "prefix.vert", 1, "volumetric_lines.vert"); shader_attach(&shader, GL_FRAGMENT_SHADER, "prefix.frag", 1, "volumetric_lines.frag"); shader_make_program(&shader, SHADER_DEFAULT_NAMES, "lines_shader"); struct Font font = {0}; font_create_from_characters(L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.,:;", 256, symbols, 9, 3, global_default_font_palette, &font); struct Canvas text_canvas = {0}; canvas_create("text_canvas", &text_canvas); canvas_add_attribute(&text_canvas, SHADER_ATTRIBUTE_VERTEX, 3, GL_FLOAT); canvas_add_attribute(&text_canvas, SHADER_ATTRIBUTE_VERTEX_COLOR, 4, GL_UNSIGNED_BYTE); canvas_add_attribute(&text_canvas, SHADER_ATTRIBUTE_VERTEX_TEXCOORD, 2, GL_FLOAT); log_assert( canvas_add_shader(&text_canvas, shader.name, &shader) < MAX_CANVAS_SHADER ); log_assert( canvas_add_font(&text_canvas, "other_font", &font) < MAX_CANVAS_FONTS ); struct GameTime time = {0}; gametime_create(1.0f / 60.0f, &time); SDL_SetEventFilter(event_filter, NULL); while (true) { SDL_Event event; while( sdl2_poll_event(&event) ) { if( sdl2_handle_quit(event) ) { goto done; } sdl2_handle_resize(event); arcball_handle_resize(&arcball, event); arcball_handle_mouse(&arcball, event); } gametime_advance(&time, sdl2_time_delta()); sdl2_debug( SDL_GL_SetSwapInterval(1) ); ogl_debug( glClearDepth(1.0f); glClearColor(.0f, .0f, .0f, 1.0f); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); ); draw_grid(&text_canvas, 0, (Mat)IDENTITY_MAT, (Color){20, 180, 240, 255}, 0.02f, 12.0f, 12.0f, 12); draw_basis(&text_canvas, 1, (Mat)IDENTITY_MAT, 0.02f, 1.0f); Mat text_matrix = {0}; Quat text_rotation = {0}; quat_from_axis_angle((Vec4f){1.0, 0.0, 0.0, 1.0}, PI/2, text_rotation); mat_rotate(NULL, text_rotation, text_matrix); mat_translate(text_matrix, (Vec4f){-3.5, -1.0, 6.25, 1.0}, text_matrix); Vec4f world_cursor = {0,0,0,1}; text_put_world(&text_canvas, 0, world_cursor, text_matrix, (Color){0, 255, 255, 255}, 0.5f, "other_font", L"Dies ist ein Test\n"); text_put_world(&text_canvas, 0, world_cursor, text_matrix, (Color){255, 255, 0, 255}, 0.5f, "other_font", L"fuer einen Text"); gametime_integrate(&time); Vec4f screen_cursor = {0,0,0,1}; double fps = text_show_fps(&global_dynamic_canvas, 0, screen_cursor, 0, 0, (Color){255, 255, 255, 255}, 20.0f, "default_font", time.frame); /* text_show_time(&text_canvas, screen_cursor, 0, "default_font", 20.0, (Color){255, 255, 255, 255}, 0, 0, time.t); */ /* text_put_screen(&text_canvas, screen_cursor, 0, "default_font", 20.0, (Color){255, 210, 255, 255}, 0, 0, L"LALA singt das Meerschweinchen\n"); */ /* text_put_screen(&text_canvas, screen_cursor, 0, "default_font", 20.0, (Color){0, 210, 255, 255}, 0, 0, L"FICKEN immer und ueberall\n"); */ /* text_put_screen(&text_canvas, screen_cursor, 0, "default_font", 20.0, (Color){20, 210, 110, 255}, 0, 0, L"FUMMELN den ganzen Tag lang\n"); */ /* text_printf(&text_canvas, screen_cursor, 0, "default_font", 20.0, (Color){255, 40, 60, 255}, 0, 0, L"PRINTF %d Luftballons\n", 99); */ canvas_render_layers(&text_canvas, 0, MAX_CANVAS_LAYERS, &arcball.camera, (Mat)IDENTITY_MAT); canvas_clear(&text_canvas); canvas_render_layers(&global_dynamic_canvas, 0, MAX_CANVAS_LAYERS, &arcball.camera, (Mat)IDENTITY_MAT); canvas_clear(&global_dynamic_canvas); sdl2_debug( SDL_GL_SwapWindow(window) ); }
void hand_pai_advice_info_display (global_t *gp) { integer_t i, j, k; widget_t canvas = hand_pai_advice_info; canvas_clear (); widget_configure (canvas, resource_pixmapstart, HANDPAISTART); collect_reveal_pai_info (gp); for (i = 0; i < hand[vself].closed_num; i++) { integer_t pai = P_KIND (hand[vself].closed[i]); integer_t reveal = pai_reveal[pai]; integer_t margin; gpixmap2_t pm; if (i == hand[vself].closed_num - 1) margin = HANDPAIMARGIN; else margin = 0; if (reveal < 0 || reveal > 4) reveal = 4; if (flag_advicedigit) { pm = &pm_tiny_digit[4 - reveal]; } else { pm = &pm_tiny_space; } print_colorpixmap2_withmargin (pm, margin); if (flag_advicepai) { for (j = 0; j < 4; j++) { if (j != vself) { if (pai_genbutu[j][pai]) { print_colorpixmap (pm_tiny_home[j]); } else { print_colorpixmap (pm_tiny_space); } } else { print_colorpixmap (pm_tiny_space); } } } else { for (j = 0; j < 4; j++) { print_colorpixmap (pm_tiny_space); } } } }
int32_t main(int32_t argc, char *argv[]) { if( init_sdl2() ) { return 1; } uint32_t width = 1280; uint32_t height = 720; SDL_Window* window = NULL; sdl2_window("cute3d: " __FILE__, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, &window); SDL_GLContext* context = NULL; sdl2_glcontext(3, 2, window, &context); if( init_shader() ) { return 1; } if( init_vbo() ) { return 1; } if( init_canvas(width, height) ) { return 1; } struct Arcball arcball = {}; arcball_create(width, height, (Vec4f){1.0,2.0,6.0,1.0}, (Vec4f){0.0,0.0,0.0,1.0}, 0.001f, 100.0, &arcball); struct GameTime time = {}; gametime_create(1.0f / 60.0f, &time); while(true) { SDL_Event event = {}; while( sdl2_poll_event(&event) ) { if( sdl2_handle_quit(event) ) { goto done; } sdl2_handle_resize(event); arcball_handle_resize(&arcball, event); arcball_handle_mouse(&arcball, event); } sdl2_gl_set_swap_interval(1); sdl2_clear((Color){0, 0, 0, 255}, 1.0f, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gametime_advance(&time, sdl2_time_delta()); gametime_integrate(&time); Mat identity = {}; mat_identity(identity); draw_grid(&global_dynamic_canvas, 0, identity, (Color){120, 120, 120, 255}, 0.01f, 12.0f, 12.0f, 12); Vec4f screen_cursor = {0,0,0,1}; text_show_fps(&global_dynamic_canvas, 0, screen_cursor, 0, 0, (Color){255, 255, 255, 255}, 20.0f, "default_font", time.frame); canvas_render_layers(&global_static_canvas, 0, MAX_CANVAS_LAYERS, &arcball.camera, (Mat)IDENTITY_MAT); canvas_render_layers(&global_dynamic_canvas, 0, MAX_CANVAS_LAYERS, &arcball.camera, (Mat)IDENTITY_MAT); canvas_clear(&global_dynamic_canvas); sdl2_gl_swap_window(window); } done: return 0; }
void step(void) { if (key_pressed(KEY_ESCAPE)) { CORE->running = 0; return; } if (key_pressed(KEY_1)) set_palette_set(PS_WHITE); else if (key_pressed(KEY_2)) set_palette_set(PS_GREEN); else if (key_pressed(KEY_3)) set_palette_set(PS_BEIGE); else if (key_pressed(KEY_4)) set_palette_set(PS_BLUE); else if (key_pressed(KEY_5)) set_palette_set(PS_RED); else if (key_pressed(KEY_6)) set_palette_set(PS_PASTEL_MIX); else if (key_pressed(KEY_7)) set_palette_set(PS_RED_GREEN); switch (game.mode) { case GAME_MODE_TITLE: { if (game.intro_cooldown --> 0) { canvas_clear(PC_TRANSPARENT); bitmap_draw(0, 0, 0, 0, &title_screen, NULL, 0, 0); } else { game.mode = GAME_MODE_MAP; } } break; case GAME_MODE_MAP: { Map *map = &game.maps[game.curr_map_index]; i32 i, j, x, y; gbVec2 old_player_pos = game.player.pos; b32 render_doctor_text = false; canvas_clear(PC_TRANSPARENT); game.player.vel = gb_vec2_zero(); if (key_down(KEY_UP)) { game.player.vel.y -= 1.0f; } if (key_down(KEY_DOWN)) { game.player.vel.y += 1.0f; } if (key_down(KEY_LEFT)) { game.player.vel.x -= 1.0f; } if (key_down(KEY_RIGHT)) { game.player.vel.x += 1.0f; } gb_vec2_norm0(&game.player.vel, game.player.vel); gb_vec2_muleq(&game.player.vel, game.player.in_grass ? 2.5f : 3.5f); gb_vec2_addeq(&game.player.pos, game.player.vel); game.player.in_grass = false; game.player.is_moving = (gb_vec2_mag(game.player.vel) > 0); if (game.player.vel.x < 0) game.player.orientation = 2; if (game.player.vel.x > 0) game.player.orientation = 3; if (game.player.vel.y > 0) game.player.orientation = 0; if (game.player.vel.y < 0) game.player.orientation = 1; game.player.pos.x = gb_clamp(game.player.pos.x, 0, (map->width-1) *TILE_SIZE); game.player.pos.y = gb_clamp(game.player.pos.y, 0, (map->height-1)*TILE_SIZE); game.grass_event_cooldown--; if (game.grass_event_cooldown < 0) game.grass_event_cooldown = 0; draw_tooltip = false; gb_zero_array(tooltip_messages, gb_count_of(tooltip_messages)); { // Handle Interactions Rect player_rect = rect_make_size(game.player.pos.x+2, game.player.pos.y+12, 12, 4); for (j = 0; j < map->height; j++) { y = j*TILE_SIZE; for (i = 0; i < map->width; i++) { Rect tile_rect; char t = map->tiles[j][i]; x = i*TILE_SIZE; tile_rect = rect_make_size(x, y, TILE_SIZE, TILE_SIZE); if (gb_char_is_digit(t)) { if (rect_collides(player_rect, tile_rect, NULL)) { change_map_to(t-'0'); return; } } if ((t != ' ' && t != '.' && t != 'g')) { Rect inter; b32 do_collision = true; if (t == 'L') { // NOTE(bill): Lab Chemicals Top tile_rect = rect_make_size(x, y+7, TILE_SIZE, TILE_SIZE-7); } if (t == 'Q' && game.has_chosen_transmog) { do_collision = false; } if (do_collision && rect_collides(player_rect, tile_rect, &inter)) { game.player.pos = old_player_pos; game.player.is_moving = false; } } if (t == 'g' && game.player.is_moving && rect_collides(player_rect, tile_rect, NULL)) { i32 random = gb_random_range_int(0, 100); game.player.in_grass = true; if ((random < 7) && (game.grass_event_cooldown <= 0)) { game.grass_event_cooldown = 50; #if 1 change_to_battle_mode(BATTLE_TYPE_GRASS); #endif return; } } if (t == 'D') { f32 dx = game.player.pos.x - (x + TILE_SIZE/2); f32 dy = game.player.pos.y - (y + TILE_SIZE/2); if (dx*dx+dy*dy < square(2*TILE_SIZE)) render_doctor_text = true; } if (t == 'Y') { set_tooltip(x, y, 1.5f, "Hello! I'm your worst nightmare!", "My name is Yugi the Boss.", "Want to battle [z]?"); if (key_pressed(KEY_Z)) { change_to_battle_mode(BATTLE_TYPE_BOSS); return; } } if (t == 'Q' && !game.has_chosen_transmog) { set_tooltip(x, y, 1.5f, "It's dangerous to go alone", "in there! You might get hurt.", "Go see The Doctor in The Lab."); } if (t == 'L' || t == 'l') { set_tooltip(x, y, 1.0f, "It appears to be weird chemicals.", NULL, NULL); } if (t == 'm' || t == 'c') { set_tooltip(x, y, 1.0f, "State of the art computers", "The new Pear Bartlett!", NULL); } if (t == 'P') { set_tooltip(x, y, 0.6f, "Such a lovely picture!", NULL, NULL); } if (t == 'B' || t == 'b') { set_tooltip(x, y, 1.2f, "It is not time to sleep.", NULL, NULL); } if (t == 'W') { set_tooltip(x, y, 0.6f, "It's a beautiful view outside.", "Why not go outside and explore?", NULL); } } } } move_game_camera(map); // Render 1x1 Sprites for (j = 0; j < map->height; j++) { y = j*TILE_SIZE; for (i = 0; i < map->width; i++) { char t = map->tiles[j][i]; x = i*TILE_SIZE; switch (t) { case ' ': case '.': case 'g': case 'Q': case 'D': case 'Y': { i32 sx = 0; i32 sy = map->outside; if (map->outside) { sx = (i+j)%2; } draw_sprite(x, y, sx, sy, 0); if (t == 'g') draw_sprite(x, y, 2, 1, 0); // grass if (t == 'Q' && !game.has_chosen_transmog) draw_sprite(x, y, 0, 3, 0); // Person in the way if (t == 'D') draw_sprite(x, y, 1, 3, 0); // Dr. if (t == 'Y') draw_sprite(x, y, 2, 3, 0); // Yugi } break; case 'x': draw_sprite(x, y, 1, 0, 0); break; // Wall case 'P': draw_sprite(x, y, 2, 0, 0); break; // Hanging Picture case 'W': draw_sprite(x, y, 3, 0, 0); break; // Window case 'T': draw_sprite(x, y, 3, 1, 0); break; // Thick Grass case 't': draw_sprite(x, y, 4, 1, 0); break; // Tree trunk case 'B': draw_sprite(x, y, 5, 0, 0); break; // Bed Top case 'b': draw_sprite(x, y, 5, 1, 0); break; // Bed bottom case 'M': draw_sprite(x, y, 6, 0, 0); break; // Computer monitor case 'm': draw_sprite(x, y, 6, 1, 0); break; // Computer keyboard case 'C': draw_sprite(x, y, 7, 0, 0); break; // Computer case case 'c': draw_sprite(x, y, 7, 1, 0); break; // Computer mouse case 'L': draw_sprite(x, y, 8, 0, 0); break; // Lap Chemicals top case 'l': draw_sprite(x, y, 8, 1, 0); break; // Lap Chemicals bottom default: { if (gb_char_is_digit(t)) draw_sprite(x, y, 4, 0, 0); } break; } } } // Render NxM Sprites // TODO(bill): Be more efficient for (j = 0; j < map->height; j++) { y = j*TILE_SIZE; for (i = 0; i < map->width; i++) { char t = map->tiles[j][i]; x = i*TILE_SIZE; switch (t) { case 'h': draw_sprite_size(x, y, 12, 2, 4, 4, 0); break; case 'd': draw_sprite_size(x, y, 8, 2, 4, 4, 0); break; } } } { // Render player and particles i32 sx = 0; u32 flags = 0; // 0 - down // 1 - up // 2 - left // 3 - right (-ve left) if (game.player.orientation == 0) sx = 0; if (game.player.orientation == 1) sx = 1; if (game.player.orientation == 2) sx = 2; if (game.player.orientation == 3) { sx = 2; flags |= DrawFlags_FlipH; } if (game.player.is_moving) { u32 flip = 10.0f*CORE->perf_frame.stamp; b32 use_flip = true; if (game.player.orientation == 0) { if (use_flip) { sx = 3; flags |= DrawFlags_FlipH * (flip%2); } } else if (game.player.orientation == 1) { if (use_flip) { sx = 4; flags |= DrawFlags_FlipH * (flip%2); } } else { sx += 3 * (flip%2); } } draw_sprite(game.player.pos.x, game.player.pos.y, sx, 2, flags); } { // Render Text CORE->translate_x = 0; CORE->translate_y = 0; if (game.show_map_name_ticks-- > 0) { if (game.show_map_name_ticks < 0) game.show_map_name_ticks = 0; { char *name = game.maps[game.curr_map_index].name; i32 name_len = gb_strlen(name); i32 w = name_len*font.char_width+6; i32 h = font.char_height+6; rect_draw(rect_make_size(1, 1, w, h), PC_WHITE); rect_draw(rect_make_size(1, 0, w, 1), PC_DARK_GREY); rect_draw(rect_make_size(1, h+1, w, 1), PC_DARK_GREY); rect_draw(rect_make_size(0, 1, 1, h), PC_DARK_GREY); rect_draw(rect_make_size(w+1, 1, 1, h), PC_DARK_GREY); text_draw(4, 4, name, PC_BLACK); } } if (render_doctor_text) { if (game.doctor_line_index < gb_count_of(doctor_lines)) { draw_message_box(doctor_lines[game.doctor_line_index], "", "[Z] to continue"); if (key_pressed(KEY_Z)) game.doctor_line_index++; } else if (!game.has_chosen_transmog) { draw_message_box("Line [X]", "Triangle [C]", "Square [V]"); if (key_pressed(KEY_X)) { game.player.my_transmog = make_transmog(TRANSMOG_TYPE_LINE); game.has_chosen_transmog = true; } else if (key_pressed(KEY_C)) { game.player.my_transmog = make_transmog(TRANSMOG_TYPE_TRIANGLE); game.has_chosen_transmog = true; } else if (key_pressed(KEY_V)) { game.player.my_transmog = make_transmog(TRANSMOG_TYPE_SQUARE); game.has_chosen_transmog = true; } } else { draw_message_box("Go now and find Transmogs!", "", ""); } } else if (draw_tooltip) { draw_message_box(tooltip_messages[0], tooltip_messages[1], tooltip_messages[2]); } } } break; case GAME_MODE_BATTLE: { i32 i, w = CANVAS_WIDTH, h = CANVAS_HEIGHT; Transmog *enemy_mog = &game.battle_mode.enemy_mog; Transmog *player_mog = game.battle_mode.player_mog; char name_buf[32] = ""; char *attack_names[3] = { "TRANSLATE", "ROTATE", "DIVIDE", }; i32 level_diff = enemy_mog->shift_level - player_mog->shift_level; CORE->translate_x = 0; CORE->translate_y = 0; canvas_clear(PC_WHITE); // Enemy Transmog gb_snprintf(name_buf, gb_size_of(name_buf), "%s LVL%d", transmog_name(enemy_mog->type), enemy_mog->shift_level); text_draw(8, 5, name_buf, PC_BLACK); draw_sprite_size(8, 12, 2, 4, 3, 1, 0); draw_sprite_size(24, 15, 3, 5, 2, 1, 0); { f32 hp_percent = cast(f32)enemy_mog->health/cast(f32)enemy_mog->max_health; rect_draw(rect_make_size(25, 16, hp_percent*30, 1), PC_LIGHT_GREY); draw_big_transmog(84, 4, enemy_mog->type); } // Player Transmog gb_snprintf(name_buf, gb_size_of(name_buf), "%s LVL%d", transmog_name(player_mog->type), player_mog->shift_level); text_draw(100, 80, name_buf, PC_BLACK); draw_sprite_size(104, 92, 5, 4, 3, 1, 0); draw_sprite_size(117, 95, 3, 5, 2, 1, 0); { f32 hp_percent = cast(f32)player_mog->health/cast(f32)player_mog->max_health; char buf[16] = {0}; gb_snprintf(buf, gb_size_of(buf), "%03d/%03d", player_mog->health, player_mog->max_health); rect_draw(rect_make_size(118, 96, hp_percent*30, 1), PC_LIGHT_GREY); text_draw(118, 99, buf, PC_BLACK); draw_big_transmog(4, 54, player_mog->type); } if (!game.battle_mode.is_enemies_turn) { switch (game.battle_mode.state) { case BATTLE_TURN_STATE_INTRO: { char buf[32] = {0}; gb_snprintf(buf, gb_size_of(buf), "A wild %s appears!", transmog_name(enemy_mog->type)); draw_message_box(buf, "", "[Z] to continue"); if (key_pressed(KEY_Z)) { game.battle_mode.state = BATTLE_TURN_STATE_WHAT_TO_DO; return; } } break; case BATTLE_TURN_STATE_WHAT_TO_DO: { u32 hot_item = 0; if (game.battle_mode.type == BATTLE_TYPE_GRASS) { game.battle_mode.state_index %= 3; hot_item = game.battle_mode.state_index; draw_message_box("What to do? Fight ", " Substitute", " Escape "); draw_sprite(70, 111, 0, 4, 0); draw_sprite(70, 127, 0, 5, 0); draw_sprite(90, 117 + hot_item*font.char_height, 5, 5, 0); if (key_pressed(KEY_DOWN)) { game.battle_mode.state_index++; } if (key_pressed(KEY_UP)) { if (game.battle_mode.state_index == 0) game.battle_mode.state_index = 2; else game.battle_mode.state_index--; } if (key_pressed(KEY_Z)) { switch (hot_item) { case 0: game.battle_mode.state = BATTLE_TURN_STATE_FIGHT; game.battle_mode.state_index = 0; game.battle_mode.fighting_state = FIGHTING_STATE_NONE; return; case 1: game.battle_mode.state = BATTLE_TURN_STATE_SUBSTITUTE; game.battle_mode.state_index = 0; case 2: game.battle_mode.state = BATTLE_TURN_STATE_ESPACE; game.battle_mode.state_index = 0; return; } } } else { game.battle_mode.state_index %= 2; hot_item = game.battle_mode.state_index; draw_message_box("What to do? Fight ", " Escape ", " "); draw_sprite(70, 111, 0, 4, 0); draw_sprite(70, 127, 0, 5, 0); draw_sprite(90, 117 + hot_item*font.char_height, 5, 5, 0); if (key_pressed(KEY_DOWN)) { game.battle_mode.state_index++; } if (key_pressed(KEY_UP)) { if (game.battle_mode.state_index == 0) game.battle_mode.state_index = 1; else game.battle_mode.state_index--; } if (key_pressed(KEY_Z)) { switch (hot_item) { case 0: game.battle_mode.state = BATTLE_TURN_STATE_FIGHT; game.battle_mode.state_index = 0; game.battle_mode.fighting_state = FIGHTING_STATE_NONE; return; case 1: game.battle_mode.state = BATTLE_TURN_STATE_ESPACE; game.battle_mode.state_index = 0; return; } } } } break; case BATTLE_TURN_STATE_FIGHT: { char buf[32] = ""; switch (game.battle_mode.fighting_state) { case FIGHTING_STATE_NONE: { u32 hot_item = game.battle_mode.state_index; draw_message_box("Which attack? Translate ", " Rotate ", " Divide "); draw_sprite(70, 111, 0, 4, 0); draw_sprite(70, 127, 0, 5, 0); draw_sprite(90, 117 + hot_item*font.char_height, 5, 5, 0); if (key_pressed(KEY_DOWN)) { game.battle_mode.state_index++; game.battle_mode.state_index %= 3; } if (key_pressed(KEY_UP)) { if (game.battle_mode.state_index == 0) game.battle_mode.state_index = 2; else game.battle_mode.state_index--; } if (key_pressed(KEY_X)) { game.battle_mode.state_index = 0; game.battle_mode.state = BATTLE_TURN_STATE_WHAT_TO_DO; return; } if (key_pressed(KEY_Z)) { game.battle_mode.attack_index = hot_item; game.battle_mode.state_index = 0; game.battle_mode.fighting_state = FIGHTING_STATE_USE; return; } } break; case FIGHTING_STATE_USE: { gb_snprintf(buf, gb_size_of(buf), "Your %s used %s", transmog_name(enemy_mog->type), attack_names[game.battle_mode.attack_index]); draw_message_box(buf, NULL, NULL); if (key_pressed(KEY_Z)) { if (-level_diff < 0) { // Higher level enemy game.battle_mode.fighting_state = FIGHTING_STATE_SUPER_EFFECTIVE; } else { if (gb_random_range_int(0, -level_diff+1) == 0) { game.battle_mode.fighting_state = FIGHTING_STATE_SUPER_EFFECTIVE; } else { if (gb_random_range_int(0, -level_diff/2 + 1) == 0) game.battle_mode.fighting_state = FIGHTING_STATE_EFFECTIVE; else game.battle_mode.fighting_state = FIGHTING_STATE_NO_EFFECT; } } return; } } break; case FIGHTING_STATE_EFFECTIVE: { gb_snprintf(buf, gb_size_of(buf), "%s was effective", attack_names[game.battle_mode.attack_index]); draw_message_box(buf, NULL, NULL); if (key_pressed(KEY_Z)) { i32 damage = gb_clamp(0, player_mog->attack_power/3 + level_diff/2, 1000); enemy_mog->health -= damage; game.battle_mode.fighting_state = FIGHTING_STATE_NEXT_TURN; } } break; case FIGHTING_STATE_SUPER_EFFECTIVE: { gb_snprintf(buf, gb_size_of(buf), "%s was super effective", attack_names[game.battle_mode.attack_index]); draw_message_box(buf, NULL, NULL); if (key_pressed(KEY_Z)) { i32 damage = gb_clamp(0, player_mog->attack_power/1 + level_diff/2, 1000); enemy_mog->health -= damage; game.battle_mode.fighting_state = FIGHTING_STATE_NEXT_TURN; game.battle_mode.state_index = 0; } } break; case FIGHTING_STATE_NO_EFFECT: { gb_snprintf(buf, gb_size_of(buf), "%s had no effect", attack_names[game.battle_mode.attack_index]); draw_message_box(buf, NULL, NULL); if (key_pressed(KEY_Z)) game.battle_mode.fighting_state = FIGHTING_STATE_NEXT_TURN; } break; case FIGHTING_STATE_NEXT_TURN: { char *end_message = ""; if (enemy_mog->health <= 0 && !(game.battle_mode.state_index & 1)) { enemy_mog->health = 0; player_mog->xp += clamp(1, 4 + level_diff, 1000); while (player_mog->xp >= 10) { player_mog->xp -= 10; player_mog->shift_level++; update_transmog_stats(player_mog); player_mog->health = player_mog->max_health; game.battle_mode.state_index |= 2; } game.battle_mode.state_index |= 1; } if (game.battle_mode.state_index & 1) { if (game.battle_mode.type == BATTLE_TYPE_GRASS) { if (game.battle_mode.state_index & 2) end_message = "Your Transmog has levelled up!"; draw_message_box("You win this battle!", end_message, "Exit the battle."); if (key_pressed(KEY_Z)) { game.mode = GAME_MODE_MAP; game.battle_mode.state_index = 0; return; } } else { canvas_clear(PC_WHITE); draw_sprite(72, 40, 2, 3, 0); draw_message_box("You defeated me?! HOW?!", "Well it's my first battle...", "Well done and thank you!"); if (key_pressed(KEY_Z)) { game.mode = GAME_MODE_END_SUCCESS; return; } } } else { draw_message_box("End turn.", NULL, NULL); if (key_pressed(KEY_Z)) { end_battle_mode_turn(); return; } } } break; } } break; case BATTLE_TURN_STATE_SUBSTITUTE: { i32 level_diff = enemy_mog->shift_level - player_mog->shift_level; if (level_diff <= 0) { draw_message_box("Failed to substitute", "", "End turn."); if (key_pressed(KEY_Z)) { end_battle_mode_turn(); return; } } else { if (game.battle_mode.state_index == 0) { if (gb_random_range_int(0, level_diff) != 0) game.battle_mode.state_index = 1; // Success else game.battle_mode.state_index = 2; // Failure } if (game.battle_mode.state_index == 1) { draw_message_box("Well done!", "You successfully substituted.", "Exit to world"); if (key_pressed(KEY_Z)) { // Change it! game.player.my_transmog = *enemy_mog; game.mode = GAME_MODE_MAP; return; } } else { draw_message_box("Substitution failed!", "", "End turn."); if (key_pressed(KEY_Z)) { end_battle_mode_turn(); return; } } } } break; case BATTLE_TURN_STATE_ESPACE: { if (game.battle_mode.state_index == 0) { if (gb_random_range_int(0, 100) < 90) { game.battle_mode.state_index = 1; } else { game.battle_mode.state_index = 2; } } if (game.battle_mode.state_index == 1) { draw_message_box("You escaped from this battle!", "", "[Z] to return to the world."); if (key_pressed(KEY_Z)) { game.mode = GAME_MODE_MAP; return; } } else { draw_message_box("You could not escape!", "You'll have to try again!", "[Z] to end turn."); end_battle_mode_turn(); return; } } break; } } else { // NOTE(bill): Enemies Turn char buf[32] = {0}; switch (game.battle_mode.fighting_state) { case FIGHTING_STATE_NONE: { game.battle_mode.attack_index = gb_random_range_int(0, 2); game.battle_mode.fighting_state = FIGHTING_STATE_USE; return; } break; case FIGHTING_STATE_USE: { gb_snprintf(buf, gb_size_of(buf), "Enemy %s used %s", transmog_name(enemy_mog->type), attack_names[game.battle_mode.attack_index]); draw_message_box(buf, NULL, NULL); if (key_pressed(KEY_Z)) { if (level_diff < 0) { // Higher level enemy game.battle_mode.fighting_state = FIGHTING_STATE_SUPER_EFFECTIVE; } else { if (gb_random_range_int(0, -level_diff+3) == 0) { game.battle_mode.fighting_state = FIGHTING_STATE_SUPER_EFFECTIVE; } else { if (gb_random_range_int(0, -level_diff/2 + 3) == 0) game.battle_mode.fighting_state = FIGHTING_STATE_EFFECTIVE; else game.battle_mode.fighting_state = FIGHTING_STATE_NO_EFFECT; } } return; } } break; case FIGHTING_STATE_EFFECTIVE: { gb_snprintf(buf, gb_size_of(buf), "%s was effective", attack_names[game.battle_mode.attack_index]); draw_message_box(buf, NULL, NULL); if (key_pressed(KEY_Z)) { i32 damage = gb_clamp(0, enemy_mog->attack_power/6.0f - level_diff/3.0f, 1000); player_mog->health -= damage; game.battle_mode.fighting_state = FIGHTING_STATE_NEXT_TURN; } } break; case FIGHTING_STATE_SUPER_EFFECTIVE: { gb_snprintf(buf, gb_size_of(buf), "%s was super effective", attack_names[game.battle_mode.attack_index]); draw_message_box(buf, NULL, NULL); if (key_pressed(KEY_Z)) { i32 damage = gb_clamp(0, enemy_mog->attack_power/3.0f - level_diff/2.0f, 1000); player_mog->health -= damage; game.battle_mode.fighting_state = FIGHTING_STATE_NEXT_TURN; } } break; case FIGHTING_STATE_NO_EFFECT: { gb_snprintf(buf, gb_size_of(buf), "%s had no effect", attack_names[game.battle_mode.attack_index]); draw_message_box(buf, NULL, NULL); if (key_pressed(KEY_Z)) game.battle_mode.fighting_state = FIGHTING_STATE_NEXT_TURN; } break; case FIGHTING_STATE_NEXT_TURN: { char *end_message = ""; if (player_mog->health <= 0 && !(game.battle_mode.state_index & 1)) { player_mog->health = 0; game.battle_mode.state_index |= 1; } if (game.battle_mode.state_index & 1) { draw_message_box("You lost this battle!", "And the game :(", "Exit the battle."); if (key_pressed(KEY_Z)) { game.mode = GAME_MODE_END_FAIL; return; } } else { draw_message_box("The enemy's turn has ended.", NULL, NULL); if (key_pressed(KEY_Z)) { end_battle_mode_turn(); return; } } } break; } } } break; case GAME_MODE_END_FAIL: { canvas_clear(PC_BLACK); draw_message_box("You have failed :(", "Would you like to try again?", "Try again [z] Exit [esc]"); if (key_pressed(KEY_Z)) { init_game(); return; } } break; case GAME_MODE_END_SUCCESS: { canvas_clear(PC_BLACK); text_draw(4, 4, "Thank you for playing Transmog!\n" "Ginger Bill (c) 2016\n" "\n" "Ludum Dare 35\n" "Theme: Shapeshift\n" "\n" "Please remember for vote!\n", PC_WHITE); draw_message_box("Exit [esc]", NULL, NULL); } break; } }
int32_t main(int32_t argc, char *argv[]) { printf("<<watchlist//>>\n"); if( init_sdl2() ) { return 1; } int32_t width = 1280; int32_t height = 720; SDL_Window* window; sdl2_window("cute3d: " __FILE__, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, &window); SDL_GLContext* context; sdl2_glcontext(3, 2, window, &context); if( init_shader() ) { return 1; } if( init_vbo() ) { return 1; } if( init_canvas(1280,720) ) { return 1; } canvas_create("global_dynamic_canvas", &global_dynamic_canvas); canvas_create("global_static_canvas", &global_static_canvas); struct Vbo vbo = {0}; vbo_create(&vbo); vbo_add_buffer(&vbo, SHADER_ATTRIBUTE_VERTEX, 3, GL_FLOAT, GL_STATIC_DRAW); vbo_add_buffer(&vbo, SHADER_ATTRIBUTE_VERTEX_NORMAL, 3, GL_FLOAT, GL_STATIC_DRAW); vbo_add_buffer(&vbo, SHADER_ATTRIBUTE_VERTEX_COLOR, 4, GL_UNSIGNED_BYTE, GL_STATIC_DRAW); struct Ibo ibo = {0}; ibo_create(GL_TRIANGLES, GL_UNSIGNED_INT, GL_STATIC_DRAW, &ibo); struct CollisionEntity entity_a = {0}; entity_create("red", (Color){ 255, 0, 0, 255 }, &vbo, &ibo, &entity_a); /* quat_mul_axis_angle(entity_a.pivot.orientation, (Vec4f)UP_AXIS, PI/4, entity_a.pivot.orientation); */ /* quat_mul_axis_angle(entity_a.pivot.orientation, (Vec4f)RIGHT_AXIS, PI/2 + 0.2, entity_a.pivot.orientation); */ vec_add(entity_a.pivot.position, (Vec4f){0.2, 0.15, 0.8, 1.0}, entity_a.pivot.position); struct CollisionEntity entity_b = {0}; entity_create("green", (Color){ 0, 255, 0, 255 }, &vbo, &ibo, &entity_b); quat_mul_axis_angle(entity_b.pivot.orientation, (Vec4f)RIGHT_AXIS, PI/4 - 0.2, entity_b.pivot.orientation); quat_mul_axis_angle(entity_b.pivot.orientation, (Vec4f)UP_AXIS, PI/2 + 0.0, entity_b.pivot.orientation); struct Shader flat_shader = {0}; shader_create(&flat_shader); shader_attach(&flat_shader, GL_VERTEX_SHADER, "prefix.vert", 1, "flat_shading.vert"); shader_attach(&flat_shader, GL_FRAGMENT_SHADER, "prefix.frag", 1, "flat_shading.frag"); shader_make_program(&flat_shader, SHADER_DEFAULT_NAMES, "flat_shader"); Vec4f light_direction = { 0.2, -0.5, -1.0 }; shader_set_uniform_3f(&flat_shader, flat_shader.program, SHADER_UNIFORM_LIGHT_DIRECTION, 3, GL_FLOAT, light_direction); Color ambiance = { 65, 25, 50, 255 }; shader_set_uniform_4f(&flat_shader, flat_shader.program, SHADER_UNIFORM_AMBIENT_LIGHT, 4, GL_UNSIGNED_BYTE, ambiance); struct Arcball arcball = {0}; arcball_create(width, height, (Vec4f){5.0, 3.0, 5.0, 1.0}, (Vec4f){0.0, 0.0, 0.0, 1.0}, 1.0, 1000.0, &arcball); size_t num_entities = 2; struct PickingSphere* picking_spheres[2]; picking_spheres[0] = &entity_a.picking_sphere; picking_spheres[1] = &entity_b.picking_sphere; struct CollisionEntity* picking_entities[2]; picking_entities[0] = &entity_a; picking_entities[1] = &entity_b; struct GameTime time = {0}; gametime_create(1.0f / 60.0f, &time); draw_grid(&global_static_canvas, 0, (Mat)IDENTITY_MAT, (Color){127, 127, 127, 127}, 0.01f, 12.0f, 12.0f, 12); while (true) { SDL_Event event; while( sdl2_poll_event(&event) ) { if( sdl2_handle_quit(event) ) { goto done; } sdl2_handle_resize(event); if( picking_sphere_drag_event(&arcball.camera, num_entities, picking_spheres, event) ) { struct CollisionEntity* selected_entity = NULL; float nearest = -FLT_MIN; for( size_t i = 0; i < num_entities; i++ ) { if( picking_spheres[i]->picked && ( picking_spheres[i]->front < nearest || nearest < 0.0f ) ) { nearest = picking_spheres[i]->front; selected_entity = picking_entities[i]; } } static int32_t last_x = -1; static int32_t last_y = -1; if( selected_entity != NULL ) { if( last_x > -1 && last_y > -1 ) { float distance = selected_entity->picking_sphere.front; Vec4f a = {0}; camera_ray(&arcball.camera, CAMERA_PERSPECTIVE, last_x, last_y, a); vec_mul1f(a, distance, a); Vec4f b = {0}; camera_ray(&arcball.camera, CAMERA_PERSPECTIVE, event.motion.x, event.motion.y, b); vec_mul1f(b, distance, b); Vec4f move = {0}; vec_sub(b, a, move); float length = vec_length(move); move[1] = 0.0f; vec_normalize(move, move); vec_mul1f(move, length, move); vec_add(selected_entity->pivot.position, move, selected_entity->pivot.position); } last_x = event.motion.x; last_y = event.motion.y; } if( event.type == SDL_MOUSEBUTTONUP ) { last_x = -1; last_y = -1; } } else { arcball_handle_resize(&arcball, event); arcball_handle_mouse(&arcball, event); } } sdl2_gl_set_swap_interval(0); gametime_advance(&time, sdl2_time_delta()); ogl_debug( glClearDepth(1.0f); glClearColor(.0f, .0f, .0f, 1.0f); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); ); Mat projection_mat = {0}; Mat view_mat = {0}; camera_matrices(&arcball.camera, CAMERA_PERSPECTIVE, projection_mat, view_mat); Mat identity = {0}; mat_identity(identity); Mat transform_a = {0}; pivot_world_transform(&entity_a.pivot, transform_a); //vbo_mesh_render(&entity_a.vbo_mesh, &flat_shader, &arcball.camera, transform_a); draw_halfedgemesh_wire(&global_dynamic_canvas, 0, transform_a, (Color){255, 0, 0, 255}, 0.02f, &entity_a.hemesh); Mat transform_b = {0}; pivot_world_transform(&entity_b.pivot, transform_b); //vbo_mesh_render(&entity_b.vbo_mesh, &flat_shader, &arcball.camera, transform_b); draw_halfedgemesh_wire(&global_dynamic_canvas, 0, transform_b, (Color){0, 255, 0, 255}, 0.02f, &entity_b.hemesh); Mat between_transform = {0}; pivot_between_transform(&entity_a.pivot, &entity_b.pivot, between_transform); Vec3f foo = {0}; mat_mul_vec(between_transform, entity_a.hemesh.vertices.array[0].position, foo); struct CollisionConvexConvex collision = {0}; struct CollisionParameter collision_parameter = { .face_tolerance = 0.9, .edge_tolerance = 0.95, .absolute_tolerance = 0.025 }; collision_create_convex_convex(&entity_a.hemesh, &entity_a.pivot, &entity_b.hemesh, &entity_b.pivot, collision_parameter, &collision); if( collision_test_convex_convex(&collision) ) { collision_contact_convex_convex(&collision); //printf("//collision: %d\n", collision_counter); const struct Contacts* contacts = &collision.contacts; VecP* m = contacts->points[contacts->num_contacts-1]; for( int32_t i = 0; i < contacts->num_contacts; i++ ) { VecP* n = contacts->points[i]; draw_line(&global_dynamic_canvas, 0, transform_b, (Color){255, 255, 255, 255}, 0.08f, m, n); m = n; } } gametime_integrate(&time); Vec4f screen_cursor = {0,0,0,1}; text_show_fps(&global_dynamic_canvas, 0, screen_cursor, 0, 0, (Color){255, 255, 255, 255}, 20.0, "default_font", time.frame); canvas_render_layers(&global_static_canvas, 0, 0, &arcball.camera, (Mat)IDENTITY_MAT); canvas_render_layers(&global_dynamic_canvas, 0, 0, &arcball.camera, (Mat)IDENTITY_MAT); canvas_clear(&global_dynamic_canvas); sdl2_gl_swap_window(window); } done: SDL_Quit(); printf("done\n"); return 0; }