/*
 *    TTTTTTTTTTTTTT  HH          HH  OOOOOOOOOOOOOO  MM          MM
 *    TTTTTTTTTTTTTT  HH          HH  OOOOOOOOOOOOOO  MMM        MMM
 *          TT        HH          HH  OO          OO  MMMM      MMMM 
 *          TT        HH          HH  OO          OO  MM MM    MM MM
 *          TT        HH          HH  OO          OO  MM  MM  MM  MM 
 *          TT        HHHHHHHHHHHHHH  OO          OO  MM   MMMM   MM
 *          TT        HHHHHHHHHHHHHH  OO          OO  MM    MM    MM
 *          TT        HH          HH  OO          OO  MM          MM
 *          TT        HH          HH  OO          OO  MM          MM
 *          TT        HH          HH  OO          OO  MM          MM
 *          TT        HH          HH  OOOOOOOOOOOOOO  MM          MM
 *          TT        HH          HH  OOOOOOOOOOOOOO  MM          MM 
 *
 *                      l'émulateur Thomson TO7-70
 *
 *  Copyright (C) 1996 Sylvain Huet, 1999-2003 Eric Botcazou.
 *
 *  This program 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.
 *
 *  This program 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
 */

/*
 *  Module     : linux/graphic.c
 *  Version    : 1.5.5
 *  Créé par   : Eric Botcazou juillet 1999
 *  Modifié par: Eric Botcazou 03/11/2003
 *
 *  Gestion de l'affichage du TO7-70.
 */


#ifndef SCAN_DEPEND

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <psptypes.h>

#endif
#include <SDL.h>

#include "psp_sdl.h"
#include "global.h"
#include "to7.h"
#include "display.h"


int psp_screenshot_mode;
# if 0 //LUDO:
int need_border_refresh = 0;
static int border_color;
# endif

#define CELL_COLS  40
#define CELL_ROWS  25

static int xcolor[TO7_NCOLORS+2];

# if 0 //LUDO:
/* RefreshBorder:
 *  Met à jour la couleur du pourtour de l'écran.
 */
void RefreshBorder(void)
{
  memset(to7_vram, 0x0, sizeof(to7_vram));
  need_border_refresh=0;
}
# endif

/* SetBorderColor:
 *  Fixe la couleur du pourtour de l'écran.
 */
void 
to7_SetBorderColor(int color)
{
# if 0 //LUDO:
    if (border_color != color)
    {
        border_color=color;
        need_border_refresh=1;
    }
# endif
}



/* DrawGPL:
 *  Affiche un Groupe Point Ligne (un octet de VRAM).
 */
void 
to7_DrawGPL(int addr, int pt, int col)
{
    register int i;
    unsigned int x,y,c1,c2;

    c1=((col>>3)&7)+(((~col)&0x40)>>3);
    c2=(col&7)+(((~col)&0x80)>>4);

    x=(addr%CELL_COLS)*8;
    y=addr/CELL_COLS;

    ushort *vram = &to7_vram[x + (y * TO7_SCREEN_W)];
    for (i=0; i<8; i++) {
      vram[i] = xcolor[pt&(0x80>>i) ? c1 : c2];
    }
}


#define LED_SIZE 6

/* SetDiskLed:
 *  Allume/éteint la led du lecteur de disquettes.
 */
void 
to7_SetDiskLed(int led_on)
{
# if 0  //LUDO:
  if (led_on) {
    psp_sdl_draw_rectangle( WINDOW_WIDTH-LED_SIZE  , 0, LED_SIZE-1, LED_SIZE-1,
           xcolor[TO7_NCOLORS], 0);
    psp_sdl_fill_rectangle( WINDOW_WIDTH-LED_SIZE+1, 1, LED_SIZE-2, LED_SIZE-2,
           xcolor[TO7_NCOLORS+1], 0);
  } else {
    need_border_refresh = 1;
  }
# endif
}

void 
to7_SetNoCapsLed(int led_on)
{
# if 0 //LUDO: TO_BE_DONE !
# endif
}

/* InitGraphic:
 *  Sélectionne le visual, met en place la palette de couleurs et
 *  initialise le mécanisme de bufferisation (dirty rectangles).
 */
void 
InitGraphic(void)
{
    int i,j;

    /* récupération de la palette du TO7-70 */
    for (i=0; i<TO7_NCOLORS; i++)
    {
        int red, green, blue;
        to7_QueryColor(i, &red, &green, &blue);
        xcolor[i] = psp_sdl_rgb(red, green, blue);
    }

    /* Couleurs de la led du lecteur de disquettes */
    xcolor[TO7_NCOLORS  ] = psp_sdl_rgb(0x00, 0x00, 0x00);
    xcolor[TO7_NCOLORS+1] = psp_sdl_rgb(0x00, 0xff, 0x00);
}

