// ***************************************************************************
// ***************************************************************************
// ***************                                            ****************
// ***************    S P R I T E   V E R W A L T U N G       ****************
// ***************                                            ****************
// ***************    Programmed in C++ for DOS && LINUX      ****************
// ***************                                            ****************
// ***************    Created by Jens Thiele August 1995      ****************
// ***************    Version 1.0                             ****************
// ***************                                            ****************
// ***************************************************************************
// ***************************************************************************


// *************************** Instructions ***********************************
// Don't include sprite01.H directly !!!
// If you want to use sprite01.H with 
// 1. DOS you must define makefordos 
//    sprites are restricted to 64kb
//    The included vga support is only 320x200x256 include File: scrdosvga.H
// 2. vgalib you must include File: scrsvgalib.H
// 3. X you must include File: scrX11.H

// ***************** KNOWN BUGS : *********************************************
// Some Identifier Lengths are longer than 32 characters.
// This will cause problems if the Identifier Lenght is restricted.
// (Borland C++ for DOS)

// Will be changed:
// - rechteck  xanz=1 || yanz=1 !!!
// - rechteckclip does not exist !!
// - copysprite(int x,int y,sprite_pcxtype *dest);
// - sprite_pcxtype  braucht einen change 
// - Linien malen !!


// ****************************************** Includes ********************
#include "sprite01.H"
//#include "sprite_tools01.H"


// ****************************************** Die Paletten Klasse *************
// ****************************************** Die Paletten Klasse *************
// ****************************************** Die Paletten Klasse *************
// ****************************************** Die Paletten Klasse *************
// ****************************************** Die Paletten Klasse *************
// ****************************************** Die Paletten Klasse *************
// ****************************************** Die Paletten Klasse *************
int palentrytype::operator==(const palentrytype &entry) const
{
  return ((entry.red==red)&&(entry.green==green)&&(entry.blue==blue));
}

float palentrytype::operator-(const palentrytype &entry) const
{
  // Red
  float rd;
  if (entry.red>red)
    rd=entry.red-red;
  else
    rd=red-entry.red;

  // Green
  float gd;
  if (entry.green>green)
    gd=entry.green-green;
  else
    gd=green-entry.green;

  // Blue
  float bd;
  if (entry.blue>blue)
    bd=entry.blue-blue;
  else
    bd=blue-entry.blue;
  return (sqrt(rd*rd+gd*gd+bd*bd));
}

float palentrytype::farbtondif(const palentrytype &entry) const
{
  float durchschnitt=(red+green+blue)/3;
  float d2=(entry.red+entry.green+entry.blue)/3;
  float reddif=(durchschnitt-red)*d2/10;
  float greendif=(durchschnitt-green)*d2/10;
  float bluedif=(durchschnitt-blue)*d2/10;
  float rd2=(d2-entry.red)*durchschnitt/10;
  float gd2=(d2-entry.green)*durchschnitt/10;
  float bd2=(d2-entry.blue)*durchschnitt/10;
  return (reddif-rd2)*(reddif-rd2)+(greendif-gd2)*(greendif-gd2)+(bluedif-bd2)*(bluedif-bd2);
}

float palentrytype::hue() const
{
  vektor2_poltype r(red,0);
  vektor2_poltype g(green,2.0*M_PI/3.0);
  vektor2_poltype b(blue,4.0*M_PI/3.0);
  vektor2_poltype erg(&r);
  erg.add(&g);
  erg.add(&b);
  return erg.dir;
}

// todo ist so net richtig !!
void palentrytype::change(iotype *ioptr,int8 mode)
{
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  char redc=(char) red;
  char greenc=(char) green;
  char bluec=(char) blue;

  cfgptr->change_char_check(&redc);
  cfgptr->change_char_check(&greenc);
  cfgptr->change_char_check(&bluec);
  red=redc;
  green=greenc;
  blue=bluec;
  delete cfgptr;
}

const char *palettetype::headerstring="P6";

palettetype::palettetype()
{
  anzentries=0;
}

palettetype::palettetype(iotype *ioptr,int8 mode) 
{
  change(ioptr,mode);
}

palettetype::palettetype(const char *dateiname,int8 mode)
{
  change(make_file_to_io_check(dateiname),mode);    
}

void palettetype::change(iotype *ioptr,int8 mode) 
{
  if (ioptr->getmode()==IOTYPE_WRITE_MODE)
    fatalfehler("sprite01.C: palettetype::change sorry currently saving isn't possible");
  check_or_save_header(this,ioptr,mode);
  anzentries=0;
  int32 sx,sy;
  cfgtype *cfgptr=choose_cfgtype(ioptr,CFG_TEXT_MODE);
  cfgptr->change_int32_check(&sx);
  cfgptr->change_int32_check(&sy);
  cfgptr->change_int16_check((int16 *)&maxval);
  cout <<"Maxval is: "<<maxval<<endl;
  delete cfgptr;
  uint8 red;
  uint8 green;
  uint8 blue;
  palentrytype paldot;
  int32 anzdots=0;
  while (anzdots<sx*sy)
    {
      ioptr->io_read_check((char *)&red);
      ioptr->io_read_check((char *)&green);
      ioptr->io_read_check((char *)&blue);
      paldot.red=red;
      paldot.green=green;
      paldot.blue=blue;
      int schonvorhanden=0;
      for (uint16 aktentry=0;aktentry<anzentries;aktentry++)
	if (palette[aktentry]==paldot)
	  {
	    schonvorhanden=1;
	    break;
	  }
      if (!schonvorhanden)
	{
	  if (anzentries>=256)
	    fatalfehler("sprite01.C: palettetype::change(...): More than 256 colors found!");
	  palette[anzentries]=paldot;
	  anzentries++;
	}
      anzdots++;
    }
  cout <<"palettetype::change(...) : I found "<<(int16)anzentries<<" colors.\n";
  cout <<"palettetype::change(...) : calculating darkdown table\n";
  calc_darkdown();
  calc_black();
  calc_white();
}

uint8 palettetype::remap(const palentrytype &entry) const
{
  // Maximaler Abstand im Quadrat
  float differs=0;
  int16 best=-1;
  for (int16 akt=0;akt<anzentries;akt++)
    {
      if (palette[akt]==entry)
	{
	  return akt;
	}
      else
	if ((best==-1)||(palette[akt]-entry<=differs))
	  {
	    best=akt;
	    differs=palette[akt]-entry;
	  }
    }
  // todo
  if (differs>256)
    cout <<"palettetype::remap: Warning verry different colors !\n";
  return best;
}

void palettetype::calc_black() 
{
  palentrytype entry;
  entry.red=0;
  entry.green=0;
  entry.blue=0;
  int16 erg=find(entry);
  if (erg==-1)
    fatalfehler("palettetype::black(): palette must have a black (0/0/0/) entry");
  cout <<"black color is "<<erg<<endl;
  cblack=erg;
}

void palettetype::calc_white()
{
  palentrytype entry;
  entry.red=maxval;
  entry.green=maxval;
  entry.blue=maxval;
  int16 erg=find(entry);
  if (erg==-1)
    fatalfehler("palettetype::white(): palette must have a white (maxval/maxval/maxval) entry");
  cout <<"white color is "<<erg<<endl;
  cwhite=erg;
}

int16 palettetype::find(const palentrytype &entry) const
{
  for (int16 akt=0;akt<anzentries;akt++)
    {
      if (palette[akt]==entry)
	{
	  return akt;
	}
    }
  return -1;
}

void palettetype::cycle()
{
  palentrytype ablage;
  ablage=palette[0];
  for (int akt=0;akt<anzentries-1;akt++)
    palette[akt]=palette[akt+1];
  palette[anzentries-1]=ablage;
}


// Das Rechteck !!!!!!! :-) **************************************************
// Das Rechteck !!!!!!! :-) **************************************************
// Das Rechteck !!!!!!! :-) **************************************************
// Das Rechteck !!!!!!! :-) **************************************************
// Das Rechteck !!!!!!! :-) **************************************************

// Type checking
const char *rechtecktype::headerstring="rechtecktype";
const char *rechtecktype::getheaderstring()
{
  return rechtecktype::headerstring;
}


void rechtecktype::change(iotype *ioptr,int8 mode)
{
  //  check_or_save_header(this,ioptr,mode);
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_int32_check(&mx);
  cfgptr->change_int32_check(&my);
  cfgptr->change_int32_check(&sx);
  cfgptr->change_int32_check(&sy);
  delete cfgptr;
}


rechtecktype *rechtecktype::rotate_rechteck(const float winkel,const float zoom)
{
  rechtecktype *erg=new rechtecktype;
  calcsize(winkel,zoom,erg->sx,erg->sy);
  calcmitte(winkel,zoom,erg->mx,erg->my);
  return erg;
}

void rechtecktype::calcsize(const float winkel,const float zoom,int32 &_sx,int32 &_sy)
{
  float sinus=sin(winkel);
  float cosinus=cos(winkel);
  _sx=ftoi(( floatabs(float(sx)*cosinus) + floatabs(float(sy)*sinus)   ) *zoom) + 2;
  _sy=ftoi(( floatabs(float(sx)*sinus)   + floatabs(float(sy)*cosinus) ) *zoom) + 2;
}

void rechtecktype::calcmitte(float winkel,float zoom,int32 &_mx,int32 &_my)
{
  float dx1,dy1,dx2,dy2,dx3,dy3,sinus,cosinus;
  sinus=sin(winkel);
  cosinus=cos(winkel);
    
  dx1 = float(mx) * zoom;
  dy1 = float(my) * zoom;

  dx2 = float(sx - mx) * zoom;
  dy2 = float(sy - my) * zoom;

  if (sinus<0) {
    if (cosinus<0) {      // 180<winkel<270
      dx3 = -( dy1*sinus + dx2*cosinus ) +1;
      dy3 = -( dx2*sinus + dy2*cosinus ) +1;
    }else{                // 270<winkel<360
      dx3 = dx1*cosinus - dy1*sinus +1;
      dy3 = dy1*cosinus - dx2*sinus +1;
    };
  }else{
    if (cosinus<0) {      // 90<winkel<180
      dx3 = dy2*sinus - dx2*cosinus +1;
      dy3 = dx1*sinus - dy2*cosinus +1;
    }else{                // 0<winkel<90
      dx3 = dx1*cosinus + dy2*sinus +1;
      dy3 = dy1*cosinus + dx1*sinus +1;
    };
  };
  _mx=ftoi(dx3);
  _my=ftoi(dy3);
}


void rechtecktype::addrechteck(const rechtecktype &other)
{
  int32 x1=-mx;
  int32 y1=-my;
  int32 x2=x1+sx-1;
  int32 y2=y1+sy-1;
  int32 ox1=-other.mx;
  int32 oy1=-other.my;
  int32 ox2=ox1+other.sx-1;
  int32 oy2=oy1+other.sy-1;
  if (x1>ox1)
    mx=other.mx;
  if (y1>oy1)
    my=other.my;
  int32 max_x2=ox2;
  if (x2>ox2)
    max_x2=x2;
  int32 max_y2=oy2;
  if (y2>oy2)
    max_y2=y2;
  //    sx=max_x2-(-mx)+1; =>
  sx=max_x2+mx+1;
  //    sy=max_y2-(-my)+1; =>
  sy=max_y2+my+1;
}

