Commit 2f4e521e024f9bcad13f1b3f5168a403cd87f75c

Thomas de Grivel 2023-12-05T12:03:07

wip sdl2_sprite

diff --git a/libc3/window/cairo/configure b/libc3/window/cairo/configure
index 4f6c3ca..4b1b995 100755
--- a/libc3/window/cairo/configure
+++ b/libc3/window/cairo/configure
@@ -44,8 +44,6 @@ config_asan
 config_gnu
 pkg_config cairo
 pkg_config freetype2
-#config_lib IL -lIL -lILU
-config_lib FREEIMAGE -lfreeimage
 pkg_config libbsd-overlay
 pkg_config xkbcommon
 config_lib_have COCOA -framework Cocoa
diff --git a/libc3/window/sdl2/configure b/libc3/window/sdl2/configure
index b33d970..1228de9 100755
--- a/libc3/window/sdl2/configure
+++ b/libc3/window/sdl2/configure
@@ -46,11 +46,10 @@ config_gnu
 pkg_config ftgl
 pkg_config gl
 pkg_config glu
-config_lib IL -lIL -lILU
+pkg_config libpng
 pkg_config sdl2
 pkg_config libbsd-overlay
 config_lib OPENGL -framework OpenGL
-#config_lib SDL2 -framework SDL2
 config_define PREFIX "\"${PREFIX}\""
 
 # Address Sanitizer config
diff --git a/libc3/window/sdl2/sdl2_sprite.c b/libc3/window/sdl2/sdl2_sprite.c
index cce8940..5b80aae 100644
--- a/libc3/window/sdl2/sdl2_sprite.c
+++ b/libc3/window/sdl2/sdl2_sprite.c
@@ -25,21 +25,77 @@ void sdl2_sprite_clean (s_sdl2_sprite *sprite)
   free(sprite->texture);
 }
 
