/*--------------------------------------------------------------------
 * FICHERO:  TrzResti.c
 * OBJETIVO: Definir la funcin Trz_Restituye()
 * AUTOR:    Pedro Reina
 * FECHA:    M.18.7.1995
 *------------------------------------------------------------------*/

/*--------------------------------------------------------------------
 * Funciones privadas
 *
 *   Trz_Cabe()
 *
 * Funciones privadas PC
 *
 *   Trz_EscribeVGA()
 *
 * Funciones privadas QL
 *
 *   Trz_RestituyeQL()
 *   Trz_EscribeQL()
 *   Trz_EscribeQLi()
 *   Trz_EscribeQLd()
 *------------------------------------------------------------------*/

/*--------------------------------------------------------------------
 * Ficheros de cabecera
 *------------------------------------------------------------------*/

#include "Trozo.h"

#ifdef OLIMPO_PC
#include <conio.h>          /*  puttext()  */
#include <mem.h>            /*  movedata() */
#endif

/*--------------------------------------------------------------------
 * Declaracin de funciones
 *------------------------------------------------------------------*/

#ifdef OLIMPO_PC
static int Trz_EscribeVGA();
#endif

#ifdef OLIMPO_QL
static void Trz_RestituyeQL();
static void Trz_EscribeQL();
static void Trz_EscribeQLi();
static void Trz_EscribeQLd();
#endif

/*--------------------------------------------------------------------
 * Definicin de funciones
 *------------------------------------------------------------------*/

/*--------------------------------------------------------------Olimpo
 * FUNCION:  Trz_Restituye()
 * OBJETIVO: Restituir un trozo a un lugar de la pantalla
 * ENTRADAS: El trozo, la fila superior y la columna izquierda
 *           en donde se desea hacer la restitucin
 * SALIDAS:  Lgica, que indica si se ha podido realizar
 *           la restitucin
 * EJEMPLO:  Trz_Restituye (Panel,3,4)
 *------------------------------------------------------------------*/
logico Trz_Restituye (Trozo, Fila, Columna)
trozo  Trozo;
octeto Fila, Columna;
  {
  logico Respuesta=SI;

  if      ( Pan_Modo() != Trz_Modo (Trozo) )  { Respuesta = NO; }
  else if ( !Trz_Cabe (Trozo,Fila,Columna) )  { Respuesta = NO; }
  else
    {
#ifdef OLIMPO_PC
    if ( Trz_Modo (Trozo) == PAN_TEXTO )
      {
      if ( !puttext (Columna+1, Fila+1,
                     Columna+Trz_Ancho(Trozo),Fila+Trz_Alto(Trozo),
                     Trz_Dato(Trozo)) )
        { Respuesta = NO; }
      }
    else
      {
      if ( !Trz_EscribeVGA (Fila*Pan_AltoCar()+Pan_MargenSuperior(),Columna,
                            Trz_Alto(Trozo)*Pan_AltoCar(),
                            Trz_Ancho(Trozo), Trz_Dato(Trozo)) )
        { Respuesta = NO; }
      }
#endif

#ifdef OLIMPO_QL
    Trz_RestituyeQL (Trozo, Fila, Columna);
#endif
    }

  return ( Respuesta );
  }

#ifdef OLIMPO_QL
/*--------------------------------------------------------------------
 * FUNCION:  Trz_RestituyeQL()
 * OBJETIVO: Restituir un trozo a un lugar de la pantalla QL cuando
 *           ya se sabe que es posible
 * ENTRADAS: El trozo, la fila superior y la columna izquierda en donde
 *           se va a hacer la restitucin
 * SALIDAS:  Ninguna
 * EJEMPLO:  Trz_Restituye (Panel,3,4)
 *------------------------------------------------------------------*/