bool rechtecktype::subrechteck(const rechtecktype &other)
{
  // todo ugly but it works
  int x1=-mx;
  int y1=-my;
  int tx2=x1+sx-1;
  int ty2=y1+sy-1;
  
  int ox1=-other.mx;
  int oy1=-other.my;
  int ox2=other.sx+ox1-1;
  int oy2=other.sy+oy1-1;
  
  int x2,y2;
  if (tx2>ox2)
    x2=ox2;
  else
    x2=tx2;
  if (ty2>oy2)
    y2=oy2;
  else
    y2=ty2;
  if (x1<ox1)
    x1=ox1;
  if (y1<oy1)
    y1=oy1;
  sx=x2-x1+1;
  sy=y2-y1+1;
  if ((sx<0)||(sy<0)) {sx=0;sy=0;mx=0;my=0;return false;}
  mx=-x1;
  my=-y1;
  return true;
}

ostream& operator<<(ostream &ost,const rechtecktype &r)
{
  ost <<"rechtecktype: mx: "<<r.mx<<" my: "<<r.my<<" sx: "<<r.sx<<" sy: "<<r.sy<<endl;
  return ost;
}

// ****************************************** Das Allgemeine Sprite **********
// ****************************************** Das Allgemeine Sprite **********
// ****************************************** Das Allgemeine Sprite **********
// ****************************************** Das Allgemeine Sprite **********
// ****************************************** Das Allgemeine Sprite **********
// ****************************************** Das Allgemeine Sprite **********
// ****************************************** Das Allgemeine Sprite **********
// ****************************************** Das Allgemeine Sprite **********
// ****************************************** Das Allgemeine Sprite **********
// ****************************************** Das Allgemeine Sprite **********
class sprite_lineartype; // Forward !

// ******************************************* Sprite Aufbau: ****************
//   string: Art d. Sprites
//   int32:      X-Breite      
//   int32:      Y-Breite      
//   int32:      Mitte X       
//   int32:      Mitte Y       
//   int32:      Pointer auf Sprite
//   int32:      Pointer auf Routine copysprite      --> sprite_lineartype
//   int32:      Pointer auf Routine copysprite_clip --> sprite_lineartype
//   int32:      Pointer auf Routine save
// ****************************************************************************

// Init / Deinit *********************************************************
spritetype::spritetype()
{
  sprite=NULL;
  oldsprite=NULL;
  oldzoom=0;
}

spritetype *spritetype::create(iotype *ioptr,int8 mode)
{
#ifdef DEBUG_sprite_H
  printf("spritetype::create aufgerufen !!\n");
#endif
  if (ioptr->getmode()!=IOTYPE_READ_MODE)
    fatalfehler("spritetype::create\n"
		"iotype befindet sich nicht im Lesemodus");

  //  int32 oldseek=ioptr->getpos();
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  string headerstring;
  cfgptr->read_string_check(&headerstring);
  delete cfgptr;
  // todo wieder hinmachen   ioptr->seekset(oldseek);

  // Welches Sprite muss ich initen *****************************************
  if (!strcmp(headerstring.c_str(),"sprite_linear_nontransparenttype"))
    {
      // Nicht Transparent
#ifdef DEBUG_sprite_H
      printf("spritetype::create: "
	     "lade Nicht transparentes Sprite...\n");
#endif
      return new sprite_linear_nontransparenttype(ioptr,mode);
    }
  else if (!strcmp(headerstring.c_str(),"P6"))
    {
#ifdef DEBUG_sprite_H
      printf("spritetype::create: load ppm Sprite...\n");
#endif
      sprite_ppmtype *erg=new sprite_ppmtype();
      erg->change(ioptr,mode);
      return erg;
    }
  else if (!strcmp(headerstring.c_str(),"sprite_linear_transparenttype"))
    {
#ifdef DEBUG_sprite_H
      printf("spritetype::create: lade transparentes Sprite...\n");
#endif
      return new sprite_linear_transparenttype(ioptr,mode);
    }
  else if (!strcmp(headerstring.c_str(),"sprite_puzzletype"))
    {
#ifdef DEBUG_sprite_H
      printf("spritetype::create: Puzzle Sprite geladen.\n");
#endif
      return new sprite_puzzletype(ioptr,mode);
    }
  else if (!strcmp(headerstring.c_str(),"sprite_coordedtype"))
    {
#ifdef DEBUG_sprite_H
      printf("spritetype::create: lade Coorded Sprite...\n");
#endif
      return new sprite_coordedtype(ioptr,mode);
    }
  else if (!strcmp(headerstring.c_str(),"sprite_modifiedtype"))
    {
#ifdef DEBUG_sprite_H
      printf("spritetype::create: lade Modified Sprite...\n");
#endif
      sprite_modifiedtype *ret=new sprite_modifiedtype;
      ret->change(ioptr,mode);
      return ret;
    }
  else if (!strcmp(headerstring.c_str(),"sprite_indextype"))
    {
#ifdef DEBUG_sprite_H
      printf("spritetype::create: lade Index Sprite...\n");
#endif
      sprite_indextype *ret=new sprite_indextype;
      ret->change(ioptr,mode);
      return ret;
    }
  else if (!strcmp(headerstring.c_str(),"sprite_movietype"))
    {
#ifdef DEBUG_sprite_H
      printf("spritetype::create: lade Movie Sprite...\n");
#endif
      sprite_movietype *ret=new sprite_movietype;
      ret->change(ioptr,mode);
      return ret;
    }
  cerr << "sprite01.C: spritetype::create(...): Wrong headerstring: "<<headerstring<<endl;
  fatalfehler("spritetype::create: Illegaler headerstring !");
#ifdef kickwarn
  return(NULL);
#endif
}

spritetype *spritetype::create(char *name)
{
  iotype *ioptr=make_file_to_io_check(name);
  spritetype *erg=create(ioptr,CFG_TEXT_MODE);      
  delete ioptr;
  return(erg);
}

// Gibt Speicher frei !!
spritetype::~spritetype()
{
#ifdef DEBUG_sprite_H
  printf("spritetype::~spritetype aufgerufen !\n");
#endif
  delete(sprite);
}

void spritetype::copysprite_clip(int x,int y,sprite_lineartype *dest,uint32 index=0)
{
  copysprite_clip_to(x,y,dest,(*dest),index);
}

void spritetype::copysprite_rotate_clip
(int x,int y,float winkel,float zoom,sprite_lineartype *dest,uint32 index=0)
{
  copysprite_rotate_clip_to(x,y,winkel,zoom,dest,*dest,index); // todo this slows down
}

void spritetype::copysprite_rotate_clip_to
(int x,int y,float winkel,float zoom,sprite_lineartype *dest,const rechtecktype &rect,uint32 index=0)
{
  // todo alles net so toll !!!
  // altes problem zwecks 1 sprite aber viele panzer !!
  // ausserdem erst clippen dann rotaten !
  // das sprite sich merken muss wohl doch der panzer !! oder ??
  // Only rotate if no rotated sprite in mem or winkel or zoom has changed
  if ((winkel!=oldwinkel)||(zoom!=oldzoom))
    {
      if ((winkel==0.0)&&(zoom==1.0))
	{
	  // Male source
	  delete oldsprite;
	  oldsprite=this;
	}
      else
	{
	  // Muss überhaupt gemalt werden ?? *******************************
	  // todo sx sy und mx my muessen stimmen !! tun sie das ? fuer welche sprites !!
	  rechtecktype *rot=rotate_rechteck(winkel,zoom);
	  int x1s=x-rot->mx;
	  int y1s=y-rot->my;
	  int x2s=x1s+rot->sx;
	  x2s--;
	  int y2s=y1s+rot->sy;
	  y2s--;
	  if (dest->rechteckcheck(x1s,y1s,x2s,y2s))
	    return;

	  // Source darf ich ja nicht killen !!
	  if (oldsprite!=this)
	    delete oldsprite;
	  oldsprite=rotate(winkel,zoom,index);
	}
      oldwinkel=winkel;
      oldzoom=zoom;
    }
  oldsprite->copysprite_clip_to(x,y,dest,rect,index);
}

// Protected Funktionen *******************************************************
void spritetype::fehler(char *str)
{
    string fehlerstring(str);
    fehlerstring+="\nInhalt des Headerstrings: \"";
    fehlerstring+=getheaderstring();
    fehlerstring+='\"';
    fatalfehler(fehlerstring.c_str());
}


//todo Nur so halt als info wieviele Sprites gemalt wurden kann spaeter weg !!

uint32 pnontrans=0;
uint32 ptrans=0;




// *******************************************************+ Spriteverwaltung
// *******************************************************+ Spriteverwaltung
// *******************************************************+ Spriteverwaltung
// *******************************************************+ Spriteverwaltung
// *******************************************************+ Spriteverwaltung
// *******************************************************+ Spriteverwaltung

// s.h listen2.h !!
sprite_kette_iqtype *allsprites_ketteptr;
void init_allsprites_kette(const char *palname)
{
  allsprites_ketteptr=new sprite_kette_iqtype(palname);
}

void deinit_allsprites_kette()
{
  cout << "Painted sprites:   transparent: "<<ptrans<<" nontransparent: "<<pnontrans<<endl;
  delete allsprites_ketteptr;
}

// Sorgt dafuer, dass gleiche sprites nicht doppelt im Speicher sind !!!
// ausser Filme, die muessen jeweils neu im speicher sein !
// s.h. auch listen2.H
// Achtung es koennen mehrere Objekte mit dem selben Namen in der Liste vorkommen !!
// unbedingt Pointer benutzen und kein get_elementadress !

// todo warum muss ich den sprite_puzzletype auch exclusiv machen ?

spritetype *sprite_kette_iqtype::make_elementadress(const char *name,int8 mode)
{
  spritetype *erg=get_elementadress(name);
  if ((!erg)||(!strcmp(erg->getheaderstring(),"sprite_movietype"))
      ||(!strcmp(erg->getheaderstring(),"sprite_puzzletype")))
    // Reihenfolge wichtig !!!   sprite nicht vorhanden oder ein Film !!
    {
      iotype *ioptr=make_file_to_io_check(name);
      erg=spritetype::create(ioptr,CFG_TEXT_MODE);      
      delete ioptr;
      erg->elementname+=name
;
      zeiger_push(erg);
      return erg;
    }
  inc_element_counter(erg);
  return erg;
}

sprite_kette_iqtype::sprite_kette_iqtype(const char *palname)
{
  paletteptr=new palettetype(palname);
}

sprite_kette_iqtype::~sprite_kette_iqtype()
{
  delete paletteptr;
}





// ****************************************** Das Lineare Sprite *************
// ****************************************** Das Lineare Sprite *************
// ****************************************** Das Lineare Sprite *************
// ****************************************** Das Lineare Sprite *************
// ****************************************** Das Lineare Sprite *************
// ****************************************** Das Lineare Sprite *************
// ****************************************** Das Lineare Sprite *************


