/*
 * sprite.c
 * Copyright (C) 2002 P.Everett <peter@everett9981.freeserve.co.uk>
 *
 * This file is part of KinoAMP, a free RISCOS MPEG program stream decoder.
 *
 * KinoAMP 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.
 *
 * KinoAMP 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/* saves the currently displayed frame as a sprite. */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "swis.h"
#include "inttypes.h"
#include "player.h"
#include "display.h"
#include "sprite.h"
#include "config.h"
#include "timer1.h"
#include "wimp.h"
#include "ka_mem.h"

#ifndef DrawFile_Render
#define DrawFile_Render 0x45540
#endif

void render_banner( const int* banner, int bannersize
                  , int x0, int y0, int width, int height)
{
  if (banner)
  {
    int trans[6];
    float tx, ty;

    tx = (float)(int)(banner[8]-banner[6]);
    ty = (float)(int)(banner[9]-banner[7]);
    tx = (16777216.f * (float) width)/tx;
    ty = (16777216.f * (float) height)/ty;
    trans[0] = (int) tx;
    trans[1] = 0;
    trans[2] = 0;
    trans[3] = (int) ty;
    tx *= banner[6];
    ty *= banner[7];
    tx *= 1.f/65536.f;
    ty *= 1.f/65536.f;
    trans[4] = 256*x0 - (int) tx;
    trans[5] = 256*y0 - (int) ty;
    if (_swix(DrawFile_Render, _INR(0,6), 0, banner, bannersize, trans, 0, 0, 0))
      banner = 0;
  }

  if (!banner)
  {
    _swix(OS_Plot, _INR(0,2), 4, x0, y0);
    _swix(OS_Plot, _INR(0,2), 101, x0 + width - 1, y0 + height - 1);
  }
}

void display_banner(int x0, int y0, int width, int height)
{
  static int* banner = NULL;
  static int bannersize = 0;

  if (!banner && bannersize == 0)
  {
    FILE* fh;
    bannersize = -1;
    fh = fopen("<Kino$Dir>.banner", "rb");
    if (fh)
    {
      fseek(fh, 0, SEEK_END);
      bannersize = (int)ftell(fh);
      fseek(fh, 0, SEEK_SET);
      banner = ka_mem_alloc(bannersize);
      if (!banner)
        bannersize = -1;
      else
        fread(banner, 1, bannersize, fh);
      fclose(fh);
    }
  }

  render_banner(banner, bannersize, x0, y0, width, height);

  if (banner)
  {
    uint32_t t;

    timer_pause(1);
    t = clock();
    while(t + 100 > clock());
    timer_pause(0);
  }
}

/*
 * save_frame
 * ----------
 * Saves the currently displayed frame as a 8bpp, 16bpp or 32bpp sprite depending
 * on the screen mode in use. This is basically a screen dump of the picture
 * area. It assumes that the picture area will be word aligned.
 */
static const unsigned int spr_modes[ka_col_depth_count] =
{ 28
, 0x79000051 // TODO - Fix NV12
, 0x79000051 // TODO - Fix NV21
, 0x79000051 // TODO - Fix UYVY
, 0x79000051 // TODO - Fix YUY2
, 0x79000051 // TODO - Fix YV12
, 0x79000051 // TODO - Fix YV16
, 0x79000051 // TBGR12
, ( 5u<<27) + (90<<14) + (90<<1) + 1 // TBGR15, pre-OS 5
, (10u<<27) + (90<<14) + (90<<1) + 1 // TBGR16, pre-OS 5
, ( 6u<<27) + (90<<14) + (90<<1) + 1 // TBGR32, pre-OS 5
, 0x79004051 // TRGB12
, 0x78504051 // TRGB15
, 0x78a04051 // TRGB16
, 0x78604051 // TRGB32
, 0x79008051 // ABGR12
, 0x78508051 // ABGR15
, 0x78a08051 // ABGR16
, 0x78608051 // ABGR32
, 0x7900C051 // ARGB12
, 0x7850C051 // ARGB15
, 0x78a0C051 // ARGB16
, 0x7860C051 // ARGB32
};

unsigned int sprite_getmode(ka_col_depth depth)
{
  return spr_modes[depth];
}

void save_frame(const player_t* player, char* filename)
{
  FILE* f;
  sprite_header_t h;
  int width, height;
  unsigned int* src;
  const uint32_t* pal;
  uint32_t palette_size = 0;
  const ka_paint_t* paint;

  // For 256 colour sprites with a palette
  if(player->screen_sprite.col_depth == ka_col_depth_256)
    palette_size = 256;

  if (player->paint.dst_base)
  {
    paint = &player->paint;
    src = (unsigned int *) (paint->dst_base + paint->dst_offset);
  }
  else
  {
    paint = &player->paint_sprite;
    src = (unsigned int *) paint->dst;
    player->drawer_sprite(paint);
  }

  width = paint->dst_byte_width >> 2; // width is now always in words
  height = paint->dst_height;

  if((f = fopen(filename,"wb")) == 0)
  {
    report_error(0, "error10:%s", filename); // (Cannot create Sprite file)
    return;
  }

  // Write sprite file header
  h.num = 1;
  h.offset = 16;
  h.size_1 = 4 * width * height + 60 + (palette_size<<3);
  h.size_2 = h.size_1 - 16;
  memset(h.name, 0, 12); // ensure it's padded with zeros
  snprintf
    (h.name, sizeof(h.name)
    , "f%05d_%1d"
    , player->draw.picturenr, player->draw.fieldnr
    );
  h.width = width - 1;
  h.height = height - 1;
  h.first = 0;
  h.last = 31;
  h.s_offset = 44 + (palette_size<<3);
  h.m_offset = h.s_offset; // no mask
  h.mode = spr_modes[player->screen_sprite.col_depth];

  fwrite(&h.num,sizeof(sprite_header_t)-4,1,f);

  // If required, insert the palette
  if(palette_size > 0)
  {
    pal = player->screen_sprite.palette;
    do
    {
      fwrite(pal,4,1,f); // normal
      fwrite(pal++,4,1,f); // flashing
    }
    while(--palette_size);
  }

  // Write sprite data
  do
  {
    fwrite(src,4,width,f);
    src += paint->dst_bpr >> 2; // word pointer
  }
  while(--height);

  fclose(f);

  // Set filetype
  _swix(OS_File, _INR(0,2), WRITE_CATINFO, filename, FILETYPE_SPRITE);
}
