add renderer abstraction
This commit is contained in:
+127
-1052
File diff suppressed because it is too large
Load Diff
+113
@@ -0,0 +1,113 @@
|
||||
#ifndef RENDERER_H
|
||||
#define RENDERER_H
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
typedef enum : Uint32 {
|
||||
R_SHADER_BASIC,
|
||||
R_SHADER_WORLD,
|
||||
R_SHADER_GRID,
|
||||
R_SHADER_COUNT,
|
||||
} R_Shader;
|
||||
|
||||
typedef enum : Uint32 {
|
||||
R_BUFFER_USAGE_UNIFORM,
|
||||
R_BUFFER_USAGE_STORAGE,
|
||||
R_BUFFER_USAGE_VERTEX,
|
||||
R_BUFFER_USAGE_INDEX,
|
||||
R_BUFFER_USAGE_COUNT,
|
||||
} R_Buffer_Usage;
|
||||
|
||||
typedef enum : Uint32 {
|
||||
R_TEXTURE_USAGE_SAMPLED,
|
||||
R_TEXTURE_USAGE_STORAGE,
|
||||
R_TEXTURE_USAGE_TARGET,
|
||||
R_TEXTURE_USAGE_COUNT,
|
||||
} R_Texture_Usage;
|
||||
|
||||
typedef enum : Uint32 {
|
||||
R_TEXTURE_FORMAT_R8_UNORM,
|
||||
R_TEXTURE_FORMAT_R16_UINT,
|
||||
R_TEXTURE_FORMAT_RGBA8_UNORM,
|
||||
R_TEXTURE_FORMAT_RGBA8_UNORM_SRGB,
|
||||
R_TEXTURE_FORMAT_BGRA8_UNORM,
|
||||
R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB,
|
||||
R_TEXTURE_FORMAT_COUNT,
|
||||
} R_Texture_Format;
|
||||
|
||||
typedef enum : Uint32 {
|
||||
R_LOAD_OP_LOAD,
|
||||
R_LOAD_OP_CLEAR,
|
||||
R_LOAD_OP_COUNT,
|
||||
} R_Load_Op;
|
||||
|
||||
typedef enum : Uint32 {
|
||||
R_STORE_OP_STORE,
|
||||
R_STORE_OP_DISCARD,
|
||||
R_STORE_OP_COUNT,
|
||||
} R_Store_Op;
|
||||
|
||||
typedef struct R_Color {
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
float a;
|
||||
} R_Color;
|
||||
|
||||
typedef struct R_Buffer_Impl *R_Buffer;
|
||||
typedef struct R_Texture_Impl *R_Texture;
|
||||
|
||||
typedef struct R_Draw_Resources {
|
||||
R_Texture *vertex_textures;
|
||||
R_Buffer *vertex_storage_buffers;
|
||||
R_Buffer *vertex_uniform_buffers;
|
||||
|
||||
Uint16 num_vertex_textures;
|
||||
Uint16 num_vertex_storage_buffers;
|
||||
Uint16 num_vertex_uniform_buffers;
|
||||
|
||||
R_Texture *fragment_textures;
|
||||
R_Buffer *fragment_storage_buffers;
|
||||
R_Buffer *fragment_uniform_buffers;
|
||||
|
||||
Uint16 num_fragment_textures;
|
||||
Uint16 num_fragment_storage_buffers;
|
||||
Uint16 num_fragment_uniform_buffers;
|
||||
} R_Draw_Resources;
|
||||
|
||||
extern R_Texture R_framebuffer;
|
||||
|
||||
bool renderer_init(SDL_Window *window);
|
||||
|
||||
R_Texture renderer_texture_create (R_Texture_Format format, R_Texture_Usage usage, Uint32 sample_count, Uint32 width, Uint32 height, void *data, const char *debug_name);
|
||||
void renderer_texture_update (R_Texture texture, Uint32 offset_x, Uint32 offset_y, Uint32 width, Uint32 height, void *data, Uint32 bytes_per_row);
|
||||
void renderer_texture_destroy(R_Texture texture);
|
||||
|
||||
R_Buffer renderer_buffer_create (R_Buffer_Usage usage, Uint32 num_bytes, void * data, const char *debug_name);
|
||||
void renderer_buffer_update (R_Buffer buffer, Uint32 offset, Uint32 num_bytes, void *data);
|
||||
void renderer_buffer_destroy(R_Buffer buffer);
|
||||
|
||||
void renderer_frame_begin();
|
||||
void renderer_frame_end();
|
||||
|
||||
void renderer_frame_set_target(R_Texture target, R_Texture resolve_target, R_Load_Op load_op, R_Store_Op store_op, R_Color clear_color);
|
||||
void renderer_frame_set_shader(R_Shader shader);
|
||||
void renderer_frame_draw(R_Buffer vertex_buffer, R_Buffer index_buffer, R_Buffer instance_buffer, Uint32 num_indices, Uint32 num_instances, const R_Draw_Resources *resources);
|
||||
|
||||
// Dear ImGui
|
||||
void ImGui_ImplRenderer_Init();
|
||||
void ImGui_ImplRenderer_NewFrame();
|
||||
void ImGui_ImplRenderer_Shutdown();
|
||||
void ImGui_ImplRenderer_RenderDrawData(void* draw_data);
|
||||
|
||||
Uint64 ImGui_ImplRenderer_GetTextureID(R_Texture texture);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // RENDERER_H
|
||||
@@ -0,0 +1,992 @@
|
||||
#include "renderer.h"
|
||||
#include <webgpu/webgpu.h>
|
||||
#include <dcimgui_impl_wgpu.h>
|
||||
|
||||
typedef struct R_Buffer_Impl {
|
||||
WGPUBuffer buffer;
|
||||
|
||||
Uint32 num_bytes;
|
||||
R_Buffer_Usage usage;
|
||||
} R_Buffer_Impl;
|
||||
|
||||
typedef struct R_Texture_Impl {
|
||||
WGPUTexture texture;
|
||||
WGPUTextureView view;
|
||||
|
||||
Uint32 width;
|
||||
Uint32 height;
|
||||
|
||||
Uint32 sample_count;
|
||||
R_Texture_Format format;
|
||||
} R_Texture_Impl;
|
||||
|
||||
R_Texture R_framebuffer;
|
||||
|
||||
static bool init_done;
|
||||
|
||||
static SDL_Window *window;
|
||||
static WGPUInstance instance;
|
||||
static WGPUDevice device;
|
||||
static WGPUQueue queue;
|
||||
static WGPUSurface surface;
|
||||
|
||||
static R_Texture_Format surface_format;
|
||||
static WGPUSurfaceConfiguration surface_configuration;
|
||||
static WGPUSurfaceTexture surface_texture;
|
||||
static WGPUTextureView surface_texture_view;
|
||||
|
||||
static R_Texture framebuffer;
|
||||
|
||||
static WGPUCommandEncoder command_encoder;
|
||||
static WGPURenderPassEncoder pass_encoder;
|
||||
|
||||
static WGPURenderPipeline shaders[R_SHADER_COUNT];
|
||||
static R_Shader current_shader;
|
||||
|
||||
static WGPUSampler bilinear_sampler;
|
||||
|
||||
static WGPUTextureFormat texture_formats[] = {
|
||||
[R_TEXTURE_FORMAT_R8_UNORM] = WGPUTextureFormat_R8Unorm,
|
||||
[R_TEXTURE_FORMAT_R16_UINT] = WGPUTextureFormat_R16Uint,
|
||||
[R_TEXTURE_FORMAT_RGBA8_UNORM] = WGPUTextureFormat_RGBA8Unorm,
|
||||
[R_TEXTURE_FORMAT_RGBA8_UNORM_SRGB] = WGPUTextureFormat_RGBA8UnormSrgb,
|
||||
[R_TEXTURE_FORMAT_BGRA8_UNORM] = WGPUTextureFormat_BGRA8Unorm,
|
||||
[R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB] = WGPUTextureFormat_BGRA8UnormSrgb,
|
||||
};
|
||||
static_assert(SDL_arraysize(texture_formats) == R_TEXTURE_FORMAT_COUNT);
|
||||
|
||||
static Uint32 texel_sizes[] = {
|
||||
[R_TEXTURE_FORMAT_R8_UNORM] = 1,
|
||||
[R_TEXTURE_FORMAT_R16_UINT] = 2,
|
||||
[R_TEXTURE_FORMAT_RGBA8_UNORM] = 4,
|
||||
[R_TEXTURE_FORMAT_RGBA8_UNORM_SRGB] = 4,
|
||||
[R_TEXTURE_FORMAT_BGRA8_UNORM] = 4,
|
||||
[R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB] = 4,
|
||||
};
|
||||
static_assert(SDL_arraysize(texel_sizes) == R_TEXTURE_FORMAT_COUNT);
|
||||
|
||||
static WGPUTextureUsage texture_usages[] = {
|
||||
[R_TEXTURE_USAGE_SAMPLED] = WGPUTextureUsage_TextureBinding,
|
||||
[R_TEXTURE_USAGE_STORAGE] = WGPUTextureUsage_StorageBinding,
|
||||
[R_TEXTURE_USAGE_TARGET] = WGPUTextureUsage_RenderAttachment,
|
||||
};
|
||||
static_assert(SDL_arraysize(texture_usages) == R_TEXTURE_USAGE_COUNT);
|
||||
|
||||
static WGPUBufferUsage buffer_usages[] = {
|
||||
[R_BUFFER_USAGE_UNIFORM] = WGPUBufferUsage_Uniform,
|
||||
[R_BUFFER_USAGE_STORAGE] = WGPUBufferUsage_Storage,
|
||||
[R_BUFFER_USAGE_VERTEX] = WGPUBufferUsage_Vertex,
|
||||
[R_BUFFER_USAGE_INDEX] = WGPUBufferUsage_Index,
|
||||
};
|
||||
static_assert(SDL_arraysize(buffer_usages) == R_BUFFER_USAGE_COUNT);
|
||||
|
||||
static WGPULoadOp load_ops[] = {
|
||||
[R_LOAD_OP_LOAD] = WGPULoadOp_Load,
|
||||
[R_LOAD_OP_CLEAR] = WGPULoadOp_Clear,
|
||||
};
|
||||
static_assert(SDL_arraysize(load_ops) == R_LOAD_OP_COUNT);
|
||||
|
||||
static WGPUStoreOp store_ops[] = {
|
||||
[R_STORE_OP_STORE] = WGPUStoreOp_Store,
|
||||
[R_STORE_OP_DISCARD] = WGPUStoreOp_Discard,
|
||||
};
|
||||
static_assert(SDL_arraysize(store_ops) == R_STORE_OP_COUNT);
|
||||
|
||||
R_Texture renderer_texture_create(R_Texture_Format format, R_Texture_Usage usage, Uint32 sample_count, Uint32 width, Uint32 height, void *data, const char *debug_name) {
|
||||
WGPUTextureDescriptor descriptor = {
|
||||
.label = { .data = debug_name, .length = WGPU_STRLEN },
|
||||
.usage = texture_usages[usage] | WGPUTextureUsage_CopyDst,
|
||||
.dimension = WGPUTextureDimension_2D,
|
||||
.size = { .width = width, .height = height, .depthOrArrayLayers = 1 },
|
||||
.format = texture_formats[format],
|
||||
.mipLevelCount = 1,
|
||||
.sampleCount = sample_count,
|
||||
.viewFormatCount = 0,
|
||||
.viewFormats = NULL,
|
||||
};
|
||||
|
||||
WGPUTexture texture = wgpuDeviceCreateTexture(device, &descriptor);
|
||||
if (!texture) return NULL;
|
||||
|
||||
WGPUTextureView view = wgpuTextureCreateView(texture, NULL);
|
||||
if (!view) {
|
||||
wgpuTextureRelease(texture);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
Uint32 texel_size = texel_sizes[format];
|
||||
|
||||
WGPUTexelCopyTextureInfo destination = {
|
||||
.texture = texture,
|
||||
.mipLevel = 0,
|
||||
.origin = { .x = 0, .y = 0, .z = 0 },
|
||||
.aspect = WGPUTextureAspect_All,
|
||||
};
|
||||
|
||||
WGPUTexelCopyBufferLayout data_layout = {
|
||||
.offset = 0,
|
||||
.bytesPerRow = width * texel_size,
|
||||
.rowsPerImage = height,
|
||||
};
|
||||
|
||||
WGPUExtent3D extent = {
|
||||
.width = width,
|
||||
.height = height,
|
||||
.depthOrArrayLayers = 1,
|
||||
};
|
||||
|
||||
wgpuQueueWriteTexture(queue, &destination, data, width * height * texel_size, &data_layout, &extent);
|
||||
}
|
||||
|
||||
R_Texture_Impl *result = SDL_calloc(1, sizeof(R_Texture_Impl));
|
||||
if (!result) {
|
||||
wgpuTextureViewRelease(view);
|
||||
wgpuTextureRelease(texture);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*result = (R_Texture_Impl){
|
||||
.texture = texture,
|
||||
.view = view,
|
||||
|
||||
.width = width,
|
||||
.height = height,
|
||||
|
||||
.sample_count = sample_count,
|
||||
.format = format,
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void renderer_texture_update(R_Texture texture, Uint32 offset_x, Uint32 offset_y, Uint32 width, Uint32 height, void *data, Uint32 bytes_per_row) {
|
||||
WGPUTexelCopyTextureInfo info = {
|
||||
.texture = texture->texture,
|
||||
.mipLevel = 0,
|
||||
.origin = { offset_x, offset_y, 0 },
|
||||
.aspect = WGPUTextureAspect_All,
|
||||
};
|
||||
|
||||
WGPUTexelCopyBufferLayout data_layout = {
|
||||
.offset = 0,
|
||||
.bytesPerRow = bytes_per_row,
|
||||
.rowsPerImage = height,
|
||||
};
|
||||
|
||||
WGPUExtent3D extent = { width, height, 1 };
|
||||
|
||||
wgpuQueueWriteTexture(queue, &info, data, data_layout.bytesPerRow * data_layout.rowsPerImage, &data_layout, &extent);
|
||||
}
|
||||
|
||||
void renderer_texture_destroy(R_Texture texture) {
|
||||
wgpuTextureViewRelease(texture->view);
|
||||
wgpuTextureRelease(texture->texture);
|
||||
SDL_free(texture);
|
||||
}
|
||||
|
||||
R_Buffer renderer_buffer_create(R_Buffer_Usage usage, Uint32 num_bytes, void *data, const char *debug_name) {
|
||||
WGPUBufferDescriptor descriptor = {
|
||||
.label = { .data = debug_name, .length = WGPU_STRLEN },
|
||||
.usage = buffer_usages[usage] | WGPUBufferUsage_CopyDst,
|
||||
.size = num_bytes,
|
||||
.mappedAtCreation = data != NULL,
|
||||
};
|
||||
|
||||
WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
|
||||
if (!buffer) return NULL;
|
||||
|
||||
if (data) {
|
||||
void *mapped_data = wgpuBufferGetMappedRange(buffer, 0, num_bytes);
|
||||
memcpy(mapped_data, data, num_bytes);
|
||||
wgpuBufferUnmap(buffer);
|
||||
}
|
||||
|
||||
R_Buffer_Impl *result = SDL_calloc(1, sizeof(R_Buffer_Impl));
|
||||
if (!result) {
|
||||
wgpuBufferRelease(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*result = (R_Buffer_Impl){
|
||||
.buffer = buffer,
|
||||
|
||||
.num_bytes = num_bytes,
|
||||
.usage = usage,
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void renderer_buffer_update(R_Buffer buffer, Uint32 offset, Uint32 num_bytes, void *data) {
|
||||
wgpuQueueWriteBuffer(queue, buffer->buffer, offset, data, num_bytes);
|
||||
}
|
||||
|
||||
void renderer_buffer_destroy(R_Buffer buffer) {
|
||||
wgpuBufferRelease(buffer->buffer);
|
||||
SDL_free(buffer);
|
||||
}
|
||||
|
||||
void renderer_frame_begin() {
|
||||
SDL_assert(command_encoder == NULL);
|
||||
SDL_assert(R_framebuffer == NULL);
|
||||
|
||||
Sint32 window_width = 0, window_height = 0;
|
||||
SDL_GetWindowSizeInPixels(window, &window_width, &window_height);
|
||||
|
||||
if (surface_configuration.width != window_width || surface_configuration.height != window_height) {
|
||||
surface_configuration.width = window_width;
|
||||
surface_configuration.height = window_height;
|
||||
wgpuSurfaceConfigure(surface, &surface_configuration);
|
||||
}
|
||||
|
||||
wgpuSurfaceGetCurrentTexture(surface, &surface_texture);
|
||||
if (surface_texture.status != WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal && surface_texture.status != WGPUSurfaceGetCurrentTextureStatus_SuccessSuboptimal) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to get current surface texture (%x). Exiting.", surface_texture.status);
|
||||
SDL_assert_always(false); // TODO: recovery on outdated or device loss
|
||||
return;
|
||||
}
|
||||
surface_texture_view = wgpuTextureCreateView(surface_texture.texture, NULL);
|
||||
|
||||
if (!framebuffer || framebuffer->width != surface_configuration.width || framebuffer->height != surface_configuration.height) {
|
||||
if (framebuffer) {
|
||||
renderer_texture_destroy(framebuffer);
|
||||
framebuffer = NULL;
|
||||
}
|
||||
|
||||
framebuffer = renderer_texture_create(surface_format, R_TEXTURE_USAGE_TARGET, 4, surface_configuration.width, surface_configuration.height, NULL, "R_framebuffer");
|
||||
}
|
||||
|
||||
command_encoder = wgpuDeviceCreateCommandEncoder(device, NULL);
|
||||
R_framebuffer = framebuffer;
|
||||
}
|
||||
|
||||
void renderer_frame_end() {
|
||||
SDL_assert(command_encoder);
|
||||
SDL_assert(R_framebuffer);
|
||||
|
||||
if (pass_encoder) {
|
||||
wgpuRenderPassEncoderEnd(pass_encoder);
|
||||
wgpuRenderPassEncoderRelease(pass_encoder);
|
||||
pass_encoder = NULL;
|
||||
}
|
||||
|
||||
pass_encoder = wgpuCommandEncoderBeginRenderPass(command_encoder, &(WGPURenderPassDescriptor){
|
||||
.colorAttachmentCount = 1,
|
||||
.colorAttachments = &(WGPURenderPassColorAttachment) {
|
||||
.view = framebuffer->view,
|
||||
.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED,
|
||||
.resolveTarget = surface_texture_view,
|
||||
.loadOp = WGPULoadOp_Load,
|
||||
.storeOp = WGPUStoreOp_Discard,
|
||||
.clearValue = { .r = 0.0f, .g = 0.0f, .b = 0.0f, .a = 0.0f },
|
||||
},
|
||||
});
|
||||
wgpuRenderPassEncoderEnd(pass_encoder);
|
||||
wgpuRenderPassEncoderRelease(pass_encoder);
|
||||
pass_encoder = NULL;
|
||||
|
||||
wgpuTextureViewRelease(surface_texture_view);
|
||||
surface_texture_view = NULL;
|
||||
|
||||
WGPUCommandBuffer command_buffer = wgpuCommandEncoderFinish(command_encoder, NULL);
|
||||
wgpuCommandEncoderRelease(command_encoder);
|
||||
command_encoder = NULL;
|
||||
|
||||
wgpuQueueSubmit(queue, 1, &command_buffer);
|
||||
wgpuCommandBufferRelease(command_buffer);
|
||||
|
||||
wgpuSurfacePresent(surface);
|
||||
wgpuTextureRelease(surface_texture.texture);
|
||||
surface_texture.texture = NULL;
|
||||
|
||||
R_framebuffer = NULL;
|
||||
}
|
||||
|
||||
void renderer_frame_set_target(R_Texture target, R_Texture resolve_target, R_Load_Op load_op, R_Store_Op store_op, R_Color clear_color) {
|
||||
SDL_assert(command_encoder);
|
||||
|
||||
if (pass_encoder) {
|
||||
wgpuRenderPassEncoderEnd(pass_encoder);
|
||||
wgpuRenderPassEncoderRelease(pass_encoder);
|
||||
}
|
||||
|
||||
pass_encoder = wgpuCommandEncoderBeginRenderPass(command_encoder, &(WGPURenderPassDescriptor){
|
||||
.colorAttachmentCount = 1,
|
||||
.colorAttachments = &(WGPURenderPassColorAttachment) {
|
||||
.view = target->view,
|
||||
.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED,
|
||||
.resolveTarget = resolve_target ? resolve_target->view : NULL,
|
||||
.loadOp = load_ops[load_op],
|
||||
.storeOp = store_ops[store_op],
|
||||
.clearValue = { .r = clear_color.r, .g = clear_color.g, .b = clear_color.b, .a = clear_color.a },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
void renderer_frame_set_shader(R_Shader shader) {
|
||||
wgpuRenderPassEncoderSetPipeline(pass_encoder, shaders[shader]);
|
||||
current_shader = shader;
|
||||
}
|
||||
|
||||
void renderer_frame_draw(R_Buffer vertex_buffer, R_Buffer index_buffer, R_Buffer instance_buffer, Uint32 num_indices, Uint32 num_instances, const R_Draw_Resources *resources) {
|
||||
SDL_assert(pass_encoder);
|
||||
|
||||
if (resources->num_vertex_textures || resources->num_vertex_storage_buffers) {
|
||||
WGPUBindGroupEntry *entries = SDL_stack_alloc(WGPUBindGroupEntry, resources->num_vertex_textures + resources->num_vertex_storage_buffers);
|
||||
|
||||
for (int i = 0; i < resources->num_vertex_textures; i++) {
|
||||
entries[i] = (WGPUBindGroupEntry){
|
||||
.binding = i,
|
||||
.textureView = resources->vertex_textures[i]->view,
|
||||
};
|
||||
}
|
||||
|
||||
for (int i = 0; i < resources->num_vertex_storage_buffers; i++) {
|
||||
entries[resources->num_vertex_textures + i] = (WGPUBindGroupEntry){
|
||||
.binding = resources->num_vertex_textures + i,
|
||||
.buffer = resources->vertex_storage_buffers[i]->buffer,
|
||||
.offset = 0,
|
||||
.size = WGPU_WHOLE_SIZE,
|
||||
};
|
||||
}
|
||||
|
||||
WGPUBindGroup bind_group = wgpuDeviceCreateBindGroup(device, &(WGPUBindGroupDescriptor){
|
||||
.layout = wgpuRenderPipelineGetBindGroupLayout(shaders[current_shader], 0),
|
||||
.entryCount = resources->num_vertex_textures + resources->num_vertex_storage_buffers,
|
||||
.entries = entries,
|
||||
});
|
||||
|
||||
SDL_stack_free(entries);
|
||||
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 0, bind_group, 0, NULL);
|
||||
wgpuBindGroupRelease(bind_group);
|
||||
} else {
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 0, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
if (resources->num_vertex_uniform_buffers) {
|
||||
WGPUBindGroupEntry *entries = SDL_stack_alloc(WGPUBindGroupEntry, resources->num_vertex_uniform_buffers);
|
||||
|
||||
for (int i = 0; i < resources->num_vertex_uniform_buffers; i++) {
|
||||
entries[i] = (WGPUBindGroupEntry){
|
||||
.binding = i,
|
||||
.buffer = resources->vertex_uniform_buffers[i]->buffer,
|
||||
.offset = 0,
|
||||
.size = WGPU_WHOLE_SIZE,
|
||||
};
|
||||
}
|
||||
|
||||
WGPUBindGroup bind_group = wgpuDeviceCreateBindGroup(device, &(WGPUBindGroupDescriptor){
|
||||
.layout = wgpuRenderPipelineGetBindGroupLayout(shaders[current_shader], 1),
|
||||
.entryCount = resources->num_vertex_uniform_buffers,
|
||||
.entries = entries,
|
||||
});
|
||||
|
||||
SDL_stack_free(entries);
|
||||
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, bind_group, 0, NULL);
|
||||
wgpuBindGroupRelease(bind_group);
|
||||
} else {
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
if (resources->num_fragment_textures || resources->num_fragment_storage_buffers) {
|
||||
WGPUBindGroupEntry *entries = SDL_stack_alloc(WGPUBindGroupEntry, resources->num_fragment_textures * 2 + resources->num_fragment_storage_buffers);
|
||||
|
||||
for (int i = 0; i < resources->num_fragment_textures; i++) {
|
||||
entries[i * 2] = (WGPUBindGroupEntry){
|
||||
.binding = i * 2,
|
||||
.textureView = resources->fragment_textures[i]->view,
|
||||
};
|
||||
|
||||
entries[i * 2 + 1] = (WGPUBindGroupEntry){
|
||||
.binding = i * 2 + 1,
|
||||
.sampler = bilinear_sampler,
|
||||
};
|
||||
}
|
||||
|
||||
for (int i = 0; i < resources->num_fragment_storage_buffers; i++) {
|
||||
entries[resources->num_fragment_textures * 2 + i] = (WGPUBindGroupEntry){
|
||||
.binding = resources->num_fragment_textures * 2 + i,
|
||||
.buffer = resources->fragment_storage_buffers[i]->buffer,
|
||||
.offset = 0,
|
||||
.size = WGPU_WHOLE_SIZE,
|
||||
};
|
||||
}
|
||||
|
||||
WGPUBindGroup bind_group = wgpuDeviceCreateBindGroup(device, &(WGPUBindGroupDescriptor){
|
||||
.layout = wgpuRenderPipelineGetBindGroupLayout(shaders[current_shader], 2),
|
||||
.entryCount = resources->num_fragment_textures * 2 + resources->num_fragment_storage_buffers,
|
||||
.entries = entries,
|
||||
});
|
||||
|
||||
SDL_stack_free(entries);
|
||||
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 2, bind_group, 0, NULL);
|
||||
wgpuBindGroupRelease(bind_group);
|
||||
} else {
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 2, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
if (resources->num_fragment_uniform_buffers) {
|
||||
WGPUBindGroupEntry *entries = SDL_stack_alloc(WGPUBindGroupEntry, resources->num_fragment_uniform_buffers);
|
||||
|
||||
for (int i = 0; i < resources->num_fragment_uniform_buffers; i++) {
|
||||
entries[i] = (WGPUBindGroupEntry){
|
||||
.binding = i,
|
||||
.buffer = resources->fragment_uniform_buffers[i]->buffer,
|
||||
.offset = 0,
|
||||
.size = WGPU_WHOLE_SIZE,
|
||||
};
|
||||
}
|
||||
|
||||
WGPUBindGroup bind_group = wgpuDeviceCreateBindGroup(device, &(WGPUBindGroupDescriptor){
|
||||
.layout = wgpuRenderPipelineGetBindGroupLayout(shaders[current_shader], 3),
|
||||
.entryCount = resources->num_fragment_uniform_buffers,
|
||||
.entries = entries,
|
||||
});
|
||||
|
||||
SDL_stack_free(entries);
|
||||
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 3, bind_group, 0, NULL);
|
||||
wgpuBindGroupRelease(bind_group);
|
||||
} else {
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 3, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
if (vertex_buffer) wgpuRenderPassEncoderSetVertexBuffer(pass_encoder, 0, vertex_buffer->buffer, 0, WGPU_WHOLE_SIZE);
|
||||
if (instance_buffer) wgpuRenderPassEncoderSetVertexBuffer(pass_encoder, 1, instance_buffer->buffer, 0, WGPU_WHOLE_SIZE);
|
||||
|
||||
if (index_buffer) {
|
||||
wgpuRenderPassEncoderSetIndexBuffer(pass_encoder, index_buffer->buffer, WGPUIndexFormat_Uint16, 0, WGPU_WHOLE_SIZE);
|
||||
wgpuRenderPassEncoderDrawIndexed(pass_encoder, num_indices, num_instances, 0, 0, 0);
|
||||
} else {
|
||||
wgpuRenderPassEncoderDraw(pass_encoder, num_indices, num_instances, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUSurface create_wgpu_surface_for_SDL_window(SDL_Window *window) {
|
||||
SDL_PropertiesID properties = SDL_GetWindowProperties(window);
|
||||
|
||||
#if defined(SDL_PLATFORM_LINUX)
|
||||
const char *display_system = SDL_GetCurrentVideoDriver();
|
||||
|
||||
if (SDL_strcmp(display_system, "wayland") == 0) {
|
||||
void *display = SDL_GetPointerProperty(properties, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, NULL);
|
||||
void *surface = SDL_GetPointerProperty(properties, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, NULL);
|
||||
if (!display || !surface) return NULL;
|
||||
|
||||
WGPUSurfaceSourceWaylandSurface surface_source = {
|
||||
.chain = { .next = NULL, .sType = WGPUSType_SurfaceSourceWaylandSurface },
|
||||
.display = display,
|
||||
.surface = surface,
|
||||
};
|
||||
|
||||
WGPUSurfaceDescriptor descriptor = {
|
||||
.nextInChain = &surface_source.chain,
|
||||
.label = { .data = NULL, .length = WGPU_STRLEN },
|
||||
};
|
||||
|
||||
return wgpuInstanceCreateSurface(instance, &descriptor);
|
||||
} else if (SDL_strcmp(display_system, "x11") == 0) {
|
||||
void *display = SDL_GetPointerProperty(properties, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL);
|
||||
uint64_t xlib_window = SDL_GetNumberProperty (properties, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
|
||||
if (!display || !xlib_window) return NULL;
|
||||
|
||||
WGPUSurfaceSourceXlibWindow surface_source = {
|
||||
.chain = { .next = NULL, .sType = WGPUSType_SurfaceSourceXlibWindow },
|
||||
.display = display,
|
||||
.window = xlib_window,
|
||||
};
|
||||
|
||||
WGPUSurfaceDescriptor descriptor = {
|
||||
.nextInChain = &surface_source.chain,
|
||||
.label = { .data = NULL, .length = WGPU_STRLEN },
|
||||
};
|
||||
|
||||
return wgpuInstanceCreateSurface(instance, &descriptor);
|
||||
} else {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_GPU, "create_wgpu_surface_for_SDL_window is not implemented for this display system (%s).", display_system);
|
||||
return NULL;
|
||||
}
|
||||
#elif defined(SDL_PLATFORM_WINDOWS)
|
||||
void *hinstance = SDL_GetPointerProperty(properties, SDL_PROP_WINDOW_WIN32_INSTANCE_POINTER, NULL);
|
||||
void *hwnd = SDL_GetPointerProperty(properties, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
|
||||
if (!hinstance || !hwnd) return NULL;
|
||||
|
||||
WGPUSurfaceSourceWindowsHWND surface_source = {
|
||||
.chain = { .next = NULL, .sType = WGPUSType_SurfaceSourceWindowsHWND },
|
||||
.hinstance = hinstance,
|
||||
.hwnd = hwnd,
|
||||
};
|
||||
|
||||
WGPUSurfaceDescriptor descriptor = {
|
||||
.nextInChain = &surface_source.chain,
|
||||
.label = { .data = NULL, .length = WGPU_STRLEN },
|
||||
};
|
||||
|
||||
return wgpuInstanceCreateSurface(instance, &descriptor);
|
||||
#else
|
||||
static_assert(false, "create_wgpu_surface_for_SDL_window is not implemented for this platform.");
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void device_request_callback(WGPURequestDeviceStatus status, WGPUDevice device_, WGPUStringView message, void *userdata1, void *userdata2) {
|
||||
if (status != WGPURequestDeviceStatus_Success) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to request webgpu device.");
|
||||
init_done = true;
|
||||
return;
|
||||
}
|
||||
|
||||
device = device_;
|
||||
queue = wgpuDeviceGetQueue(device);
|
||||
init_done = true;
|
||||
}
|
||||
|
||||
static void adapter_request_callback(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void *userdata1, void *userdata2) {
|
||||
if (status != WGPURequestAdapterStatus_Success) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to request webgpu adapter.");
|
||||
init_done = true;
|
||||
return;
|
||||
}
|
||||
|
||||
WGPURequestDeviceCallbackInfo request_device_callback_info = {
|
||||
.mode = WGPUCallbackMode_AllowProcessEvents,
|
||||
.callback = device_request_callback,
|
||||
};
|
||||
|
||||
WGPUDeviceDescriptor device_descriptor = {
|
||||
.label = {},
|
||||
.requiredFeatureCount = 0,
|
||||
.requiredFeatures = NULL,
|
||||
.requiredLimits = NULL,
|
||||
.defaultQueue = {},
|
||||
.deviceLostCallbackInfo = {},
|
||||
.uncapturedErrorCallbackInfo = {},
|
||||
};
|
||||
|
||||
wgpuAdapterRequestDevice(adapter, &device_descriptor, request_device_callback_info);
|
||||
}
|
||||
|
||||
bool renderer_init(SDL_Window *window_) {
|
||||
window = window_;
|
||||
|
||||
instance = wgpuCreateInstance(NULL);
|
||||
if (!instance) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create webgpu instance.");
|
||||
return false;
|
||||
}
|
||||
|
||||
surface = create_wgpu_surface_for_SDL_window(window);
|
||||
if (!surface) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create webgpu surface for SDL window.");
|
||||
return false;
|
||||
}
|
||||
|
||||
WGPURequestAdapterCallbackInfo request_adapter_callback_info = {
|
||||
.mode = WGPUCallbackMode_AllowProcessEvents,
|
||||
.callback = adapter_request_callback,
|
||||
};
|
||||
|
||||
WGPURequestAdapterOptions request_adapter_options = {
|
||||
.featureLevel = WGPUFeatureLevel_Core,
|
||||
.powerPreference = WGPUPowerPreference_HighPerformance,
|
||||
.forceFallbackAdapter = false,
|
||||
.backendType = WGPUBackendType_Vulkan,
|
||||
.compatibleSurface = surface,
|
||||
};
|
||||
|
||||
wgpuInstanceRequestAdapter(instance, &request_adapter_options, request_adapter_callback_info);
|
||||
|
||||
while (!init_done) {
|
||||
wgpuInstanceProcessEvents(instance);
|
||||
}
|
||||
|
||||
if (!device) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to get webgpu device.");
|
||||
return false;
|
||||
}
|
||||
|
||||
surface_format = R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB;
|
||||
surface_configuration = (WGPUSurfaceConfiguration){
|
||||
.device = device,
|
||||
.format = WGPUTextureFormat_BGRA8UnormSrgb,
|
||||
.usage = WGPUTextureUsage_RenderAttachment,
|
||||
.width = 1280,
|
||||
.height = 720,
|
||||
.viewFormatCount = 0,
|
||||
.viewFormats = NULL,
|
||||
.alphaMode = WGPUCompositeAlphaMode_Opaque,
|
||||
.presentMode = WGPUPresentMode_Fifo,
|
||||
};
|
||||
|
||||
wgpuSurfaceConfigure(surface, &surface_configuration);
|
||||
|
||||
WGPUSamplerDescriptor bilinear_sampler_descriptor = {
|
||||
.label = { .data = "bilinear_sampler", .length = WGPU_STRLEN },
|
||||
|
||||
.addressModeU = WGPUAddressMode_ClampToEdge,
|
||||
.addressModeV = WGPUAddressMode_ClampToEdge,
|
||||
.addressModeW = WGPUAddressMode_ClampToEdge,
|
||||
|
||||
.magFilter = WGPUFilterMode_Linear,
|
||||
.minFilter = WGPUFilterMode_Linear,
|
||||
.mipmapFilter = WGPUMipmapFilterMode_Nearest,
|
||||
|
||||
.maxAnisotropy = 1,
|
||||
};
|
||||
|
||||
bilinear_sampler = wgpuDeviceCreateSampler(device, &bilinear_sampler_descriptor);
|
||||
|
||||
WGPUBlendState blend_state = {
|
||||
.color = { .operation = WGPUBlendOperation_Add, .srcFactor = WGPUBlendFactor_SrcAlpha, .dstFactor = WGPUBlendFactor_OneMinusSrcAlpha },
|
||||
.alpha = { .operation = WGPUBlendOperation_Add, .srcFactor = WGPUBlendFactor_SrcAlpha, .dstFactor = WGPUBlendFactor_OneMinusSrcAlpha },
|
||||
};
|
||||
|
||||
WGPUColorTargetState color_target_state = {
|
||||
.format = surface_configuration.format,
|
||||
.blend = &blend_state,
|
||||
.writeMask = WGPUColorWriteMask_All,
|
||||
};
|
||||
|
||||
// Shader
|
||||
{ // Basic
|
||||
const char shader_source[] = {
|
||||
#embed "shaders/wgsl/basic.wgsl"
|
||||
};
|
||||
|
||||
WGPUShaderModule shader = wgpuDeviceCreateShaderModule(device, &(WGPUShaderModuleDescriptor){
|
||||
.nextInChain = (WGPUChainedStruct *)&(WGPUShaderSourceWGSL){
|
||||
.chain = { .next = NULL, .sType = WGPUSType_ShaderSourceWGSL },
|
||||
.code = { .data = shader_source, .length = SDL_arraysize(shader_source) },
|
||||
},
|
||||
.label = { .data = "basic shader", .length = WGPU_STRLEN }
|
||||
});
|
||||
|
||||
shaders[R_SHADER_BASIC] = wgpuDeviceCreateRenderPipeline(device, &(WGPURenderPipelineDescriptor){
|
||||
.label = { .data = "basic render_pipeline", .length = WGPU_STRLEN },
|
||||
|
||||
.layout = wgpuDeviceCreatePipelineLayout(device, &(WGPUPipelineLayoutDescriptor){
|
||||
.label = { .data = "basic pipeline_layout", .length = WGPU_STRLEN },
|
||||
.bindGroupLayoutCount = 4,
|
||||
.bindGroupLayouts = (WGPUBindGroupLayout[]){
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 0,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 1,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Vertex, .buffer = { .type = WGPUBufferBindingType_Uniform } },
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 2,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Fragment, .texture = { .sampleType = WGPUTextureSampleType_Float, .viewDimension = WGPUTextureViewDimension_2D } },
|
||||
{ .binding = 1, .visibility = WGPUShaderStage_Fragment, .sampler = { .type = WGPUSamplerBindingType_Filtering } },
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 1,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Fragment, .buffer = { .type = WGPUBufferBindingType_Uniform } },
|
||||
},
|
||||
}),
|
||||
},
|
||||
}),
|
||||
|
||||
.vertex = {
|
||||
.module = shader,
|
||||
.entryPoint = { .data = "main_vertex", .length = WGPU_STRLEN },
|
||||
.constantCount = 0,
|
||||
.constants = NULL,
|
||||
.bufferCount = 2,
|
||||
.buffers = (WGPUVertexBufferLayout[]){
|
||||
{
|
||||
.stepMode = WGPUVertexStepMode_Vertex,
|
||||
.arrayStride = 20,
|
||||
.attributeCount = 2,
|
||||
.attributes = (WGPUVertexAttribute[]){
|
||||
{
|
||||
.format = WGPUVertexFormat_Float32x3,
|
||||
.offset = 0,
|
||||
.shaderLocation = 0,
|
||||
},
|
||||
{
|
||||
.format = WGPUVertexFormat_Float32x2,
|
||||
.offset = 12,
|
||||
.shaderLocation = 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.stepMode = WGPUVertexStepMode_Instance,
|
||||
.arrayStride = 8,
|
||||
.attributeCount = 1,
|
||||
.attributes = (WGPUVertexAttribute[]){
|
||||
{
|
||||
.format = WGPUVertexFormat_Float32x2,
|
||||
.offset = 0,
|
||||
.shaderLocation = 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
.primitive = {
|
||||
.topology = WGPUPrimitiveTopology_TriangleList,
|
||||
.stripIndexFormat = WGPUIndexFormat_Undefined,
|
||||
.frontFace = WGPUFrontFace_CCW,
|
||||
.cullMode = WGPUCullMode_Back,
|
||||
.unclippedDepth = false,
|
||||
},
|
||||
|
||||
.depthStencil = NULL,
|
||||
|
||||
.multisample = {
|
||||
.count = 4,
|
||||
.mask = ~0u,
|
||||
.alphaToCoverageEnabled = false,
|
||||
},
|
||||
|
||||
.fragment = &(WGPUFragmentState){
|
||||
.module = shader,
|
||||
.entryPoint = { .data = "main_fragment", .length = WGPU_STRLEN },
|
||||
.constantCount = 0,
|
||||
.constants = NULL,
|
||||
.targetCount = 1,
|
||||
.targets = &color_target_state,
|
||||
},
|
||||
});
|
||||
|
||||
wgpuShaderModuleRelease(shader);
|
||||
}
|
||||
|
||||
{ // World
|
||||
const char shader_source[] = {
|
||||
#embed "shaders/wgsl/world.wgsl"
|
||||
};
|
||||
|
||||
WGPUShaderModule shader = wgpuDeviceCreateShaderModule(device, &(WGPUShaderModuleDescriptor){
|
||||
.nextInChain = (WGPUChainedStruct *)&(WGPUShaderSourceWGSL){
|
||||
.chain = { .next = NULL, .sType = WGPUSType_ShaderSourceWGSL },
|
||||
.code = { .data = shader_source, .length = SDL_arraysize(shader_source) },
|
||||
},
|
||||
.label = { .data = "world shader", .length = WGPU_STRLEN }
|
||||
});
|
||||
|
||||
shaders[R_SHADER_WORLD] = wgpuDeviceCreateRenderPipeline(device, &(WGPURenderPipelineDescriptor){
|
||||
.label = { .data = "world render_pipeline", .length = WGPU_STRLEN },
|
||||
|
||||
.layout = wgpuDeviceCreatePipelineLayout(device, &(WGPUPipelineLayoutDescriptor){
|
||||
.label = { .data = "world pipeline_layout", .length = WGPU_STRLEN },
|
||||
.bindGroupLayoutCount = 4,
|
||||
.bindGroupLayouts = (WGPUBindGroupLayout[]){
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 1,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Vertex, .texture = { .sampleType = WGPUTextureSampleType_Uint, .viewDimension = WGPUTextureViewDimension_2D } },
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 2,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Vertex, .buffer = { .type = WGPUBufferBindingType_Uniform } },
|
||||
{ .binding = 1, .visibility = WGPUShaderStage_Vertex, .buffer = { .type = WGPUBufferBindingType_Uniform } },
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 3,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Fragment, .texture = { .sampleType = WGPUTextureSampleType_Float, .viewDimension = WGPUTextureViewDimension_2D } },
|
||||
{ .binding = 1, .visibility = WGPUShaderStage_Fragment, .sampler = { .type = WGPUSamplerBindingType_Filtering } },
|
||||
{ .binding = 2, .visibility = WGPUShaderStage_Fragment, .buffer = { .type = WGPUBufferBindingType_ReadOnlyStorage } },
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 1,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Fragment, .buffer = { .type = WGPUBufferBindingType_Uniform } },
|
||||
},
|
||||
}),
|
||||
},
|
||||
}),
|
||||
|
||||
.vertex = {
|
||||
.module = shader,
|
||||
.entryPoint = { .data = "main_vertex", .length = WGPU_STRLEN },
|
||||
.constantCount = 0,
|
||||
.constants = NULL,
|
||||
.bufferCount = 0,
|
||||
.buffers = (WGPUVertexBufferLayout[]){
|
||||
|
||||
},
|
||||
},
|
||||
|
||||
.primitive = {
|
||||
.topology = WGPUPrimitiveTopology_TriangleList,
|
||||
.stripIndexFormat = WGPUIndexFormat_Undefined,
|
||||
.frontFace = WGPUFrontFace_CCW,
|
||||
.cullMode = WGPUCullMode_Back,
|
||||
.unclippedDepth = false,
|
||||
},
|
||||
|
||||
.depthStencil = NULL,
|
||||
|
||||
.multisample = {
|
||||
.count = 4,
|
||||
.mask = ~0u,
|
||||
.alphaToCoverageEnabled = false,
|
||||
},
|
||||
|
||||
.fragment = &(WGPUFragmentState){
|
||||
.module = shader,
|
||||
.entryPoint = { .data = "main_fragment", .length = WGPU_STRLEN },
|
||||
.constantCount = 0,
|
||||
.constants = NULL,
|
||||
.targetCount = 1,
|
||||
.targets = &color_target_state,
|
||||
},
|
||||
});
|
||||
|
||||
wgpuShaderModuleRelease(shader);
|
||||
}
|
||||
|
||||
{ // Grid
|
||||
const char shader_source[] = {
|
||||
#embed "shaders/wgsl/grid.wgsl"
|
||||
};
|
||||
|
||||
WGPUShaderModule shader = wgpuDeviceCreateShaderModule(device, &(WGPUShaderModuleDescriptor){
|
||||
.nextInChain = (WGPUChainedStruct *)&(WGPUShaderSourceWGSL){
|
||||
.chain = { .next = NULL, .sType = WGPUSType_ShaderSourceWGSL },
|
||||
.code = { .data = shader_source, .length = SDL_arraysize(shader_source) },
|
||||
},
|
||||
.label = { .data = "grid shader", .length = WGPU_STRLEN }
|
||||
});
|
||||
|
||||
shaders[R_SHADER_GRID] = wgpuDeviceCreateRenderPipeline(device, &(WGPURenderPipelineDescriptor){
|
||||
.label = { .data = "grid render_pipeline", .length = WGPU_STRLEN },
|
||||
|
||||
.layout = wgpuDeviceCreatePipelineLayout(device, &(WGPUPipelineLayoutDescriptor){
|
||||
.label = { .data = "grid pipeline_layout", .length = WGPU_STRLEN },
|
||||
.bindGroupLayoutCount = 4,
|
||||
.bindGroupLayouts = (WGPUBindGroupLayout[]){
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 0,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 2,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Vertex, .buffer = { .type = WGPUBufferBindingType_Uniform } },
|
||||
{ .binding = 1, .visibility = WGPUShaderStage_Vertex, .buffer = { .type = WGPUBufferBindingType_Uniform } },
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 0,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 0,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
|
||||
},
|
||||
}),
|
||||
},
|
||||
}),
|
||||
|
||||
.vertex = {
|
||||
.module = shader,
|
||||
.entryPoint = { .data = "main_vertex", .length = WGPU_STRLEN },
|
||||
.constantCount = 0,
|
||||
.constants = NULL,
|
||||
.bufferCount = 1,
|
||||
.buffers = (WGPUVertexBufferLayout[]){
|
||||
{
|
||||
.stepMode = WGPUVertexStepMode_Vertex,
|
||||
.arrayStride = 20,
|
||||
.attributeCount = 1,
|
||||
.attributes = (WGPUVertexAttribute[]){
|
||||
{
|
||||
.format = WGPUVertexFormat_Float32x3,
|
||||
.offset = 0,
|
||||
.shaderLocation = 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
.primitive = {
|
||||
.topology = WGPUPrimitiveTopology_TriangleList,
|
||||
.stripIndexFormat = WGPUIndexFormat_Undefined,
|
||||
.frontFace = WGPUFrontFace_CCW,
|
||||
.cullMode = WGPUCullMode_Back,
|
||||
.unclippedDepth = false,
|
||||
},
|
||||
|
||||
.depthStencil = NULL,
|
||||
|
||||
.multisample = {
|
||||
.count = 4,
|
||||
.mask = ~0u,
|
||||
.alphaToCoverageEnabled = false,
|
||||
},
|
||||
|
||||
.fragment = &(WGPUFragmentState){
|
||||
.module = shader,
|
||||
.entryPoint = { .data = "main_fragment", .length = WGPU_STRLEN },
|
||||
.constantCount = 0,
|
||||
.constants = NULL,
|
||||
.targetCount = 1,
|
||||
.targets = &color_target_state,
|
||||
},
|
||||
});
|
||||
|
||||
wgpuShaderModuleRelease(shader);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplRenderer_Init() {
|
||||
cImGui_ImplWGPU_Init(&(ImGui_ImplWGPU_InitInfo){
|
||||
.Device = device,
|
||||
.NumFramesInFlight = 3,
|
||||
.RenderTargetFormat = surface_configuration.format,
|
||||
|
||||
.PipelineMultisampleState = {
|
||||
.count = 4,
|
||||
.mask = ~0,
|
||||
.alphaToCoverageEnabled = false,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
void ImGui_ImplRenderer_NewFrame() {
|
||||
cImGui_ImplWGPU_NewFrame();
|
||||
}
|
||||
|
||||
void ImGui_ImplRenderer_Shutdown() {
|
||||
cImGui_ImplWGPU_Shutdown();
|
||||
}
|
||||
|
||||
void ImGui_ImplRenderer_RenderDrawData(void* draw_data) {
|
||||
cImGui_ImplWGPU_RenderDrawData(draw_data, pass_encoder);
|
||||
}
|
||||
|
||||
Uint64 ImGui_ImplRenderer_GetTextureID(R_Texture texture) {
|
||||
return (Uint64)texture->view;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#language 2026
|
||||
|
||||
struct VertexShaderInput {
|
||||
uint32_t vertex_index : SV_VertexID;
|
||||
|
||||
[vk::location(0)] float3 pos;
|
||||
[vk::location(1)] float2 uv;
|
||||
|
||||
// Per Instance
|
||||
[vk::location(2)] float2 world_pos;
|
||||
};
|
||||
|
||||
struct VertexShaderOutput {
|
||||
float4 pos : SV_Position;
|
||||
|
||||
float2 uv;
|
||||
};
|
||||
|
||||
struct FragmentShaderOutput {
|
||||
float4 color : SV_Target;
|
||||
};
|
||||
|
||||
[vk::binding(0, 1)] ConstantBuffer<float4x4> view_projection_matrix : register(b0, space1);
|
||||
|
||||
[shader("vertex")]
|
||||
VertexShaderOutput main_vertex(VertexShaderInput input) {
|
||||
var output: VertexShaderOutput;
|
||||
|
||||
output.pos = mul(float4(input.world_pos + input.pos.xy, 0, 1), view_projection_matrix);
|
||||
output.uv = input.uv;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
[vk::binding(0, 2)] Sampler2D<float4> texture1 : register(t0, space2);
|
||||
|
||||
[vk::binding(0, 3)] ConstantBuffer<float3> tint : register(b0, space3);
|
||||
|
||||
[shader("pixel")]
|
||||
FragmentShaderOutput main_fragment(VertexShaderOutput input) {
|
||||
var output: FragmentShaderOutput;
|
||||
|
||||
output.color = pixel_art_sample(texture1, input.uv);
|
||||
output.color = float4(output.color.rgb * tint.rgb, output.color.a);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float4 pixel_art_sample(Sampler2D<float4> input_texture, float2 input_uv) {
|
||||
var dimensions: float2;
|
||||
input_texture.__getTexture().GetDimensions(dimensions.x, dimensions.y);
|
||||
|
||||
let texture_uv = input_uv * dimensions.xy;
|
||||
let sample_uv = (floor(texture_uv) + min(fract(texture_uv) / fwidth(texture_uv), float2(1.0, 1.0)) - 0.5) / dimensions.xy;
|
||||
|
||||
return input_texture.Sample(sample_uv);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#language 2026
|
||||
|
||||
struct VertexShaderInput {
|
||||
uint32_t vertex_index : SV_VertexID;
|
||||
uint32_t instance_index : SV_InstanceID;
|
||||
|
||||
[vk::location(0)] float3 pos;
|
||||
};
|
||||
|
||||
struct VertexShaderOutput {
|
||||
float4 pos : SV_Position;
|
||||
|
||||
int selected;
|
||||
};
|
||||
|
||||
struct FragmentShaderOutput {
|
||||
float4 color : SV_Target;
|
||||
};
|
||||
|
||||
struct Per_Frame_Data {
|
||||
int2 drag_start;
|
||||
int2 mouse;
|
||||
float2 grid_offset;
|
||||
uint32_t grid_width;
|
||||
uint32_t map_width;
|
||||
};
|
||||
|
||||
[vk::binding(0, 1)] ConstantBuffer<float4x4> view_projection_matrix : register(b0, space1);
|
||||
[vk::binding(1, 1)] ConstantBuffer<Per_Frame_Data> per_frame : register(b1, space1);
|
||||
|
||||
[shader("vertex")]
|
||||
VertexShaderOutput main_vertex(VertexShaderInput input) {
|
||||
var output: VertexShaderOutput;
|
||||
|
||||
let tile_pos = float2(float(input.instance_index % per_frame.grid_width), float(input.instance_index / per_frame.grid_width));
|
||||
output.pos = mul(float4(tile_pos + per_frame.grid_offset + input.pos.xy, 0, 1), view_projection_matrix);
|
||||
|
||||
let pos = int2(tile_pos + round(per_frame.grid_offset));
|
||||
let selection_min = min(per_frame.drag_start, per_frame.mouse);
|
||||
let selection_max = max(per_frame.drag_start, per_frame.mouse);
|
||||
output.selected = select(all(pos >= selection_min) && all(pos <= selection_max), 1, 0);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static const float4 color = float4(1.0, 1.0, 1.0, 0.1);
|
||||
static const float4 selected_color = float4(1.0, 0.0, 1.0, 1.0);
|
||||
|
||||
[shader("pixel")]
|
||||
FragmentShaderOutput main_fragment(VertexShaderOutput input) {
|
||||
var output: FragmentShaderOutput;
|
||||
|
||||
output.color = select(input.selected != 0, selected_color, color);
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#language 2026
|
||||
|
||||
struct VertexShaderInput {
|
||||
uint32_t vertex_index : SV_VertexID;
|
||||
uint32_t instance_index : SV_InstanceID;
|
||||
};
|
||||
|
||||
struct VertexShaderOutput {
|
||||
float4 pos : SV_Position;
|
||||
|
||||
float2 uv;
|
||||
uint32_t tile;
|
||||
};
|
||||
|
||||
struct FragmentShaderOutput {
|
||||
float4 color : SV_Target;
|
||||
};
|
||||
|
||||
struct Per_Frame_Data {
|
||||
int2 drag_start;
|
||||
int2 mouse;
|
||||
float2 grid_offset;
|
||||
uint32_t grid_width;
|
||||
uint32_t map_width;
|
||||
};
|
||||
|
||||
[vk::binding(0, 1)] ConstantBuffer<float4x4> view_projection_matrix : register(b0, space1);
|
||||
[vk::binding(1, 1)] ConstantBuffer<Per_Frame_Data> per_frame : register(b1, space1);
|
||||
|
||||
[vk::binding(0, 0)] Texture2D<uint32_t> map_texture : register(t0, space0);
|
||||
|
||||
[shader("vertex")]
|
||||
VertexShaderOutput main_vertex(VertexShaderInput input) {
|
||||
var output: VertexShaderOutput;
|
||||
|
||||
let tile_pos = uint32_t2(input.instance_index % per_frame.map_width, input.instance_index / per_frame.map_width);
|
||||
output.tile = map_texture.Load(uint32_t3(tile_pos, 0));
|
||||
|
||||
switch (input.vertex_index) {
|
||||
case 0: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2(-0.5, 0.5), 0, 1), view_projection_matrix); output.uv = float2(0, 0); } break;
|
||||
case 1: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2(-0.5, -0.5), 0, 1), view_projection_matrix); output.uv = float2(0, 1); } break;
|
||||
case 2: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2( 0.5, -0.5), 0, 1), view_projection_matrix); output.uv = float2(1, 1); } break;
|
||||
case 3: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2(-0.5, 0.5), 0, 1), view_projection_matrix); output.uv = float2(0, 0); } break;
|
||||
case 4: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2( 0.5, -0.5), 0, 1), view_projection_matrix); output.uv = float2(1, 1); } break;
|
||||
case 5: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2( 0.5, 0.5), 0, 1), view_projection_matrix); output.uv = float2(1, 0); } break;
|
||||
default: {}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
[vk::binding(0, 2)] Sampler2D<float4> tile_atlas : register(t0, space2);
|
||||
[vk::binding(2, 2)] StructuredBuffer<float4> tile_uvs : register(t1, space2);
|
||||
|
||||
[vk::binding(0, 3)] ConstantBuffer<float3> tint : register(b0, space3);
|
||||
|
||||
[shader("pixel")]
|
||||
FragmentShaderOutput main_fragment(VertexShaderOutput input) {
|
||||
var output: FragmentShaderOutput;
|
||||
|
||||
output.color = pixel_art_sample(tile_atlas, input.uv, input.tile);
|
||||
output.color = float4(output.color.rgb * tint.rgb, output.color.a);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float4 pixel_art_sample(Sampler2D<float4> input_texture, float2 input_uv, uint32_t tile) {
|
||||
var dimensions: float2;
|
||||
input_texture.__getTexture().GetDimensions(dimensions.x, dimensions.y);
|
||||
|
||||
let tile_uv = tile_uvs[tile];
|
||||
|
||||
let texture_uv = lerp(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 input_texture.Sample(uv);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
struct _MatrixStorage_float4x4_ColMajorstd140_0
|
||||
{
|
||||
@align(16) data_0 : array<vec4<f32>, i32(4)>,
|
||||
};
|
||||
|
||||
@binding(0) @group(1) var<uniform> view_projection_matrix_0 : _MatrixStorage_float4x4_ColMajorstd140_0;
|
||||
@binding(0) @group(2) var texture1_texture_0 : texture_2d<f32>;
|
||||
|
||||
@binding(1) @group(2) var texture1_sampler_0 : sampler;
|
||||
|
||||
@binding(0) @group(3) var<uniform> tint_0 : vec3<f32>;
|
||||
struct VertexShaderOutput_0
|
||||
{
|
||||
@builtin(position) pos_0 : vec4<f32>,
|
||||
@location(0) uv_0 : vec2<f32>,
|
||||
};
|
||||
|
||||
struct vertexInput_0
|
||||
{
|
||||
@location(0) pos_1 : vec3<f32>,
|
||||
@location(1) uv_1 : vec2<f32>,
|
||||
@location(2) world_pos_0 : vec2<f32>,
|
||||
};
|
||||
|
||||
@vertex
|
||||
fn main_vertex( _S1 : vertexInput_0, @builtin(vertex_index) vertex_index_0 : u32) -> VertexShaderOutput_0
|
||||
{
|
||||
var output_0 : VertexShaderOutput_0;
|
||||
output_0.pos_0 = (((mat4x4<f32>(view_projection_matrix_0.data_0[i32(0)][i32(0)], view_projection_matrix_0.data_0[i32(1)][i32(0)], view_projection_matrix_0.data_0[i32(2)][i32(0)], view_projection_matrix_0.data_0[i32(3)][i32(0)], view_projection_matrix_0.data_0[i32(0)][i32(1)], view_projection_matrix_0.data_0[i32(1)][i32(1)], view_projection_matrix_0.data_0[i32(2)][i32(1)], view_projection_matrix_0.data_0[i32(3)][i32(1)], view_projection_matrix_0.data_0[i32(0)][i32(2)], view_projection_matrix_0.data_0[i32(1)][i32(2)], view_projection_matrix_0.data_0[i32(2)][i32(2)], view_projection_matrix_0.data_0[i32(3)][i32(2)], view_projection_matrix_0.data_0[i32(0)][i32(3)], view_projection_matrix_0.data_0[i32(1)][i32(3)], view_projection_matrix_0.data_0[i32(2)][i32(3)], view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4<f32>(_S1.world_pos_0 + _S1.pos_1.xy, 0.0f, 1.0f))));
|
||||
output_0.uv_0 = _S1.uv_1;
|
||||
return output_0;
|
||||
}
|
||||
|
||||
fn pixel_art_sample_0( input_texture_texture_0 : texture_2d<f32>, input_texture_sampler_0 : sampler, input_uv_0 : vec2<f32>) -> vec4<f32>
|
||||
{
|
||||
var dimensions_0 : vec2<f32>;
|
||||
var _S2 : f32 = dimensions_0[i32(0)];
|
||||
var _S3 : f32 = dimensions_0[i32(1)];
|
||||
{var dim = textureDimensions((input_texture_texture_0));((_S2)) = f32(dim.x);((_S3)) = f32(dim.y);};
|
||||
dimensions_0[i32(0)] = _S2;
|
||||
dimensions_0[i32(1)] = _S3;
|
||||
var _S4 : vec2<f32> = input_uv_0 * dimensions_0.xy;
|
||||
var _S5 : vec2<f32> = (floor(_S4) + min(fract(_S4) / (fwidth((_S4))), vec2<f32>(1.0f, 1.0f)) - vec2<f32>(0.5f)) / dimensions_0.xy;
|
||||
;
|
||||
return (textureSample((input_texture_texture_0), (input_texture_sampler_0), (_S5)));
|
||||
}
|
||||
|
||||
struct FragmentShaderOutput_0
|
||||
{
|
||||
@location(0) color_0 : vec4<f32>,
|
||||
};
|
||||
|
||||
struct pixelInput_0
|
||||
{
|
||||
@location(0) uv_2 : vec2<f32>,
|
||||
};
|
||||
|
||||
@fragment
|
||||
fn main_fragment( _S6 : pixelInput_0, @builtin(position) pos_2 : vec4<f32>) -> FragmentShaderOutput_0
|
||||
{
|
||||
var output_1 : FragmentShaderOutput_0;
|
||||
var _S7 : vec4<f32> = pixel_art_sample_0(texture1_texture_0, texture1_sampler_0, _S6.uv_2);
|
||||
output_1.color_0 = vec4<f32>(_S7.xyz * tint_0.xyz, _S7.w);
|
||||
return output_1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
struct Per_Frame_Data_std140_0
|
||||
{
|
||||
@align(16) drag_start_0 : vec2<i32>,
|
||||
@align(8) mouse_0 : vec2<i32>,
|
||||
@align(16) grid_offset_0 : vec2<f32>,
|
||||
@align(8) grid_width_0 : u32,
|
||||
@align(4) map_width_0 : u32,
|
||||
};
|
||||
|
||||
@binding(1) @group(1) var<uniform> per_frame_0 : Per_Frame_Data_std140_0;
|
||||
struct _MatrixStorage_float4x4_ColMajorstd140_0
|
||||
{
|
||||
@align(16) data_0 : array<vec4<f32>, i32(4)>,
|
||||
};
|
||||
|
||||
@binding(0) @group(1) var<uniform> view_projection_matrix_0 : _MatrixStorage_float4x4_ColMajorstd140_0;
|
||||
struct VertexShaderOutput_0
|
||||
{
|
||||
@builtin(position) pos_0 : vec4<f32>,
|
||||
@location(0) selected_0 : i32,
|
||||
};
|
||||
|
||||
struct vertexInput_0
|
||||
{
|
||||
@location(0) pos_1 : vec3<f32>,
|
||||
};
|
||||
|
||||
@vertex
|
||||
fn main_vertex( _S1 : vertexInput_0, @builtin(vertex_index) vertex_index_0 : u32, @builtin(instance_index) instance_index_0 : u32) -> VertexShaderOutput_0
|
||||
{
|
||||
var _S2 : u32 = instance_index_0 % per_frame_0.grid_width_0;
|
||||
var _S3 : f32 = f32(_S2);
|
||||
var _S4 : u32 = instance_index_0 / per_frame_0.grid_width_0;
|
||||
var _S5 : vec2<f32> = vec2<f32>(_S3, f32(_S4));
|
||||
var output_0 : VertexShaderOutput_0;
|
||||
output_0.pos_0 = (((mat4x4<f32>(view_projection_matrix_0.data_0[i32(0)][i32(0)], view_projection_matrix_0.data_0[i32(1)][i32(0)], view_projection_matrix_0.data_0[i32(2)][i32(0)], view_projection_matrix_0.data_0[i32(3)][i32(0)], view_projection_matrix_0.data_0[i32(0)][i32(1)], view_projection_matrix_0.data_0[i32(1)][i32(1)], view_projection_matrix_0.data_0[i32(2)][i32(1)], view_projection_matrix_0.data_0[i32(3)][i32(1)], view_projection_matrix_0.data_0[i32(0)][i32(2)], view_projection_matrix_0.data_0[i32(1)][i32(2)], view_projection_matrix_0.data_0[i32(2)][i32(2)], view_projection_matrix_0.data_0[i32(3)][i32(2)], view_projection_matrix_0.data_0[i32(0)][i32(3)], view_projection_matrix_0.data_0[i32(1)][i32(3)], view_projection_matrix_0.data_0[i32(2)][i32(3)], view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4<f32>(_S5 + per_frame_0.grid_offset_0 + _S1.pos_1.xy, 0.0f, 1.0f))));
|
||||
var _S6 : vec2<i32> = vec2<i32>(_S5 + round(per_frame_0.grid_offset_0));
|
||||
var _S7 : vec2<i32> = max(per_frame_0.drag_start_0, per_frame_0.mouse_0);
|
||||
var _S8 : bool;
|
||||
if((all((_S6 >= (min(per_frame_0.drag_start_0, per_frame_0.mouse_0))))))
|
||||
{
|
||||
_S8 = (all((_S6 <= _S7)));
|
||||
}
|
||||
else
|
||||
{
|
||||
_S8 = false;
|
||||
}
|
||||
output_0.selected_0 = select(i32(0), i32(1), _S8);
|
||||
return output_0;
|
||||
}
|
||||
|
||||
struct FragmentShaderOutput_0
|
||||
{
|
||||
@location(0) color_0 : vec4<f32>,
|
||||
};
|
||||
|
||||
struct pixelInput_0
|
||||
{
|
||||
@location(0) selected_1 : i32,
|
||||
};
|
||||
|
||||
@fragment
|
||||
fn main_fragment( _S9 : pixelInput_0, @builtin(position) pos_2 : vec4<f32>) -> FragmentShaderOutput_0
|
||||
{
|
||||
var output_1 : FragmentShaderOutput_0;
|
||||
output_1.color_0 = select(vec4<f32>(1.0f, 1.0f, 1.0f, 0.10000000149011612f), vec4<f32>(1.0f, 0.0f, 1.0f, 1.0f), (_S9.selected_1) != i32(0));
|
||||
return output_1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
struct Per_Frame_Data_std140_0
|
||||
{
|
||||
@align(16) drag_start_0 : vec2<i32>,
|
||||
@align(8) mouse_0 : vec2<i32>,
|
||||
@align(16) grid_offset_0 : vec2<f32>,
|
||||
@align(8) grid_width_0 : u32,
|
||||
@align(4) map_width_0 : u32,
|
||||
};
|
||||
|
||||
@binding(1) @group(1) var<uniform> per_frame_0 : Per_Frame_Data_std140_0;
|
||||
@binding(0) @group(0) var map_texture_0 : texture_2d<u32>;
|
||||
|
||||
struct _MatrixStorage_float4x4_ColMajorstd140_0
|
||||
{
|
||||
@align(16) data_0 : array<vec4<f32>, i32(4)>,
|
||||
};
|
||||
|
||||
@binding(0) @group(1) var<uniform> view_projection_matrix_0 : _MatrixStorage_float4x4_ColMajorstd140_0;
|
||||
@binding(2) @group(2) var<storage, read> tile_uvs_0 : array<vec4<f32>>;
|
||||
|
||||
@binding(0) @group(2) var tile_atlas_texture_0 : texture_2d<f32>;
|
||||
|
||||
@binding(1) @group(2) var tile_atlas_sampler_0 : sampler;
|
||||
|
||||
@binding(0) @group(3) var<uniform> tint_0 : vec3<f32>;
|
||||
struct VertexShaderOutput_0
|
||||
{
|
||||
@builtin(position) pos_0 : vec4<f32>,
|
||||
@location(0) uv_0 : vec2<f32>,
|
||||
@location(1) tile_0 : u32,
|
||||
};
|
||||
|
||||
@vertex
|
||||
fn main_vertex(@builtin(vertex_index) vertex_index_0 : u32, @builtin(instance_index) instance_index_0 : u32) -> VertexShaderOutput_0
|
||||
{
|
||||
var _S1 : u32 = instance_index_0 % per_frame_0.map_width_0;
|
||||
var _S2 : u32 = instance_index_0 / per_frame_0.map_width_0;
|
||||
var _S3 : vec2<u32> = vec2<u32>(_S1, _S2);
|
||||
var output_0 : VertexShaderOutput_0;
|
||||
var _S4 : vec3<i32> = vec3<i32>(vec3<u32>(_S3, u32(0)));
|
||||
output_0.tile_0 = (textureLoad((map_texture_0), ((_S4)).xy, ((_S4)).z).x);
|
||||
switch(vertex_index_0)
|
||||
{
|
||||
case u32(0):
|
||||
{
|
||||
output_0.pos_0 = (((mat4x4<f32>(view_projection_matrix_0.data_0[i32(0)][i32(0)], view_projection_matrix_0.data_0[i32(1)][i32(0)], view_projection_matrix_0.data_0[i32(2)][i32(0)], view_projection_matrix_0.data_0[i32(3)][i32(0)], view_projection_matrix_0.data_0[i32(0)][i32(1)], view_projection_matrix_0.data_0[i32(1)][i32(1)], view_projection_matrix_0.data_0[i32(2)][i32(1)], view_projection_matrix_0.data_0[i32(3)][i32(1)], view_projection_matrix_0.data_0[i32(0)][i32(2)], view_projection_matrix_0.data_0[i32(1)][i32(2)], view_projection_matrix_0.data_0[i32(2)][i32(2)], view_projection_matrix_0.data_0[i32(3)][i32(2)], view_projection_matrix_0.data_0[i32(0)][i32(3)], view_projection_matrix_0.data_0[i32(1)][i32(3)], view_projection_matrix_0.data_0[i32(2)][i32(3)], view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4<f32>(vec2<f32>(_S3) - vec2<f32>(0.5f, 0.5f) + vec2<f32>(-0.5f, 0.5f), 0.0f, 1.0f))));
|
||||
output_0.uv_0 = vec2<f32>(0.0f, 0.0f);
|
||||
break;
|
||||
}
|
||||
case u32(1):
|
||||
{
|
||||
output_0.pos_0 = (((mat4x4<f32>(view_projection_matrix_0.data_0[i32(0)][i32(0)], view_projection_matrix_0.data_0[i32(1)][i32(0)], view_projection_matrix_0.data_0[i32(2)][i32(0)], view_projection_matrix_0.data_0[i32(3)][i32(0)], view_projection_matrix_0.data_0[i32(0)][i32(1)], view_projection_matrix_0.data_0[i32(1)][i32(1)], view_projection_matrix_0.data_0[i32(2)][i32(1)], view_projection_matrix_0.data_0[i32(3)][i32(1)], view_projection_matrix_0.data_0[i32(0)][i32(2)], view_projection_matrix_0.data_0[i32(1)][i32(2)], view_projection_matrix_0.data_0[i32(2)][i32(2)], view_projection_matrix_0.data_0[i32(3)][i32(2)], view_projection_matrix_0.data_0[i32(0)][i32(3)], view_projection_matrix_0.data_0[i32(1)][i32(3)], view_projection_matrix_0.data_0[i32(2)][i32(3)], view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4<f32>(vec2<f32>(_S3) - vec2<f32>(0.5f, 0.5f) + vec2<f32>(-0.5f, -0.5f), 0.0f, 1.0f))));
|
||||
output_0.uv_0 = vec2<f32>(0.0f, 1.0f);
|
||||
break;
|
||||
}
|
||||
case u32(2):
|
||||
{
|
||||
output_0.pos_0 = (((mat4x4<f32>(view_projection_matrix_0.data_0[i32(0)][i32(0)], view_projection_matrix_0.data_0[i32(1)][i32(0)], view_projection_matrix_0.data_0[i32(2)][i32(0)], view_projection_matrix_0.data_0[i32(3)][i32(0)], view_projection_matrix_0.data_0[i32(0)][i32(1)], view_projection_matrix_0.data_0[i32(1)][i32(1)], view_projection_matrix_0.data_0[i32(2)][i32(1)], view_projection_matrix_0.data_0[i32(3)][i32(1)], view_projection_matrix_0.data_0[i32(0)][i32(2)], view_projection_matrix_0.data_0[i32(1)][i32(2)], view_projection_matrix_0.data_0[i32(2)][i32(2)], view_projection_matrix_0.data_0[i32(3)][i32(2)], view_projection_matrix_0.data_0[i32(0)][i32(3)], view_projection_matrix_0.data_0[i32(1)][i32(3)], view_projection_matrix_0.data_0[i32(2)][i32(3)], view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4<f32>(vec2<f32>(_S3) - vec2<f32>(0.5f, 0.5f) + vec2<f32>(0.5f, -0.5f), 0.0f, 1.0f))));
|
||||
output_0.uv_0 = vec2<f32>(1.0f, 1.0f);
|
||||
break;
|
||||
}
|
||||
case u32(3):
|
||||
{
|
||||
output_0.pos_0 = (((mat4x4<f32>(view_projection_matrix_0.data_0[i32(0)][i32(0)], view_projection_matrix_0.data_0[i32(1)][i32(0)], view_projection_matrix_0.data_0[i32(2)][i32(0)], view_projection_matrix_0.data_0[i32(3)][i32(0)], view_projection_matrix_0.data_0[i32(0)][i32(1)], view_projection_matrix_0.data_0[i32(1)][i32(1)], view_projection_matrix_0.data_0[i32(2)][i32(1)], view_projection_matrix_0.data_0[i32(3)][i32(1)], view_projection_matrix_0.data_0[i32(0)][i32(2)], view_projection_matrix_0.data_0[i32(1)][i32(2)], view_projection_matrix_0.data_0[i32(2)][i32(2)], view_projection_matrix_0.data_0[i32(3)][i32(2)], view_projection_matrix_0.data_0[i32(0)][i32(3)], view_projection_matrix_0.data_0[i32(1)][i32(3)], view_projection_matrix_0.data_0[i32(2)][i32(3)], view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4<f32>(vec2<f32>(_S3) - vec2<f32>(0.5f, 0.5f) + vec2<f32>(-0.5f, 0.5f), 0.0f, 1.0f))));
|
||||
output_0.uv_0 = vec2<f32>(0.0f, 0.0f);
|
||||
break;
|
||||
}
|
||||
case u32(4):
|
||||
{
|
||||
output_0.pos_0 = (((mat4x4<f32>(view_projection_matrix_0.data_0[i32(0)][i32(0)], view_projection_matrix_0.data_0[i32(1)][i32(0)], view_projection_matrix_0.data_0[i32(2)][i32(0)], view_projection_matrix_0.data_0[i32(3)][i32(0)], view_projection_matrix_0.data_0[i32(0)][i32(1)], view_projection_matrix_0.data_0[i32(1)][i32(1)], view_projection_matrix_0.data_0[i32(2)][i32(1)], view_projection_matrix_0.data_0[i32(3)][i32(1)], view_projection_matrix_0.data_0[i32(0)][i32(2)], view_projection_matrix_0.data_0[i32(1)][i32(2)], view_projection_matrix_0.data_0[i32(2)][i32(2)], view_projection_matrix_0.data_0[i32(3)][i32(2)], view_projection_matrix_0.data_0[i32(0)][i32(3)], view_projection_matrix_0.data_0[i32(1)][i32(3)], view_projection_matrix_0.data_0[i32(2)][i32(3)], view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4<f32>(vec2<f32>(_S3) - vec2<f32>(0.5f, 0.5f) + vec2<f32>(0.5f, -0.5f), 0.0f, 1.0f))));
|
||||
output_0.uv_0 = vec2<f32>(1.0f, 1.0f);
|
||||
break;
|
||||
}
|
||||
case u32(5):
|
||||
{
|
||||
const _S5 : vec2<f32> = vec2<f32>(0.5f, 0.5f);
|
||||
output_0.pos_0 = (((mat4x4<f32>(view_projection_matrix_0.data_0[i32(0)][i32(0)], view_projection_matrix_0.data_0[i32(1)][i32(0)], view_projection_matrix_0.data_0[i32(2)][i32(0)], view_projection_matrix_0.data_0[i32(3)][i32(0)], view_projection_matrix_0.data_0[i32(0)][i32(1)], view_projection_matrix_0.data_0[i32(1)][i32(1)], view_projection_matrix_0.data_0[i32(2)][i32(1)], view_projection_matrix_0.data_0[i32(3)][i32(1)], view_projection_matrix_0.data_0[i32(0)][i32(2)], view_projection_matrix_0.data_0[i32(1)][i32(2)], view_projection_matrix_0.data_0[i32(2)][i32(2)], view_projection_matrix_0.data_0[i32(3)][i32(2)], view_projection_matrix_0.data_0[i32(0)][i32(3)], view_projection_matrix_0.data_0[i32(1)][i32(3)], view_projection_matrix_0.data_0[i32(2)][i32(3)], view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4<f32>(vec2<f32>(_S3) - _S5 + _S5, 0.0f, 1.0f))));
|
||||
output_0.uv_0 = vec2<f32>(1.0f, 0.0f);
|
||||
break;
|
||||
}
|
||||
default :
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return output_0;
|
||||
}
|
||||
|
||||
fn pixel_art_sample_0( input_texture_texture_0 : texture_2d<f32>, input_texture_sampler_0 : sampler, input_uv_0 : vec2<f32>, tile_1 : u32) -> vec4<f32>
|
||||
{
|
||||
var dimensions_0 : vec2<f32>;
|
||||
var _S6 : f32 = dimensions_0[i32(0)];
|
||||
var _S7 : f32 = dimensions_0[i32(1)];
|
||||
{var dim = textureDimensions((input_texture_texture_0));((_S6)) = f32(dim.x);((_S7)) = f32(dim.y);};
|
||||
dimensions_0[i32(0)] = _S6;
|
||||
dimensions_0[i32(1)] = _S7;
|
||||
var _S8 : vec4<f32> = tile_uvs_0[tile_1];
|
||||
var _S9 : vec2<f32> = _S8.xy;
|
||||
var _S10 : vec2<f32> = _S8.zw;
|
||||
var _S11 : vec2<f32> = mix(_S9, _S10, input_uv_0);
|
||||
var _S12 : vec2<f32> = vec2<f32>(0.5f);
|
||||
var _S13 : vec2<f32> = clamp((floor(_S11) + saturate(fract(_S11) / (fwidth((_S11)))) - _S12) / dimensions_0, (_S9 + _S12) / dimensions_0, (_S10 - _S12) / dimensions_0);
|
||||
;
|
||||
return (textureSample((input_texture_texture_0), (input_texture_sampler_0), (_S13)));
|
||||
}
|
||||
|
||||
struct FragmentShaderOutput_0
|
||||
{
|
||||
@location(0) color_0 : vec4<f32>,
|
||||
};
|
||||
|
||||
struct pixelInput_0
|
||||
{
|
||||
@location(0) uv_1 : vec2<f32>,
|
||||
@location(1) tile_2 : u32,
|
||||
};
|
||||
|
||||
@fragment
|
||||
fn main_fragment( _S14 : pixelInput_0, @builtin(position) pos_1 : vec4<f32>) -> FragmentShaderOutput_0
|
||||
{
|
||||
var output_1 : FragmentShaderOutput_0;
|
||||
var _S15 : vec4<f32> = pixel_art_sample_0(tile_atlas_texture_0, tile_atlas_sampler_0, _S14.uv_1, _S14.tile_2);
|
||||
output_1.color_0 = vec4<f32>(_S15.xyz * tint_0.xyz, _S15.w);
|
||||
return output_1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user