change tiles from a texture array to a texture atlas
This commit is contained in:
+110
-79
@@ -6,6 +6,7 @@
|
||||
#include <imgui_impl_sdl3.h>
|
||||
#include <imgui_impl_sdlgpu3.h>
|
||||
|
||||
#include "smol-atlas.h"
|
||||
#include "defer.h"
|
||||
#include "log.h"
|
||||
#include "m_string.h"
|
||||
@@ -31,8 +32,8 @@ SDL_GPUBuffer *index_buffer;
|
||||
SDL_GPUBuffer *tiles_instance_buffer;
|
||||
SDL_GPUBuffer *player_instance_buffer;
|
||||
|
||||
Sint16 window_width;
|
||||
Sint16 window_height;
|
||||
Sint32 window_width;
|
||||
Sint32 window_height;
|
||||
|
||||
bool Running = true;
|
||||
|
||||
@@ -68,14 +69,10 @@ Instance tiles_instances[view_width * view_height] = {
|
||||
|
||||
Instance player_instance = { { 0.5f + 0.5f / view_width, 0.5f, 1.0f / view_width, 1.0f / view_height}, 0, {0, 0, 1, 1}};
|
||||
|
||||
struct Tile {
|
||||
Uint32 type;
|
||||
};
|
||||
|
||||
Uint32 map_width = view_width;
|
||||
Uint32 map_height = view_height;
|
||||
|
||||
Tile* map_tiles;
|
||||
Uint32* map_tiles;
|
||||
|
||||
struct Player {
|
||||
Sint64 pos_x;
|
||||
@@ -94,6 +91,24 @@ struct PerFrame {
|
||||
|
||||
PerFrame per_frame = {1};
|
||||
|
||||
typedef struct {
|
||||
Uint32 type;
|
||||
const char *asset_path;
|
||||
|
||||
smol_atlas_item_t *atlas_item;
|
||||
} TileInfo;
|
||||
|
||||
TileInfo tile_infos[] = {
|
||||
{ 0x0001, "../assets/tiles/error.png" },
|
||||
{ 0x0000, "../assets/tiles/empty.png" },
|
||||
{ 0x0100, "../assets/tiles/grass_1.png" },
|
||||
{ 0x0200, "../assets/tiles/ground_1.png" },
|
||||
{ 0x0300, "../assets/tiles/water_1.png" },
|
||||
};
|
||||
|
||||
int tile_atlas_size = 256;
|
||||
smol_atlas_t *tile_atlas;
|
||||
|
||||
void save_map() {
|
||||
log("Save file is under construction.");
|
||||
FILE* file = fopen("../assets/map/map.sv", "wb");
|
||||
@@ -115,7 +130,8 @@ void save_map() {
|
||||
}
|
||||
|
||||
for (int i = 0; i < map_width * map_height; i++) {
|
||||
if (fwrite(&map_tiles[i], sizeof(Tile), 1, file) != 1) {
|
||||
Uint32 type = tile_infos[map_tiles[i]].type;
|
||||
if (fwrite(&type, sizeof(Uint32), 1, file) != 1) {
|
||||
log_error("fwrite for tile_type at tile number %d has failed.", i);
|
||||
return;
|
||||
}
|
||||
@@ -142,17 +158,26 @@ void load_map() {
|
||||
if (map_tiles)
|
||||
free(map_tiles);
|
||||
|
||||
map_tiles = (Tile*)malloc(map_width * map_height * sizeof(Tile));
|
||||
map_tiles = (Uint32*)malloc(map_width * map_height * sizeof(Uint32));
|
||||
|
||||
for (int i = 0; i < map_width * map_height; i++) {
|
||||
map_tiles[i] = read<Tile>(file);
|
||||
Uint32 type = read<Uint32>(file);
|
||||
Uint32 kind = 0;
|
||||
for (int i = 0; i < SDL_arraysize(tile_infos); i++) {
|
||||
if (tile_infos[i].type == type) {
|
||||
kind = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
map_tiles[i] = kind;
|
||||
}
|
||||
|
||||
log("Loading map was successful.");
|
||||
}
|
||||
|
||||
void change_map_size(char direction, int amount) {
|
||||
Tile* old_map = map_tiles;
|
||||
Uint32* old_map = map_tiles;
|
||||
auto old_map_width = map_width;
|
||||
auto old_map_height = map_height;
|
||||
|
||||
@@ -200,7 +225,7 @@ void change_map_size(char direction, int amount) {
|
||||
to_fill_y_offset = old_map_height;
|
||||
}
|
||||
|
||||
map_tiles = (Tile*)malloc(map_width * map_height * sizeof(Tile));
|
||||
map_tiles = (Uint32*)malloc(map_width * map_height * sizeof(Uint32));
|
||||
|
||||
for (int y = 0; y < min(old_map_height, map_height); y++) {
|
||||
for (int x = 0; x < min(old_map_width, map_width); x++) {
|
||||
@@ -210,7 +235,7 @@ void change_map_size(char direction, int amount) {
|
||||
|
||||
for (int y = 0; y < to_fill_height; y++) {
|
||||
for (int x = 0; x < to_fill_width; x++) {
|
||||
map_tiles[(y + to_fill_y_offset) * map_width + (x + to_fill_x_offset)].type = 0;
|
||||
map_tiles[(y + to_fill_y_offset) * map_width + (x + to_fill_x_offset)] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,27 +431,27 @@ SDL_GPUTexture *create_shader_texture(const char *path) {
|
||||
return texture;
|
||||
}
|
||||
|
||||
SDL_GPUTexture* create_shader_texture_array(Uint32 num_textures, const char **texture_paths, const char *debug_name) {
|
||||
if (!num_textures) return NULL;
|
||||
|
||||
int width = 0, height = 0, channels = 0;
|
||||
stbi_uc *data = stbi_load(texture_paths[0], &width, &height, &channels, 4);
|
||||
if (!data) {
|
||||
log_error("Failed to load texture (\"%s\").", texture_paths[0]);
|
||||
SDL_GPUTexture *create_shader_texture(const char *name, const char *data, int width, int height, int channels) {
|
||||
SDL_GPUTextureFormat format = SDL_GPU_TEXTUREFORMAT_INVALID;
|
||||
if (channels == 1) format = SDL_GPU_TEXTUREFORMAT_A8_UNORM;
|
||||
if (channels == 4) format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
|
||||
|
||||
if (format == SDL_GPU_TEXTUREFORMAT_INVALID) {
|
||||
log_error("Failed to find texture format for texture.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_PropertiesID properties = SDL_CreateProperties();
|
||||
if (properties) SDL_SetStringProperty(properties, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING, debug_name);
|
||||
if (properties) SDL_SetStringProperty(properties, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING, name);
|
||||
|
||||
SDL_GPUTextureCreateInfo texture_info = {
|
||||
.type = SDL_GPU_TEXTURETYPE_2D_ARRAY,
|
||||
.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM,
|
||||
.type = SDL_GPU_TEXTURETYPE_2D,
|
||||
.format = format,
|
||||
.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER,
|
||||
.width = (Uint32)width,
|
||||
.height = (Uint32)height,
|
||||
|
||||
.layer_count_or_depth = (Uint32)num_textures,
|
||||
.layer_count_or_depth = 1,
|
||||
.num_levels = 1,
|
||||
|
||||
.props = properties,
|
||||
@@ -435,23 +460,20 @@ SDL_GPUTexture* create_shader_texture_array(Uint32 num_textures, const char **te
|
||||
SDL_GPUTexture *texture = SDL_CreateGPUTexture(device, &texture_info);
|
||||
if (!texture) {
|
||||
log_error("Failed to create gpu texture (%s).", SDL_GetError());
|
||||
stbi_image_free(data);
|
||||
return NULL;
|
||||
}
|
||||
if (properties) SDL_DestroyProperties(properties);
|
||||
|
||||
Uint32 upload_size = width * height * 4;
|
||||
Uint32 total_upload_size = upload_size * num_textures;
|
||||
Uint32 upload_size = width * height * channels;
|
||||
SDL_GPUTransferBufferCreateInfo transfer_buffer_info = {
|
||||
.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD,
|
||||
.size = total_upload_size,
|
||||
.size = upload_size,
|
||||
};
|
||||
|
||||
SDL_GPUTransferBuffer *transfer_buffer = SDL_CreateGPUTransferBuffer(device, &transfer_buffer_info);
|
||||
if (!transfer_buffer) {
|
||||
log_error("Failed to create gpu transfer buffer (%s).", SDL_GetError());
|
||||
SDL_ReleaseGPUTexture(device, texture);
|
||||
stbi_image_free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -460,30 +482,23 @@ SDL_GPUTexture* create_shader_texture_array(Uint32 num_textures, const char **te
|
||||
log_error("Failed to map gpu transfer buffer (%s).", SDL_GetError());
|
||||
SDL_ReleaseGPUTransferBuffer(device, transfer_buffer);
|
||||
SDL_ReleaseGPUTexture(device, texture);
|
||||
stbi_image_free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(transfer_data, data, upload_size);
|
||||
stbi_image_free(data);
|
||||
|
||||
for (int i = 1; i < num_textures; i++) {
|
||||
int width2 = 0, height2 = 0;
|
||||
stbi_uc *data = stbi_load(texture_paths[i], &width2, &height2, &channels, 4);
|
||||
if (!data || width != width2 || height != height2) {
|
||||
log_error("Failed to load texture (\"%s\").", texture_paths[i]);
|
||||
SDL_UnmapGPUTransferBuffer(device, transfer_buffer);
|
||||
SDL_ReleaseGPUTransferBuffer(device, transfer_buffer);
|
||||
SDL_ReleaseGPUTexture(device, texture);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy((void *)((char *)transfer_data + i * upload_size), data, upload_size);
|
||||
stbi_image_free(data);
|
||||
}
|
||||
|
||||
SDL_UnmapGPUTransferBuffer(device, transfer_buffer);
|
||||
|
||||
SDL_GPUTextureTransferInfo transfer_info = {
|
||||
.transfer_buffer = transfer_buffer,
|
||||
.pixels_per_row = (Uint32)width,
|
||||
};
|
||||
|
||||
SDL_GPUTextureRegion tetxure_region = {
|
||||
.texture = texture,
|
||||
.w = (Uint32)width,
|
||||
.h = (Uint32)height,
|
||||
.d = 1,
|
||||
};
|
||||
|
||||
SDL_GPUCommandBuffer *command_buffer = SDL_AcquireGPUCommandBuffer(device);
|
||||
if (!command_buffer) {
|
||||
log_error("Failed to acquire gpu command buffer (%s).", SDL_GetError());
|
||||
@@ -493,26 +508,7 @@ SDL_GPUTexture* create_shader_texture_array(Uint32 num_textures, const char **te
|
||||
}
|
||||
|
||||
SDL_GPUCopyPass *copy_pass = SDL_BeginGPUCopyPass(command_buffer);
|
||||
|
||||
for (int i = 0; i < num_textures; i++) {
|
||||
SDL_GPUTextureTransferInfo transfer_info = {
|
||||
.transfer_buffer = transfer_buffer,
|
||||
.offset = i * upload_size,
|
||||
.pixels_per_row = (Uint32)width,
|
||||
.rows_per_layer = (Uint32)height,
|
||||
};
|
||||
|
||||
SDL_GPUTextureRegion tetxure_region = {
|
||||
.texture = texture,
|
||||
.layer = (Uint32)i,
|
||||
.w = (Uint32)width,
|
||||
.h = (Uint32)height,
|
||||
.d = 1,
|
||||
};
|
||||
|
||||
SDL_UploadToGPUTexture(copy_pass, &transfer_info, &tetxure_region, false);
|
||||
}
|
||||
|
||||
SDL_UploadToGPUTexture(copy_pass, &transfer_info, &tetxure_region, false);
|
||||
SDL_EndGPUCopyPass(copy_pass);
|
||||
|
||||
if (!SDL_SubmitGPUCommandBuffer(command_buffer)) {
|
||||
@@ -527,6 +523,11 @@ SDL_GPUTexture* create_shader_texture_array(Uint32 num_textures, const char **te
|
||||
return texture;
|
||||
}
|
||||
|
||||
void blit(char *dst, Sint32 dst_width, Sint32 dst_x, Sint32 dst_y, char *src, Sint32 width, Sint32 height, int components = 4) {
|
||||
for (Sint32 y = 0; y < height; y++)
|
||||
memmove(&dst[((dst_y + y) * dst_width + dst_x) * components], &src[y * width * components], width * components);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) {
|
||||
log_error("Failed to initialize SDL (%s). Exiting.", SDL_GetError());
|
||||
@@ -684,17 +685,35 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
const char *player_texture_array[] = { "../assets/decorations/strawberry.png" };
|
||||
SDL_GPUTexture *player_texture = create_shader_texture_array(SDL_arraysize(player_texture_array), player_texture_array, "player_textures");
|
||||
SDL_GPUTexture *player_texture = create_shader_texture("../assets/decorations/strawberry.png");
|
||||
if (!player_texture) {
|
||||
log_error("Failed to create shader texture. Exiting.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *tile_texture_array[] = { "../assets/tiles/empty.png", "../assets/tiles/grass_1.png" , "../assets/tiles/ground_1.png" , "../assets/tiles/water_1.png", "../assets/tiles/error.png" };
|
||||
SDL_GPUTexture *tile_texture = create_shader_texture_array(SDL_arraysize(tile_texture_array), tile_texture_array, "tile_textures");
|
||||
if (!player_texture) {
|
||||
log_error("Failed to create shader texture array. Exiting.");
|
||||
tile_atlas = sma_atlas_create(tile_atlas_size, tile_atlas_size);
|
||||
char *tile_atlas_texture_cpu = (char *)calloc(1, tile_atlas_size * tile_atlas_size * 4);
|
||||
for (int i = 0; i < SDL_arraysize(tile_infos); i++) {
|
||||
int width = 0, height = 0;
|
||||
stbi_uc *data = stbi_load(tile_infos[i].asset_path, &width, &height, NULL, 4);
|
||||
if (!data) {
|
||||
log_error("Failed to load texture (\"%s\"). Exiting.", tile_infos[i].asset_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
tile_infos[i].atlas_item = sma_item_add(tile_atlas, width, height);
|
||||
if (!tile_infos[i].atlas_item) {
|
||||
log_error("Failed to add tile texture to atlas. Exiting.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
blit(tile_atlas_texture_cpu, tile_atlas_size, sma_item_x(tile_infos[i].atlas_item), sma_item_y(tile_infos[i].atlas_item), (char *)data, width, height);
|
||||
stbi_image_free(data);
|
||||
}
|
||||
SDL_GPUTexture *tile_atlas_texture = create_shader_texture("tile_atlas", tile_atlas_texture_cpu, tile_atlas_size, tile_atlas_size, 4);
|
||||
free(tile_atlas_texture_cpu);
|
||||
if (!tile_atlas_texture) {
|
||||
log_error("Failed to create tile atlas texture. Exiting.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -755,6 +774,9 @@ int main(int argc, char **argv) {
|
||||
bool show_demo_window = true;
|
||||
bool first_frame = true;
|
||||
|
||||
|
||||
SDL_GetWindowSizeInPixels(window, &window_width, &window_height);
|
||||
|
||||
// MSG Message;
|
||||
while (Running) {
|
||||
ImGui_ImplSDLGPU3_NewFrame();
|
||||
@@ -861,7 +883,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
if(0 <= tile_x && tile_x < map_width &&
|
||||
0 <= tile_y && tile_y < map_height)
|
||||
map_tiles[tile_x + map_width * tile_y].type = (map_tiles[tile_x + map_width * tile_y].type + 1) % 4;
|
||||
map_tiles[tile_x + map_width * tile_y] = (map_tiles[tile_x + map_width * tile_y] + 1) % 4;
|
||||
|
||||
SDL_Keymod modifiers = SDL_GetModState();
|
||||
if (modifiers & SDL_KMOD_SHIFT && tile_x == -1) {
|
||||
@@ -900,10 +922,19 @@ int main(int argc, char **argv) {
|
||||
for (int x = 0; x < view_width; x++) {
|
||||
if (x + player.pos_x - view_width / 2 >= 0 && x + player.pos_x - view_width / 2 < map_width &&
|
||||
y + player.pos_y - view_height / 2 >= 0 && y + player.pos_y - view_height / 2 < map_height) {
|
||||
tiles_instances[x + y * view_width].tile_type = map_tiles[(x + player.pos_x - view_width / 2) + (y + player.pos_y - view_height / 2) * map_width].type;
|
||||
tiles_instances[x + y * view_width].tile_type = map_tiles[(x + player.pos_x - view_width / 2) + (y + player.pos_y - view_height / 2) * map_width];
|
||||
} else {
|
||||
tiles_instances[x + y * view_width].tile_type = 4;
|
||||
tiles_instances[x + y * view_width].tile_type = 0;
|
||||
}
|
||||
|
||||
Uint32 type = tiles_instances[x + y * view_width].tile_type;
|
||||
|
||||
float x0 = sma_item_x(tile_infos[type].atlas_item);
|
||||
float y0 = sma_item_y(tile_infos[type].atlas_item);
|
||||
float x1 = x0 + sma_item_width(tile_infos[type].atlas_item);
|
||||
float y1 = y0 + sma_item_height(tile_infos[type].atlas_item);
|
||||
|
||||
tiles_instances[x + y * view_width].uv0uv1 = { x0 / tile_atlas_size, y0 / tile_atlas_size, x1 / tile_atlas_size, y1 / tile_atlas_size };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -942,7 +973,7 @@ int main(int argc, char **argv) {
|
||||
{ .buffer = tiles_instance_buffer, .offset = 0 },
|
||||
};
|
||||
SDL_GPUTextureSamplerBinding texture_bindings[] = {
|
||||
{ .texture = tile_texture, .sampler = point_sampler },
|
||||
{ .texture = tile_atlas_texture, .sampler = point_sampler },
|
||||
};
|
||||
|
||||
SDL_BindGPUGraphicsPipeline(render_pass, basic_graphics_pipeline);
|
||||
@@ -987,4 +1018,4 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user