// ******************************************* Linear_Sprite-Datei Aufbau: ***
/*
   int32: X-Breite  --\
   int32: Y-Breite  ---\__ Header
   int32: Mitte X   ---/
   int32: Mitte Y   --/

   char : Bildpunkt --\
   char : Bildpunkt ---\
    :               ----\
    :               ------ Bild als RAW anz Bytes=X-Breite*Y-Breite
    :               ----/
    :               ---/
   char : Bildpunkt --/

 [ char : Transparente Farbe ] nur bei Transparenten Sprites
                               (s.h Konstruktor von
                               sprite_linear_transparenttype)
			       */
// ***************************************************************************



// ************************** INIT **********************************
// ************************** INIT **********************************
// ************************** INIT **********************************


// Standardkonstruktor: ACHTUNG ES WIRD KEIN SPEICHER RESERVIERT !
sprite_lineartype::sprite_lineartype(){}
    
// Sprite daten initen !
void sprite_lineartype::initspritedat
(int _sx,int _sy,int _mx,int _my)
{
    sx=_sx;
    sy=_sy;
    mx=_mx;
    my=_my;

    sprite=new char[sx*sy+100];
    // Check Byte
    for (int a=0;a<100;a++)
      sprite[sx*sy+a]=66;
}

int sprite_lineartype::spritecheck()  //spaeter
{
  int f=0;
  for (int a=0;a<100;a++)
    if (sprite[sx*sy+a]!=66)
      f++;
  return f;
}

// Sprite initen
sprite_lineartype::sprite_lineartype(int _sx,int _sy,int _mx,int _my)
{
    initspritedat(_sx,_sy,_mx,_my);
}

// Einfarbiges Sprite initen
sprite_lineartype::sprite_lineartype
(int _sx,int _sy,int _mx,int _my,char _farbe)
{
    initspritedat(_sx,_sy,_mx,_my);
    clearsprite(_farbe);
}






// ****************************************************** PUBLIC


void sprite_lineartype::putpixel_clip(int x,int y,char farbe)
{
	if (punktinrechteck(x,y))
		*(calcadresse(x,y))=farbe;
}

void sprite_lineartype::putpixel_clip_to(int x,int y,char farbe,const rechtecktype &rect)
{
	if (rect.punktinrechteck(x,y))
		*(calcadresse(x,y))=farbe;
}

int sprite_lineartype::getpixel_clip(int x,int y,char *farbe,uint32)
{
	if (punktinrechteck(x,y))
	    {
		*farbe=*(calcadresse(x,y));
		return(0);
	    }
	return(-1);
}

char sprite_lineartype::farbeinsprite(char farbe)
{
    return ((void *)memchr(sprite,farbe,(int32)sx*(int32)sy)!=NULL);
}


void sprite_lineartype::hline_clip(int x1,int x2,int y,char farbe)
{
	if (!ycoordinrechteck(y))
		// Linie garnicht im Sprite
		return;
	if (x2<x1)
	{
		int ablage=x2;
		x2=x1;
		x1=ablage;
	}
	if ((x1+mx>=sx)||(x2+mx<0))
		return;
	if (!xcoordinrechteck(x1))
		x1=-mx;
	if (!xcoordinrechteck(x2))
	{
		x2=sx-mx;
		x2--;
	}
	hline(x1,x2,y,farbe);
}


void sprite_lineartype::vline_clip(int x,int y1,int y2,char farbe)
{
  if (!xcoordinrechteck(x))
    // Linie garnicht im Sprite
    return;
  if (y2<y1)
    {
      int ablage=y2;
      y2=y1;
      y1=ablage;
    }
  if ((y1+my>=sy)||(y2+my<0))
    return;
  if (!ycoordinrechteck(y1))
		y1=-my;
  if (!ycoordinrechteck(y2))
    {
      y2=sy-my;
      y2--;
    }
  vline(x,y1,y2,farbe);
}

void sprite_lineartype::kreis(int x,int y,int radius,char farbe)
{
	int f;
	int ax=0;
	ulong radiusquadrat=(ulong)radius*(ulong)radius;
	do
	{
		f=(int)sqrt(radiusquadrat-(ulong)ax*(ulong)ax);
		putpixel(x+ax,y-f,farbe);//OOR
		putpixel(x-ax,y-f,farbe);//OOL
		putpixel(x+f,y-ax,farbe);//OUR
		putpixel(x-f,y-ax,farbe);//OUL

		putpixel(x+ax,y+f,farbe);//UUR
		putpixel(x-ax,y+f,farbe);//UUL
		putpixel(x+f,y+ax,farbe);//UOR
		putpixel(x-f,y+ax,farbe);//UOL

		ax++;
	}while(ax<f);
}

void sprite_lineartype::kreis_clip(int x,int y,int radius,char farbe)
{
	// Check ob Kreis überhaupt im Screen ??? Rechteckcheck !!
	if (rechteckcheck(x-radius,y-radius,x+radius,y+radius))
		return;
	int f;
	int ax=0;
	ulong radiusquadrat=(ulong)radius*(ulong)radius;
	do
	{
		f=(int)sqrt(radiusquadrat-(ulong)ax*(ulong)ax);
		putpixel_clip(x+ax,y-f,farbe);//OOR
		putpixel_clip(x-ax,y-f,farbe);//OOL
		putpixel_clip(x+f,y-ax,farbe);//OUR
		putpixel_clip(x-f,y-ax,farbe);//OUL

		putpixel_clip(x+ax,y+f,farbe);//UUR
		putpixel_clip(x-ax,y+f,farbe);//UUL
		putpixel_clip(x+f,y+ax,farbe);//UOR
		putpixel_clip(x-f,y+ax,farbe);//UOL

		ax++;
	}while(ax<f);
}

void sprite_lineartype::kreis_flaeche(int x,int y,int radius,char farbe)
{
	int f;
	int ax=0;
	ulong radiusquadrat=(ulong)radius*(ulong)radius;
	do
	{
		f=(int)sqrt(radiusquadrat-(ulong)ax*(ulong)ax);
		hline(x-ax,x+ax,y-f,farbe); // OOL => OOR
		hline(x-f,x+f,y-ax,farbe);  // OUL => OUR

		hline(x-ax,x+ax,y+f,farbe); // UUL => UUR
		hline(x-f,x+f,y+ax,farbe);  // UOL => UOR

		ax++;
	}while(ax<f);
}

int sprite_lineartype::kreis_flaeche_clip(int x,int y,int radius,char farbe)
{
  // Check ob Kreis überhaupt im Screen ??? Rechteckcheck !!
  if (rechteckcheck(x-radius,y-radius,x+radius,y+radius))
    return 1;
  // Check ob der kreis nicht den ganzen screen fuellt ?
  // sind alle vier eckpunkte des sprites im kreis ?
  // Kreis ueberhaupt gross genug
  ulong radiusquadrat=(ulong)radius*(ulong)radius;
  if (ulong(abs((sx*sx)>>2))+ulong(abs((sy*sy)>>2))<radiusquadrat)
    {
      //      cout <<"Kreis gross genug\n";
      int olx=-mx-x;
      int oly=-my-y;
      ulong rdifx=ulong(abs(olx+sx-1));
      ulong rdifx2=rdifx*rdifx;
      ulong udify=ulong(abs(oly+sy-1));
      ulong udify2=udify*udify;
      ulong ldifx=abs(olx);
      ulong ldifx2=ldifx*ldifx;
      ulong odify=abs(oly);
      ulong odify2=odify*odify;
      if ((radiusquadrat>ldifx2+odify2)&&(radiusquadrat>rdifx2+odify2)
	  &&(radiusquadrat>ldifx2+udify2)&&(radiusquadrat>rdifx2+udify2))
	{
	  //	  cout <<"Kreis verdeckt alles\n";
	  clearsprite(farbe);
	  return 0;
	}
    }
  int f;
  int ax=0;
  do
    {
      f=(int)sqrt(radiusquadrat-(ulong)ax*(ulong)ax);
      hline_clip(x-ax,x+ax,y-f,farbe); // OOL => OOR
      hline_clip(x-f,x+f,y-ax,farbe);  // OUL => OUR
      
      hline_clip(x-ax,x+ax,y+f,farbe); // UUL => UUR
      hline_clip(x-f,x+f,y+ax,farbe);  // UOL => UOR
      
      ax++;
    }while(ax<f);
  return 2;
}


void sprite_lineartype::malerechteck(int x1,int y1,int xanz,int yanz,char farbe)
{
	char *dest=calcadresse(x1,y1);
	memset(dest,farbe,xanz);
	dest+=sx;
	yanz-=2;
	int zwadder=xanz;
	zwadder--;
	int adder=sx-zwadder;
	for (;yanz;yanz--)
	{
		*dest=farbe;
		dest+=zwadder;
		*dest=farbe;
		dest+=adder;
	}
	memset(dest,farbe,xanz);
}

// spaeter richtig !!!
void sprite_lineartype::malerechteck_clip(int x1,int y1,int xanz,int yanz,char farbe)
{
	int x2=x1+xanz;
	x2--;
	int y2=y1+yanz;
	y2--;
	if ((!punktinrechteck(x1,y1))||(!punktinrechteck(x2,y2)))
	{
		if (rechteckcheck(x1,y1,x2,y2))
			// Rechteck nicht im Sprite
			return;
		if (!xcoordinrechteck(x1))
			x1=0;
		if (!ycoordinrechteck(y1))
			y1=0;
		if (!xcoordinrechteck(x2))
		{
			x2=sx-mx;
			x2--;
		}
		if (!ycoordinrechteck(y2))
		{
			y2=sy-my;
			y2--;
		}
		xanz=x2-x1;
		xanz++;
		yanz=y2-y1;
		yanz++;
	}
	cout <<"male rechteck: "<<x1<<" "<<y1<<" "<<xanz<<" "<<yanz<<endl;
	malerechteck(x1,y1,xanz,yanz,farbe);
}

void sprite_lineartype::malerechteck_flaeche(int x1,int y1,int xanz,int yanz,char farbe)
{
	char *dest=calcadresse(x1,y1);
	for (int akt=0;akt<yanz;akt++)
	{
		memset(dest,farbe,xanz);
		dest+=sx;
	}
}

void sprite_lineartype::malerechteck_flaeche_clip(int x1,int y1,int xanz,int yanz,char farbe)
{
	int x2=x1+xanz;
	x2--;
	int y2=y1+yanz;
	y2--;
	if ((!punktinrechteck(x1,y1))||(!punktinrechteck(x2,y2)))
	{
		if (rechteckcheck(x1,y1,x2,y2))
			// Rechteck nicht im Sprite
			return;
		if (!xcoordinrechteck(x1))
			x1=0;
		if (!ycoordinrechteck(y1))
			y1=0;
		if (!xcoordinrechteck(x2))
		{
			x2=sx-mx;
			x2--;
		}
		if (!ycoordinrechteck(y2))
		{
			y2=sy-my;
			y2--;
		}
		xanz=x2-x1;
		xanz++;
		yanz=y2-y1;
		yanz++;
	}
	malerechteck_flaeche(x1,y1,xanz,yanz,farbe);
}

char sprite_lineartype::rechteckcheck(int x1,int y1,int x2,int y2)
{
	return ((x1+mx>=sx)||(y1+my>=sy)||(x2+mx<0)||(y2+my<0));
}

