change world tiles texture from texture_2d_array to an atlas texture_2d
This commit is contained in:
parent
9dd37f6d40
commit
b549728a24
99
src/main.cpp
99
src/main.cpp
@ -24,7 +24,9 @@ using namespace M;
|
||||
#define ASSETS_PATH "./assets/"
|
||||
|
||||
#define NEAR_PLANE (0.01f)
|
||||
#define TILE_SIZE (32)
|
||||
|
||||
#define TILE_SIZE (32)
|
||||
#define TILE_ATLAS_SIZE (256)
|
||||
|
||||
static SDL_Window *window;
|
||||
static bool wgpu_init_done;
|
||||
@ -47,9 +49,9 @@ static WGPUBindGroup basic_bind_group;
|
||||
static WGPUTexture player_texture;
|
||||
static WGPUTextureView player_texture_view;
|
||||
|
||||
static WGPUTexture tile_textures_array;
|
||||
static WGPUTextureView tile_textures_array_view;
|
||||
static WGPUTextureView *tile_textures_array_view_individual;
|
||||
static WGPUTexture tile_textures_atlas;
|
||||
static WGPUTextureView tile_textures_atlas_view;
|
||||
static WGPUTextureView tile_textures_atlas_view_unorm;
|
||||
|
||||
static WGPUBuffer view_projection_matrix_buffer;
|
||||
static WGPUBuffer per_frame_buffer;
|
||||
@ -60,7 +62,7 @@ static WGPUBuffer index_buffer;
|
||||
static WGPUBuffer grid_vertex_buffer;
|
||||
static WGPUBuffer grid_index_buffer;
|
||||
static WGPUBuffer player_instance_buffer;
|
||||
static WGPUBuffer tile_infos_buffer;
|
||||
static WGPUBuffer tile_uvs_buffer;
|
||||
|
||||
static WGPUSurfaceConfiguration surface_configuration;
|
||||
|
||||
@ -261,6 +263,8 @@ static TileInfo tile_infos[] = {
|
||||
{ 0x0423, "tiles/grass_ground_two_corner.png", TILE_CORNER_INFO(TILEKIND_GRASS, TILEKIND_GROUND, TILEKIND_GRASS, TILEKIND_GROUND ) },
|
||||
};
|
||||
|
||||
static V4 tile_uvs[SDL_arraysize(tile_infos)];
|
||||
|
||||
static Sint32 selected_tile_kind = -1;
|
||||
|
||||
static Sint32 selected_tile = -1;
|
||||
@ -566,7 +570,7 @@ static void blit(char *dst, Sint32 dst_pitch, Sint32 dst_x, Sint32 dst_y, char *
|
||||
memmove(&dst[((dst_y + y) * dst_pitch + dst_x) * components], &src[y * src_pitch * components], width * components);
|
||||
}
|
||||
|
||||
static bool SelectableTile(const char *label, bool selected, Uint32 tile_index, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), Uint8 orientation = 0) {
|
||||
static bool SelectableTile(const char *label, bool selected, Uint32 tile_index, const ImVec2& image_size, Uint8 orientation = 0) {
|
||||
const ImGuiContext *context = ImGui::GetCurrentContext();
|
||||
const ImVec2 padding = context->Style.FramePadding;
|
||||
|
||||
@ -575,11 +579,13 @@ static bool SelectableTile(const char *label, bool selected, Uint32 tile_index,
|
||||
ImVec2 min = ImGui::GetItemRectMin();
|
||||
ImVec2 max = ImGui::GetItemRectMax();
|
||||
|
||||
V4 uv = tile_uvs[tile_index] / TILE_ATLAS_SIZE;
|
||||
|
||||
switch (orientation) {
|
||||
case 0: context->CurrentWindow->DrawList->AddImageQuad((ImTextureID)tile_textures_array_view_individual[tile_index], min + padding, ImVec2(max.x - padding.x, min.y + padding.y), max - padding, ImVec2(min.x + padding.x, max.y - padding.y), ImVec2(uv0.x, uv0.y), ImVec2(uv1.x, uv0.y), ImVec2(uv1.x, uv1.y), ImVec2(uv0.x, uv1.y)); break;
|
||||
case 1: context->CurrentWindow->DrawList->AddImageQuad((ImTextureID)tile_textures_array_view_individual[tile_index], min + padding, ImVec2(max.x - padding.x, min.y + padding.y), max - padding, ImVec2(min.x + padding.x, max.y - padding.y), ImVec2(uv1.x, uv0.y), ImVec2(uv1.x, uv1.y), ImVec2(uv0.x, uv1.y), ImVec2(uv0.x, uv0.y)); break;
|
||||
case 2: context->CurrentWindow->DrawList->AddImageQuad((ImTextureID)tile_textures_array_view_individual[tile_index], min + padding, ImVec2(max.x - padding.x, min.y + padding.y), max - padding, ImVec2(min.x + padding.x, max.y - padding.y), ImVec2(uv1.x, uv1.y), ImVec2(uv0.x, uv1.y), ImVec2(uv0.x, uv0.y), ImVec2(uv1.x, uv0.y)); break;
|
||||
case 3: context->CurrentWindow->DrawList->AddImageQuad((ImTextureID)tile_textures_array_view_individual[tile_index], min + padding, ImVec2(max.x - padding.x, min.y + padding.y), max - padding, ImVec2(min.x + padding.x, max.y - padding.y), ImVec2(uv0.x, uv1.y), ImVec2(uv0.x, uv0.y), ImVec2(uv1.x, uv0.y), ImVec2(uv1.x, uv1.y)); break;
|
||||
case 0: context->CurrentWindow->DrawList->AddImageQuad((ImTextureID)tile_textures_atlas_view_unorm, min + padding, ImVec2(max.x - padding.x, min.y + padding.y), max - padding, ImVec2(min.x + padding.x, max.y - padding.y), ImVec2(uv.x, uv.y), ImVec2(uv.z, uv.y), ImVec2(uv.z, uv.w), ImVec2(uv.x, uv.w)); break;
|
||||
case 1: context->CurrentWindow->DrawList->AddImageQuad((ImTextureID)tile_textures_atlas_view_unorm, min + padding, ImVec2(max.x - padding.x, min.y + padding.y), max - padding, ImVec2(min.x + padding.x, max.y - padding.y), ImVec2(uv.z, uv.y), ImVec2(uv.z, uv.w), ImVec2(uv.x, uv.w), ImVec2(uv.x, uv.y)); break;
|
||||
case 2: context->CurrentWindow->DrawList->AddImageQuad((ImTextureID)tile_textures_atlas_view_unorm, min + padding, ImVec2(max.x - padding.x, min.y + padding.y), max - padding, ImVec2(min.x + padding.x, max.y - padding.y), ImVec2(uv.z, uv.w), ImVec2(uv.x, uv.w), ImVec2(uv.x, uv.y), ImVec2(uv.z, uv.y)); break;
|
||||
case 3: context->CurrentWindow->DrawList->AddImageQuad((ImTextureID)tile_textures_atlas_view_unorm, min + padding, ImVec2(max.x - padding.x, min.y + padding.y), max - padding, ImVec2(min.x + padding.x, max.y - padding.y), ImVec2(uv.x, uv.w), ImVec2(uv.x, uv.y), ImVec2(uv.z, uv.y), ImVec2(uv.z, uv.w)); break;
|
||||
default: SDL_assert_always(false); break;
|
||||
}
|
||||
|
||||
@ -856,7 +862,7 @@ static bool recreate_graphics_pipelines() {
|
||||
|
||||
.texture = {
|
||||
.sampleType = WGPUTextureSampleType_Float,
|
||||
.viewDimension = WGPUTextureViewDimension_2DArray,
|
||||
.viewDimension = WGPUTextureViewDimension_2D,
|
||||
.multisampled = false,
|
||||
},
|
||||
},
|
||||
@ -878,6 +884,16 @@ static bool recreate_graphics_pipelines() {
|
||||
.minBindingSize = 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.binding = 3,
|
||||
.visibility = WGPUShaderStage_Fragment,
|
||||
|
||||
.buffer = {
|
||||
.type = WGPUBufferBindingType_ReadOnlyStorage,
|
||||
.hasDynamicOffset = false,
|
||||
.minBindingSize = 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
WGPUBindGroupLayoutDescriptor world_bind_group_layout_descriptor = {
|
||||
@ -1098,10 +1114,10 @@ static bool recreate_tile_textures() {
|
||||
};
|
||||
|
||||
WGPUTextureDescriptor descriptor = {
|
||||
.label = { .data = "tile_textures_array", .length = WGPU_STRLEN },
|
||||
.label = { .data = "tile_textures_atlas", .length = WGPU_STRLEN },
|
||||
.usage = WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst,
|
||||
.dimension = WGPUTextureDimension_2D,
|
||||
.size = { .width = TILE_SIZE, .height = TILE_SIZE, .depthOrArrayLayers = SDL_arraysize(tile_infos) },
|
||||
.size = { .width = TILE_ATLAS_SIZE, .height = TILE_ATLAS_SIZE, .depthOrArrayLayers = 1 },
|
||||
.format = WGPUTextureFormat_RGBA8UnormSrgb,
|
||||
.mipLevelCount = 1,
|
||||
.sampleCount = 1,
|
||||
@ -1109,24 +1125,21 @@ static bool recreate_tile_textures() {
|
||||
.viewFormats = view_formats,
|
||||
};
|
||||
|
||||
tile_textures_array = wgpuDeviceCreateTexture(device, &descriptor);
|
||||
if (!tile_textures_array) {
|
||||
tile_textures_atlas = wgpuDeviceCreateTexture(device, &descriptor);
|
||||
if (!tile_textures_atlas) {
|
||||
log_error("Failed to create texture.");
|
||||
return WGPUOptionalBool_False;
|
||||
return false;
|
||||
}
|
||||
tile_textures_array_view = wgpuTextureCreateView(tile_textures_array, NULL);
|
||||
tile_textures_atlas_view = wgpuTextureCreateView(tile_textures_atlas, NULL);
|
||||
|
||||
tile_textures_array_view_individual = (WGPUTextureView *)malloc(SDL_arraysize(tile_infos) * sizeof(WGPUTextureView));
|
||||
for (Uint32 i = 0; i < SDL_arraysize(tile_infos); i++) {
|
||||
WGPUTextureViewDescriptor descriptor = {
|
||||
WGPUTextureViewDescriptor unorm_view_descriptor = {
|
||||
.format = WGPUTextureFormat_RGBA8Unorm,
|
||||
.dimension = WGPUTextureViewDimension_2D,
|
||||
.mipLevelCount = 1,
|
||||
.baseArrayLayer = i,
|
||||
.baseArrayLayer = 0,
|
||||
.arrayLayerCount = 1,
|
||||
};
|
||||
tile_textures_array_view_individual[i] = wgpuTextureCreateView(tile_textures_array, &descriptor);
|
||||
}
|
||||
tile_textures_atlas_view_unorm = wgpuTextureCreateView(tile_textures_atlas, &unorm_view_descriptor);
|
||||
|
||||
for (Uint32 i = 0; i < SDL_arraysize(tile_infos); i++) {
|
||||
char path[256] = ASSETS_PATH;
|
||||
@ -1136,17 +1149,25 @@ static bool recreate_tile_textures() {
|
||||
stbi_uc *data = stbi_load(path, &width, &height, NULL, 4);
|
||||
if (!data) {
|
||||
log_error("Failed to load texture (\"%s\"). Exiting.", path);
|
||||
wgpuTextureRelease(tile_textures_array);
|
||||
wgpuTextureRelease(tile_textures_atlas);
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_assert_always(width == TILE_SIZE);
|
||||
SDL_assert_always(height == TILE_SIZE);
|
||||
|
||||
Uint32 x = (i * TILE_SIZE) % TILE_ATLAS_SIZE;
|
||||
Uint32 y = ((i * TILE_SIZE) / TILE_ATLAS_SIZE) * TILE_SIZE;
|
||||
|
||||
tile_uvs[i].x = x;
|
||||
tile_uvs[i].y = y;
|
||||
tile_uvs[i].z = x + TILE_SIZE;
|
||||
tile_uvs[i].w = y + TILE_SIZE;
|
||||
|
||||
WGPUTexelCopyTextureInfo texel_copy_texture_info = {
|
||||
.texture = tile_textures_array,
|
||||
.texture = tile_textures_atlas,
|
||||
.mipLevel = 0,
|
||||
.origin = { .x = 0, .y = 0, .z = i },
|
||||
.origin = { .x = x, .y = y, .z = 0 },
|
||||
.aspect = WGPUTextureAspect_All,
|
||||
};
|
||||
|
||||
@ -1166,6 +1187,8 @@ static bool recreate_tile_textures() {
|
||||
stbi_image_free(data);
|
||||
}
|
||||
|
||||
tile_uvs_buffer = create_buffer(WGPUBufferUsage_Storage | WGPUBufferUsage_CopyDst, sizeof(tile_uvs), tile_uvs, "tile_uvs_buffer");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1445,7 +1468,7 @@ static bool init_webgpu() {
|
||||
.minFilter = WGPUFilterMode_Linear,
|
||||
.mipmapFilter = WGPUMipmapFilterMode_Linear,
|
||||
|
||||
.maxAnisotropy = 16,
|
||||
.maxAnisotropy = 1,
|
||||
};
|
||||
|
||||
pixel_sampler = wgpuDeviceCreateSampler(device, &pixel_sampler_descriptor);
|
||||
@ -1525,9 +1548,10 @@ static bool init_webgpu() {
|
||||
per_frame_bind_group = wgpuDeviceCreateBindGroup(device, &per_frame_bind_group_descriptor);
|
||||
|
||||
WGPUBindGroupEntry world_bind_group_entries[] = {
|
||||
{ .binding = 0, .textureView = tile_textures_array_view },
|
||||
{ .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 = {
|
||||
@ -1869,13 +1893,10 @@ int main(int argc, char **argv) {
|
||||
for (int i = 0; i < SDL_arraysize(tile_infos); i++) {
|
||||
ImGui::PushID(i);
|
||||
|
||||
ImVec2 uv0 = ImVec2(0, 0);
|
||||
ImVec2 uv1 = ImVec2(1, 1);
|
||||
|
||||
if (i != 0)
|
||||
SameLineOrWrap(ImVec2(32, 32));
|
||||
|
||||
if (SelectableTile("##tile", selected_tile == i, i, ImVec2(32, 32), uv0, uv1, SDL_max(selected_rotation, 0))) {
|
||||
if (SelectableTile("##tile", selected_tile == i, i, ImVec2(32, 32), SDL_max(selected_rotation, 0))) {
|
||||
selected_tile_kind = -1;
|
||||
selected_tile = i;
|
||||
}
|
||||
@ -1886,23 +1907,20 @@ int main(int argc, char **argv) {
|
||||
if (selected_tile != -1) {
|
||||
ImGui::Text("Rotation:");
|
||||
|
||||
ImVec2 uv0 = ImVec2(0, 0);
|
||||
ImVec2 uv1 = ImVec2(1, 1);
|
||||
|
||||
if (SelectableTile("##None", selected_rotation == 0, selected_tile, ImVec2(32, 32), uv0, uv1, 0))
|
||||
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), uv0, uv1, 1))
|
||||
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), uv0, uv1, 2))
|
||||
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), uv0, uv1, 3))
|
||||
if (SelectableTile("##270", selected_rotation == 3, selected_tile, ImVec2(32, 32), 3))
|
||||
selected_rotation = 3;
|
||||
|
||||
if (ImGui::Selectable("Random", selected_rotation == -1))
|
||||
@ -1994,9 +2012,10 @@ int main(int argc, char **argv) {
|
||||
if (event.key.key == SDLK_F5) {
|
||||
recreate_tile_textures();
|
||||
WGPUBindGroupEntry world_bind_group_entries[] = {
|
||||
{ .binding = 0, .textureView = tile_textures_array_view },
|
||||
{ .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 = {
|
||||
|
||||
@ -37,9 +37,9 @@ struct Per_Frame_Data {
|
||||
var output: VertexShaderOutput;
|
||||
|
||||
let tile_type = extractBits(input.tile_info, 0, 16);
|
||||
let rotation = extractBits(input.tile_info, 16, 2);
|
||||
let rotation = extractBits(input.tile_info, 16, 2);
|
||||
|
||||
let tile_pos = vec2<f32>(f32(input.instance_index % per_frame.map_width), f32(input.instance_index / per_frame.map_width)) - vec2<f32>(0.5, 0.5);
|
||||
let tile_pos = vec2<f32>(f32(input.instance_index % per_frame.map_width), f32(input.instance_index / per_frame.map_width)) - vec2<f32>(0.5, 0.5);
|
||||
|
||||
output.tile = tile_type;
|
||||
output.pos = vec4<f32>(tile_pos + input.pos.xy, 0, 1) * view_projection_matrix;
|
||||
@ -55,11 +55,13 @@ struct Per_Frame_Data {
|
||||
return output;
|
||||
}
|
||||
|
||||
@group(1) @binding(0) var texture1: texture_2d_array<f32>;
|
||||
@group(1) @binding(0) var texture1: texture_2d<f32>;
|
||||
@group(1) @binding(1) var sampler1: sampler;
|
||||
|
||||
@group(1) @binding(2) var<uniform> tint: vec3<f32>;
|
||||
|
||||
@group(1) @binding(3) var<storage> tile_uvs: array<vec4<f32>>;
|
||||
|
||||
@fragment fn main_fragment(input: VertexShaderOutput) -> FragmentShaderOutput {
|
||||
var output: FragmentShaderOutput;
|
||||
|
||||
@ -69,11 +71,15 @@ struct Per_Frame_Data {
|
||||
return output;
|
||||
}
|
||||
|
||||
fn pixel_art_sample(input_texture: texture_2d_array<f32>, input_sampler: sampler, input_uv: vec2<f32>, index: u32) -> vec4<f32> {
|
||||
fn pixel_art_sample(input_texture: texture_2d<f32>, input_sampler: sampler, input_uv: vec2<f32>, tile: u32) -> vec4<f32> {
|
||||
let dimensions = vec2<f32>(textureDimensions(input_texture));
|
||||
|
||||
let texture_uv = input_uv * dimensions.xy;
|
||||
let sample_uv = (floor(texture_uv) + min(fract(texture_uv) / fwidth(texture_uv), vec2<f32>(1.0, 1.0)) - 0.5) / dimensions.xy;
|
||||
let tile_uv = tile_uvs[tile];
|
||||
|
||||
return textureSample(input_texture, input_sampler, sample_uv, index);
|
||||
let texture_uv = mix(tile_uv.xy, tile_uv.zw, input_uv);
|
||||
let sample_uv = (floor(texture_uv) + saturate(fract(texture_uv) / fwidth(texture_uv)) - 0.5) / dimensions;
|
||||
|
||||
let uv = clamp(sample_uv, (tile_uv.xy + 0.5) / dimensions, (tile_uv.zw - 0.5) / dimensions);
|
||||
|
||||
return textureSample(input_texture, input_sampler, uv);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user