diff --git a/src/main.cpp b/src/main.cpp index f9fea9a..128915a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -67,8 +67,8 @@ static WGPUBuffer tile_uvs_buffer; static WGPUSurfaceConfiguration surface_configuration; -static Sint32 window_width = 1280; -static Sint32 window_height = 720; +static i32vec2 window_size = { 1280, 720 }; +static i32vec2 framebuffer_size; static MIX_Mixer *mixer; static MIX_Track *music_track; @@ -99,6 +99,12 @@ static SDL_DateTime calendar_time; static vec2 mouse_pos; +static bool in_editor; + +static bool show_demo_window = false; +static bool show_tile_picker = false; +static bool show_settings = false; + #define log_error(...) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__) float remap(float in_a, float in_b, float out_a, float out_b, float v) { @@ -665,7 +671,7 @@ static vec3 Unproject(vec3 screen_pos) { } static vec2 get_floor_intersection_of_mouse(vec2 mouse_pos) { - vec2 mouse = remap(vec2(0, 0), vec2((float)window_width, (float)window_height), vec2(-1, 1), vec2(1, -1), mouse_pos); + vec2 mouse = remap(vec2(0, 0), window_size, vec2(-1, 1), vec2(1, -1), mouse_pos); vec3 camera_position = (vec4(0, 0, 0, 1) * inverse_view_matrix).xyz(); vec3 probe = Unproject(vec3(mouse, .5)); @@ -1642,6 +1648,724 @@ static void setup_working_directory() { change_directory(current_directory); } +static void process_event_editor(SDL_Event event) { + ZoneScopedN("process_event_editor"); + + ImGuiIO &io = ImGui::GetIO(); + + ImGui_ImplSDL3_ProcessEvent(&event); + + switch (event.type) { + case SDL_EVENT_KEY_DOWN: { + if (event.key.key == SDLK_F9) { + in_editor = !in_editor; + } + + if (io.WantCaptureKeyboard) + return; + + SDL_Keymod modifiers = SDL_GetModState(); + + if (event.key.key == SDLK_F1) { + save_map(current_map); + } + + if (event.key.key == SDLK_F4) { + char *map_path = SDL_strdup(current_map.name); + unload_map(¤t_map); + load_map(map_path, ¤t_map); + SDL_free(map_path); + } + + if (event.key.key == SDLK_F5) { + recreate_tile_textures(); + WGPUBindGroupEntry world_bind_group_entries[] = { + { .binding = 0, .textureView = tile_textures_atlas_view }, + { .binding = 1, .sampler = pixel_sampler }, + { .binding = 2, .buffer = tint_color_buffer, .offset = 0, .size = WGPU_WHOLE_SIZE }, + { .binding = 3, .buffer = tile_uvs_buffer, .offset = 0, .size = WGPU_WHOLE_SIZE }, + }; + + WGPUBindGroupDescriptor world_bind_group_descriptor = { + .label = { .data = "world_bind_group", .length = WGPU_STRLEN }, + .layout = wgpuRenderPipelineGetBindGroupLayout(world_render_pipeline, 1), + .entryCount = SDL_arraysize(world_bind_group_entries), + .entries = world_bind_group_entries, + }; + world_bind_group = wgpuDeviceCreateBindGroup(device, &world_bind_group_descriptor); + } + + if (event.key.key == SDLK_R) { + if (selected_tile != -1 && selected_rotation != -1) { + if (modifiers & SDL_KMOD_SHIFT) { + selected_rotation = (selected_rotation - 1) & 3; + } else { + selected_rotation = (selected_rotation + 1) & 3; + } + } + } + } break; + + case SDL_EVENT_MOUSE_BUTTON_DOWN: { + if (io.WantCaptureMouse) + return; + + vec2 floor_intersection = get_floor_intersection_of_mouse(vec2(event.button.x, event.button.y)); + i32vec2 tile_pos = grid_tile_pos_from_floor_intersection(floor_intersection); + + drag_start_pos = floor_intersection; + + if (selected_tile_kind != -1) { + change_map_tile(tile_pos.x, tile_pos.y, (TileKind)selected_tile_kind); + + if (-1 <= tile_pos.x && tile_pos.x < current_map.size.x && -1 <= tile_pos.y && tile_pos.y < current_map.size.y) { + dragging_tile_change = true; + } + } + + if (0 <= tile_pos.x && tile_pos.x < current_map.size.x && 0 <= tile_pos.y && tile_pos.y < current_map.size.y) { + dragging_tile_change = true; + } + + SDL_Keymod modifiers = SDL_GetModState(); + if (modifiers & SDL_KMOD_SHIFT && tile_pos.x <= -1) { + if(modifiers & SDL_KMOD_CTRL) + change_map_size(¤t_map, 'W', -1); + else + change_map_size(¤t_map, 'W', 1); + } + + if (modifiers & SDL_KMOD_SHIFT && tile_pos.x == current_map.size.x) { + if (modifiers & SDL_KMOD_CTRL) + change_map_size(¤t_map, 'E', -1); + else + change_map_size(¤t_map, 'E', 1); + } + + if (modifiers & SDL_KMOD_SHIFT && tile_pos.y <= -1) { + if (modifiers & SDL_KMOD_CTRL) + change_map_size(¤t_map, 'N', -1); + else + change_map_size(¤t_map, 'N', 1); + } + + if (modifiers & SDL_KMOD_SHIFT && tile_pos.y == current_map.size.y) { + if (modifiers & SDL_KMOD_CTRL) + change_map_size(¤t_map, 'S', -1); + else + change_map_size(¤t_map, 'S', 1); + } + } break; + + case SDL_EVENT_MOUSE_BUTTON_UP: { + if (io.WantCaptureMouse) + return; + + if (selected_tile != -1 && dragging_tile_change) { + vec2 floor_intersection = get_floor_intersection_of_mouse(vec2(event.button.x, event.button.y)); + i32vec2 tile_pos = grid_tile_pos_from_floor_intersection(floor_intersection); + + Sint32 tile_x = clamp(0, tile_pos.x, current_map.size.x - 1); + Sint32 tile_y = clamp(0, tile_pos.y, current_map.size.y - 1); + + i32vec2 drag_start = grid_tile_pos_from_floor_intersection(drag_start_pos); + + Sint32 start_x = min(tile_x, drag_start.x); + Sint32 start_y = min(tile_y, drag_start.y); + + Sint32 end_x = max(tile_x, drag_start.x); + Sint32 end_y = max(tile_y, drag_start.y); + + for (Sint32 y = start_y; y <= end_y; y++) { + for (Sint32 x = start_x; x <= end_x; x++) { + if (selected_rotation == -1) { + Sint32 rotation = SDL_rand(4); + current_map.tiles[x + current_map.size.x * y] = ((rotation & 3) << 16) | selected_tile; + } else { + current_map.tiles[x + current_map.size.x * y] = ((selected_rotation & 3) << 16) | selected_tile; + } + } + } + + update_buffer(current_map.gpu_buffer, 0, current_map.size.x * current_map.size.y * sizeof(Uint32), current_map.tiles); + } + + dragging_tile_change = false; + } break; + + case SDL_EVENT_MOUSE_MOTION: { + mouse_pos = vec2(event.motion.x, event.motion.y); + + if (selected_tile_kind != -1 && dragging_tile_change) { + vec2 floor_intersection = get_floor_intersection_of_mouse(mouse_pos); + i32vec2 tile_pos = grid_tile_pos_from_floor_intersection(floor_intersection); + change_map_tile(tile_pos.x, tile_pos.y, (TileKind)selected_tile_kind); + } + } break; + } +} + +static void update_state_editor() { + ZoneScopedN("update_state_editor"); + + ImGui_ImplWGPU_NewFrame(); + ImGui_ImplSDL3_NewFrame(); + ImGui::NewFrame(); + + if (ImGui::BeginMainMenuBar()) { + if (ImGui::BeginMenu("File")) { + ImGui::MenuItem("Settings", NULL, &show_settings); + ImGui::MenuItem("Demo Window", NULL, &show_demo_window); + ImGui::Separator(); + if (ImGui::MenuItem("Exit")) { + Running = false; + } + + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Edit")) { + ImGui::MenuItem("Tile Picker", NULL, &show_tile_picker); + ImGui::EndMenu(); + } + + ImGui::EndMainMenuBar(); + } + + ImGuiID main_viewport_dock = ImGui::GetID("main_viewport_dock"); + if (!ImGui::DockBuilderGetNode(main_viewport_dock)) { + ImGui::DockBuilderAddNode (main_viewport_dock, (ImGuiDockNodeFlags)ImGuiDockNodeFlags_DockSpace | ImGuiDockNodeFlags_AutoHideTabBar | ImGuiDockNodeFlags_PassthruCentralNode | ImGuiDockNodeFlags_NoDockingOverCentralNode); + ImGui::DockBuilderSetNodePos (main_viewport_dock, ImGui::GetMainViewport()->WorkPos); + ImGui::DockBuilderSetNodeSize(main_viewport_dock, ImGui::GetMainViewport()->WorkSize); + + ImGuiID left_dock = ImGui::DockBuilderSplitNode(main_viewport_dock, ImGuiDir_Left, 0.2f, NULL, NULL); + ImGui::DockBuilderDockWindow("Tile Picker", left_dock); + ImGui::DockBuilderFinish(main_viewport_dock); + } + ImGui::DockSpaceOverViewport(main_viewport_dock, ImGui::GetMainViewport(), ImGuiDockNodeFlags_AutoHideTabBar | ImGuiDockNodeFlags_PassthruCentralNode | ImGuiDockNodeFlags_NoDockingOverCentralNode); + + if (show_settings) { + ImGui::SetNextWindowSize(ImVec2(400, 0), ImGuiCond_FirstUseEver); + if (ImGui::Begin("Settings", &show_settings)) { + if (ImGui::DragFloat("Master", &volume_master, 1.0f, 0.0f, 100.0f, "%.0f", ImGuiSliderFlags_AlwaysClamp)) { + MIX_SetMixerGain(mixer, volume_master / 100.0f); + }; + if (ImGui::DragFloat("Music", &volume_music, 1.0f, 0.0f, 100.0f, "%.0f", ImGuiSliderFlags_AlwaysClamp)) { + MIX_SetTrackGain(music_track, volume_music / 100.0f); + } + if (ImGui::DragFloat("SFX", &volume_sfx, 1.0f, 0.0f, 100.0f, "%.0f", ImGuiSliderFlags_AlwaysClamp)) { + MIX_SetTrackGain(sfx_track, volume_sfx / 100.0f); + } + ImGui::NewLine(); + + ImGui::DragFloat("fovy", &camera_fovy_degrees); + ImGui::DragFloat("camera_distance", &camera_distance, 0.25f, 1.0f, INFINITY); + ImGui::DragFloat("camera_tilt", &camera_tilt, 0.25f, 0.0f, 89.0f); + + ImGui::NewLine(); + ImGui::BeginDisabled(use_actual_time); + ImGui::DragScalarN("Time", ImGuiDataType_S32, &calendar_time.hour, 3); + ImGui::EndDisabled(); + ImGui::Checkbox("use actual time", &use_actual_time); + ImGui::Checkbox("enable time based tinting", &enable_time_tints); + + ImGui::NewLine(); + for (int i = 0; i < num_used_tint_times; i++) { + ImGui::PushID(i); + imgui_time_picker("##time", time_tints_times[i]); + ImGui::PopID(); + } + + if (ImGui::Button("Add")) num_used_tint_times = clamp(1, num_used_tint_times + 1, MAX_TINT_TIMES); + ImGui::SameLine(); + if (ImGui::Button("Remove")) num_used_tint_times = clamp(1, num_used_tint_times - 1, MAX_TINT_TIMES); + + ImGui::NewLine(); + for (int i = 0; i < num_used_tint_times; i++) { + ImGui::PushID(i); + ImGui::ColorEdit3("##color", glm::value_ptr(time_tints[i])); + ImGui::PopID(); + } + + if (!ImGui::IsAnyItemActive()) { + for (int j = 0; j < num_used_tint_times; j++) { + for (int i = 0; i < num_used_tint_times - 1; i++) { + if (time_tints_times[i][0] > time_tints_times[i + 1][0] || + time_tints_times[i][0] == time_tints_times[i + 1][0] && time_tints_times[i][1] > time_tints_times[i + 1][1] || + time_tints_times[i][0] == time_tints_times[i + 1][0] && time_tints_times[i][1] == time_tints_times[i + 1][1] && time_tints_times[i][2] > time_tints_times[i + 1][2]) { + + int temp_time[3] = { time_tints_times[i][0], time_tints_times[i][1], time_tints_times[i][2] }; + vec3 temp_color = time_tints[i]; + + time_tints_times[i][0] = time_tints_times[i + 1][0]; + time_tints_times[i][1] = time_tints_times[i + 1][1]; + time_tints_times[i][2] = time_tints_times[i + 1][2]; + + time_tints[i] = time_tints[i + 1]; + + time_tints_times[i + 1][0] = temp_time[0]; + time_tints_times[i + 1][1] = temp_time[1]; + time_tints_times[i + 1][2] = temp_time[2]; + + time_tints[i + 1] = temp_color; + } + } + } + } + } + ImGui::End(); + } + + if (show_tile_picker) { + if (ImGui::Begin("Tile Picker", &show_tile_picker, ImGuiWindowFlags_NoFocusOnAppearing)) { + if (ImGui::Selectable("None", selected_tile_kind == -1 && selected_tile == -1)) { + selected_tile_kind = -1; + selected_tile = -1; + } + + if (ImGui::Selectable("Grass", selected_tile_kind == TILEKIND_GRASS)) { + selected_tile_kind = TILEKIND_GRASS; + selected_tile = -1; + } + + if (ImGui::Selectable("Ground", selected_tile_kind == TILEKIND_GROUND)) { + selected_tile_kind = TILEKIND_GROUND; + selected_tile = -1; + } + + for (int i = 0; i < SDL_arraysize(tile_infos); i++) { + ImGui::PushID(i); + + if (i != 0) + SameLineOrWrap(ImVec2(32, 32)); + + if (SelectableTile("##tile", selected_tile == i, i, ImVec2(32, 32), SDL_max(selected_rotation, 0))) { + selected_tile_kind = -1; + selected_tile = i; + } + + ImGui::PopID(); + } + + if (selected_tile != -1) { + ImGui::Text("Rotation:"); + + if (SelectableTile("##None", selected_rotation == 0, selected_tile, ImVec2(32, 32), 0)) + selected_rotation = 0; + + + SameLineOrWrap(ImVec2(32, 32)); + if (SelectableTile("##90", selected_rotation == 1, selected_tile, ImVec2(32, 32), 1)) + selected_rotation = 1; + + SameLineOrWrap(ImVec2(32, 32)); + if (SelectableTile("##180", selected_rotation == 2, selected_tile, ImVec2(32, 32), 2)) + selected_rotation = 2; + + SameLineOrWrap(ImVec2(32, 32)); + if (SelectableTile("##270", selected_rotation == 3, selected_tile, ImVec2(32, 32), 3)) + selected_rotation = 3; + + if (ImGui::Selectable("Random", selected_rotation == -1)) + selected_rotation = -1; + } + + if (selected_tile != -1 && ImGui::IsWindowFocused() && ImGui::IsKeyPressed(ImGuiKey_R, false)) { + if (ImGui::IsKeyDown(ImGuiKey_LeftShift)) { + selected_rotation = (selected_rotation - 1) & 3; + } else { + selected_rotation = (selected_rotation + 1) & 3; + } + } + } + ImGui::End(); + } else { + selected_tile = -1; + selected_tile_kind = -1; + } + + if (show_demo_window) + ImGui::ShowDemoWindow(&show_demo_window); +} + +static void render_editor(WGPURenderPassColorAttachment framebuffer) { + ZoneScopedN("render_editor"); + + { + ZoneScopedN("update buffers"); + { + ZoneScopedN("player_instance_buffer"); + player_instance.pos = player.position; + + update_buffer(player_instance_buffer, 0, sizeof(player_instance), &player_instance); + } + + { + ZoneScopedN("per_frame"); + + float aspect_ratio = ((float)window_size.x / (float)window_size.y); + + view_matrix = view (vec3(player.position, 0), radians(camera_tilt), camera_distance); + inverse_view_matrix = inverse_view(vec3(player.position, 0), radians(camera_tilt), camera_distance); + + projection_matrix = projection (radians(camera_fovy_degrees), aspect_ratio, NEAR_PLANE); + inverse_projection_matrix = inverse_projection(radians(camera_fovy_degrees), aspect_ratio, NEAR_PLANE); + + mat4x4 view_projection_matrix = view_matrix * projection_matrix; + update_buffer(view_projection_matrix_buffer, 0, sizeof(view_projection_matrix), &view_projection_matrix); + + vec2 floor_intersection = get_floor_intersection_of_mouse(mouse_pos); + i32vec2 tile_pos = grid_tile_pos_from_floor_intersection(floor_intersection); + + per_frame.map_width = current_map.size.x; + per_frame.grid_width = selected_tile != -1 ? current_map.size.x : current_map.size.x + 1; + per_frame.grid_offset = selected_tile != -1 ? vec2(-0.5f, -0.5f) : vec2(-1.0f, -1.0f); + per_frame.mouse = tile_pos; + + if (dragging_tile_change && selected_tile != -1) { + i32vec2 grid_tile_pos = grid_tile_pos_from_floor_intersection(drag_start_pos); + per_frame.drag_start = grid_tile_pos; + } else { + per_frame.drag_start = tile_pos; + } + + update_buffer(per_frame_buffer, 0, sizeof(per_frame), &per_frame); + } + + { + ZoneScopedN("tint color"); + Sint64 tint_times_ns[MAX_TINT_TIMES]; + for (int i = 0; i < num_used_tint_times; i++) + tint_times_ns[i] = (time_tints_times[i][0] * 60 * 60 + time_tints_times[i][1] * 60 + time_tints_times[i][2]) * SDL_NS_PER_SECOND; + tint_times_ns[num_used_tint_times] = (24 * 60 * 60 + 60 * 60 + 60) * SDL_NS_PER_SECOND + tint_times_ns[0]; + + Sint64 calendar_time_ns = (calendar_time.hour * 60 * 60 + calendar_time.minute * 60 + calendar_time.second) * SDL_NS_PER_SECOND + (Sint64)calendar_time.nanosecond; + + int last_time_index = num_used_tint_times - 1; + for (int i = 0; i < num_used_tint_times; i++) { + if (calendar_time_ns > tint_times_ns[i]) + last_time_index = i; + } + if (calendar_time_ns <= tint_times_ns[0]) calendar_time_ns += (24 * 60 * 60 + 60 * 60 + 60) * SDL_NS_PER_SECOND; + + Sint64 v = calendar_time_ns - tint_times_ns[last_time_index]; + Sint64 time_between = tint_times_ns[last_time_index + 1] - tint_times_ns[last_time_index]; + + double t = v / (double)time_between; + + vec3 tint_color = mix(time_tints[last_time_index], time_tints[(last_time_index + 1) % num_used_tint_times], t); + if (!enable_time_tints) tint_color = vec3(1, 1, 1); + update_buffer(tint_color_buffer, 0, sizeof(tint_color), &tint_color); + } + } + + WGPUCommandEncoder command_encoder = wgpuDeviceCreateCommandEncoder(device, NULL); + + WGPURenderPassDescriptor render_pass_descriptor = { + .label = { .data = "main_render_pass", .length = WGPU_STRLEN }, + .colorAttachmentCount = 1, + .colorAttachments = &framebuffer, + .depthStencilAttachment = NULL, + .occlusionQuerySet = NULL, + .timestampWrites = NULL, + }; + + WGPURenderPassEncoder render_pass_encoder = wgpuCommandEncoderBeginRenderPass(command_encoder, &render_pass_descriptor); + wgpuRenderPassEncoderSetBindGroup(render_pass_encoder, 0, per_frame_bind_group, 0, NULL); + + { // Draw Map + ZoneScopedN("Draw Map"); + wgpuRenderPassEncoderSetPipeline(render_pass_encoder, world_render_pipeline); + wgpuRenderPassEncoderSetIndexBuffer(render_pass_encoder, index_buffer, WGPUIndexFormat_Uint16, 0, WGPU_WHOLE_SIZE); + wgpuRenderPassEncoderSetVertexBuffer(render_pass_encoder, 0, vertex_buffer, 0, WGPU_WHOLE_SIZE); + wgpuRenderPassEncoderSetVertexBuffer(render_pass_encoder, 1, current_map.gpu_buffer, 0, WGPU_WHOLE_SIZE); + wgpuRenderPassEncoderSetBindGroup(render_pass_encoder, 1, world_bind_group, 0, NULL); + wgpuRenderPassEncoderDrawIndexed(render_pass_encoder, 6, current_map.size.y * current_map.size.x, 0, 0, 0); + } + + if (show_tile_picker) { // Draw Grid + ZoneScopedN("Draw Grid"); + + Uint32 num_grid_cells = current_map.size.y * current_map.size.x; + if (selected_tile == -1) + num_grid_cells = (current_map.size.y + 1) * (current_map.size.x + 1); + + wgpuRenderPassEncoderSetPipeline(render_pass_encoder, grid_render_pipeline); + wgpuRenderPassEncoderSetIndexBuffer(render_pass_encoder, grid_index_buffer, WGPUIndexFormat_Uint16, 0, WGPU_WHOLE_SIZE); + wgpuRenderPassEncoderSetVertexBuffer(render_pass_encoder, 0, grid_vertex_buffer, 0, WGPU_WHOLE_SIZE); + wgpuRenderPassEncoderDrawIndexed(render_pass_encoder, SDL_arraysize(grid_indices), num_grid_cells, 0, 0, 0); + } + + { + ZoneScopedN("ImGui Render"); + ImGui::Render(); + ImDrawData *draw_data = ImGui::GetDrawData(); + ImGui_ImplWGPU_RenderDrawData(draw_data, render_pass_encoder); + } + + wgpuRenderPassEncoderEnd(render_pass_encoder); + wgpuRenderPassEncoderRelease(render_pass_encoder); + + { + ZoneScopedN("SubmitGPUCommandBuffer"); + WGPUCommandBufferDescriptor command_buffer_descriptor = {}; + WGPUCommandBuffer command_buffer = wgpuCommandEncoderFinish(command_encoder, &command_buffer_descriptor); + wgpuCommandEncoderRelease(command_encoder); + wgpuQueueSubmit(queue, 1, &command_buffer); + wgpuCommandBufferRelease(command_buffer); + } +} + +static void process_event_game(SDL_Event event) { + ZoneScopedN("process_event"); + + switch (event.type) { + case SDL_EVENT_KEY_DOWN: { + if (event.key.key == SDLK_UP || event.key.key == SDLK_W) { + player.position.y = clamp(0, player.position.y + 1, current_map.size.y - 2); + } + + if (event.key.key == SDLK_LEFT || event.key.key == SDLK_A) { + player.position.x = clamp(0, player.position.x - 1, current_map.size.x - 2); + } + + if (event.key.key == SDLK_DOWN || event.key.key == SDLK_S) { + player.position.y = clamp(0, player.position.y - 1, current_map.size.y - 2); + } + + if (event.key.key == SDLK_RIGHT || event.key.key == SDLK_D) { + player.position.x = clamp(0, player.position.x + 1, current_map.size.x - 2); + } + + if (event.key.key == SDLK_F9) { + in_editor = !in_editor; + } + } break; + + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: { + if (event.gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_UP) { + player.position.y = clamp(0, player.position.y + 1, current_map.size.y - 2); + } + + if (event.gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_LEFT) { + player.position.x = clamp(0, player.position.x - 1, current_map.size.x - 2); + } + + if (event.gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_DOWN) { + player.position.y = clamp(0, player.position.y - 1, current_map.size.y - 2); + } + + if (event.gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_RIGHT) { + player.position.x = clamp(0, player.position.x + 1, current_map.size.x - 2); + } + } break; + } +} + +static void update_state_game() { + ZoneScopedN("update_state_game"); + + if (!MIX_TrackPlaying(music_track)) { + MIX_SetTrackAudio(music_track, music_setting_off_piano); + MIX_PlayTrack(music_track, 0); + } +} + +static void render_game(WGPURenderPassColorAttachment framebuffer) { + ZoneScopedN("render_game"); + + { + ZoneScopedN("update buffers"); + { + ZoneScopedN("player_instance_buffer"); + player_instance.pos = player.position; + + update_buffer(player_instance_buffer, 0, sizeof(player_instance), &player_instance); + } + + { + ZoneScopedN("per_frame"); + + float aspect_ratio = ((float)window_size.x / (float)window_size.y); + + view_matrix = view (vec3(player.position, 0), radians(camera_tilt), camera_distance); + inverse_view_matrix = inverse_view(vec3(player.position, 0), radians(camera_tilt), camera_distance); + + projection_matrix = projection (radians(camera_fovy_degrees), aspect_ratio, NEAR_PLANE); + inverse_projection_matrix = inverse_projection(radians(camera_fovy_degrees), aspect_ratio, NEAR_PLANE); + + mat4x4 view_projection_matrix = view_matrix * projection_matrix; + update_buffer(view_projection_matrix_buffer, 0, sizeof(view_projection_matrix), &view_projection_matrix); + + per_frame.map_width = current_map.size.x; + update_buffer(per_frame_buffer, 0, sizeof(per_frame), &per_frame); + } + + { + ZoneScopedN("tint color"); + Sint64 tint_times_ns[MAX_TINT_TIMES]; + for (int i = 0; i < num_used_tint_times; i++) + tint_times_ns[i] = (time_tints_times[i][0] * 60 * 60 + time_tints_times[i][1] * 60 + time_tints_times[i][2]) * SDL_NS_PER_SECOND; + tint_times_ns[num_used_tint_times] = (24 * 60 * 60 + 60 * 60 + 60) * SDL_NS_PER_SECOND + tint_times_ns[0]; + + Sint64 calendar_time_ns = (calendar_time.hour * 60 * 60 + calendar_time.minute * 60 + calendar_time.second) * SDL_NS_PER_SECOND + (Sint64)calendar_time.nanosecond; + + int last_time_index = num_used_tint_times - 1; + for (int i = 0; i < num_used_tint_times; i++) { + if (calendar_time_ns > tint_times_ns[i]) + last_time_index = i; + } + if (calendar_time_ns <= tint_times_ns[0]) calendar_time_ns += (24 * 60 * 60 + 60 * 60 + 60) * SDL_NS_PER_SECOND; + + Sint64 v = calendar_time_ns - tint_times_ns[last_time_index]; + Sint64 time_between = tint_times_ns[last_time_index + 1] - tint_times_ns[last_time_index]; + + double t = v / (double)time_between; + + vec3 tint_color = mix(time_tints[last_time_index], time_tints[(last_time_index + 1) % num_used_tint_times], t); + if (!enable_time_tints) tint_color = vec3(1, 1, 1); + update_buffer(tint_color_buffer, 0, sizeof(tint_color), &tint_color); + } + } + + WGPUCommandEncoder command_encoder = wgpuDeviceCreateCommandEncoder(device, NULL); + + WGPURenderPassDescriptor render_pass_descriptor = { + .label = { .data = "main_render_pass", .length = WGPU_STRLEN }, + .colorAttachmentCount = 1, + .colorAttachments = &framebuffer, + .depthStencilAttachment = NULL, + .occlusionQuerySet = NULL, + .timestampWrites = NULL, + }; + + WGPURenderPassEncoder render_pass_encoder = wgpuCommandEncoderBeginRenderPass(command_encoder, &render_pass_descriptor); + wgpuRenderPassEncoderSetBindGroup(render_pass_encoder, 0, per_frame_bind_group, 0, NULL); + + { // Draw Map + ZoneScopedN("Draw Map"); + wgpuRenderPassEncoderSetPipeline(render_pass_encoder, world_render_pipeline); + wgpuRenderPassEncoderSetIndexBuffer(render_pass_encoder, index_buffer, WGPUIndexFormat_Uint16, 0, WGPU_WHOLE_SIZE); + wgpuRenderPassEncoderSetVertexBuffer(render_pass_encoder, 0, vertex_buffer, 0, WGPU_WHOLE_SIZE); + wgpuRenderPassEncoderSetVertexBuffer(render_pass_encoder, 1, current_map.gpu_buffer, 0, WGPU_WHOLE_SIZE); + wgpuRenderPassEncoderSetBindGroup(render_pass_encoder, 1, world_bind_group, 0, NULL); + wgpuRenderPassEncoderDrawIndexed(render_pass_encoder, 6, current_map.size.y * current_map.size.x, 0, 0, 0); + } + + { // Draw Player + ZoneScopedN("Draw Player"); + wgpuRenderPassEncoderSetPipeline(render_pass_encoder, basic_render_pipeline); + wgpuRenderPassEncoderSetIndexBuffer(render_pass_encoder, index_buffer, WGPUIndexFormat_Uint16, 0, WGPU_WHOLE_SIZE); + wgpuRenderPassEncoderSetVertexBuffer(render_pass_encoder, 0, vertex_buffer, 0, WGPU_WHOLE_SIZE); + wgpuRenderPassEncoderSetVertexBuffer(render_pass_encoder, 1, player_instance_buffer, 0, WGPU_WHOLE_SIZE); + wgpuRenderPassEncoderSetBindGroup(render_pass_encoder, 1, basic_bind_group, 0, NULL); + wgpuRenderPassEncoderDrawIndexed(render_pass_encoder, 6, 1, 0, 0, 0); + } + + wgpuRenderPassEncoderEnd(render_pass_encoder); + wgpuRenderPassEncoderRelease(render_pass_encoder); + + { + ZoneScopedN("SubmitGPUCommandBuffer"); + WGPUCommandBuffer command_buffer = wgpuCommandEncoderFinish(command_encoder, NULL); + wgpuCommandEncoderRelease(command_encoder); + wgpuQueueSubmit(queue, 1, &command_buffer); + wgpuCommandBufferRelease(command_buffer); + } +} + +static void process_events() { + ZoneScopedN("process_events"); + + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_EVENT_QUIT: { + Running = false; + } break; + + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: { + window_size.x = event.window.data1; + window_size.y = event.window.data2; + } break; + } + + if (in_editor) { + process_event_editor(event); + } else { + process_event_game(event); + } + } +} + +static void update_state() { + ZoneScopedN("update_state"); + + SDL_GetCurrentTime(&time); + + if (use_actual_time) + SDL_TimeToDateTime(time, &calendar_time, true); + + calendar_time.minute += calendar_time.second >= 0 ? calendar_time.second / 60 : calendar_time.second / 60 - 1; + calendar_time.hour += calendar_time.minute >= 0 ? calendar_time.minute / 60 : calendar_time.minute / 60 - 1; + + calendar_time.second = real_mod(calendar_time.second, 60); + calendar_time.minute = real_mod(calendar_time.minute, 60); + calendar_time.hour = real_mod(calendar_time.hour, 24); + + if (in_editor) { + update_state_editor(); + } else { + update_state_game(); + } +} + +static void render(WGPUTexture surface_texture) { + ZoneScopedN("render"); + + u32vec2 surface_size = { wgpuTextureGetWidth(surface_texture), wgpuTextureGetHeight(surface_texture) }; + + if (framebuffer_size.x != surface_size.x || framebuffer_size.x != surface_size.y) { + if (framebuffer) wgpuTextureRelease(framebuffer); + + WGPUTextureDescriptor descriptor = { + .label = { .data = "framebuffer", .length = WGPU_STRLEN }, + .usage = WGPUTextureUsage_RenderAttachment, + .dimension = WGPUTextureDimension_2D, + .size = { .width = surface_size.x, .height = surface_size.y, .depthOrArrayLayers = 1 }, + .format = surface_configuration.format, + .mipLevelCount = 1, + .sampleCount = 4, + .viewFormatCount = 0, + .viewFormats = NULL, + }; + + framebuffer = wgpuDeviceCreateTexture(device, &descriptor); + framebuffer_size = surface_size; + } + + WGPUTextureView surface_texture_view = wgpuTextureCreateView(surface_texture, NULL); + WGPUTextureView framebuffer_view = wgpuTextureCreateView(framebuffer, NULL); + + WGPURenderPassColorAttachment framebuffer_color_attachment = { + .view = framebuffer_view, + .depthSlice = WGPU_DEPTH_SLICE_UNDEFINED, + .resolveTarget = surface_texture_view, + .loadOp = WGPULoadOp_Clear, + .storeOp = WGPUStoreOp_Discard, + .clearValue = { .r = 0.01f, .g = 0.01f, .b = 0.01f, .a = 1.0f }, + }; + + if (in_editor) { + render_editor(framebuffer_color_attachment); + } else { + render_game(framebuffer_color_attachment); + } + + wgpuTextureViewRelease(framebuffer_view); + wgpuTextureViewRelease(surface_texture_view); +} + int main(int argc, char **argv) { setup_memory_functions(); setup_working_directory(); @@ -1661,7 +2385,7 @@ int main(int argc, char **argv) { return 1; } - window = SDL_CreateWindow("Mikemon", window_width, window_height, SDL_WINDOW_RESIZABLE); + window = SDL_CreateWindow("Mikemon", window_size.x, window_size.y, SDL_WINDOW_RESIZABLE); if (!window) { log_error("Failed to create window (%s). Exiting.", SDL_GetError()); return 1; @@ -1789,214 +2513,10 @@ int main(int argc, char **argv) { }; ImGui::AddSettingsHandler(&settings_handler); - bool first_frame = true; - bool show_demo_window = false; - bool show_tile_picker = false; - bool show_settings = false; + SDL_GetWindowSizeInPixels(window, &window_size.x, &window_size.y); - SDL_GetWindowSizeInPixels(window, &window_width, &window_height); - - Uint32 framebuffer_width = 0; - Uint32 framebuffer_height = 0; - - // MSG Message; while (Running) { - ZoneScopedN("Loop"); - ImGui_ImplWGPU_NewFrame(); - ImGui_ImplSDL3_NewFrame(); - ImGui::NewFrame(); - - SDL_GetCurrentTime(&time); - - if (use_actual_time) - SDL_TimeToDateTime(time, &calendar_time, true); - - calendar_time.minute += calendar_time.second >= 0 ? calendar_time.second / 60 : calendar_time.second / 60 - 1; - calendar_time.hour += calendar_time.minute >= 0 ? calendar_time.minute / 60 : calendar_time.minute / 60 - 1; - - calendar_time.second = real_mod(calendar_time.second, 60); - calendar_time.minute = real_mod(calendar_time.minute, 60); - calendar_time.hour = real_mod(calendar_time.hour, 24); - - if (ImGui::BeginMainMenuBar()) { - if (ImGui::BeginMenu("File")) { - ImGui::MenuItem("Settings", NULL, &show_settings); - ImGui::MenuItem("Demo Window", NULL, &show_demo_window); - ImGui::Separator(); - if (ImGui::MenuItem("Exit")) { - Running = false; - } - - ImGui::EndMenu(); - } - - if (ImGui::BeginMenu("Edit")) { - ImGui::MenuItem("Tile Picker", NULL, &show_tile_picker); - ImGui::EndMenu(); - } - - ImGui::EndMainMenuBar(); - } - - ImGuiID main_viewport_dock = ImGui::GetID("main_viewport_dock"); - if (!ImGui::DockBuilderGetNode(main_viewport_dock)) { - ImGui::DockBuilderAddNode (main_viewport_dock, (ImGuiDockNodeFlags)ImGuiDockNodeFlags_DockSpace | ImGuiDockNodeFlags_AutoHideTabBar | ImGuiDockNodeFlags_PassthruCentralNode | ImGuiDockNodeFlags_NoDockingOverCentralNode); - ImGui::DockBuilderSetNodePos (main_viewport_dock, ImGui::GetMainViewport()->WorkPos); - ImGui::DockBuilderSetNodeSize(main_viewport_dock, ImGui::GetMainViewport()->WorkSize); - - ImGuiID left_dock = ImGui::DockBuilderSplitNode(main_viewport_dock, ImGuiDir_Left, 0.2f, NULL, NULL); - ImGui::DockBuilderDockWindow("Tile Picker", left_dock); - ImGui::DockBuilderFinish(main_viewport_dock); - } - ImGui::DockSpaceOverViewport(main_viewport_dock, ImGui::GetMainViewport(), ImGuiDockNodeFlags_AutoHideTabBar | ImGuiDockNodeFlags_PassthruCentralNode | ImGuiDockNodeFlags_NoDockingOverCentralNode); - - if (show_settings) { - ImGui::SetNextWindowSize(ImVec2(400, 0), ImGuiCond_FirstUseEver); - if (ImGui::Begin("Settings", &show_settings)) { - if (ImGui::DragFloat("Master", &volume_master, 1.0f, 0.0f, 100.0f, "%.0f", ImGuiSliderFlags_AlwaysClamp)) { - MIX_SetMixerGain(mixer, volume_master / 100.0f); - }; - if (ImGui::DragFloat("Music", &volume_music, 1.0f, 0.0f, 100.0f, "%.0f", ImGuiSliderFlags_AlwaysClamp)) { - MIX_SetTrackGain(music_track, volume_music / 100.0f); - } - if (ImGui::DragFloat("SFX", &volume_sfx, 1.0f, 0.0f, 100.0f, "%.0f", ImGuiSliderFlags_AlwaysClamp)) { - MIX_SetTrackGain(sfx_track, volume_sfx / 100.0f); - } - ImGui::NewLine(); - - ImGui::DragFloat("fovy", &camera_fovy_degrees); - ImGui::DragFloat("camera_distance", &camera_distance, 0.25f, 1.0f, INFINITY); - ImGui::DragFloat("camera_tilt", &camera_tilt, 0.25f, 0.0f, 89.0f); - - ImGui::NewLine(); - ImGui::BeginDisabled(use_actual_time); - ImGui::DragScalarN("Time", ImGuiDataType_S32, &calendar_time.hour, 3); - ImGui::EndDisabled(); - ImGui::Checkbox("use actual time", &use_actual_time); - ImGui::Checkbox("enable time based tinting", &enable_time_tints); - - ImGui::NewLine(); - for (int i = 0; i < num_used_tint_times; i++) { - ImGui::PushID(i); - imgui_time_picker("##time", time_tints_times[i]); - ImGui::PopID(); - } - - if (ImGui::Button("Add")) num_used_tint_times = clamp(1, num_used_tint_times + 1, MAX_TINT_TIMES); - ImGui::SameLine(); - if (ImGui::Button("Remove")) num_used_tint_times = clamp(1, num_used_tint_times - 1, MAX_TINT_TIMES); - - ImGui::NewLine(); - for (int i = 0; i < num_used_tint_times; i++) { - ImGui::PushID(i); - ImGui::ColorEdit3("##color", glm::value_ptr(time_tints[i])); - ImGui::PopID(); - } - - if (!ImGui::IsAnyItemActive()) { - for (int j = 0; j < num_used_tint_times; j++) { - for (int i = 0; i < num_used_tint_times - 1; i++) { - if (time_tints_times[i][0] > time_tints_times[i + 1][0] || - time_tints_times[i][0] == time_tints_times[i + 1][0] && time_tints_times[i][1] > time_tints_times[i + 1][1] || - time_tints_times[i][0] == time_tints_times[i + 1][0] && time_tints_times[i][1] == time_tints_times[i + 1][1] && time_tints_times[i][2] > time_tints_times[i + 1][2]) { - - int temp_time[3] = { time_tints_times[i][0], time_tints_times[i][1], time_tints_times[i][2] }; - vec3 temp_color = time_tints[i]; - - time_tints_times[i][0] = time_tints_times[i + 1][0]; - time_tints_times[i][1] = time_tints_times[i + 1][1]; - time_tints_times[i][2] = time_tints_times[i + 1][2]; - - time_tints[i] = time_tints[i + 1]; - - time_tints_times[i + 1][0] = temp_time[0]; - time_tints_times[i + 1][1] = temp_time[1]; - time_tints_times[i + 1][2] = temp_time[2]; - - time_tints[i + 1] = temp_color; - } - } - } - } - } - ImGui::End(); - } - - if (show_tile_picker) { - if (ImGui::Begin("Tile Picker", &show_tile_picker, ImGuiWindowFlags_NoFocusOnAppearing)) { - if (ImGui::Selectable("None", selected_tile_kind == -1 && selected_tile == -1)) { - selected_tile_kind = -1; - selected_tile = -1; - } - - if (ImGui::Selectable("Grass", selected_tile_kind == TILEKIND_GRASS)) { - selected_tile_kind = TILEKIND_GRASS; - selected_tile = -1; - } - - if (ImGui::Selectable("Ground", selected_tile_kind == TILEKIND_GROUND)) { - selected_tile_kind = TILEKIND_GROUND; - selected_tile = -1; - } - - for (int i = 0; i < SDL_arraysize(tile_infos); i++) { - ImGui::PushID(i); - - if (i != 0) - SameLineOrWrap(ImVec2(32, 32)); - - if (SelectableTile("##tile", selected_tile == i, i, ImVec2(32, 32), SDL_max(selected_rotation, 0))) { - selected_tile_kind = -1; - selected_tile = i; - } - - ImGui::PopID(); - } - - if (selected_tile != -1) { - ImGui::Text("Rotation:"); - - if (SelectableTile("##None", selected_rotation == 0, selected_tile, ImVec2(32, 32), 0)) - selected_rotation = 0; - - - SameLineOrWrap(ImVec2(32, 32)); - if (SelectableTile("##90", selected_rotation == 1, selected_tile, ImVec2(32, 32), 1)) - selected_rotation = 1; - - SameLineOrWrap(ImVec2(32, 32)); - if (SelectableTile("##180", selected_rotation == 2, selected_tile, ImVec2(32, 32), 2)) - selected_rotation = 2; - - SameLineOrWrap(ImVec2(32, 32)); - if (SelectableTile("##270", selected_rotation == 3, selected_tile, ImVec2(32, 32), 3)) - selected_rotation = 3; - - if (ImGui::Selectable("Random", selected_rotation == -1)) - selected_rotation = -1; - } - - if (selected_tile != -1 && ImGui::IsWindowFocused() && ImGui::IsKeyPressed(ImGuiKey_R, false)) { - if (ImGui::IsKeyDown(ImGuiKey_LeftShift)) { - selected_rotation = (selected_rotation - 1) & 3; - } else { - selected_rotation = (selected_rotation + 1) & 3; - } - } - } - ImGui::End(); - } else { - selected_tile = -1; - selected_tile_kind = -1; - } - - if (show_demo_window) - ImGui::ShowDemoWindow(&show_demo_window); - - if (first_frame) { - ImGui::SetWindowFocus(NULL); - first_frame = false; - } + ZoneScopedN("main_loop"); TracyCZoneN(tracy_wgpuSurfaceGetCurrentTexture, "wgpuSurfaceGetCurrentTexture", true); WGPUSurfaceTexture surface_texture = {}; @@ -2008,399 +2528,28 @@ int main(int argc, char **argv) { WGPUTextureView surface_texture_view = wgpuTextureCreateView(surface_texture.texture, NULL); TracyCZoneEnd(tracy_wgpuSurfaceGetCurrentTexture); - { - ZoneScopedN("Events"); - SDL_Event event; - while (SDL_PollEvent(&event)) { - ZoneScopedN("Event"); - ImGui_ImplSDL3_ProcessEvent(&event); + process_events(); - switch (event.type) { - case SDL_EVENT_QUIT: { - Running = false; - } break; - - case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: { - window_width = event.window.data1; - window_height = event.window.data2; - } break; - - case SDL_EVENT_KEY_DOWN: { - if (io.WantCaptureKeyboard) - continue; - - SDL_Keymod modifiers = SDL_GetModState(); - - if (event.key.key == SDLK_UP || event.key.key == SDLK_W) { - player.position.y = clamp(0, player.position.y + 1, current_map.size.y - 2); - } - - if (event.key.key == SDLK_LEFT || event.key.key == SDLK_A) { - player.position.x = clamp(0, player.position.x - 1, current_map.size.x - 2); - } - - if (event.key.key == SDLK_DOWN || event.key.key == SDLK_S) { - player.position.y = clamp(0, player.position.y - 1, current_map.size.y - 2); - } - - if (event.key.key == SDLK_RIGHT || event.key.key == SDLK_D) { - player.position.x = clamp(0, player.position.x + 1, current_map.size.x - 2); - } - - if (event.key.key == SDLK_F1) { - save_map(current_map); - } - - if (event.key.key == SDLK_F4) { - char *map_path = SDL_strdup(current_map.name); - unload_map(¤t_map); - load_map(map_path, ¤t_map); - SDL_free(map_path); - } - - if (event.key.key == SDLK_F5) { - recreate_tile_textures(); - WGPUBindGroupEntry world_bind_group_entries[] = { - { .binding = 0, .textureView = tile_textures_atlas_view }, - { .binding = 1, .sampler = pixel_sampler }, - { .binding = 2, .buffer = tint_color_buffer, .offset = 0, .size = WGPU_WHOLE_SIZE }, - { .binding = 3, .buffer = tile_uvs_buffer, .offset = 0, .size = WGPU_WHOLE_SIZE }, - }; - - WGPUBindGroupDescriptor world_bind_group_descriptor = { - .label = { .data = "world_bind_group", .length = WGPU_STRLEN }, - .layout = wgpuRenderPipelineGetBindGroupLayout(world_render_pipeline, 1), - .entryCount = SDL_arraysize(world_bind_group_entries), - .entries = world_bind_group_entries, - }; - world_bind_group = wgpuDeviceCreateBindGroup(device, &world_bind_group_descriptor); - } - - if (event.key.key == SDLK_R) { - if (selected_tile != -1 && selected_rotation != -1) { - if (modifiers & SDL_KMOD_SHIFT) { - selected_rotation = (selected_rotation - 1) & 3; - } else { - selected_rotation = (selected_rotation + 1) & 3; - } - } - } - } break; - - case SDL_EVENT_MOUSE_BUTTON_DOWN: { - if (io.WantCaptureMouse) - continue; - - vec2 floor_intersection = get_floor_intersection_of_mouse(vec2(event.button.x, event.button.y)); - i32vec2 tile_pos = grid_tile_pos_from_floor_intersection(floor_intersection); - - drag_start_pos = floor_intersection; - - if (selected_tile_kind != -1) { - change_map_tile(tile_pos.x, tile_pos.y, (TileKind)selected_tile_kind); - - if (-1 <= tile_pos.x && tile_pos.x < current_map.size.x && -1 <= tile_pos.y && tile_pos.y < current_map.size.y) { - dragging_tile_change = true; - } - } - - if (0 <= tile_pos.x && tile_pos.x < current_map.size.x && 0 <= tile_pos.y && tile_pos.y < current_map.size.y) { - dragging_tile_change = true; - } - - SDL_Keymod modifiers = SDL_GetModState(); - if (modifiers & SDL_KMOD_SHIFT && tile_pos.x <= -1) { - if(modifiers & SDL_KMOD_CTRL) - change_map_size(¤t_map, 'W', -1); - else - change_map_size(¤t_map, 'W', 1); - } - - if (modifiers & SDL_KMOD_SHIFT && tile_pos.x == current_map.size.x) { - if (modifiers & SDL_KMOD_CTRL) - change_map_size(¤t_map, 'E', -1); - else - change_map_size(¤t_map, 'E', 1); - } - - if (modifiers & SDL_KMOD_SHIFT && tile_pos.y <= -1) { - if (modifiers & SDL_KMOD_CTRL) - change_map_size(¤t_map, 'N', -1); - else - change_map_size(¤t_map, 'N', 1); - } - - if (modifiers & SDL_KMOD_SHIFT && tile_pos.y == current_map.size.y) { - if (modifiers & SDL_KMOD_CTRL) - change_map_size(¤t_map, 'S', -1); - else - change_map_size(¤t_map, 'S', 1); - } - } break; - - case SDL_EVENT_MOUSE_BUTTON_UP: { - if (io.WantCaptureMouse) - continue; - - if (selected_tile != -1 && dragging_tile_change) { - vec2 floor_intersection = get_floor_intersection_of_mouse(vec2(event.button.x, event.button.y)); - i32vec2 tile_pos = grid_tile_pos_from_floor_intersection(floor_intersection); - - Sint32 tile_x = clamp(0, tile_pos.x, current_map.size.x - 1); - Sint32 tile_y = clamp(0, tile_pos.y, current_map.size.y - 1); - - i32vec2 drag_start = grid_tile_pos_from_floor_intersection(drag_start_pos); - - Sint32 start_x = min(tile_x, drag_start.x); - Sint32 start_y = min(tile_y, drag_start.y); - - Sint32 end_x = max(tile_x, drag_start.x); - Sint32 end_y = max(tile_y, drag_start.y); - - for (Sint32 y = start_y; y <= end_y; y++) { - for (Sint32 x = start_x; x <= end_x; x++) { - if (selected_rotation == -1) { - Sint32 rotation = SDL_rand(4); - current_map.tiles[x + current_map.size.x * y] = ((rotation & 3) << 16) | selected_tile; - } else { - current_map.tiles[x + current_map.size.x * y] = ((selected_rotation & 3) << 16) | selected_tile; - } - } - } - - update_buffer(current_map.gpu_buffer, 0, current_map.size.x * current_map.size.y * sizeof(Uint32), current_map.tiles); - } - - dragging_tile_change = false; - } break; - - case SDL_EVENT_MOUSE_MOTION: { - mouse_pos = vec2(event.motion.x, event.motion.y); - - if (selected_tile_kind != -1 && dragging_tile_change) { - vec2 floor_intersection = get_floor_intersection_of_mouse(mouse_pos); - i32vec2 tile_pos = grid_tile_pos_from_floor_intersection(floor_intersection); - change_map_tile(tile_pos.x, tile_pos.y, (TileKind)selected_tile_kind); - } - } break; - - case SDL_EVENT_GAMEPAD_BUTTON_DOWN: { - if (io.WantCaptureKeyboard) - continue; - - if (event.gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_UP) { - player.position.y = clamp(0, player.position.y + 1, current_map.size.y - 2); - } - - if (event.gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_LEFT) { - player.position.x = clamp(0, player.position.x - 1, current_map.size.x - 2); - } - - if (event.gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_DOWN) { - player.position.y = clamp(0, player.position.y - 1, current_map.size.y - 2); - } - - if (event.gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_RIGHT) { - player.position.x = clamp(0, player.position.x + 1, current_map.size.x - 2); - } - } break; - } - } - } - - if (!MIX_TrackPlaying(music_track)) { - MIX_SetTrackAudio(music_track, music_setting_off_piano); - MIX_PlayTrack(music_track, 0); - } - - Uint32 surface_width = wgpuTextureGetWidth (surface_texture.texture); - Uint32 surface_height = wgpuTextureGetHeight(surface_texture.texture); - if (surface_width != window_width || surface_height != window_height) { + i32vec2 surface_size = { wgpuTextureGetWidth(surface_texture.texture), wgpuTextureGetHeight(surface_texture.texture) }; + if (surface_size != window_size) { wgpuTextureViewRelease(surface_texture_view); wgpuTextureRelease(surface_texture.texture); - ImGui::EndFrame(); - surface_configuration.width = window_width; - surface_configuration.height = window_height; + surface_configuration.width = window_size.x; + surface_configuration.height = window_size.y; wgpuSurfaceConfigure(surface, &surface_configuration); continue; } - if (framebuffer_width != surface_width || framebuffer_height != surface_height) { - if (framebuffer) wgpuTextureRelease(framebuffer); - - WGPUTextureDescriptor descriptor = { - .label = { .data = "framebuffer", .length = WGPU_STRLEN }, - .usage = WGPUTextureUsage_RenderAttachment, - .dimension = WGPUTextureDimension_2D, - .size = { .width = surface_width, .height = surface_height, .depthOrArrayLayers = 1 }, - .format = surface_configuration.format, - .mipLevelCount = 1, - .sampleCount = 4, - .viewFormatCount = 0, - .viewFormats = NULL, - }; - - framebuffer = wgpuDeviceCreateTexture(device, &descriptor); - framebuffer_width = surface_width; - framebuffer_height = surface_height; - } - - WGPUTextureView framebuffer_view = wgpuTextureCreateView(framebuffer, NULL); - - WGPUCommandEncoderDescriptor command_encoder_descriptor = {}; - WGPUCommandEncoder command_encoder = wgpuDeviceCreateCommandEncoder(device, &command_encoder_descriptor); - - { - ZoneScopedN("Update"); - { - ZoneScopedN("player_instance_buffer"); - player_instance.pos = player.position; - - update_buffer(player_instance_buffer, 0, sizeof(player_instance), &player_instance); - } - - { - ZoneScopedN("per_frame"); - - float aspect_ratio = ((float) window_width / (float) window_height); - - view_matrix = view (vec3(player.position, 0), radians(camera_tilt), camera_distance); - inverse_view_matrix = inverse_view(vec3(player.position, 0), radians(camera_tilt), camera_distance); - - projection_matrix = projection (radians(camera_fovy_degrees), aspect_ratio, NEAR_PLANE); - inverse_projection_matrix = inverse_projection(radians(camera_fovy_degrees), aspect_ratio, NEAR_PLANE); - - mat4x4 view_projection_matrix = view_matrix * projection_matrix; - update_buffer(view_projection_matrix_buffer, 0, sizeof(view_projection_matrix), &view_projection_matrix); - - vec2 floor_intersection = get_floor_intersection_of_mouse(mouse_pos); - i32vec2 tile_pos = grid_tile_pos_from_floor_intersection(floor_intersection); - - per_frame.map_width = current_map.size.x; - per_frame.grid_width = selected_tile != -1 ? current_map.size.x : current_map.size.x + 1; - per_frame.grid_offset = selected_tile != -1 ? vec2(-0.5f, -0.5f) : vec2(-1.0f, -1.0f); - per_frame.mouse = tile_pos; - - if (dragging_tile_change && selected_tile != -1) { - i32vec2 grid_tile_pos = grid_tile_pos_from_floor_intersection(drag_start_pos); - per_frame.drag_start = grid_tile_pos; - } else { - per_frame.drag_start = tile_pos; - } - - update_buffer(per_frame_buffer, 0, sizeof(per_frame), &per_frame); - } - - { - ZoneScopedN("tint color"); - Sint64 tint_times_ns[MAX_TINT_TIMES]; - for (int i = 0; i < num_used_tint_times; i++) - tint_times_ns[i] = (time_tints_times[i][0] * 60 * 60 + time_tints_times[i][1] * 60 + time_tints_times[i][2]) * SDL_NS_PER_SECOND; - tint_times_ns[num_used_tint_times] = (24 * 60 * 60 + 60 * 60 + 60) * SDL_NS_PER_SECOND + tint_times_ns[0]; - - Sint64 calendar_time_ns = (calendar_time.hour * 60 * 60 + calendar_time.minute * 60 + calendar_time.second) * SDL_NS_PER_SECOND + (Sint64)calendar_time.nanosecond; - - int last_time_index = num_used_tint_times - 1; - for (int i = 0; i < num_used_tint_times; i++) { - if (calendar_time_ns > tint_times_ns[i]) - last_time_index = i; - } - if (calendar_time_ns <= tint_times_ns[0]) calendar_time_ns += (24 * 60 * 60 + 60 * 60 + 60) * SDL_NS_PER_SECOND; - - Sint64 v = calendar_time_ns - tint_times_ns[last_time_index]; - Sint64 time_between = tint_times_ns[last_time_index + 1] - tint_times_ns[last_time_index]; - - double t = v / (double)time_between; - - vec3 tint_color = mix(time_tints[last_time_index], time_tints[(last_time_index + 1) % num_used_tint_times], t); - if (!enable_time_tints) tint_color = vec3(1, 1, 1); - update_buffer(tint_color_buffer, 0, sizeof(tint_color), &tint_color); - } - } - - WGPURenderPassColorAttachment render_pass_color_attachment = { - .view = framebuffer_view, - .depthSlice = WGPU_DEPTH_SLICE_UNDEFINED, - .resolveTarget = surface_texture_view, - .loadOp = WGPULoadOp_Clear, - .storeOp = WGPUStoreOp_Discard, - .clearValue = { .r = 0.01f, .g = 0.01f, .b = 0.01f, .a = 1.0f }, - }; - - WGPURenderPassDescriptor render_pass_descriptor = { - .label = { .data = "main_render_pass", .length = WGPU_STRLEN }, - .colorAttachmentCount = 1, - .colorAttachments = &render_pass_color_attachment, - .depthStencilAttachment = NULL, - .occlusionQuerySet = NULL, - .timestampWrites = NULL, - }; - - WGPURenderPassEncoder render_pass_encoder = wgpuCommandEncoderBeginRenderPass(command_encoder, &render_pass_descriptor); - wgpuRenderPassEncoderSetBindGroup(render_pass_encoder, 0, per_frame_bind_group, 0, NULL); - - { // Draw Map - ZoneScopedN("Draw Map"); - wgpuRenderPassEncoderSetPipeline(render_pass_encoder, world_render_pipeline); - wgpuRenderPassEncoderSetIndexBuffer(render_pass_encoder, index_buffer, WGPUIndexFormat_Uint16, 0, WGPU_WHOLE_SIZE); - wgpuRenderPassEncoderSetVertexBuffer(render_pass_encoder, 0, vertex_buffer, 0, WGPU_WHOLE_SIZE); - wgpuRenderPassEncoderSetVertexBuffer(render_pass_encoder, 1, current_map.gpu_buffer, 0, WGPU_WHOLE_SIZE); - wgpuRenderPassEncoderSetBindGroup(render_pass_encoder, 1, world_bind_group, 0, NULL); - wgpuRenderPassEncoderDrawIndexed(render_pass_encoder, 6, current_map.size.y * current_map.size.x, 0, 0, 0); - } - - { // Draw Player - ZoneScopedN("Draw Player"); - wgpuRenderPassEncoderSetPipeline(render_pass_encoder, basic_render_pipeline); - wgpuRenderPassEncoderSetIndexBuffer(render_pass_encoder, index_buffer, WGPUIndexFormat_Uint16, 0, WGPU_WHOLE_SIZE); - wgpuRenderPassEncoderSetVertexBuffer(render_pass_encoder, 0, vertex_buffer, 0, WGPU_WHOLE_SIZE); - wgpuRenderPassEncoderSetVertexBuffer(render_pass_encoder, 1, player_instance_buffer, 0, WGPU_WHOLE_SIZE); - wgpuRenderPassEncoderSetBindGroup(render_pass_encoder, 1, basic_bind_group, 0, NULL); - wgpuRenderPassEncoderDrawIndexed(render_pass_encoder, 6, 1, 0, 0, 0); - } - - if (show_tile_picker) { // Draw Grid - ZoneScopedN("Draw Grid"); - - Uint32 num_grid_cells = current_map.size.y * current_map.size.x; - if (selected_tile == -1) - num_grid_cells = (current_map.size.y + 1) * (current_map.size.x + 1); - - wgpuRenderPassEncoderSetPipeline(render_pass_encoder, grid_render_pipeline); - wgpuRenderPassEncoderSetIndexBuffer(render_pass_encoder, grid_index_buffer, WGPUIndexFormat_Uint16, 0, WGPU_WHOLE_SIZE); - wgpuRenderPassEncoderSetVertexBuffer(render_pass_encoder, 0, grid_vertex_buffer, 0, WGPU_WHOLE_SIZE); - wgpuRenderPassEncoderDrawIndexed(render_pass_encoder, SDL_arraysize(grid_indices), num_grid_cells, 0, 0, 0); - } - - { - ZoneScopedN("ImGui Render"); - ImGui::Render(); - ImDrawData *draw_data = ImGui::GetDrawData(); - ImGui_ImplWGPU_RenderDrawData(draw_data, render_pass_encoder); - } - - wgpuRenderPassEncoderEnd(render_pass_encoder); - wgpuRenderPassEncoderRelease(render_pass_encoder); - - { - ZoneScopedN("SubmitGPUCommandBuffer"); - WGPUCommandBufferDescriptor command_buffer_descriptor = {}; - WGPUCommandBuffer command_buffer = wgpuCommandEncoderFinish(command_encoder, &command_buffer_descriptor); - wgpuCommandEncoderRelease(command_encoder); - wgpuQueueSubmit(queue, 1, &command_buffer); - wgpuCommandBufferRelease(command_buffer); - } + update_state(); + render(surface_texture.texture); { ZoneScopedN("wgpuSurfacePresent"); wgpuSurfacePresent(surface); + wgpuTextureRelease(surface_texture.texture); } - wgpuTextureViewRelease(framebuffer_view); - wgpuTextureViewRelease(surface_texture_view); - wgpuTextureRelease(surface_texture.texture); - FrameMark; }