static void
to7_display_screen_blit(void)
{
  ushort* src_vram = to7_vram;
  ushort* dst_vram = blit_surface->pixels;
  
  int y;
  for (y = 0; y < TO7_SCREEN_H; y++) {
    memcpy( dst_vram, src_vram, TO7_SCREEN_W * sizeof(ushort));
    dst_vram += blit_surface->w;
    src_vram += TO7_SCREEN_W;
  }
}



static void
to7_display_screen_gu_normal()
{
  SDL_Rect srcRect;
  SDL_Rect dstRect;

  srcRect.x = 0;
  srcRect.y = 0;
  srcRect.w = TO7_SCREEN_W;
  srcRect.h = TO7_SCREEN_H;
  dstRect.x = 80;
  dstRect.y = 36;
  dstRect.w = TO7_SCREEN_W;
  dstRect.h = TO7_SCREEN_H;

  to7_display_screen_blit();
  psp_sdl_gu_stretch(&srcRect, &dstRect);
}

static void
to7_display_screen_gu_x125()
{
  SDL_Rect srcRect;
  SDL_Rect dstRect;

  srcRect.x = 0;
  srcRect.y = 0;
  srcRect.w = TO7_SCREEN_W;
  srcRect.h = TO7_SCREEN_H;
  dstRect.x = 40;
  dstRect.y = 10;
  dstRect.w = 400;
  dstRect.h = 250;

  to7_display_screen_blit();
  psp_sdl_gu_stretch(&srcRect, &dstRect);
}

static void
to7_display_screen_gu_x15()
{
  SDL_Rect srcRect;
  SDL_Rect dstRect;

  srcRect.x = 10;
  srcRect.y = 0;
  srcRect.w = TO7_SCREEN_W;
  srcRect.h = 180;
  dstRect.x = 0;
  dstRect.y = 0;
  dstRect.w = 480;
  dstRect.h = 270;

  to7_display_screen_blit();
  psp_sdl_gu_stretch(&srcRect, &dstRect);
}

static void
to7_display_screen_normal(void)
{
  ushort* src_vram = to7_vram;
  ushort* dst_vram = psp_sdl_get_vram_addr(80,36);
  
  int y;
  for (y = 0; y < TO7_SCREEN_H; y++) {
    memcpy( dst_vram, src_vram, TO7_SCREEN_W * sizeof(ushort));
    dst_vram += PSP_LINE_SIZE;
    src_vram += TO7_SCREEN_W;
  }
}

typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned int dword;

/* 

  LUDO: 16-bit HiColor (565 format) 
  see http://www.compuphase.com/graphic/scale3.htm

 */
static inline word loc_coloraverage(word a, word b)
{
  return (word)(((a ^ b) & 0xf7deU) >> 1) + (a & b);
}

static inline void 
render16bpp_X15_pixel(word *dist, word *src)
{
  dist[0] = src[0];
  dist[1] = loc_coloraverage(src[0], src[1]);
  dist[2] = src[1];
  dist[3] = src[2];
  dist[4] = loc_coloraverage(src[2], src[3]);
  dist[5] = src[3];
}

static inline void 
render16bpp_X125_pixel(word *dist, word *src)
{
  dist[0] = src[0];
  dist[1] = loc_coloraverage(src[0], src[1]);
  dist[2] = src[1];
  dist[3] = src[2];
  dist[4] = src[3];
}

static void
to7_display_screen_x125(void)
{
  ushort* src_vram = to7_vram;
  ushort* dst_vram = psp_sdl_get_vram_addr(40,10);
  ushort* src_vram_line = src_vram;
  ushort* dst_vram_line = dst_vram;
  
  int src_y;
  int dst_x;
  int dst_y;
  int count;

  /* [ TO7_WIDTH  = 320 ] x 1.25 -> 400 */
  /* [ TO7_HEIGHT = 200 ] x 1.25 -> 250 */

  for (dst_y = 0; dst_y < 250; dst_y++) {

    src_y = (dst_y * 200) / 250;

    src_vram_line = &src_vram[(src_y * TO7_SCREEN_W)];
    dst_vram_line = dst_vram;

    count = 320;
    while (count > 0) {
      render16bpp_X125_pixel(dst_vram_line, src_vram_line);
      src_vram_line += 4;
      dst_vram_line += 5;
      count -= 4;
    }

    dst_vram += PSP_LINE_SIZE;
  }
}

static void
to7_display_screen_x15(void)
{
  ushort* src_vram = to7_vram;
  ushort* dst_vram = psp_sdl_get_vram_addr(0,0);
  ushort* src_vram_line = src_vram;
  ushort* dst_vram_line = dst_vram;
  
  int src_y;
  int dst_x;
  int dst_y;
  int count;

  /* [ TO7_WIDTH  = 320 ] x 1.5 -> 480 */
  /* [ TO7_HEIGHT = 200 ] x 1.5 -> 300  */

  for (dst_y = 0; dst_y < 270; dst_y++) {

    src_y = 10 + (dst_y * 180) / 270;

    src_vram_line = &src_vram[(src_y * TO7_SCREEN_W)];
    dst_vram_line = dst_vram;

    count = 320;
    while (count > 0) {
      render16bpp_X15_pixel(dst_vram_line, src_vram_line);
      src_vram_line += 4;
      dst_vram_line += 6;
      count -= 4;
    }

    dst_vram += PSP_LINE_SIZE;
  }
}

