#ifndef __INC_POS_PCOM_EXT_SGOS1_C
#define __INC_POS_PCOM_EXT_SGOS1_C
/*******************************************************************
 $CRT 05 Dec 1996 : hp

 $AUT Holger Burkarth
 $DAT >>SGOSdemo1.c<<   29 Jan 1997    14:25:42 - (C) ProDAD
*******************************************************************/


//##ex mcpp:cppc -gs -o pos:pos/Ex/SGOSdemo1 p:pLib/StartCode.o p:/pOS_RKRM/SGOS/SGOSdemo1.c p:pLib/StdIO.o -l pOSStub -l pOS


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

  ACHTUNG: PBall muss sich im Games-Verzeichnis befinden

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

/***********************************************************
  pOS programing example - Copyright (C) 1995-97 proDAD

  This code was written as an easy to understand example,
  how to program pOS features. It is provided 'as-is',
  without any express or implied warranty.

  Permission is hereby granted to use, copy and modify
  this source code for any purpose, without fee, subject
  to the following conditions:

    (1) This notice may not be removed or altered from any
        source distribution.

    (2) Altered source versions must be plainly marked as
        such, and must not be misrepresented as being
        the original source code.

    (3) If only executable code is distributed, then the
        accompanying documentation have to state that
        "this software is based in part on examples of
        the pOS developer packet".

    (4) Permission for use of this code is granted only
        if the user accepts full responsibility for any
        undesirable consequences. proDAD accept NO LIABILITY
        for damages of any kind.

  ©proDAD
***********************************************************/

#include <p:pExec/Types.h>
#include <p:pDevice/Timer.h>
#include <p:pDOS/ArgTags.h>
#include <p:pDOS/DosSig.h>
#include <p:pDOS/DosErrors.h>
#include <p:pScreen/ScrTags.h>
#include <p:pScreen/Window.h>
#include <p:pScreen/Screen.h>
#include <p:pIntui/IntuMsg.h>
#include <p:pIntui/Tags.h>
#include <p:pGFX/GfxMap.h>
#include <p:pGFX/GfxEx.h>
#include <p:pGFX/Color.h>
#include <p:pGFX/GfxTags.h>
#include <p:pGFX/Text.h>
#include <p:pGFX/StdCMap.h>
#include <p:pGFX/StdGMap.h>
#include <p:pDtType/DtBase.h>
#include <p:pDtType/Picture.h>
#include <p:pDtType/DtTags.h>
#include <p:SGOS/SGOS.h>
#include <p:SGOS/SGOSTags.h>
#include <p:pProto/pLibExt.h>
#include <p:pProto/pExec2.h>
#include <p:pProto/pTimer2.h>
#include <p:pProto/pIntui2.h>
#include <p:pProto/pUtil2.h>
#include <p:pProto/pGFX2.h>
#include <p:pProto/pLayer2.h>
#include <p:pProto/pDtType2.h>
#include <p:pProto/pDOS2.h>
#include <p:pProto/SGOS2.h>


#ifdef __cplusplus
extern "C" {
#endif
  #include <string.h>
  #include <stdio.h>
#ifdef __cplusplus
}
#endif

#ifndef ABS
#define ABS(a) ((a)<0 ? -(a) : (a))
#endif


struct MasterData
{
  SLONG        NewX, NewY;
  SBYTE        AnimDelta;
  UBYTE        AnimDelay;

  pOS_TimeVal  LastColl;
};

struct SlaveData
{
  pOS_SGObject  *Master;
};



#define DEMOOBJANIMDELAY 3

extern struct pOS_DosBase *gb_DosBase;

struct pOS_IntuiDevice  *gb_IntuiBase;
struct pOS_GfxBase      *gb_GfxBase;
struct pOS_DataTypeBase *gb_DtTypeBase;
struct pOS_TimerDevice  *gb_TimerBase;
struct pOS_Library      *gb_SGOSBase;

const CHAR *HelpText=
""
;

const CHAR *PrgHeader=
"Simple SGOS demo";

const CHAR *PrgVerText=
"$VER: SGOSdemo1 1.0 ("__DATE2__") (Copyright 1996-97 by proDAD) (Created by Holger Papajewski)";


struct DemoObj;

pOS_GfxMap  *CreateSuperMap( pOS_Screen* );
pOS_SGOInfo *MakeGfx( pOS_Window* );

BOOL HandleWinMsg(pOS_Window*,pOS_SGOInfo*);