static void Trz_RestituyeQL (Trozo, F1, C1)
trozo  Trozo;
octeto F1, C1;
  {
  contador PrimerPixel, Altura;
  octeto   PrimeraColumna, Columna, BitsIzquierda;
  menudo   BitsDerecha;
  octeto   Desplazamiento;
  octeto   MascaraIzquierda, MascaraDerecha;
  memoria  Comienzo;

  PrimerPixel = Pan_MargenIzquierdo() + Pan_AnchoCar() * C1;
  PrimeraColumna = PrimerPixel / 8;
  Columna = Trz_Columna (Trozo);
  BitsIzquierda = PrimerPixel - 8 * PrimeraColumna;
  Comienzo = (memoria) (Pan_Comienzo() +
             128 * (F1*Pan_AltoCar()+Pan_MargenSuperior()) +
             2 * PrimeraColumna);
  Altura = Trz_Alto(Trozo) * Pan_AltoCar();

  if ( BitsIzquierda == Trz_BitsIzquierda (Trozo) )
    {
    MascaraIzquierda = 0xFF >> BitsIzquierda;
    MascaraDerecha   = 0xFF << Trz_BitsDerecha(Trozo);
    Trz_EscribeQL (Comienzo, Altura, Trz_Columna(Trozo), Trz_Dato(Trozo),
                   MascaraIzquierda, MascaraDerecha );
    }

  else if ( BitsIzquierda < Trz_BitsIzquierda (Trozo) )
    {
    Desplazamiento = Trz_BitsIzquierda(Trozo) - BitsIzquierda;
    BitsIzquierda = Trz_BitsIzquierda(Trozo) - Desplazamiento;
    BitsDerecha   = Trz_BitsDerecha(Trozo) + Desplazamiento;
    if ( BitsDerecha >= 8 )
      {
      BitsDerecha -= 8;
      Columna--;
      }
    MascaraIzquierda = 0xFF >> BitsIzquierda;
    MascaraDerecha   = 0xFF << BitsDerecha;
    Trz_EscribeQLi (Comienzo, Altura, Trz_Columna(Trozo), Columna,
                    Trz_Dato(Trozo), MascaraIzquierda, MascaraDerecha,
                    Desplazamiento );
    }

  else  /*  BitsIzquierda > Trz_BitsIzquierda (Trozo) */
    {
    Desplazamiento = BitsIzquierda - Trz_BitsIzquierda(Trozo);
    BitsIzquierda = Trz_BitsIzquierda(Trozo) + Desplazamiento;
    BitsDerecha   = Trz_BitsDerecha(Trozo) - Desplazamiento;
    if ( BitsDerecha < 0 )
      {
      BitsDerecha += 8;
      Columna++;
      }
    MascaraIzquierda = 0xFF >> BitsIzquierda;
    MascaraDerecha   = 0xFF << BitsDerecha;
    Trz_EscribeQLd (Comienzo, Altura, Trz_Columna(Trozo), Columna,
                    Trz_Dato(Trozo), MascaraIzquierda, MascaraDerecha,
                    Desplazamiento );
    }
  }
#endif

#ifdef OLIMPO_PC
/*--------------------------------------------------------------------
 * FUNCION:  Trz_EscribeVGA()
 * OBJETIVO: Escribir en un fragmento de pantalla VGA
 * ENTRADAS: La fila superior (medida en pixels), la columna izquierda
 *           (medida en octetos), la altura (en pixels), la anchura (en
 *           octetos) y la zona de memoria donde estn los datos
 * SALIDAS:  1, que indica que ha ido bien
 * EJEMPLO:  Trz_EscribeVGA (100,3,120,40,Aux)
 *------------------------------------------------------------------*/
static int Trz_EscribeVGA (Fila, Columna, Alto, Ancho, Memoria)
contador Fila, Columna, Alto, Ancho;
memoria  Memoria;
  {
  contador Plano, i;
  unsigned Comienzo;

  Pan_MandaOrden (0x3CE, 5, 0);
  Pan_MandaOrden (0x3CE, 1, 0);
  Pan_MandaOrden (0x3CE, 3, 0);
  Pan_MandaOrden (0x3CE, 8, 0xFF);

  for ( Plano=1 ; Plano<16 ; Plano*=2 )
    {
    Pan_MandaOrden (0x3C4, 2, Plano);
    Comienzo = 80 * Fila + Columna;

    for ( i=0 ; i<Alto ; i++ )
      {
      movedata (FP_SEG(Memoria), FP_OFF(Memoria), 0xA000, Comienzo, Ancho);
      Memoria += Ancho;
      Comienzo += 80;
      }
    }

  Pan_MandaOrden (0x3CE, 1, 0);
  Pan_MandaOrden (0x3C4, 2, 0x0F);

  return ( 1 );
  }
#endif

#ifdef OLIMPO_QL
/*--------------------------------------------------------------------
 * FUNCION:  Trz_EscribeQL()
 * OBJETIVO: Escribir en un fragmento de pantalla QL
 * ENTRADAS: La direccin de comienzo donde escribir, la altura (en pixels),
 *           la anchura (en octetos), la zona de memoria donde estn los datos,
 *           la mscara para la columna izquierda y para la derecha.
 * SALIDAS:  Ninguna
 * EJEMPLO:  Trz_EscribeQL (142346,100,3,Imagen,0x07,0xF0)
 *------------------------------------------------------------------*/
static void Trz_EscribeQL (Comienzo, Alto, Ancho, Memoria, MascaraIzquierda,
                           MascaraDerecha)