void sprite_lineartype::resize(int sxneu,int syneu)
{
  delete sprite;
  initspritedat(sxneu,syneu,mx,my);
}

void sprite_lineartype::resize(int sxneu,int syneu,char farbe)
{
	resize(sxneu,syneu);
	clearsprite(farbe);
}

void sprite_lineartype::fuellen(int x,int y,char farbe)
{
  char ufarbe,ufarbe2;
  if (!(getpixel_clip(x,y,&ufarbe)))
    {
      if (ufarbe!=farbe)
	{
	  putpixel(x,y,farbe);
	  if (!(getpixel_clip(x-1,y,&ufarbe2)))
	    {
	      if (ufarbe2==ufarbe)
		fuellen(x-1,y,farbe);
	    }
	  if (!(getpixel_clip(x+1,y,&ufarbe2)))
	    {
	      if (ufarbe2==ufarbe)
		fuellen(x+1,y,farbe);
	    }
	  if (!(getpixel_clip(x,y-1,&ufarbe2)))
	    {
	      if (ufarbe2==ufarbe)
		fuellen(x,y-1,farbe);
	    }
	  if (!(getpixel_clip(x,y+1,&ufarbe2)))
	    {
	      if (ufarbe2==ufarbe)
		fuellen(x,y+1,farbe);
	    }
	}
    }
}

void sprite_lineartype::raster(uint32 wert)
{
  for (int akt=0;akt<(sx*sy)>>2;akt++)
    ((uint32 *)sprite)[akt]=wert;
  //  memfill(sprite,  todo
}




spritetype *sprite_lineartype::rotate(float winkel,float zoom,uint32,char trans=255)
{
    return (ROTATE_generatenewsprite(this,winkel,zoom,trans));
}





// **************************************************** Protected

void sprite_lineartype::change(iotype *ioptr,int8 mode)
{    
  //  check_or_save_header(this,ioptr,mode);
  headertype header;
  // SPEICHERN **************************************************************
  if (ioptr->getmode()==IOTYPE_WRITE_MODE)
    {
      cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
      // todo ?
      string hdstr(getheaderstring());
	    cfgptr->change_string_check(&hdstr);
	    delete cfgptr;

	    header.sx=sx;
	    header.sy=sy;
	    header.mx=mx;
	    header.my=my;
	}
    ioptr->io_change_check((char *)(&header),sizeof(header));
    // LADEN ******************************************************************
    if (ioptr->getmode()==IOTYPE_READ_MODE)
	{
	    initspritedat(header.sx,header.sy,header.mx,header.my);
	}    
    ioptr->io_change_check(sprite,(int32)sx*(int32)sy); 
}


/***********************************************************************

                                ROTATE

***********************************************************************/

/***********************************************************************
  winkel>0 -> rechtsrum drehen    0=nodreh
  zoom>1 -> lupe                  1=nozoom
  gedreht wird um den mittelpunkt des dots
                                        AUTHOR:ERIK   MAINTAINER:ERIK !
 *****************************************************^^^^^^^^^^^^^^^*/

// ********************* DREHT EIN SPRITE IN EIN EXISTIERENDES SPRITE
void sprite_lineartype::ROTATE_rotatetoexisting(sprite_lineartype *dest,sprite_lineartype *source,
			     float winkel,float zoom,char trans)
{
  if (int a=spritecheck())
    {
      cout <<"Anzahl Fehler: "<<a<<endl;
      fatalfehler("sprite01.C: rotate");
    }
    float dx1,dy1,dx2,dy2,dx3,dy3,ax,ay,sinus,cosinus;
    int addr,x,y,ssx,ssy,dsx,dsy,aktzeile,t;
    char *sou,*des;

    ssx=source->sx;
    ssy=source->sy;

    sinus = sin(winkel);
    cosinus = cos(winkel);

    dsx=dest->sx;
    dsy=dest->sy;

    ax = cosinus / zoom;
    ay = sinus   / zoom;

    dx1 = dest->mx / zoom;
    dy1 = dest->my / zoom;
    dx2 = source->mx - dx1*cosinus - dy1*sinus;
    dy2 = source->my - dy1*cosinus + dx1*sinus;
    addr = 0;

    sou=source->sprite;
    des=dest->sprite;
    for (aktzeile=0;aktzeile<dsy;aktzeile++) {
	dx3=dx2;
	dy3=dy2;
	for (t=0;t<dsx;t++) {
	    x=ftoi(dx3);
	    y=ftoi(dy3);

	    // von erik an erik:
	    // wenn dieser folgende if einen trans feststellt, dann
	    // rechne fuer jede der 4 bedingungen die naechste nicht treffer aus
	    // und dann max nehmen !!!! so einfach geht das !
	    // dann die linken schon mal weg und die rechten auch, aber
	    // die nichttransdots die koennens dann net, die needen immer nen if
	    // -> irgendwie die auch noch machen !!!! dnan alles c00l
	    // und rotate max schnell
	    // ausserdem die adder via int32 machen mit exacty part
	    // keine floats..... okay cu ! Montag 30.10.1995 2:00 Uhr

	    if ((x>=0)&&(y>=0)&&(x<ssx)&&(y<ssy))
		des[addr++]=sou[(ssx*y)+x];
	    else
		des[addr++]=trans;
	    dx3+=ax;
	    dy3-=ay;
	};
	dx2+=ay;
	dy2+=ax;
    };
  if (int a=spritecheck())
    {
      cout <<"Anzahl Fehler: "<<a<<endl;
      fatalfehler("sprite01.C: rotate");
    }
};

// *********** DREHT EIN SPRITE IN EIN OPTIMAL GESIZEDES NEUES SPRITE
sprite_linear_transparenttype *sprite_lineartype::ROTATE_generatenewsprite
(sprite_lineartype *source,float winkel,float zoom,char trans)
{
  rechtecktype *neues=rotate_rechteck(winkel,zoom);
  sprite_linear_transparenttype *dest=new 
    sprite_linear_transparenttype(neues->sx,neues->sy,neues->mx,neues->my,trans);
  delete neues;

  ROTATE_rotatetoexisting(dest,source,winkel,zoom,trans);
  return(dest);
};















// Nichttransparente Lineare Sprites ****************************************
// Nichttransparente Lineare Sprites ****************************************
// Nichttransparente Lineare Sprites ****************************************
// Nichttransparente Lineare Sprites ****************************************
// Nichttransparente Lineare Sprites ****************************************
// Nichttransparente Lineare Sprites ****************************************

// Type checking
const char *sprite_linear_nontransparenttype::headerstring="sprite_linear_nontransparenttype";
const char *sprite_linear_nontransparenttype::getheaderstring()
{
  return sprite_linear_nontransparenttype::headerstring;
}


// Init ***********************************************************
// Sprite laden !!
sprite_linear_nontransparenttype::sprite_linear_nontransparenttype(
    iotype *ioptr,int8 mode) 
{change(ioptr,mode);}
// Sprite initen
sprite_linear_nontransparenttype::sprite_linear_nontransparenttype(
    int _sx,int _sy,int _mx,int _my) 
    : sprite_lineartype(_sx,_sy,_mx,_my){}
// Einfarbiges Sprite initen
sprite_linear_nontransparenttype::sprite_linear_nontransparenttype(
    int _sx,int _sy,int _mx,int _my,char _farbe) 
    : sprite_lineartype(_sx,_sy,_mx,_my,_farbe){}
//protected:
sprite_linear_nontransparenttype::sprite_linear_nontransparenttype(){};


// Deinit *********************************************************
// Gibt Speicher frei !!
//~sprite_linear_nontransparenttype(){};



// ***********************************************+ PUBLIC ROUTINEN
// ***********************************************+ PUBLIC ROUTINEN

void sprite_linear_nontransparenttype::copysprite(int x,int y,sprite_lineartype *dest,uint32)
{
    int x1s=x-mx+dest->mx;
    int y1s=y-my+dest->my;
    // Destination adder berechnen ****************************************
    int startadderd=y1s*dest->sx+x1s;
    int adderd=dest->sx;
    // Eigentliches malen
    char *aktd;
    char *akts;
    aktd=dest->sprite+startadderd;
    akts=sprite;
    for (int anzzeilens=sy;anzzeilens;anzzeilens--)
	{
	    memcpy(aktd,akts,sx);
	    aktd+=adderd;
	    akts+=sx;
	}
}


void sprite_linear_nontransparenttype::copysprite_clip(int x,int y,sprite_lineartype *dest,uint32)
{
  // todo
  pnontrans++;
    int x1s=x-mx;
    int y1s=y-my;
    int x2s=x1s+sx;
    x2s--;
    int y2s=y1s+sy;
    y2s--;
    // Muss überhaupt gemalt werden ?? *******************************
    if (dest->rechteckcheck(x1s,y1s,x2s,y2s))
	return;
    x1s+=dest->mx;
    y1s+=dest->my;
    x2s+=dest->mx;
    y2s+=dest->my;
    // Soruce clipping *************************************************
    int startadders=0;
    int anzpunktes=sx;
    int anzzeilens=sy;
    // Destination Clipping *****************************************
    int startadderd=0;
    int anzpunkted=dest->sx; // später spaeter
    int adderd=dest->sx;
    int anzzeilend=dest->sy; // später spaeter
    // Horizontal
    if (x1s<0)
	{
	    startadders=-x1s;
	    anzpunktes-=startadders;
	}else{
	    startadderd+=x1s;
	    anzpunkted-=startadderd;
	}
    if (x2s>=dest->sx)
	{
	    anzpunktes-=x2s-dest->sx;
	    anzpunktes--;
	}else{
	    anzpunkted-=dest->sx-x2s;
	    anzpunkted++;
	}
    if (anzpunktes!=anzpunkted) // spaeter
	fehler("Fehler in der Routine sprite_linear:copysprite(..)");
    // Vertikal
    if (y1s<0)
	{
	    startadders+=-y1s*sx;
	    anzzeilens+=y1s;
	}else{
	    startadderd+=y1s*dest->sx;
	    anzzeilend-=y1s;
	}
    if (y2s>=dest->sy)
	{
	    anzzeilens-=y2s-dest->sy;
	    anzzeilens--;
	}else{
	    anzzeilend-=dest->sy-y2s;
	    anzzeilend++; // später
	}
    if (anzzeilens!=anzzeilend) // später
	fehler("Fehler in der Routine sprite_linear:copysprite(..)");
    // Eigentliches malen
    char *aktd;
    char *akts;
    aktd=dest->sprite+startadderd;
    akts=sprite+startadders;
    for (;anzzeilens;anzzeilens--)
      {
	memcpy(aktd,akts,anzpunktes);
	aktd+=adderd;
	akts+=sx;
      }
}