VOID BorColl_func(_R_A0 pOS_SGObject*,_R_A1 pOS_IBox*,UWORD);
VOID MasterMove_func(_R_A0 pOS_SGObject*);
VOID SlaveMove_func(_R_A0 pOS_SGObject*);

ULONG DemoAnim_func(_R_A0 pOS_SGObject*);

VOID MuenzeBorColl_func(_R_A0 pOS_SGObject*,_R_A1 pOS_IBox*,UWORD);
VOID MuenzeMove_func(_R_A0 pOS_SGObject*);

VOID MasterSlaveColl_func(_R_A0 pOS_SGObject*,_R_A1 pOS_SGObject*);

#ifdef __cplusplus
extern "C"
#endif
/*----------------------------------
-----------------------------------*/
VOID main( void )
{
  gb_IntuiBase  =(struct pOS_IntuiDevice*)pOS_OpenLibrary("pintui.library",0);
  gb_GfxBase    =(struct pOS_GfxBase*)pOS_OpenLibrary("pgraphics.library",0);
  gb_DtTypeBase =(struct pOS_DataTypeBase*)pOS_OpenLibrary("pDtType.library",0);
  gb_TimerBase  =(struct pOS_TimerDevice*)pOS_OpenLibrary("ptimer.library",0L);

  if(gb_SGOSBase=pOS_OpenLibrary("sgos.library",0)) {

    pOS_DosArgs  *Args;
    UWORD Err=0;
    ULONG Ops[1]={0};

    Args=pOS_ReadDosArgs("",Ops,sizeof(Ops)/sizeof(ULONG),
      ARGTAG_PrgHeaderText, (ULONG)PrgHeader,    /* kurze Programm-Beschreibung */
      ARGTAG_HelpText,      (ULONG)HelpText,     /* Help-Texte */
      ARGTAG_PrgVerText,    (ULONG)PrgVerText,   /* VER-String */
      TAG_END);

    if(Args) {
      pOS_Screen   *Scr;

      if( Scr = pOS_LockPubScreen(NULL)) {
        pOS_GfxMap *SuperMap;

        /* GfxMap für SuperBitMap-Window erzeugen */
        if( SuperMap = CreateSuperMap( Scr )) {
          pOS_Window *Win;

          Win=pOS_OpenWindow(
            SCRTAG_Title,   (ULONG)"SGOSdemo1",
            SCRTAG_Screen,  (ULONG)Scr,
            SCRTAG_Flags,   WINFLGF_DepthGadget | WINFLGF_GimmeZeroZero |
                            WINFLGF_Activate | WINFLGF_CloseGadget |
                            WINFLGF_Dragbar,
            SCRTAG_IDCMP,   IDCMP_CloseWindow | IDCMP_VanillaKey |
                            IDCMP_MouseMove | IDCMP_RefreshWindow,
            SCRTAG_InnerWidth,  SuperMap->gm_Width,
            SCRTAG_InnerHeight, SuperMap->gm_Height,
            SCRTAG_UnderMouse,  TRUE,
            SCRTAG_SuperGfxMap, (ULONG)SuperMap,
            TAG_DONE);

          if(Win) {
            pOS_SGOInfo *Info;

            /* SGOS-System erzeugen */
            Info = MakeGfx( Win );

            if( Info ) {
              BOOL  Quit=FALSE;
              ULONG sig;
              ULONG WinSig=1L<<Win->win_UserPort->mp_SigBit;

              /* Background-Zeichenprocess starten */
              pOS_StartSGOS( Info );
              while( !Quit ) {
                sig=pOS_WaitSignal(WinSig|DOSSIGF_CTRL_C);

                if( sig & DOSSIGF_CTRL_C )
                  Quit=TRUE;

                if( sig & WinSig )
                  Quit=HandleWinMsg( Win, Info );

              }

              /* komplettes SGOS löschen */
              /* beendet auch Backgroundprocess & löscht alle Objekte */
              pOS_DeleteSGOInfo( Info );
            }
            else printf("Cannot Create SGOS\n");

            pOS_CloseWindow( Win );
          }
          else printf("Cannot Open Window\n");

          pOS_FreeGfxMap( SuperMap );
        }
        else printf("Cannot Allocate SuperGfxMap.\n");

        pOS_UnlockPubScreen( Scr );
      }
      else printf("Cannot Lock Workbench\n");

      pOS_DeleteDosArgs( Args );
    }

    pOS_CloseLibrary(gb_SGOSBase);
  }

  pOS_CloseLibrary((pOS_Library*)gb_TimerBase);
  pOS_CloseLibrary((pOS_Library*)gb_DtTypeBase);
  pOS_CloseLibrary((pOS_Library*)gb_IntuiBase);
  pOS_CloseLibrary((pOS_Library*)gb_GfxBase);
}