# if 0
static void
to7_display_screen_x125(void)
{
  ushort* src_vram = to7_vram;
  ushort* dst_vram = psp_sdl_get_vram_addr(0,0);
  
  int src_x;
  int src_y;
  int dst_x;
  int dst_y;

  /* [ TO7_WIDTH  = 320 ] x 1.25 -> 400 */
  /* [ TO7_HEIGHT = 200 ] x 1.25 -> 250 */

  for (dst_y = 0; dst_y < 400; dst_y++) {
    src_y = (dst_y * 200) / 400;
    for (dst_x = 0; dst_x < 250; dst_x++) {
      src_x = (dst_x * 320) / 250;
      dst_vram[(dst_y * PSP_LINE_SIZE) + dst_x] = src_vram[(src_y * TO7_SCREEN_W) + src_x];
    }
  }
}

static void
to7_display_screen_fit_height(void)
{
  ushort* src_vram = to7_vram;
  ushort* dst_vram = psp_sdl_get_vram_addr(0,0);
  
  int src_x;
  int src_y;
  int dst_x;
  int dst_y;

  /*  W 320 -> 435 */
  /*  H 200 -> 272 */

  for (dst_y = 0; dst_y < 272; dst_y++) {
    src_y = (dst_y * 200) / 272;
    for (dst_x = 0; dst_x < 435; dst_x++) {
      src_x = (dst_x * 320) / 435;
      dst_vram[(dst_y * PSP_LINE_SIZE) + dst_x] = src_vram[(src_y * TO7_SCREEN_W) + src_x];
    }
  }
}

static void
to7_display_screen_fit(void)
{
  ushort* src_vram = to7_vram;
  ushort* dst_vram = psp_sdl_get_vram_addr(0,0);
  
  int src_x;
  int src_y;
  int dst_x;
  int dst_y;

  /*  W 320 -> 480 */
  /*  H 200 -> 272 */

  for (dst_y = 0; dst_y < 272; dst_y++) {
    src_y = (dst_y * 200) / 272;
    for (dst_x = 0; dst_x < 480; dst_x++) {
      src_x = (dst_x * 320) / 480;
      dst_vram[(dst_y * PSP_LINE_SIZE) + dst_x] = src_vram[(src_y * TO7_SCREEN_W) + src_x];
    }
  }
}
# endif

static void
to7_synchronize(void)
{
	static u32 nextclock = 1;

  if (THOM.thom_speed_limiter) {

	  if (nextclock) {
		  u32 curclock;
		  do {
			  curclock = clock();
		  } while (curclock < nextclock);
  
		  nextclock = curclock + ((CLK_TCK * THOM.thom_speed_limiter) / 60);
    }
  }
}


/* RefreshScreen:
 *  Rafraîchit l'écran du TO7-70.
 */
void 
RefreshScreen(void)
{ 
  if (THOM.psp_skip_cur_frame <= 0) {

    THOM.psp_skip_cur_frame = THOM.psp_skip_max_frame;

    if (THOM.thom_render_smooth) {

      if (THOM.thom_render_mode == THOM_RENDER_NORMAL    ) to7_display_screen_gu_normal(); 
      else
      if (THOM.thom_render_mode == THOM_RENDER_X125      ) to7_display_screen_gu_x125(); 
      else
      if (THOM.thom_render_mode == THOM_RENDER_X15       ) to7_display_screen_gu_x15(); 

    } else {

      if (THOM.thom_render_mode == THOM_RENDER_NORMAL    ) to7_display_screen_normal(); 
      else
      if (THOM.thom_render_mode == THOM_RENDER_X125      ) to7_display_screen_x125(); 
      else
      if (THOM.thom_render_mode == THOM_RENDER_X15       ) to7_display_screen_x15(); 
    }

    if (THOM.thom_speed_limiter) {
      to7_synchronize();
    }

    if (psp_kbd_is_danzeff_mode()) {
      danzeff_moveTo(-165, -50);
      danzeff_render();
    }

    psp_kbd_display_active_mapping();
    psp_sdl_flip();
  
    if (psp_screenshot_mode) {
      psp_screenshot_mode--;
      if (psp_screenshot_mode <= 0) {
        psp_sdl_save_screenshot();
        psp_screenshot_mode = 0;
      }
    }

  } else if (THOM.psp_skip_max_frame) {
    THOM.psp_skip_cur_frame--;
  }
}
