/* Copyright 2022-2026 Kurt Nienhaus
 *
 * This file is part of VgaGames.
 * VgaGames is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 * VgaGames is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with VgaGames.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include "iolib.h"
#include "image/image.h"

void init_image_sdl2(void);

static struct VG_Image * sdl2_image_load(const char *, char *, size_t);
static VG_BOOL sdl2_image_save(const struct VG_Image *, const char *, VG_BOOL);

static struct iolib * get_iolib(void);


/* set functions */
void
init_image_sdl2(void)
{
  vg4data.iolib.f.image_load = sdl2_image_load;
  vg4data.iolib.f.image_save = sdl2_image_save;
} /* Ende init_image_sdl2 */


/* check if is valid and return iolib pointer */
static struct iolib *
get_iolib(void)
{
  struct iolib *iolib = (struct iolib *)vg4data.iolib.stptr;

  if (iolib == NULL) { return NULL; }
  if (iolib->window.wd == NULL) { return NULL; }

  return iolib;
} /* Ende get_iolib */


/* sdl2_image_load:
 * load image from memory
 * @param filename  filename
 * @param memptr    memory
 * @param memsize   size of memory in bytes
 * @return  image or NULL = error
 */
struct VG_Image *
sdl2_image_load(const char *filename, char *memptr, size_t memsize)
{
  struct iolib *iolib;
  struct VG_Image *imgp;
  SDL_RWops *sfp;
  SDL_Surface *surface, *tsurf;
  int xpos, ypos, use_u;
  struct VG_PixelColor *ppix;
  Uint32 *surfpixels;
  union { struct VG_PixelColor px; Uint32 i; } u;

  if ((iolib = get_iolib()) == NULL) { return NULL; }

  if (filename == NULL) { filename = "[from memory]"; }
  if (memptr == NULL || memsize == 0) {
    outerr("loading image: no data to load");
    return NULL;
  }

  sfp = iolib->syms.SDL_RWFromMem(memptr, memsize);
  if (sfp == NULL) {
    outerr("loading image \"%s\": %s", filename, iolib->syms.SDL_GetError());
    return NULL;
  }

  tsurf = iolib->syms.SDL_LoadBMP_RW(sfp, 1);
  if (tsurf == NULL) {
    outerr("loading image \"%s\": %s", filename, iolib->syms.SDL_GetError());
    return NULL;
  }

  surface = iolib->syms.SDL_ConvertSurfaceFormat(tsurf, iolib->window.pixelformatenum, 0);
  if (surface == NULL) {
    outerr("converting surface: %s", iolib->syms.SDL_GetError());
    iolib->syms.SDL_FreeSurface(tsurf);
    return NULL;
  }

  iolib->syms.SDL_FreeSurface(tsurf);
  iolib->syms.SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);

  /* convert surface to image */
#ifdef SML3_ENDIAN_IS_LITTLE
  if (iolib->window.pixelformatenum == SDL_PIXELFORMAT_ABGR8888) { use_u = 1; } else { use_u = 0; }
#else
  if (iolib->window.pixelformatenum == SDL_PIXELFORMAT_RGBA8888) { use_u = 1; } else { use_u = 0; }
#endif
  imgp = vg4_image_create_nolist(surface->w, surface->h);
  imgp->img.hasopq = VG_FALSE;
  imgp->img.isclear = VG_TRUE;
  for (ypos = 0; ypos < imgp->img.h; ypos++) {
    surfpixels = (Uint32 *)((unsigned char *)surface->pixels + ypos * surface->pitch);
    ppix = &imgp->img.pixels[ypos * imgp->img.w];
    for (xpos = 0; xpos < imgp->img.w; xpos++) {
      if (use_u) {
        u.i = surfpixels[xpos]; *ppix = u.px;
      } else {
        iolib->syms.SDL_GetRGBA(surfpixels[xpos], surface->format, &ppix->r, &ppix->g, &ppix->b, &ppix->a);
      }
      if (ppix->a != 255) { imgp->img.hasopq = VG_TRUE; }
      if (ppix->a != 0) { imgp->img.isclear = VG_FALSE; }
      ppix++;
    }
  }
  iolib->syms.SDL_FreeSurface(surface);

  return imgp;
} /* Ende sdl2_image_load */