void sprite_linear_nontransparenttype::copysprite_clip_to(int x,int y,sprite_lineartype *dest,const rechtecktype &rect,uint32)
{
  pnontrans++;
  int cx1=-rect.mx;
  int cy1=-rect.my;
  int csx=rect.sx;
  int csy=rect.sy;
  //  cout <<"x:"<<x<<" y:"<<y<<" cx:"<<cx1<<" cy:"<<cy1<<" csx:"<<csx<<" csy:"<<csy<<endl;
  // y clipping
  int d_yoffset=dest->my+cy1;
  int s_yoffset=0;
  int dy1=y-my;
  if (dy1<cy1)
    // source clipping
    s_yoffset=cy1-dy1;
  else if (dy1>cy1+csy-1)
    // Nothing to paint
    return;
  else
    d_yoffset+=dy1-cy1;

  int s_anzlines=sy-s_yoffset;
  if (!s_anzlines)
    return;
  int sende=d_yoffset+s_anzlines;
  int dende=dest->my+cy1+csy;
  if (sende>dende)
    s_anzlines-=sende-dende;
  if (s_anzlines<=0)
    return;

  // x clipping
  int d_xoffset=dest->mx+cx1;
  int s_xoffset=0;
  int dx1=x-mx;
  if (dx1<cx1)
    // source clipping
    s_xoffset=cx1-dx1;
  else if (dx1>cx1+csx-1)
    // Nothing to paint
    return;
  else
    d_xoffset+=dx1-cx1;

  int s_anzcol=sx-s_xoffset;
  if (!s_anzcol)
    return;
  int sendex=d_xoffset+s_anzcol;
  int dendex=dest->mx+cx1+csx;
  if (sendex>dendex)
    s_anzcol-=sendex-dendex;
  if (s_anzcol<=0)
    return;

  char *aktd=dest->sprite+d_yoffset*dest->sx+d_xoffset;
  char *akts=sprite+s_yoffset*sx+s_xoffset;
  int adder=dest->sx;
  //  cout <<"d_yoffset: "<<d_yoffset<<" s_yoffset:"<<s_yoffset<<" adder:"<<adder<<" anzlines:"<<s_anzlines<<" anzcol:"<<s_anzcol<<endl;
  for (;s_anzlines;s_anzlines--)
    {
      memcpy(aktd,akts,s_anzcol);
      aktd+=adder;
      akts+=sx;
    }
}

spritetype *sprite_linear_nontransparenttype::rotate
(float winkel,float zoom,uint32,char trans)
{
    return (ROTATE_generatenewsprite(this,winkel,zoom,trans));
}

void sprite_linear_nontransparenttype::change(iotype *ioptr,int8 mode)
{
  sprite_lineartype::change(ioptr,mode);
}


// Nichttransparente Lineare Sprites !!! PPM FORMAT !!! ******************************
// Nichttransparente Lineare Sprites !!! PPM FORMAT !!! ******************************
// Nichttransparente Lineare Sprites !!! PPM FORMAT !!! ******************************
// Nichttransparente Lineare Sprites !!! PPM FORMAT !!! ******************************

// Type checking
const char *sprite_ppmtype::headerstring="sprite_ppmtype";
const char *sprite_ppmtype::getheaderstring()
{
  return sprite_ppmtype::headerstring;
}

void sprite_ppmtype::change(iotype *ioptr,int8 mode)
{
  if (ioptr->getmode()==IOTYPE_WRITE_MODE)
    fehler("sprite01.C: sprite_ppmtype::change sorry currently saving isn't possible");
  cfgtype *cfgptr=choose_cfgtype(ioptr,CFG_TEXT_MODE);
  cfgptr->change_int32_check(&sx);
  cfgptr->change_int32_check(&sy);
  int32 maxval;
  cfgptr->change_int32_check(&maxval);
  cout <<"Maxval is: "<<maxval<<endl;
  delete cfgptr;
  uint8 red;
  uint8 green;
  uint8 blue;
  // todo !!! 
  uint32 scale=allsprites_ketteptr->paletteptr->maxval/maxval;
  cout <<"Scale: "<<scale<<endl;
  palentrytype entry;
  initspritedat(sx,sy,sx/2-1,sy/2-1);
  int32 anzdots=0;
  while (anzdots<sx*sy)
    {
      ioptr->io_read_check((char *)&red);
      ioptr->io_read_check((char *)&green);
      ioptr->io_read_check((char *)&blue);
      //      cout <<"R: "<<(uint16)red<<" G:"<<(uint16)green<<" B:"<<(uint16)blue<<endl;
      // Meine Paletten gehen von 0-65535
      entry.red=scale*(uint16)red;
      entry.green=scale*(uint16)green;
      entry.blue=scale*(uint16)blue;
      //      cout <<"=> R: "<<entry.red<<" G:"<<entry.green<<" B:"<<entry.blue<<endl;
      *(sprite+anzdots)=allsprites_ketteptr->paletteptr->remap(entry);
      anzdots++;
    }
}




// Lineare Transparente Sprites *********************************************
// Lineare Transparente Sprites *********************************************
// Lineare Transparente Sprites *********************************************
// Lineare Transparente Sprites *********************************************
// Lineare Transparente Sprites *********************************************
// Lineare Transparente Sprites *********************************************

// Type checking
const char *sprite_linear_transparenttype::headerstring="sprite_linear_transparenttype";
const char *sprite_linear_transparenttype::getheaderstring()
{
  return sprite_linear_transparenttype::headerstring;
}


// Init ***********************************************************
// Sprite laden !!
sprite_linear_transparenttype::sprite_linear_transparenttype(iotype *ioptr,int8 mode)
{change(ioptr,mode);}
    
// Sprite initen
sprite_linear_transparenttype::sprite_linear_transparenttype(int _sx,int _sy,int _mx,int _my,char _transcolor=255) 
    : sprite_lineartype(_sx,_sy,_mx,_my)
{transcolor=_transcolor;}
    
// Einfarbiges Sprite initen
sprite_linear_transparenttype::sprite_linear_transparenttype(
							     int _sx,int _sy,int _mx,int _my,char _farbe,char _transcolor) 
  : sprite_lineartype(_sx,_sy,_mx,_my,_farbe)
{transcolor=_transcolor;}
    
// Deinit *********************************************************
// Bis jetzt keine Funktion !!
// ~sprite_linear_transparenttype() {};
    
// ***********************************************+ PUBLIC ROUTINEN

void sprite_linear_transparenttype::copysprite
(int x,int y,sprite_lineartype *dest,uint32)
{
    int x1s=x-mx+dest->mx;
    int y1s=y-my+dest->my;
    // Destination adder berechnen ****************************************
    int startadderd=y1s*dest->sx+x1s;
    int adderd=dest->sx-sx;
    // Eigentliches malen
    char *aktd;
    char *akts;
    aktd=dest->sprite+startadderd;
    akts=sprite;
    char aktfarbe;
    int anz;
    for (int anzzeilens=sy;anzzeilens;anzzeilens--)
	{
	    for (anz=sx;anz;anz--)
		{
		    aktfarbe=*akts;
		    if (aktfarbe!=transcolor)
			*aktd=aktfarbe;
		    akts++;
		    aktd++;
		}
	    aktd+=adderd;
	}
}


void sprite_linear_transparenttype::copysprite_clip(int x,int y,sprite_lineartype *dest,uint32)
{
  //todo
  ptrans++;
    int x1s=x-mx;
    int y1s=y-my;
    int x2s=x1s+sx;
    x2s--;
    int y2s=y1s+sy;
    y2s--;
    // Muss überhaupt gemalt werden ?? *******************************
    if (dest->rechteckcheck(x1s,y1s,x2s,y2s))
	return;
    x1s+=dest->mx;
    y1s+=dest->my;
    x2s+=dest->mx;
    y2s+=dest->my;
    // Soruce clipping *************************************************
    int startadders=0;
    int anzpunktes=sx;
    int adders=sx;
    int anzzeilens=sy;
    // Destination Clipping *****************************************
    int startadderd=0;
    int anzpunkted=dest->sx; // später spaeter
    int adderd=dest->sx;
    int anzzeilend=dest->sy; // später spaeter
    // Horizontal
    if (x1s<0)
	{
	    startadders-=x1s;
	    anzpunktes-=startadders;
	}else{
	    startadderd+=x1s;
	    anzpunkted-=startadderd;
	}
    if (x2s>=dest->sx)
	{
	    anzpunktes-=x2s-dest->sx;
	    anzpunktes--;
	}else{
	    anzpunkted-=dest->sx-x2s;
	    anzpunkted++;
	}
    if (anzpunktes!=anzpunkted) // spaeter
	fehler("Fehler in der Routine sprite_linear:copysprite(..)");
    // Vertikal
    if (y1s<0)
	{
	    startadders+=-y1s*sx;
	    anzzeilens+=y1s;
	}else{
	    startadderd+=y1s*dest->sx;
	    anzzeilend-=y1s;
	}
    if (y2s>=dest->sy)
	{
	    anzzeilens-=y2s-dest->sy;
	    anzzeilens--;
	}else{
	    anzzeilend-=dest->sy-y2s;
	    anzzeilend++; // später
	}
    if (anzzeilens!=anzzeilend) // später
	fehler("Fehler in der Routine sprite_linear:copysprite(..)");
    // Eigentliches malen
    char *aktd;
    char *akts;
    aktd=dest->sprite+startadderd;
    akts=sprite+startadders;
    adderd-=anzpunktes;
    adders-=anzpunktes;
    char aktfarbe;
    int anz;
    for (;anzzeilens;anzzeilens--)
	{
	    for (anz=anzpunktes;anz;anz--)
		{
		    aktfarbe=*akts;
		    if (aktfarbe!=transcolor)
			*aktd=aktfarbe;
		    akts++;
		    aktd++;
		}
	    aktd+=adderd;
	    akts+=adders;
	}
}

// hallo jens 
void sprite_linear_transparenttype::copysprite_clip_to(int x,int y,sprite_lineartype *dest,const rechtecktype &rect,uint32)
{
  ptrans++;
  int cx1=-rect.mx;
  int cy1=-rect.my;
  int csx=rect.sx;
  int csy=rect.sy;

  //  cout <<"x:"<<x<<" y:"<<y<<" cx:"<<cx1<<" cy:"<<cy1<<" csx:"<<csx<<" csy:"<<csy<<endl;
  // y clipping
  int d_yoffset=dest->my+cy1;
  int s_yoffset=0;
  int dy1=y-my;
  if (dy1<cy1)
    // source clipping
    s_yoffset=cy1-dy1;
  else if (dy1>cy1+csy-1)
    // Nothing to paint
    return;
  else
    d_yoffset+=dy1-cy1;

  int s_anzlines=sy-s_yoffset;
  if (!s_anzlines)
    return;
  int sende=d_yoffset+s_anzlines;
  int dende=dest->my+cy1+csy;
  if (sende>dende)
    s_anzlines-=sende-dende;
  if (s_anzlines<=0)
    return;

  // x clipping
  int d_xoffset=dest->mx+cx1;
  int s_xoffset=0;
  int dx1=x-mx;
  if (dx1<cx1)
    // source clipping
    s_xoffset=cx1-dx1;
  else if (dx1>cx1+csx-1)
    // Nothing to paint
    return;
  else
    d_xoffset+=dx1-cx1;

  int s_anzcol=sx-s_xoffset;
  if (!s_anzcol)
    return;
  int sendex=d_xoffset+s_anzcol;
  int dendex=dest->mx+cx1+csx;
  if (sendex>dendex)
    s_anzcol-=sendex-dendex;
  if (s_anzcol<=0)
    return;

  char *aktd=dest->sprite+d_yoffset*dest->sx+d_xoffset;
  char *akts=sprite+s_yoffset*sx+s_xoffset;
  int adder=dest->sx-s_anzcol;
  int adders=sx-s_anzcol;
  //  cout <<"d_yoffset: "<<d_yoffset<<" s_yoffset:"<<s_yoffset<<" adder:"<<adder<<" anzlines:"<<s_anzlines<<" anzcol:"<<s_anzcol<<endl;
  int akt;
  char color;
  for (;s_anzlines;s_anzlines--)
    {
      for (akt=s_anzcol;akt;akt--)
	{
	  color=*akts;
	  if (color!=transcolor)
	    *aktd=color;
	  aktd++;
	  akts++;
	}
      aktd+=adder;
      akts+=adders;
    }
}