+static GLenum png_info_to_gl_format (int png_color_type,
+                                     int png_bit_depth)
+{
+  switch (png_color_type) {
+  case PNG_COLOR_TYPE_GRAY:
+    switch (png_bit_depth) {
+    case 8:  return GL_LUMINANCE8;
+    case 16: return GL_LUMINANCE16;
+    }
+    break;
+  case PNG_COLOR_TYPE_GRAY_ALPHA:
+    switch (png_bit_depth) {
+    case 8:  return GL_LUMINANCE8_ALPHA8;
+    case 16: return GL_LUMINANCE16_ALPHA16;
+    }
+    break;
+  case PNG_COLOR_TYPE_RGB:
+    switch (png_bit_depth) {
+    case 8:  return GL_RGB8;
+    case 16: return GL_RGB16;
+    }
+    break;
+  case PNG_COLOR_TYPE_RGBA:
+    switch (png_bit_depth) {
+    case 8:  return GL_RGBA8;
+    case 16: return GL_RGBA16;
+    }
+    break;
+  }
+  return 0;
+}
+
+static GLenum png_info_to_gl_type (int png_bit_depth)
+{
+  switch (png_bit_depth) {
+  case 8:
+    return GL_UNSIGNED_BYTE;
+  case 16:
+    return GL_UNSIGNED_SHORT;
+  }
+  return 0;
+}
+
 s_sdl2_sprite * sdl2_sprite_init (s_sdl2_sprite *sprite,
                                   const s8 *path,
                                   uw dim_x, uw dim_y,
                                   uw frame_count)
 {
+  u8 *data;
   FILE *fp;
+  GLenum gl_format;
+  GLenum gl_type;
   uw i;
-  png_infop png_info;
+  u8          png_header[8]; // maximum size is 8
+  png_infop   png_info;
   png_structp png_read;
+  png_bytep  *png_row;
+  u32         png_w;
+  u32         png_h;
+  s32         png_bit_depth;
+  s32         png_color_type;
+  u8 *sprite_data;
+  uw  sprite_stride;
   uw x;
   uw y;
+  uw v;
   assert(sprite);
   assert(path);
   assert(dim_x);
   assert(dim_y);
+  frame_count = (frame_count > 0) ? frame_count : (dim_x * dim_y);
   str_init_copy_1(&sprite->path, path);
   if (! file_search(&sprite->path, sym_1("r"), &sprite->real_path)) {
     warnx("sdl2_sprite_init: file not found: %s", path);
@@ -68,63 +124,120 @@ s_sdl2_sprite * sdl2_sprite_init (s_sdl2_sprite *sprite,
     str_clean(&sprite->real_path);
     return NULL;
   }
-  png_read = png_create_read_struct
-    (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-
-   if (!png_ptr)
-     return ERROR;
-  sprite->total_w = ilGetInteger(IL_IMAGE_WIDTH);
-  sprite->total_h = ilGetInteger(IL_IMAGE_HEIGHT);
-  //bpp = ilGetInteger(IL_IMAGE_BPP);
+  png_read = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL,
+                                    NULL);
+  if (!png_read) {
+    warn("sdl2_sprite_init: %s: png_create_read_struct",
+         sprite->real_path.ptr.ps8);
+    fclose(fp);
+    str_clean(&sprite->path);
+    str_clean(&sprite->real_path);
+    return NULL;
+  }
+  if (setjmp(png_jmpbuf(png_read))) {
+    png_destroy_read_struct(&png_read, &png_info, NULL);
+    fclose(fp);
+    str_clean(&sprite->path);
+    str_clean(&sprite->real_path);
+    return NULL;
+  }
+  png_init_io(png_read, fp);
+  png_set_sig_bytes(png_read, sizeof(png_header));
+  //png_set_compression_buffer_size(png_read, buffer_size);
+  png_read_png(png_read, png_info,
+               PNG_TRANSFORM_PACKING, NULL);
+  png_get_IHDR(png_read, png_info, &png_w, &png_h,
+               &png_bit_depth, &png_color_type,
+               NULL, NULL, NULL);
+  if (png_color_type == PNG_COLOR_TYPE_PALETTE) {
+    warnx("sdl2_sprite_init: %s: PNG_COLOR_TYPE_PALETTE",
+          sprite->real_path.ptr.ps8);
+    png_destroy_read_struct(&png_read, &png_info, NULL);
+    fclose(fp);
+    str_clean(&sprite->path);
+    str_clean(&sprite->real_path);
+    return NULL;
+  }
+  png_row = png_get_rows(png_read, png_info);
+  if (! png_row) {
+    warnx("sdl2_sprite_init: %s: png_get_rows => NULL",
+          sprite->real_path.ptr.ps8);
+    png_destroy_read_struct(&png_read, &png_info, NULL);
+    fclose(fp);
+    str_clean(&sprite->path);
+    str_clean(&sprite->real_path);
+    return NULL;
+  }
+  sprite->total_w = png_w;
+  sprite->total_h = png_h;
   sprite->dim_x = dim_x;
   sprite->dim_y = dim_y;
   sprite->w = sprite->total_w / dim_x;
   sprite->h = sprite->total_h / dim_y;
-  sprite->frame_count = frame_count ? frame_count : (dim_x * dim_y);
+  sprite->frame_count = frame_count;
   sprite->texture = malloc(frame_count * sizeof(GLuint));
   if (! sprite->texture) {
     warn("sdl2_sprite_init: sprite->texture");
-    ilDeleteImages(2, il_image);
+    png_destroy_read_struct(&png_read, &png_info, NULL);
+    fclose(fp);
+    str_clean(&sprite->path);
+    str_clean(&sprite->real_path);
+    return NULL;
+  }
+  gl_format = png_info_to_gl_format(png_color_type, png_bit_depth);
+  if (! gl_format) {
+    warnx("sdl2_sprite_init: %s: unknown OpenGL format",
+          sprite->real_path.ptr.ps8);
+    free(sprite->texture);
+    png_destroy_read_struct(&png_read, &png_info, NULL);
+    fclose(fp);
+    str_clean(&sprite->path);
+    str_clean(&sprite->real_path);
+    return NULL;
+  }
+  gl_type = png_info_to_gl_type(png_bit_depth);
+  if (! gl_type) {
+    warnx("sdl2_sprite_init: %s: unknown OpenGL type",
+          sprite->real_path.ptr.ps8);
+    free(sprite->texture);
+    png_destroy_read_struct(&png_read, &png_info, NULL);
+    fclose(fp);
+    str_clean(&sprite->path);
+    str_clean(&sprite->real_path);
+    return NULL;
+  }
+  sprite_stride = sprite->w * (png_bit_depth / 8);
+  data = malloc(sprite->h * sprite_stride);
+  if (! data) {
+    warn("sdl2_sprite_init: %s", sprite->real_path.ptr.ps8);
+    free(sprite->texture);
+    png_destroy_read_struct(&png_read, &png_info, NULL);
+    fclose(fp);
     str_clean(&sprite->path);
     str_clean(&sprite->real_path);
     return NULL;
   }
-  glGenTextures(frame_count, sprite->texture);
-  ilBindImage(il_image[1]);
-  ilTexImage(sprite->w, sprite->h, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE,
-             NULL);
-  data[1] = ilGetData();
-  ilBindImage(il_image[2]);
-  sprite->tex_w = 1;
-  while (sprite->tex_w < sprite->w)
-    sprite->tex_w *= 2;
-  sprite->tex_h = 1;
-  while (sprite->tex_h < sprite->h)
-    sprite->tex_h *= 2;
-  ilTexImage(sprite->tex_w, sprite->tex_h, 1, 4, IL_RGBA,
-             IL_UNSIGNED_BYTE, NULL);
-  data[2] = ilGetData();
-  ilBindImage(il_image[0]);
   i = 0;
   y = 0;
   while (i < sprite->frame_count && y < dim_y) {
     x = 0;
     while (i < sprite->frame_count && x < dim_x) {
-      ilCopyPixels(x * sprite->w, y * sprite->h, 0,
-                   sprite->w, sprite->h, 1, IL_RGBA, IL_UNSIGNED_BYTE,
-                   data[1]);
-      iluImageParameter(ILU_FILTER, ILU_SCALE_MITCHELL);
-      ilBlit(il_image[1], 0, 0, 0, 0, 0, 0,
-             sprite->tex_w, sprite->tex_h, 1);
+      sprite_data = data;
+      v = 0;
+      while (v < sprite->h) {
+        memcpy(sprite_data, png_row[v], sprite_stride);
+        v++;
+      }
       glBindTexture(GL_TEXTURE_2D, sprite->texture[i]);
-      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
-                   sprite->tex_w, sprite->tex_h, 0, GL_RGBA,
-                   GL_UNSIGNED_BYTE, data[2]);
+      glTexImage2D(GL_TEXTURE_2D, 0, gl_format, sprite->w, sprite->h,
+                   0, gl_format, gl_type, data);
       i++;
       x++;
     }
     y++;
   }
-  ilDeleteImages(3, il_image);
+  free(data);
+  png_destroy_read_struct(&png_read, &png_info, NULL);
+  fclose(fp);
   return sprite;
 }