/* sdl2_image_save:
 * save image to file
 * @param imgp      image
 * @param filename  filename to save
 * @param noalpha   if VG_TRUE, set alpha to 255
 * @return  VG_TRUE = OK or VG_FALSE = error
 */
VG_BOOL
sdl2_image_save(const struct VG_Image *imgp, const char *filename, VG_BOOL noalpha)
{
  struct iolib *iolib;
  SDL_RWops *sfp;
  SDL_Surface *surface, *tsurf;
  int xpos, ypos, use_u;
  struct VG_PixelColor *ppix, pxctransp;
  Uint32 *surfpixels;
  union { struct VG_PixelColor px; Uint32 i; } u;

  if ((iolib = get_iolib()) == NULL) { return VG_FALSE; }

  if (imgp == NULL) { outerr("saving image: no image to save"); return VG_FALSE; }
  if (filename == NULL || *filename == '\0') {
    outerr("saving image: no filename");
    return VG_FALSE;
  }

  GET_RGBA(VG_COLOR_TRANSPARENT, &pxctransp.r, &pxctransp.g, &pxctransp.b, &pxctransp.a);

  tsurf = iolib->syms.SDL_CreateRGBSurface(0, imgp->img.w, imgp->img.h, 32, 0, 0, 0, 0);
  if (tsurf == NULL) {
    outerr("creating surface: %s", iolib->syms.SDL_GetError());
    return VG_FALSE;
  }
  surface = iolib->syms.SDL_ConvertSurfaceFormat(tsurf, iolib->window.pixelformatenum, 0);
  if (surface == NULL) {
    outerr("converting surface: %s", iolib->syms.SDL_GetError());
    iolib->syms.SDL_FreeSurface(tsurf);
    return VG_FALSE;
  }

  iolib->syms.SDL_FreeSurface(tsurf);
  iolib->syms.SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);

#ifdef SML3_ENDIAN_IS_LITTLE
  if (iolib->window.pixelformatenum == SDL_PIXELFORMAT_ABGR8888) { use_u = 1; } else { use_u = 0; }
#else
  if (iolib->window.pixelformatenum == SDL_PIXELFORMAT_RGBA8888) { use_u = 1; } else { use_u = 0; }
#endif

  for (ypos = 0; ypos < imgp->img.h; ypos++) {
    ppix = &imgp->img.pixels[ypos * imgp->img.w];
    surfpixels = (Uint32 *)((unsigned char *)surface->pixels + ypos * surface->pitch);
    for (xpos = 0; xpos < imgp->img.w; xpos++) {
      u.px = ppix[xpos];
      if (noalpha) { u.px.a = 255; }
      if (use_u) {
        surfpixels[xpos] = u.i;
      } else {
        surfpixels[xpos] = iolib->syms.SDL_MapRGBA(iolib->window.bsurf->format, u.px.r, u.px.g, u.px.b, u.px.a);
      }
    }
  }
  sfp = iolib->syms.SDL_RWFromFile(filename, "wb");
  if (sfp == NULL) {
    outerr("saving image to \"%s\": %s", filename, iolib->syms.SDL_GetError());
    iolib->syms.SDL_FreeSurface(surface);
    return VG_FALSE;
  }

  if (iolib->syms.SDL_SaveBMP_RW(surface, sfp, 1) < 0) {
    outerr("saving image to \"%s\": %s", filename, iolib->syms.SDL_GetError());
    iolib->syms.SDL_FreeSurface(surface);
    return VG_FALSE;
  }

  iolib->syms.SDL_FreeSurface(surface);

  return VG_TRUE;
} /* Ende sdl2_image_save */