spritetype *sprite_linear_transparenttype::rotate(float winkel,float zoom,uint32,char)
{
    return (ROTATE_generatenewsprite(this,winkel,zoom,transcolor));
}

/* schwachsinn ??
spritetype *sprite_linear_transparenttype::rotate(float winkel,float zoom,uint32,char trans)
{
    return (ROTATE_generatenewsprite(this,winkel,zoom,trans));
}
*/

void sprite_linear_transparenttype::change(iotype *ioptr,int8 mode)
{
#ifdef DEBUG_sprite_H
    printf("sprite_linear_transparenttype::change aufgerufen !\n");
#endif
    sprite_lineartype::change(ioptr,mode);
    ioptr->io_change_check((char *)(&transcolor),sizeof(transcolor));
}

void sprite_linear_transparenttype::minimize()
{
  int32 minx=sx;
  int32 miny=sy;
  int32 maxx=0;
  int32 maxy=0;
  for (int32 akty=0;akty<sy;akty++)
    for (int32 aktx=0;aktx<sx;aktx++)
      {
	char farbe;
	if (getpixel_clip(aktx-mx,akty-my,&farbe))
	  fatalfehler("sprite_linear_transparenttype::minimize: This error isn't possible?");
	if (farbe!=transcolor)
	  {
	    if (aktx<minx)
	      minx=aktx;
	    if (aktx>maxx)
	      maxx=aktx;
	    if (akty<miny)
	      miny=akty;
	    if (akty>maxy)
	      maxy=akty;
	  }
      }
  // jetzt muss das sprite mutieren ?!!
  if ((minx!=0)||(miny!=0)||(maxx!=sx-1)||(maxy!=sy-1))
    {
      sprite_linear_transparenttype *neues=new sprite_linear_transparenttype(maxx-minx+1,maxy-miny+1,
									     mx-minx,my-miny,
									     transcolor,transcolor);
      copysprite_clip(0,0,neues);
      resize(maxx-minx+1,maxy-miny+1);
      clearsprite(transcolor);
      mx-=minx;
      my-=miny;
      neues->copysprite_clip(0,0,this);
      delete neues;
    }
}




// maxsteigung= ungefaer Maximale Steigung der Landschaft
// scale=(mx-x1)*maxsteigung
// spaeter  con uebergeben 
// con=RAND_MAX/scale;
// scale_2=scale/2;
// Wenn scale Nicht ungerade oefters tiefere Punkte !!
void sprite_linear_transparenttype::putrandompixel
(int x,int y,int basis,int scale)
{
    int con=RAND_MAX/scale;
    int hoehe=basis+random()/con-scale/2;
    if (hoehe<1)
	hoehe=1;
    else 
	if (hoehe>255)
	    hoehe=255;
    putpixel(x,y,hoehe);
//    printf("\nMale Punkt: %i , %i Farbe: %i",x,y,hoehe);
}


// Die Eckpunkte duerfen nicht transparent sein !!!!
void sprite_linear_transparenttype::randomrechteck
(int x1,int y1,int x2,int y2,int steigung)
{
    printf("\n\nNeues Rechteck:");
//    int anzdots=0;
    int geshoehe=0;
    int akthoehe;
/*
    for (int akty=y1;akty<=y2;akty++)
    {
	for (int aktx=x1;aktx<=x2;aktx++)
	{
	    if ((akthoehe=(uchar)getpixel(aktx,akty))!=transcolor)
	    {
		geshoehe+=akthoehe;
		anzdots++;
	    }
	}
    }*/

    // Nur vier Eckpunkte als durchschnitt verwenden
    if ((akthoehe=(uchar)getpixel(x1,y1))!=transcolor)
    {
	geshoehe+=akthoehe;
    }
    if ((akthoehe=(uchar)getpixel(x2,y1))!=transcolor)
    {
	geshoehe+=akthoehe;
    }
    if ((akthoehe=(uchar)getpixel(x1,y2))!=transcolor)
    {
	geshoehe+=akthoehe;
    }
    if ((akthoehe=(uchar)getpixel(x2,y2))!=transcolor)
    {
	geshoehe+=akthoehe;
    }
    int durchschnitt=geshoehe/4;

    int mxr=(x2+x1)/2;
    int myr=(y2+y1)/2;
    int scale=(mxr-x1)*steigung+1;/* spaeter */
//    int scale=17;  // ungerade !!

    // Oben
    if (getpixel(mxr,y1)==transcolor)
	putrandompixel(mxr,y1,durchschnitt,scale);
    // Links
    if (getpixel(x1,myr)==transcolor)
	putrandompixel(x1,myr,durchschnitt,scale);
    // Rechts
    if (getpixel(x2,myr)==transcolor)
	putrandompixel(x2,myr,durchschnitt,scale);
    // Unten
    if (getpixel(mxr,y2)==transcolor)
	putrandompixel(mxr,y2,durchschnitt,scale);
    // Mitte
    if (getpixel(mxr,myr)==transcolor)
	putrandompixel(mxr,myr,durchschnitt,scale);

    // Abbruchbedingung
    if ((mxr==x1)&&(myr==y1))
    {
	printf("\nRechteck geschlossen\n");
	return;
    }

    // OL
    printf("\nIch rufe auf OL: %i,%i ; %i,%i",x1,y1,mxr,myr);
    randomrechteck(x1,y1,mxr,myr,steigung);
    // OR
    printf("\nIch rufe auf OR: %i,%i ; %i,%i",mxr,y1,x2,myr);
    randomrechteck(mxr,y1,x2,myr,steigung);
    // UL
    printf("\nIch rufe auf UL: %i,%i ; %i,%i",x1,myr,mxr,y2);
    randomrechteck(x1,myr,mxr,y2,steigung);
    // UR
    printf("\nIch rufe auf UR: %i,%i ; %i,%i",mxr,myr,x2,y2);
    randomrechteck(mxr,myr,x2,y2,steigung);
}


void sprite_linear_transparenttype::randomsprite()
{
    randomrechteck(0,0,sx-1,sy-1,1);    
}
    











// *********************************** Das Koordinaten Sprite *****************
// *********************************** Das Koordinaten Sprite *****************
// *********************************** Das Koordinaten Sprite *****************
// *********************************** Das Koordinaten Sprite *****************
// *********************************** Das Koordinaten Sprite *****************
// *********************************** Das Koordinaten Sprite *****************
// *********************************** Das Koordinaten Sprite *****************
// *********************************** Das Koordinaten Sprite *****************
// *********************************** Das Koordinaten Sprite *****************

// Type checking
const char *sprite_coordedtype::headerstring="sprite_coordedtype";
const char *sprite_coordedtype::getheaderstring()
{
  return sprite_coordedtype::headerstring;
}

sprite_coordedtype::sprite_coordedtype()
{
#ifdef DEBUG_sprite_H
  printf("Neues sprite_coordedtype::sprite_coordedtype aufgerufen.\n");
#endif
}

sprite_coordedtype::sprite_coordedtype
(iotype *ioptr,int8 mode)
{
#ifdef DEBUG_sprite_H
    printf("Neues sprite_coordedtype::sprite_coordedtype aufgerufen.\n");
#endif
    change(ioptr,mode);
}

sprite_coordedtype::~sprite_coordedtype()
{
#ifdef DEBUG_sprite_H
    printf("Loesche sprite_coordedtype !\n");
#endif
    allsprites_ketteptr->delete_elementadress(spriteptr);
}

void sprite_coordedtype::copysprite_clip_to
(int x,int y,sprite_lineartype *dest,const rechtecktype &rect,uint32 index)
{
    spriteptr->copysprite_clip_to(posx+x,posy+y,dest,rect,index);
}

void sprite_coordedtype::copysprite_rotate_clip_to
(int x,int y,float winkel,float zoom,sprite_lineartype *dest,const rechtecktype &rect,uint32 index=0)
{
  if ((winkel==0.0)&&(zoom==1.0))
    {
      spriteptr->copysprite_rotate_clip_to(posx+x,posy+y,0.0,1.0,dest,rect,index);
      return;
    }
  vektor2_koordtype pos(posx,posy);
  pos.rotate(winkel);
  pos.x*=zoom;
  pos.y*=zoom;

  spriteptr->copysprite_rotate_clip_to(ftoi(pos.x)+x,ftoi(pos.y)+y,winkel,zoom,dest,rect,index);
}

int sprite_coordedtype::getpixel_clip(int x,int y,char *farbe,uint32 index)
{
    return(spriteptr->getpixel_clip(x-posx,y-posy,farbe,index));
}

/* STOP GEHT NET DA NAME AUF SPRITE !
spritetype *sprite_coordedtype::rotate
(float winkel,float zoom,uint32 index,char trans=0)
{
  sprite_coordedtype *erg=new sprite_coordedtype();
  vektor2_koordtype pos(posx,posy);
  pos.rotate(winkel);
  pos.x*=zoom;
  pos.y*=zoom;
  erg->posx=ftoi(pos.x);
  erg->posy=ftoi(pos.y);
  erg->spriteptr=spriteptr->rotate(winkel,zoom,index,trans);
  return erg;
}
*/

void sprite_coordedtype::change(iotype *ioptr,int8 mode)
{
    cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
    cfgptr->change_string_check(&spritename);
    cfgptr->change_int32_check(&posx);
    cfgptr->change_int32_check(&posy);
    delete cfgptr;
    if (ioptr->getmode()==IOTYPE_READ_MODE)    
      {
#ifdef DEBUG_sprite_H
	printf("Hole Adresse von Sprite: %s\n",spritename.c_str());
#endif
	spriteptr=allsprites_ketteptr->make_elementadress(spritename.c_str());
	sx=spriteptr->sx;
	sy=spriteptr->sy;
	mx=spriteptr->mx-posx;
	my=spriteptr->my-posy;
      }
}



// *********************************** Das Modifizierte Sprite *****************
// *********************************** Das Modifizierte Sprite *****************
// *********************************** Das Modifizierte Sprite *****************
// *********************************** Das Modifizierte Sprite *****************
// *********************************** Das Modifizierte Sprite *****************
// *********************************** Das Modifizierte Sprite *****************
// *********************************** Das Modifizierte Sprite *****************

// Type checking
const char *sprite_modifiedtype::headerstring="sprite_modifiedtype";
const char *sprite_modifiedtype::getheaderstring()
{
  return sprite_modifiedtype::headerstring;
}

sprite_modifiedtype::sprite_modifiedtype()
{
#ifdef DEBUG_sprite_H
  printf("Neues sprite_modifiedtype::sprite_modifiedtype aufgerufen.\n");
#endif
  modwinkel=0;
  modzoom=1;
}

