Files
librefront/src/common/world.c
T
2025-09-24 20:14:07 +02:00

132 lines
3.2 KiB
C

#include <common/world.h>
typedef struct
{
const unsigned char *data;
size_t size;
size_t offset;
} PngBuffer;
static void
glib_png_read (png_structp png_ptr, png_bytep out_bytes, png_size_t len)
{
PngBuffer *buf = (PngBuffer *) png_get_io_ptr (png_ptr);
if (buf->offset + len > buf->size)
{
png_error (png_ptr, "Read beyond buffer");
}
memcpy (out_bytes, buf->data + buf->offset, len);
buf->offset += len;
}
World *
World_load_from_path (const char *path)
{
World *self = g_new0 (World, 1);
self->buildings = g_array_new (FALSE, FALSE, sizeof (Building *));
char *png_content = NULL;
size_t len = 0;
GError *err = NULL;
if (!g_file_get_contents (path, &png_content, &len, &err))
{
g_critical ("Failed to load map file %s: %s", path, err->message);
g_error_free (err);
return NULL;
}
png_structp png_ptr =
png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info_ptr = png_create_info_struct (png_ptr);
if (!png_ptr || !info_ptr)
{
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_set_expand (png_ptr);
png_set_gray_to_rgb (png_ptr);
png_set_filler (png_ptr, 0xFF, PNG_FILLER_AFTER);
if (png_get_bit_depth (png_ptr, info_ptr) == 16)
{
png_set_strip_16 (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);
mt->x = x;
mt->y = y;
unsigned char *px = &row_pointers[y][x * 4];
unsigned char r = px[0], g = px[1], b = px[2];
/* Improved color ranges (handles light blue water better) */
if (b > 120 && (b > g || b > r))
{
/* Water: medium-to-light blues */
mt->terrain_type = TERRAIN_WATER;
}
else if (g > 140 && g >= r && g >= b)
{
/* Green-dominant = flat/grassland */
mt->terrain_type = TERRAIN_FLAT;
}
else
{
/* Otherwise: hills/mountains */
mt->terrain_type = TERRAIN_HILL;
}
/* Thanks, ChatGPT! */
g_array_append_val (self->tiles, mt);
}
}
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
g_free (row_pointers);
g_free (image_data);
g_free (png_content);
return self;
}