Loading maps using libpng instead of SDL_image
This commit is contained in:
@@ -22,7 +22,7 @@ RM := rm -f
|
|||||||
DEBUG ?= 1
|
DEBUG ?= 1
|
||||||
|
|
||||||
COMMON_CFLAGS := -std=$(STD) -Werror -Wextra -Wall -MMD -MP -I$(SRC_DIR) `pkg-config --cflags glib-2.0 gio-2.0`
|
COMMON_CFLAGS := -std=$(STD) -Werror -Wextra -Wall -MMD -MP -I$(SRC_DIR) `pkg-config --cflags glib-2.0 gio-2.0`
|
||||||
COMMON_LDFLAGS := -std=$(STD) -lm `pkg-config --libs glib-2.0 gio-2.0 sdl3 sdl3-image`
|
COMMON_LDFLAGS := -std=$(STD) -lm `pkg-config --libs glib-2.0 gio-2.0`
|
||||||
|
|
||||||
ifeq ($(DEBUG),1)
|
ifeq ($(DEBUG),1)
|
||||||
COMMON_CFLAGS += -g -DDEBUG
|
COMMON_CFLAGS += -g -DDEBUG
|
||||||
@@ -31,12 +31,12 @@ else
|
|||||||
COMMON_CFLAGS += -O2 -DNDEBUG
|
COMMON_CFLAGS += -O2 -DNDEBUG
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# libpng should be gone from the client after the server is working
|
||||||
|
CLIENT_CFLAGS := $(COMMON_CFLAGS) `pkg-config --cflags sdl3 libpng`
|
||||||
|
CLIENT_LDFLAGS := $(COMMON_LDFLAGS) `pkg-config --libs sdl3 libpng`
|
||||||
|
|
||||||
CLIENT_CFLAGS := $(COMMON_CFLAGS) # `pkg-config --cflags sdl3`
|
SERVER_CFLAGS := $(COMMON_CFLAGS) `pkg-config --cflags libpng`
|
||||||
CLIENT_LDFLAGS := $(COMMON_LDFLAGS) # `pkg-config --libs sdl3`
|
SERVER_LDFLAGS := $(COMMON_LDFLAGS) `pkg-config --libs libpng`
|
||||||
|
|
||||||
SERVER_CFLAGS := $(COMMON_CFLAGS)
|
|
||||||
SERVER_LDFLAGS := $(COMMON_LDFLAGS)
|
|
||||||
|
|
||||||
CLIENT := librefront
|
CLIENT := librefront
|
||||||
SERVER := librefront-headless
|
SERVER := librefront-headless
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ in
|
|||||||
pkgs.mkShellNoCC {
|
pkgs.mkShellNoCC {
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
sdl3
|
sdl3
|
||||||
sdl3-image
|
libpng
|
||||||
glib
|
glib
|
||||||
|
|
||||||
gcc
|
gcc
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ static World *test_world;
|
|||||||
World *
|
World *
|
||||||
_make_test_World ()
|
_make_test_World ()
|
||||||
{
|
{
|
||||||
World *self = World_load_from_file ("res/test_map_2.png");
|
World *self = World_load_from_path ("res/test_map_2.png");
|
||||||
|
|
||||||
/* TODO: add players and so on. That will be in GameState,
|
/* TODO: add players and so on. That will be in GameState,
|
||||||
though. Or GameData. */
|
though. Or GameData. */
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ GfxContext_render (GfxContext *self)
|
|||||||
{
|
{
|
||||||
SDL_RenderTexture (self->renderer, self->world_texture, NULL, NULL);
|
SDL_RenderTexture (self->renderer, self->world_texture, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_RenderPresent (self->renderer);
|
SDL_RenderPresent (self->renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ typedef struct GfxContext
|
|||||||
} GfxContext;
|
} GfxContext;
|
||||||
|
|
||||||
GfxContext *GfxContext_new ();
|
GfxContext *GfxContext_new ();
|
||||||
void GfxContext_render (GfxContext *self);
|
void GfxContext_render (GfxContext * self);
|
||||||
void GfxContext_free (GfxContext * self);
|
void GfxContext_free (GfxContext * self);
|
||||||
|
|
||||||
void GfxContext_cache_World (GfxContext * self, World * world);
|
void GfxContext_cache_World (GfxContext * self, World * world);
|
||||||
void GfxContext_update_Players (GfxContext *self, World * world);
|
void GfxContext_update_Players (GfxContext * self, World * world);
|
||||||
|
|||||||
+92
-46
@@ -1,69 +1,113 @@
|
|||||||
#include <common/world.h>
|
#include <common/world.h>
|
||||||
|
|
||||||
static inline Uint32
|
typedef struct
|
||||||
_surf_pixel (SDL_Surface *surface, int x, int y)
|
|
||||||
{
|
{
|
||||||
int bpp = SDL_BYTESPERPIXEL (surface->format);
|
const guchar *data;
|
||||||
Uint8 *p = (Uint8 *) surface->pixels + y * surface->pitch + x * bpp;
|
gsize size;
|
||||||
|
gsize offset;
|
||||||
|
} PngBuffer;
|
||||||
|
|
||||||
switch (bpp)
|
static void
|
||||||
{
|
glib_png_read (png_structp png_ptr, png_bytep out_bytes, png_size_t len)
|
||||||
case 1:
|
{
|
||||||
return *p;
|
PngBuffer *buf = (PngBuffer *) png_get_io_ptr (png_ptr);
|
||||||
case 2:
|
if (buf->offset + len > buf->size)
|
||||||
return *(Uint16 *) p;
|
png_error (png_ptr, "Read beyond buffer");
|
||||||
case 3:
|
|
||||||
if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
|
memcpy (out_bytes, buf->data + buf->offset, len);
|
||||||
{
|
buf->offset += len;
|
||||||
return p[0] << 16 | p[1] << 8 | p[2];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return p[0] | p[1] << 8 | p[2] << 16;
|
|
||||||
}
|
|
||||||
case 4:
|
|
||||||
return *(Uint32 *) p;
|
|
||||||
default:
|
|
||||||
return 0; // shouldn't happen
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
World *
|
World *
|
||||||
World_load_from_file (const char *path)
|
World_load_from_path (const char *path)
|
||||||
{
|
{
|
||||||
|
UNUSED (path);
|
||||||
|
|
||||||
World *self = g_new0 (World, 1);
|
World *self = g_new0 (World, 1);
|
||||||
self->buildings = g_array_new (FALSE, FALSE, sizeof (Building *));
|
self->buildings = g_array_new (FALSE, FALSE, sizeof (Building *));
|
||||||
|
|
||||||
SDL_Surface *surf = IMG_Load (path);
|
char *png_content = NULL;
|
||||||
|
size_t len = 0;
|
||||||
|
GError *err = NULL;
|
||||||
|
|
||||||
if (!surf)
|
if (!g_file_get_contents (path, &png_content, &len, &err))
|
||||||
{
|
{
|
||||||
g_warning ("Failed to load map from path %s (returning NULL): %s", path,
|
g_critical ("Failed to load map file %s: %s", path, err->message);
|
||||||
SDL_GetError ());
|
g_error_free (err);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->width = surf->w;
|
png_structp png_ptr =
|
||||||
self->height = surf->h;
|
png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
self->tiles =
|
png_infop info_ptr = png_create_info_struct (png_ptr);
|
||||||
g_array_sized_new (FALSE, FALSE, sizeof (MapTile *), surf->w * surf->h);
|
|
||||||
|
|
||||||
SDL_LockSurface (surf);
|
if (!png_ptr || !info_ptr)
|
||||||
const SDL_PixelFormatDetails *details =
|
|
||||||
SDL_GetPixelFormatDetails (surf->format);
|
|
||||||
|
|
||||||
for (int y = 0; y < surf->h; ++y)
|
|
||||||
{
|
{
|
||||||
for (int x = 0; x < surf->w; ++x)
|
g_critical ("%s is not a valid PNG file.", path);
|
||||||
|
g_free (png_content);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setjmp (png_jmpbuf (png_ptr)))
|
||||||
|
{
|
||||||
|
g_critical ("Something got fucked up while loading PNG.");
|
||||||
|
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
|
||||||
|
g_free (png_content);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PngBuffer buf = { (unsigned char *) png_content, len, 0 };
|
||||||
|
png_set_read_fn (png_ptr, &buf, glib_png_read);
|
||||||
|
|
||||||
|
png_read_info (png_ptr, info_ptr);
|
||||||
|
|
||||||
|
self->width = png_get_image_width (png_ptr, info_ptr);
|
||||||
|
self->height = png_get_image_height (png_ptr, info_ptr);
|
||||||
|
self->tiles = g_array_sized_new (FALSE, FALSE, sizeof (MapTile *),
|
||||||
|
self->width * self->height);
|
||||||
|
|
||||||
|
png_byte color_type = png_get_color_type (png_ptr, info_ptr);
|
||||||
|
png_byte bit_depth = png_get_bit_depth (png_ptr, info_ptr);
|
||||||
|
|
||||||
|
if (bit_depth == 16)
|
||||||
|
png_set_strip_16 (png_ptr);
|
||||||
|
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||||
|
png_set_palette_to_rgb (png_ptr);
|
||||||
|
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
||||||
|
png_set_expand_gray_1_2_4_to_8 (png_ptr);
|
||||||
|
if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
|
||||||
|
png_set_tRNS_to_alpha (png_ptr);
|
||||||
|
if (color_type == PNG_COLOR_TYPE_RGB ||
|
||||||
|
color_type == PNG_COLOR_TYPE_GRAY ||
|
||||||
|
color_type == PNG_COLOR_TYPE_PALETTE)
|
||||||
|
png_set_filler (png_ptr, 0xFF, PNG_FILLER_AFTER);
|
||||||
|
if (color_type == PNG_COLOR_TYPE_GRAY ||
|
||||||
|
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||||
|
png_set_gray_to_rgb (png_ptr);
|
||||||
|
|
||||||
|
png_read_update_info (png_ptr, info_ptr);
|
||||||
|
|
||||||
|
int rowbytes = png_get_rowbytes (png_ptr, info_ptr);
|
||||||
|
unsigned char *image_data = g_malloc (rowbytes * self->height);
|
||||||
|
png_bytep *row_pointers = g_new (png_bytep, self->height);
|
||||||
|
|
||||||
|
for (unsigned int y = 0; y < self->height; y++)
|
||||||
|
row_pointers[y] = image_data + y * rowbytes;
|
||||||
|
|
||||||
|
png_read_image (png_ptr, row_pointers);
|
||||||
|
|
||||||
|
for (unsigned int y = 0; y < self->height; ++y)
|
||||||
|
{
|
||||||
|
for (unsigned int x = 0; x < self->width; ++x)
|
||||||
{
|
{
|
||||||
MapTile *mt = g_new0 (MapTile, 1);
|
MapTile *mt = g_new0 (MapTile, 1);
|
||||||
mt->x = x;
|
mt->x = x;
|
||||||
mt->y = y;
|
mt->y = y;
|
||||||
|
|
||||||
Uint32 pixel = _surf_pixel (surf, x, y);
|
unsigned char *px = &row_pointers[y][x * 4];
|
||||||
Uint8 r, g, b, a;
|
unsigned char r = px[0];
|
||||||
/* NULL is a palette, only used in indexed images. */
|
unsigned char g = px[1];
|
||||||
SDL_GetRGBA (pixel, details, NULL, &r, &g, &b, &a);
|
unsigned char b = px[2];
|
||||||
|
|
||||||
/* Improved color ranges (handles light blue water better) */
|
/* Improved color ranges (handles light blue water better) */
|
||||||
if (b > 120 && (b > g || b > r))
|
if (b > 120 && (b > g || b > r))
|
||||||
@@ -82,13 +126,15 @@ World_load_from_file (const char *path)
|
|||||||
mt->terrain_type = TERRAIN_HILL;
|
mt->terrain_type = TERRAIN_HILL;
|
||||||
}
|
}
|
||||||
/* Thanks, ChatGPT! */
|
/* Thanks, ChatGPT! */
|
||||||
|
|
||||||
g_array_append_val (self->tiles, mt);
|
g_array_append_val (self->tiles, mt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_UnlockSurface (surf);
|
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
|
||||||
SDL_DestroySurface (surf);
|
g_free (row_pointers);
|
||||||
|
g_free (image_data);
|
||||||
|
g_free (png_content);
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -1,9 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
#include <SDL3_image/SDL_image.h>
|
|
||||||
|
|
||||||
#include <glib-2.0/glib.h>
|
#include <glib-2.0/glib.h>
|
||||||
|
#include <png.h>
|
||||||
|
|
||||||
|
#include <common/util.h>
|
||||||
|
|
||||||
typedef enum TerrainType
|
typedef enum TerrainType
|
||||||
{
|
{
|
||||||
@@ -37,5 +37,5 @@ typedef struct Building
|
|||||||
unsigned int (*at_what_cost) (struct Building * self, World * world);
|
unsigned int (*at_what_cost) (struct Building * self, World * world);
|
||||||
} Building;
|
} Building;
|
||||||
|
|
||||||
World *World_load_from_file (const char *path);
|
World *World_load_from_path (const char *path);
|
||||||
void World_tick (World * self);
|
void World_tick (World * self);
|
||||||
|
|||||||
Reference in New Issue
Block a user