sprite_modifiedtype::~sprite_modifiedtype()
{
#ifdef DEBUG_sprite_H
    printf("Loesche sprite_modifiedtype !\n");
#endif
    delete spriteptr;
    // Wegen Destruktor von sprite_coordedtype
    spriteptr=NULL;
}

void sprite_modifiedtype::change(iotype *ioptr,int8 mode)
{
  sprite_coordedtype::change(ioptr,mode);
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_float_check(&modwinkel);
  cfgptr->change_float_check(&modzoom);
  delete cfgptr;
  if (ioptr->getmode()==IOTYPE_READ_MODE)    
    {
      spritetype *ablage=spriteptr->rotate(modwinkel,modzoom);
      allsprites_ketteptr->delete_elementadress(spriteptr);
      spriteptr=ablage;
      sx=spriteptr->sx;
      sy=spriteptr->sy;
      mx=spriteptr->mx-posx;
      my=spriteptr->my-posy;
    }
}




// **************************************** Das Index-Sprite ******************
// **************************************** Das Index-Sprite ******************
// **************************************** Das Index-Sprite ******************
// **************************************** Das Index-Sprite ******************
// **************************************** Das Index-Sprite ******************
// **************************************** Das Index-Sprite ******************
// **************************************** Das Index-Sprite ******************

// Type checking
const char *sprite_indextype::headerstring="sprite_indextype";
const char *sprite_indextype::getheaderstring()
{
  return sprite_indextype::headerstring;
}

sprite_indextype::sprite_indextype()
{}

void sprite_indextype::copysprite_clip_to(int x,int y,sprite_lineartype *dest,const rechtecktype &rect,uint32 index)
{
  spritetype *akt=sprite_kette_iq.zeiger_get(index);
  akt->copysprite_clip_to(x,y,dest,rect,index);
}

int sprite_indextype::getpixel_clip(int x,int y,char *farbe,uint32 index)
{
  spritetype *akt=sprite_kette_iq.zeiger_get(index);
  return akt->getpixel_clip(x,y,farbe,index);
}

void sprite_indextype::change(iotype *ioptr,int8 mode)
{
  sprite_kette_iq.change(ioptr,mode);
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_marke_check("ende");
  delete cfgptr;
  if (ioptr->getmode()==IOTYPE_READ_MODE)
    {
      // Spritegroesse !?
      const int32 maxvalue=0x0fffffff;
      int32 minx=maxvalue,miny=maxvalue,maxx=-maxvalue,maxy=-maxvalue;
      spritetype *akt=sprite_kette_iq.anfang->next;
      while (akt!=sprite_kette_iq.ende)
	{
	  if (-akt->mx<minx)
	    minx=-akt->mx;
	  if (-akt->my<miny)
	    miny=-akt->my;
	  if (-akt->mx+akt->sx-1>maxx)
	    maxx=-akt->mx+akt->sx-1;
	  if (-akt->my+akt->sy-1>maxy)
	    maxy=-akt->my+akt->sy-1;
	  akt=akt->next;
	  mx=-minx;
	  my=-miny;
	  sx=maxx-minx+1;
	  sy=maxy-miny+1;
	}
    }
}

void sprite_indextype::copysprite_rotate_clip_to
(int x,int y,float winkel,float zoom,sprite_lineartype *dest,const rechtecktype &rect,uint32 index=0)
{
  spritetype *akt=sprite_kette_iq.zeiger_get(index);
  akt->copysprite_rotate_clip_to(x,y,winkel,zoom,dest,rect,index);
}

spritetype *sprite_indextype::rotate(float winkel,float zoom,uint32 index,char trans)
{
  spritetype *akt=sprite_kette_iq.zeiger_get(index);
  return akt->rotate(winkel,zoom,index,trans);  
}


// **************************************** Das Movie-Sprite ******************
// **************************************** Das Movie-Sprite ******************
// **************************************** Das Movie-Sprite ******************
// **************************************** Das Movie-Sprite ******************
// **************************************** Das Movie-Sprite ******************
// **************************************** Das Movie-Sprite ******************
// **************************************** Das Movie-Sprite ******************

// Type checking
const char *sprite_movietype::headerstring="sprite_movietype";
const char *sprite_movietype::getheaderstring()
{
  return sprite_movietype::headerstring;
}

void displaytime_zeigerelemtype::change(iotype *ioptr,int8 mode)
{
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  // spaeter !! es muss ein uint32 check !!
  cfgptr->change_int32_check((int32 *)&display_ms);
  delete cfgptr;
}

sprite_movietype::sprite_movietype()
{
}

void sprite_movietype::copysprite_clip_to(int x,int y,sprite_lineartype *dest,const rechtecktype &rect,uint32 index)
{
  uint32 ind=calcindex(index);
  if (ind!=(uint32)-1)
    sprite_indextype::copysprite_clip_to(x,y,dest,rect,ind);
}

void sprite_movietype::copysprite_rotate_clip_to
(int x,int y,float winkel,float zoom,sprite_lineartype *dest,const rechtecktype &rect, uint32 index=0)
{
  uint32 ind=calcindex(index);
  if (ind!=(uint32)-1)
    sprite_indextype::copysprite_rotate_clip_to(x,y,winkel,zoom,dest,rect,ind);
}

int sprite_movietype::getpixel_clip(int x,int y,char *farbe,uint32 index)
{
  uint32 ind=calcindex(index);
  if (ind!=(uint32)-1)
    return sprite_indextype::getpixel_clip(x,y,farbe,ind);
  else
    return -1;
}

spritetype *sprite_movietype::rotate(float winkel,float zoom,uint32 index,char trans=255)
{
  uint32 ind=calcindex(index);
  if (ind!=(uint32)-1)
    return sprite_indextype::rotate(winkel,zoom,ind,trans);
  else
    return 0;
}

void sprite_movietype::change(iotype *ioptr,int8 mode)
{
  displaytime_kette.change(ioptr,mode);
  sprite_indextype::change(ioptr,mode);
  if (ioptr->getmode()==IOTYPE_READ_MODE)
    init();
}

void sprite_movietype::init()
{
  mspassed=0;
  akt_displaytimeptr=displaytime_kette.anfang->next;
  aktelemnr=0;
  loop=0;
  repeat=1;
}

uint32 sprite_movietype::calcindex(uint32 index)
{
  mspassed+=index;
  while (mspassed>=akt_displaytimeptr->display_ms)
    {
      // Nächstes Bild !!
      mspassed-=akt_displaytimeptr->display_ms;
      akt_displaytimeptr=akt_displaytimeptr->next;
      if (akt_displaytimeptr==displaytime_kette.ende)
	{
	  // Reached the end of the movie 
	  loop++;
	  if (repeat)
	    {
	      // Start at the beginning
	      akt_displaytimeptr=displaytime_kette.anfang->next;
	      aktelemnr=0;
	    }
	  else
	    { 
	      // Stop Playing
	      return (uint32)-1;
	    }
	}
      else
	aktelemnr++;
    }
  return(aktelemnr);
}

uint32 sprite_movietype::getloop()
{
  return loop;
}

// **************************************** Das Puzzle-Sprite *****************
// **************************************** Das Puzzle-Sprite *****************
// **************************************** Das Puzzle-Sprite *****************
// **************************************** Das Puzzle-Sprite *****************
// **************************************** Das Puzzle-Sprite *****************
// **************************************** Das Puzzle-Sprite *****************
// **************************************** Das Puzzle-Sprite *****************
// **************************************** Das Puzzle-Sprite *****************

// Type checking
const char *sprite_puzzletype::headerstring="sprite_puzzletype";
const char *sprite_puzzletype::getheaderstring()
{
  return sprite_puzzletype::headerstring;
}

// Beim copysprite !!!:
// spaeter erst einen Rechteckecheck ob uebrhaupt drin !
// aus dem puzzle Sprite muss ein Sprite werden => mx,my,sx,sy
// muessen sinnvolle werte bekommen !

// **** Puzzleteile ***********************************************************
// **** Puzzleteile ***********************************************************

sprite_puzzletype::sprite_puzzletype()
{
  mx=0;
  my=0;
  lastspriteptr=NULL;
}

sprite_puzzletype::sprite_puzzletype(iotype *ioptr,int8 mode)
{
  lastspriteptr=NULL;
  change(ioptr,mode);
  if (ioptr->getmode()==IOTYPE_READ_MODE)
    {
      int32 minx=0,maxx=0,miny=0,maxy=0;
      spritetype *laufzeiger;
      laufzeiger=sprite_kette_iq.anfang->next;
      while (laufzeiger!=sprite_kette_iq.ende)
	{
	  if (-laufzeiger->mx<minx)
	    minx=-laufzeiger->mx;
	  else
	    if (-laufzeiger->mx+laufzeiger->sx>maxx)
	      maxx=-laufzeiger->mx+laufzeiger->sx;
	  if (-laufzeiger->my<miny)
	    miny=-laufzeiger->my;
	  else
	    if (-laufzeiger->my+laufzeiger->sy>maxy)
	      maxy=-laufzeiger->my+laufzeiger->sy;
	  laufzeiger=laufzeiger->next;
	};
      mx=-minx;
      my=-miny;
      sx=maxx-minx+1;
      sy=maxy-miny+1;
      //todo isch total falsch !!
      //	cout << "Size of the Puzzlesprite: mx: "<<mx<<", my: "<<my<<", sx: "<<sx<<", sy: "<<sy<<endl;
    }
}

sprite_puzzletype::~sprite_puzzletype()
{
  sprite_kette_iq.clear();
} 

void sprite_puzzletype::copysprite_clip_to(int x,int y,sprite_lineartype *dest,const rechtecktype &rect,uint32 index)
{
  spritetype *laufzeiger;
  laufzeiger=sprite_kette_iq.anfang->next;
  while (laufzeiger!=sprite_kette_iq.ende)
    {
      laufzeiger->copysprite_clip_to(x,y,dest,rect,index);
      laufzeiger=laufzeiger->next;
    };
}

void sprite_puzzletype::copysprite_rotate_clip_to
(int x,int y,float winkel,float zoom,sprite_lineartype *dest,const rechtecktype &rect,uint32 index=0)
{
  spritetype *laufzeiger;
  laufzeiger=sprite_kette_iq.anfang->next;
  while (laufzeiger!=sprite_kette_iq.ende)
    {
      laufzeiger->copysprite_rotate_clip_to(x,y,winkel,zoom,dest,rect,index);
      laufzeiger=laufzeiger->next;
    };
}

int sprite_puzzletype::getpixel_clip(int x,int y,char *farbe,uint32 index)
{
  if (lastspriteptr)
    {
      if (!(lastspriteptr->getpixel_clip(x,y,farbe,index)))
	return 0;
    }
  spritetype *laufzeiger;
  laufzeiger=sprite_kette_iq.ende->previous;
  while (laufzeiger!=sprite_kette_iq.anfang)
    {
      if (!(laufzeiger->getpixel_clip(x,y,farbe,index)))
	{
	  lastspriteptr=laufzeiger;
	  return(0);
	}
      laufzeiger=laufzeiger->previous;
    };    
  return(-1);
}