/*----------------------------------
-----------------------------------*/
BOOL HandleWinMsg(pOS_Window *win,pOS_SGOInfo *info)
{
  BOOL ret=FALSE;
  pOS_IntuiMessage *Msg;
  pOS_SGObject *obj=(pOS_SGObject*)info->sgoi_UserData[0];
  MasterData   *MD=(MasterData*)obj->sgo_UserData[0];

  while( Msg=(pOS_IntuiMessage*)pOS_GetMsg(win->win_UserPort)) {

    switch(Msg->im_Class) {
// -----
      case IDCMP_CloseWindow:
        ret=TRUE;
        break;
// -----
      case IDCMP_RefreshWindow:
        pOS_LockSGOInfo( info );
        pOS_BeginRefresh( win, NULL );
        pOS_EndRefresh( win, TRUE );
        pOS_DrawSGOS( info, SGOSDM_Refresh );
        pOS_UnlockSGOInfo( info );
        break;
// -----
      case IDCMP_MouseMove:
        /* neue Koordinaten im privaten Teil vermerken */
        /* nie außerhalb der Callback-Funktionen direkt in die */
        /* SGObject-Struktur schreiben */
        {
          MD->NewX = Msg->im_MouseX-(obj->sgo_Width>>1);
          MD->NewY = Msg->im_MouseY-(obj->sgo_Height>>1);
        }
        break;
// -----
      default:
        break;
    }

    if(!pOS_SysIMessage(Msg))
      pOS_ReplyMsg((pOS_Message*)Msg);
  }

  return(ret);
}



/*----------------------------------
SuperGfxMap erzeugen
-----------------------------------*/
pOS_GfxMap *CreateSuperMap( pOS_Screen *scr )
{
  pOS_StdChunky8GfxMap *GfxMap;
  pOS_GfxMap *TempMap=NULL;
  pOS_StdRLColorMap    *ColorMap;

  /* Standard-ColorMap erzeugen - darf direkt beschrieben werden */
  ColorMap=(pOS_StdRLColorMap*)pOS_AllocColorMap(NULL,
           GFXTAG_ColorType,   COLMAPTYP_StdRLut,
           GFXTAG_Colors,      256,
           TAG_END);

  /* Standard-ChunkyGfxMap erzeugen - darf direkt beschrieben werden */
  GfxMap=(pOS_StdChunky8GfxMap*)pOS_AllocGfxMap(NULL,
           GFXTAG_Width,       200,
           GFXTAG_Height,      200,
           GFXTAG_GfxType,     GFXMAPTYP_StdChunky8,
           GFXTAG_CrtGfxMapEx, TRUE,
           GFXTAG_ColorMap,    (ULONG)ColorMap,
           TAG_END);

  /* Friend-GfxMap erzeugen */
  TempMap=pOS_AllocGfxMap(scr->scr_RastPort->rp_Base,
           GFXTAG_Width,       200,
           GFXTAG_Height,      200,
           GFXTAG_CrtGfxMapEx, TRUE,
           GFXTAG_FriendGfxMap,scr->scr_RastPort->rp_GfxMap,
           TAG_DONE);

  if(ColorMap && GfxMap && TempMap) {
    ULONG x;

    /* Farbpalette erzeugen */
    for(x=0; x<256; ++x) {
      ColorMap->rlcm_Colors[x].rc_U.rc_E.rcue_R=0;
      ColorMap->rlcm_Colors[x].rc_U.rc_E.rcue_G=x;
      ColorMap->rlcm_Colors[x].rc_U.rc_E.rcue_B=255-x;
    }

    /* ChunkyGfxMap beschreiben */
    for(x=0; x<200; ++x)
      GfxMap->ckgm_Chunky[x]=x+25;
    for(x=1; x<200; ++x)
      memcpy(&GfxMap->ckgm_Chunky[x*200],GfxMap->ckgm_Chunky,200);

    /* StdChunkyMap in die Friend-GfxMap konvertieren */
    pOS_WriteStdGfxMap(&GfxMap->ckgm_Gfx,0,0,TempMap,0,0,200,200,0,NULL);
  }
  else {
    if(TempMap) pOS_FreeGfxMap(TempMap);
    TempMap=NULL;
  }

  if(GfxMap)  pOS_FreeGfxMap(&GfxMap->ckgm_Gfx);
  if(ColorMap) pOS_FreeColorMap(&ColorMap->rlcm_CM);

  return(TempMap);
}