memoria  Comienzo;
contador Alto;
octeto   Ancho;
memoria  Memoria;
octeto   MascaraIzquierda, MascaraDerecha;
  {
  contador i;
  octeto   MascaraUnica;
  entero   k=0;

  if ( Ancho == 1 )
    {
    MascaraUnica = MascaraIzquierda & MascaraDerecha;
    for ( i=0 ; i<Alto ; i++ )
      {
      *Comienzo     =  MascaraUnica & Memoria[k++] |
                      ~MascaraUnica & *Comienzo;
      *(Comienzo+1) =  MascaraUnica & Memoria[k++] |
                      ~MascaraUnica & *(Comienzo+1);
      Comienzo += 128;
      }
    }

  else  /* Ancho > 1 */
    {
    Ancho = 2 * (Ancho-2);
    for ( i=0 ; i<Alto ; i++ )
      {
      *Comienzo     =  MascaraIzquierda & Memoria[k++] |
                      ~MascaraIzquierda & *Comienzo;
      *(Comienzo+1) =  MascaraIzquierda & Memoria[k++] |
                      ~MascaraIzquierda & *(Comienzo+1);
      Mem_Copia (Comienzo+2, Memoria+k, Ancho);
      k += Ancho;
      *(Comienzo+Ancho+2) =  MascaraDerecha & Memoria[k++] |
                            ~MascaraDerecha & *(Comienzo+Ancho+2);
      *(Comienzo+Ancho+3) =  MascaraDerecha & Memoria[k++] |
                            ~MascaraDerecha & *(Comienzo+Ancho+3);
      Comienzo += 128;
      }
    }
  }
#endif

#ifdef OLIMPO_QL
/*--------------------------------------------------------------------
 * FUNCION:  Trz_EscribeQLi()
 * OBJETIVO: Escribir en un fragmento de pantalla QL desplazando algunos
 *           bits hacia la izquierda
 * ENTRADAS: La direccin de comienzo donde escribir, la altura (en pixels),
 *           la anchura (en octetos) de la imagen original, la anchura (en
 *           octetos) de la zona donde hay que escribir, la zona de memoria
 *           donde estn los datos, la mscara para la columna izquierda
 *           y para la derecha y el nmero de bits que hay que desplazar
 *           hacia la izquierda.
 * SALIDAS:  Ninguna
 * EJEMPLO:  Trz_EscribeQLi (142346,100,3,2,Imagen,0x07,0xF0,2)
 *------------------------------------------------------------------*/
static void Trz_EscribeQLi (Comienzo, Alto, AnchoOrigen, AnchoDestino,
                            Memoria, MascaraIzquierda, MascaraDerecha,
                            Desplazamiento)
memoria  Comienzo;
contador Alto;
octeto   AnchoOrigen, AnchoDestino;
memoria  Memoria;
octeto   MascaraIzquierda, MascaraDerecha, Desplazamiento;
  {
  contador i, j;
  octeto   MascaraUnica, DesplazamientoComplementario;
  octeto   Aux[128];
  entero   k;

  DesplazamientoComplementario = 8 - Desplazamiento;

  if ( AnchoDestino == 1 )
    {
    MascaraUnica = MascaraIzquierda & MascaraDerecha;
    for ( i=0 , k=0; i<Alto ; i++ , k++ )
      {
      *Comienzo     =  MascaraUnica & Memoria[k] << Desplazamiento  &
                       Memoria[k+2] >> DesplazamientoComplementario |
                      ~MascaraUnica & *Comienzo;
      k++;
      *(Comienzo+1) =  MascaraUnica & Memoria[k] << Desplazamiento  &
                       Memoria[k+2] >> DesplazamientoComplementario |
                      ~MascaraUnica & *(Comienzo+1);
      Comienzo += 128;
      Memoria += 2 * AnchoOrigen;
      }
    }

  else  /* AnchoDestino > 1 */
    {
    AnchoDestino = 2 * (AnchoDestino-2);
    for ( i=0 ; i<Alto ; i++ )
      {
      /* Primero se copia de memoria a Aux, desplazando hacia
         la izquierda todos los bits la cantidad indicada */
      for ( j=0 , k=0; j<AnchoDestino ; j++ , k++ )
        {
        Aux[k] = Memoria[k]   << Desplazamiento |
                 Memoria[k+2] >> DesplazamientoComplementario;
        k++;
        Aux[k] = Memoria[k]   << Desplazamiento |
                 Memoria[k+2] >> DesplazamientoComplementario;
        }
      Memoria += 2 * AnchoOrigen;

      /* Ahora se copia de Aux a la pantalla */
      k=0;
      *Comienzo     =  MascaraIzquierda & Aux[k++] |
                      ~MascaraIzquierda & *Comienzo;
      *(Comienzo+1) =  MascaraIzquierda & Aux[k++] |
                      ~MascaraIzquierda & *(Comienzo+1);
      Mem_Copia (Comienzo+2, Aux+k, AnchoDestino);
      k += AnchoDestino;
      *(Comienzo+AnchoDestino+2) = MascaraDerecha & Aux[k++] |
                                  ~MascaraDerecha & *(Comienzo+AnchoDestino+2);
      *(Comienzo+AnchoDestino+3) = MascaraDerecha & Aux[k++] |
                                  ~MascaraDerecha & *(Comienzo+AnchoDestino+3);
      Comienzo += 128;
      }
    }
  }