/*
spritetype *sprite_puzzletype::rotate(float winkel,float zoom,uint32 index,char trans=0)
{
  sprite_puzzletype *erg=new sprite_puzzletype;
  spritetype *laufzeiger;
  laufzeiger=sprite_kette_iq.anfang->next;
  while (laufzeiger!=sprite_kette_iq.ende)
  {
    spritetype *neues=laufzeiger->rotate(winkel,zoom,index,trans);
    //    (*neues)::zeigerelem_iqtype<spritetype>=(*laufzeiger)::zeigerlem_iqtype<spritetype>;
    erg->sprite_kette_iq.zeiger_push(neues);
    laufzeiger=laufzeiger->next;
  };
  return erg;
}
*/

void sprite_puzzletype::change(iotype *ioptr,int8 mode)
{
  sprite_kette_iq.change(ioptr,mode); 
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_marke_check("ende");
  delete cfgptr;
}





// ****************************************** Das PCX-Sprite *****************
// ****************************************** Das PCX-Sprite *****************
// ****************************************** Das PCX-Sprite *****************
// ****************************************** Das PCX-Sprite *****************
// ****************************************** Das PCX-Sprite *****************
// ****************************************** Das PCX-Sprite *****************
// ****************************************** Das PCX-Sprite *****************

// Type checking
const char *sprite_pcxtype::headerstring="sprite_pcxtype";
const char *sprite_pcxtype::getheaderstring()
{
  return sprite_pcxtype::headerstring;
}

// Init ***************************************************************
// Reine PCX-Bildinfo laden !!! Nicht direct verwenden !!! 
// Dazu gehoerige Routinen verwenden !
sprite_pcxtype::sprite_pcxtype
(iotype *ioptr,int32 kompsize,int _sx,int _sy,int _mx,int _my)
{
    sx=_sx;
    sy=_sy;
    mx=_mx;
    my=_my;
    sprite=new char[kompsize];
    ioptr->io_read_check(sprite,kompsize);
}


// ************************************************* Public Routinen *********
void sprite_pcxtype::copysprite(int x,int y,sprite_lineartype *dest,uint32)
{
	int x1s=x-mx+dest->mx;
	int y1s=y-my+dest->my;
	// Destination adder berechnen ****************************************
	int startadderd=y1s*dest->sx+x1s;
	int adderd=dest->sx - sx;

	// Eigentliches malen
	char *aktd=dest->sprite+startadderd;
	char *akts=sprite;
	uchar aktbytes;
	uchar anzgleich;
	int anzx;
	for (int anzzeilens=sy;anzzeilens;anzzeilens--)
	{
		anzx=sx;
		while (anzx)
		{
			aktbytes=*akts;
			akts++;
			if (aktbytes<192)
			{
				// Nicht Gepackt
				*aktd=aktbytes;
				aktd++;
				anzx--;
			}else{
				// Gepackt
				anzgleich=aktbytes&63;	// untere sechs bits
				memset(aktd,*akts,anzgleich);
				akts++;
				aktd+=anzgleich;
				anzx-=anzgleich;
			}
		aktd+=adderd;
		}
	}
}

/*  Not yet implemented ( Ever needed ? )
void change(iotype *ioptr,int8 mode)
{
}
*/














// ***************************************************** Ladepcx- Bild ****

sprite_pcxtype *ladepcx_to_sprite_pcxtype(iotype *ioptr,int mx,int my)
{
    if (ioptr->getmode()!=IOTYPE_READ_MODE)
	fatalfehler("ladepcx_to_sprite_pcxtype:\n"
		    "iotype befindet sich nicht im Lesemodus");
    char header[128];
    ioptr->io_read_check(header,128);
    if ((*header!=0xa)||(!header[2])||(header[3]!=8)||(header[65]!=1))
	fatalfehler("ladepcx_to_sprite_pcxtype: UNGUELTIGE PCX DATEI");
    
    int _sx=*((int16 *)(header+8))- *((int16 *)(header+4)) +1;
    int _sy=*((int16 *)(header+10))- *((int16 *)(header+6)) +1;
    cout <<"PCX Sprite - Sprite Size: "<<_sx<<","<<_sy<<endl;
    int32 kompsize=(ioptr->get_buffersize())-768-128-1;

    return new sprite_pcxtype(ioptr,kompsize,_sx,_sy,mx,my);
}

sprite_linear_nontransparenttype *ladepcx_to_sprite_linear_nontransparenttype
(iotype *ioptr,int mx,int my)
{
  sprite_pcxtype *ablage=ladepcx_to_sprite_pcxtype(ioptr,mx,my);
  sprite_linear_nontransparenttype *erg
    =new sprite_linear_nontransparenttype(ablage->sx,ablage->sy,mx,my);
  ablage->copysprite(0,0,erg);
  delete ablage;
  return (erg);
}

sprite_linear_transparenttype *ladepcx_to_sprite_linear_transparenttype
(iotype *ioptr,int mx,int my,char transcolor=255)
{
  sprite_pcxtype *ablage=ladepcx_to_sprite_pcxtype(ioptr,mx,my);
  sprite_linear_transparenttype *erg=new sprite_linear_transparenttype(
								       ablage->sx,ablage->sy,mx,my,transcolor);
  ablage->copysprite(0,0,erg);
  delete ablage;
  return (erg);
}

palettetype *ladepcxpalette_to_palettetype(iotype *ioptr)
{
    if (ioptr->getmode()!=IOTYPE_READ_MODE)
	fatalfehler("ladepcxpalette_to_palettetype:\n"
		    "iotype befindet sich nicht im Lesemodus");
    char header[128];
    ioptr->io_read_check(header,128);
    if ((*header!=0xa)||(!header[2])||(header[3]!=8)||(header[65]!=1))
	fatalfehler("ladepcxpalette_to_palettetype: UNGUELTIGE PCX DATEI");
    
    palettetype *pal=new palettetype;
    uint8 *pcxpal=(uint8 *)((ioptr->get_buffer())+(ioptr->get_buffersize())-768);

    // Die PCX-Paletten Eintraege gehen von 0-256 (uint8)
    // Meine Paletten Eintraege gehen aber von 0-65535 (uint16)
    for (int a=0;a<256;a++)
      {
	pal->palette[a].red=((int32)pcxpal[a*3])<<8;
	pal->palette[a].green=((int32)pcxpal[a*3+1])<<8;
	pal->palette[a].blue=((int32)pcxpal[a*3+2])<<8;
      }

    return pal;
}





// layer_spritetype ******************************************************************
// layer_spritetype ******************************************************************
// layer_spritetype ******************************************************************

layer_spritetype::~layer_spritetype()
{
  if (alloced)
    allsprites_ketteptr->delete_elementadress(sprite);
}

void layer_spritetype::paint()
{
  sprite->copysprite_rotate_clip(x,y,dir,zoom,screenptr->get_drawable());
  screenptr->paint_layers_above(layer,back);
  screenptr->map(back);
}
void layer_spritetype::paint_to(const rechtecktype &rect)
{
  sprite->copysprite_rotate_clip_to(x,y,dir,zoom,screenptr->get_drawable(),rect);
}

void layer_spritetype::modify_sprite(int _x,int _y,float _dir,float _zoom)
{
  rechtecktype oldback=back;
  screenptr->paint_layers(oldback);
  x=_x;
  y=_y;
  dir=_dir;
  zoom=_zoom;
  calc_rectangle();
  screenptr->paint_layers(oldback);
  paint_to(back);
  screenptr->paint_layers_above(layer,back);
  screenptr->map(back);
  screenptr->map(oldback);
}

void layer_spritetype::calc_rectangle()
{
  rechtecktype *n=sprite->rotate_rechteck(dir,zoom);
  back=*n;
  delete n;
  back.mx-=x;
  back.my-=y;
  //  cout <<"Before sub:"<<back<<endl;;
  back.subrechteck(*(screenptr->get_drawable())); // todo this is slow
  //  cout <<"After sub:"<<back<<endl;;
}



// layer object **********************************************************************
// layer object **********************************************************************
// layer object **********************************************************************

layer_spritetype *layertype::add_sprite(const char *spritename,int _x,int _y,float _dir,float _zoom)
{
  cout <<"HALLO\n";
  cout <<"Erstelle jetzt: "<<spritename<<endl;
  cout <<screenptr<<" "<<this<<" "<<spritename<<endl;
  layer_spritetype *neues=new layer_spritetype(screenptr,this,spritename,_x,_y,_dir,_zoom);
  sprites.push_back(neues);
  return neues;
}

layer_spritetype *layertype::add_sprite(spritetype *sprite,int _x,int _y,float _dir,float _zoom=1)
{
  layer_spritetype *neues=new layer_spritetype(screenptr,this,sprite,_x,_y,_dir,_zoom);
  sprites.push_back(neues);
  return neues;
}

void layertype::del_sprite(layer_spritetype *sprite)
{
  list<layer_spritetype *>::iterator pos;
  pos=find(sprites.begin(),sprites.end(),sprite);
  if (pos!=sprites.end())
    {
      rechtecktype back=sprite->get_back();
      delete sprite;
      sprites.erase(pos);
      screenptr->paint_layers(back);
      screenptr->map(back);
    }
  else
    fatalfehler("layertype::del_sprite(): sprite not found\n");
}

void layertype::paint_layer(const rechtecktype &rect)
{
  list<layer_spritetype *>::iterator pos;
  for (pos=sprites.begin();pos!=sprites.end();++pos)
    (*pos)->paint_to(rect);
}

void layertype::paint_layers_below(const rechtecktype &rect)
{
  screenptr->paint_layers_below(this,rect);
}

void layertype::paint_layers_above(const rechtecktype &rect)
{
  screenptr->paint_layers_above(this,rect);
}


/// screen object
/// this is to use layers based on one sprite as drawable
/// container for the layers

layertype *screentype::add_layer()
{
  layertype *ret=new layertype(this);
  layers.push_back(ret);
  return ret;
}

/*
  void screentype::del_layer(){}
  void screentype::raise_layer(layertype *layer){}
  void screentype::lower_layer(layertype *layer){}*/

void screentype::paint_layers_below(layertype *layer, const rechtecktype &rect)
{
  list<layertype *>::iterator pos;
  pos=find(layers.begin(),layers.end(), layer);
  if (pos!=layers.end())
    {
      if (pos!=layers.begin())
	{
	  do{
	    pos--;
	    (*pos)->paint_layer(rect);
	  }while(pos!=layers.begin());
	}
    }
  else
    fatalfehler("screentype::paint_layers_below(): layer not found\n");
}

void screentype::paint_layers(const rechtecktype &rect)
{
  list<layertype *>::iterator pos;
  for (pos=layers.begin();pos!=layers.end();pos++)
    (*pos)->paint_layer(rect);
}

void screentype::paint_layers_above(layertype *layer, const rechtecktype &rect)
{
  list<layertype *>::iterator pos;
  pos=find(layers.begin(),layers.end(), layer);
  if (pos!=layers.end())
    {
      pos++;
      while (pos!=layers.end())
	{
	    (*pos)->paint_layer(rect);
	    pos++;
	}
    }
  else
    fatalfehler("screentype::paint_layers_above(): layer not found\n");
}
sprite_lineartype *screentype::get_drawable(){return spriteptr;}