/*----------------------------------
SGOS-System erzeugen
-----------------------------------*/
pOS_SGOInfo *MakeGfx( pOS_Window *win )
{
  static MasterData MD;
  static SlaveData  SD;

  memset(&MD,0,sizeof(MasterData));
  memset(&SD,0,sizeof(SlaveData));

  pOS_SGOInfo  *info=NULL;
  pOS_SGObject *m, *s;
  pOS_SGObject *g;

  /* initialisiert SGOInfo-Struktur */
  info = pOS_CreateSGOInfo( win,
    SGOSTAG_CollHandler0, (ULONG)MasterSlaveColl_func,
    SGOSTAG_FramesPerSec, 25,
    TAG_DONE );

  if( info ) {
    /* Master-Object erzeugen */
    /* Gfx-Files werden automatisch mit der DtType.library geladen */
    if( m = pOS_CreateSGObject( info,
// *****      SGOSTAG_SGObjSize,        sizeof(DemoObj),
      SGOSTAG_GfxFile,          (ULONG)"Sys:Games/Gfx/Ball",
      SGOSTAG_MaskFile,         (ULONG)"Sys:Games/Gfx/Ball_Mask",
      SGOSTAG_InitialX,         40,
      SGOSTAG_InitialY,         40,
      SGOSTAG_MoveFunc,         (ULONG)MasterMove_func,
      SGOSTAG_BorCollisionFunc, (ULONG)BorColl_func,
      SGOSTAG_AnimObjFunc,      (ULONG)DemoAnim_func,
      SGOSTAG_HitID,            0x00,
      SGOSTAG_HitMask,          0x01,
      TAG_DONE )) {

      /* Werte für eigene Anim-Funktion initialisieren */
// *****      obj1->do_AnimDelta=1;
// *****      obj1->do_AnimDelay=DEMOOBJANIMDELAY;

      m->sgo_UserData[0] = (ULONG)&MD;
      MD.AnimDelta = 1;
      MD.AnimDelay = DEMOOBJANIMDELAY;

      /* obj1 clonen */
      /* eigene MoveFunktion setzten */
      /* AnimFunktion wird auf Default zurückgesetzt */
      if( s = pOS_CloneSGObject( m,
        SGOSTAG_InitialX,         80,
        SGOSTAG_InitialY,         80,
        SGOSTAG_MoveFunc,         (ULONG)SlaveMove_func,
        SGOSTAG_BorCollisionFunc, (ULONG)BorColl_func,
        SGOSTAG_AnimObjFunc,      NULL,
        SGOSTAG_HitID,            0x01,
        SGOSTAG_HitMask,          0x00,
        TAG_DONE )) {

        s->sgo_UserData[0] = (ULONG)&SD;
        SD.Master = m;
        info->sgoi_UserData[0] = (ULONG)m;

        if( g = pOS_CreateSGObject( info,
          SGOSTAG_GfxFile,          (ULONG)"Sys:Games/Gfx/GMuenze",
          SGOSTAG_MaskFile,         (ULONG)"Sys:Games/Gfx/Muenze_Mask",
          SGOSTAG_MoveFunc,         (ULONG)MuenzeMove_func,
          SGOSTAG_BorCollisionFunc, (ULONG)MuenzeBorColl_func,
          SGOSTAG_Inactive,         TRUE,
          TAG_DONE )) {

          /* Muenze im Master merken */
          m->sgo_UserData[1] = (ULONG)g;
        }
        else {
          printf("Cannot Clone Ball Object\n");
          pOS_DeleteSGOInfo(info);
          info=NULL;
        }
      }
      else {
        printf("Cannot Clone Ball Object\n");
        pOS_DeleteSGOInfo(info);
        info=NULL;
      }
    }
    else {
      printf("Cannot Create Ball Object\n");
      pOS_DeleteSGOInfo(info);
      info=NULL;
    }
  }

  return( info );
}