#endif

#ifdef OLIMPO_QL
/*--------------------------------------------------------------------
 * FUNCION:  Trz_EscribeQLd()
 * OBJETIVO: Escribir en un fragmento de pantalla QL desplazando algunos
 *           bits hacia la derecha
 * ENTRADAS: La direccin de comienzo donde escribir, la altura (en pixels),
 *           la anchura (en octetos) de la imagen original, la anchura (en
 *           octetos) de la zona donde hay que escribir, la zona de memoria
 *           donde estn los datos, la mscara para la columna izquierda
 *           y para la derecha y el nmero de bits que hay que desplazar
 *           hacia la derecha
 * SALIDAS:  Ninguna
 * EJEMPLO:  Trz_EscribeQLd (142346,100,3,2,Imagen,0x07,0xF0,2)
 *------------------------------------------------------------------*/
static void Trz_EscribeQLd (Comienzo, Alto, AnchoOrigen, AnchoDestino,
                            Memoria, MascaraIzquierda, MascaraDerecha,
                            Desplazamiento)
memoria  Comienzo;
contador Alto;
octeto   AnchoOrigen, AnchoDestino;
memoria  Memoria;
octeto   MascaraIzquierda, MascaraDerecha, Desplazamiento;
  {
  contador i, j;
  octeto   MascaraUnica, DesplazamientoComplementario;
  octeto   Aux[128];
  entero   k;

  DesplazamientoComplementario = 8 - Desplazamiento;

  if ( AnchoDestino == 1 )
    {
    MascaraUnica = MascaraIzquierda & MascaraDerecha;
    for ( i=0 , k=0; i<Alto ; i++ , k++ )
      {
      *Comienzo     =  MascaraUnica & Memoria[k] >> Desplazamiento  &
                       Memoria[k+2] << DesplazamientoComplementario |
                      ~MascaraUnica & *Comienzo;
      k++;
      *(Comienzo+1) =  MascaraUnica & Memoria[k] >> Desplazamiento  &
                       Memoria[k+2] << DesplazamientoComplementario |
                      ~MascaraUnica & *(Comienzo+1);
      Comienzo += 128;
      Memoria += 2 * AnchoOrigen;
      }
    }

  else  /* AnchoDestino > 1 */
    {
    AnchoDestino = 2 * (AnchoDestino-2);
    for ( i=0 ; i<Alto ; i++ )
      {
      /* Primero se copia de memoria a Aux, desplazando hacia
         la derecha todos los bits la cantidad indicada */
      for ( j=0 , k=0; j<AnchoDestino ; j++ , k++ )
        {
        Aux[k] = Memoria[k]   >> Desplazamiento |
                 Memoria[k-2] << DesplazamientoComplementario;
        k++;
        Aux[k] = Memoria[k]   >> Desplazamiento |
                 Memoria[k-2] << DesplazamientoComplementario;
        }
      Memoria += 2 * AnchoOrigen;

      /* Ahora se copia de Aux a la pantalla */
      k=0;
      *Comienzo     =  MascaraIzquierda & Aux[k++] |
                      ~MascaraIzquierda & *Comienzo;
      *(Comienzo+1) =  MascaraIzquierda & Aux[k++] |
                      ~MascaraIzquierda & *(Comienzo+1);
      Mem_Copia (Comienzo+2, Aux+k, AnchoDestino);
      k += AnchoDestino;
      *(Comienzo+AnchoDestino+2) = MascaraDerecha & Aux[k++] |
                                  ~MascaraDerecha & *(Comienzo+AnchoDestino+2);
      *(Comienzo+AnchoDestino+3) = MascaraDerecha & Aux[k++] |
                                  ~MascaraDerecha & *(Comienzo+AnchoDestino+3);
      Comienzo += 128;
      }
    }
  }
#endif