/*----------------------------------
Funktion wird bei Kollision mit der ClipBox aufgerufen
Das Objekt wird immer an den Rand gesetzt - es kann sich
nie aus der ClipBox bewegen
-----------------------------------*/
VOID BorColl_func(_R_A0 pOS_SGObject *obj,_R_A1 pOS_IBox *cb ,UWORD mask)
{
  /* LayerOffsets beachten */
  SLONG lX = obj->sgo_Info->sgoi_Window->win_Layer->ly_ScrollX;
  SLONG lY = obj->sgo_Info->sgoi_Window->win_Layer->ly_ScrollY;

  if( mask & SGOBCB_Left )
    obj->sgo_X = cb->Left - lX;
  else if( mask & SGOBCB_Right )
    obj->sgo_X = cb->Left - lX + cb->Width - obj->sgo_Width;

  if( mask & SGOBCB_Top )
    obj->sgo_Y = cb->Top - lY;
  else if( mask & SGOBCB_Bottom )
    obj->sgo_Y = cb->Top -lY + cb->Height - obj->sgo_Height;
}



/*----------------------------------
Der Master wird mit der Maus bewegt
Hier werden nur die im Messageloop ermittelten Werte in die
SGObject-Struktur übertragen
-----------------------------------*/
VOID MasterMove_func(_R_A0 pOS_SGObject *m )
{
  MasterData *MD = (MasterData*)m->sgo_UserData[0];
  m->sgo_X = MD->NewX;
  m->sgo_Y = MD->NewY;
}


/*----------------------------------
Der Slave folgt immer dem Master
-----------------------------------*/
VOID SlaveMove_func(_R_A0 pOS_SGObject *s )
{
  SlaveData *SD = (SlaveData*)s->sgo_UserData[0];
  pOS_SGObject *master=SD->Master;
  SLONG dx = master->sgo_X - s->sgo_X;
  SLONG dy = master->sgo_Y - s->sgo_Y;
  SLONG dd = (ABS(dx)<<1) + (ABS(dy)<<1);

  if( dd > ((master->sgo_Width+5)<<1) ) {
    if( ABS(dx) > s->sgo_Width+2) {
      if(dx>0) {
        while( dx > s->sgo_Width+2 ) {
          s->sgo_X++;
          dx -= s->sgo_Width;
        }
      }
      else {
        while( dx < -s->sgo_Width-2 ) {
          s->sgo_X--;
          dx += s->sgo_Width;
        }
      }
    }

    if( ABS(dy) > s->sgo_Height+2) {
      if(dy>0) {
        while( dy > s->sgo_Height+2 ) {
          s->sgo_Y++;
          dy -= s->sgo_Height;
        }
      }
      else {
        while( dy < -s->sgo_Height-2 ) {
          s->sgo_Y--;
          dy += s->sgo_Height;
        }
      }
    }
  }
}



/*----------------------------------
-----------------------------------*/
VOID MasterSlaveColl_func(_R_A0 pOS_SGObject *m,_R_A1 pOS_SGObject *s)
{
  MasterData *MD = (MasterData*)m->sgo_UserData[0];
  pOS_TimeVal  t;

  pOS_GetSysTime(&t);
  pOS_SubTime(&t,&MD->LastColl);

  if( t.tv_Secs >= 1 )
  {
    pOS_CloneSGObject( (pOS_SGObject*)m->sgo_UserData[1],
      SGOSTAG_InitialX, m->sgo_X,
      SGOSTAG_InitialY, m->sgo_Y,
      TAG_DONE );
  }
  pOS_GetSysTime(&MD->LastColl)
}



/*----------------------------------
Eigene AnimFunktion - es muss der nächste Frame zurückgegeben werden
Animation langsamer vorwärts - rückwärts abspielen
-----------------------------------*/
ULONG DemoAnim_func(_R_A0 pOS_SGObject *m )
{
  MasterData *MD = (MasterData*)m->sgo_UserData[0];
  ULONG ret=m->sgo_CurFrame;

  /* DelayWert runterzählen */
  /* bei 0 nächszen Frame setzen */
  if(--MD->AnimDelay==0) {

    MD->AnimDelay=DEMOOBJANIMDELAY;
    ret += MD->AnimDelta;
  }
  /* wenn Ende bzw. Anfang erreicht - Abspielrichtung umdrehen */
  if(ret==0 || ret==m->sgo_FrameCount-1)
    MD->AnimDelta = -MD->AnimDelta;

  return(ret);
}



/*----------------------------------
-----------------------------------*/
VOID MuenzeBorColl_func(_R_A0 pOS_SGObject *m,_R_A1 pOS_IBox *box,UWORD mask)
{
  if( mask & SGOBCB_Bottom ) pOS_RemoveSGObject( m );
}



/*----------------------------------
-----------------------------------*/
VOID MuenzeMove_func(_R_A0 pOS_SGObject *m)
{
  m->sgo_Y = m->sgo_Y+2;
}


#endif
