/* This example is both example and documentation. It teaches you both the special
   features of this Video Driver and also some functions that can be directly
   called from rtgmaster.library. */

/* To define the colortable : Change Colortable: in AmigaQuakeVideo.asm !!! */

#include <exec/libraries.h>  // Is needed because of the Library Structure
#include <rtgmaster/rtgsublibs.h> // Is needed because of Rtgmaster itself
#include <stdio.h> // needed for test output
#include <intuition/intuition.h> // needed for Input Handling
#include <clib/rtgmaster_protos.h> // needed for rtgmaster support
#include <pragmas/rtgmaster_pragmas.h>  // needed for rtgmaster support
#include <clib/exec_protos.h>
#include <pragmas/exec_pragmas.h>

/* InitData is the structure that contains the data of the Screen that
   was opened and about the Screenmode that was chosen by the user */

struct InitData
                       {
                        struct Library *id_RTGMasterBase; /* Baseaddress of rtgmaster.library */
                        ULONG id_Signal;                  /* A Signal for rtgmaster c2p
                                                              (only needed if rtgmaster is also used for
                                                               Planar Screens and not only for GFX Board ones */
                        struct ScreenReq *id_sr;          /* The Data that the Screenmode-Requester returns */
                        struct RtgScreen *id_myscreen;    /* The Screen itself */
                        void *id_MapA;                    /* Video RAM base Address of Buffer 0 */
                        void *id_MapB;                    /* If doublebuffering is used : Same of buffer 1 */
                        void *id_MapC;                    /* If triplebuffering is used : Same of buffer 2 */
                        ULONG id_mpsigbit;                /* The MP_SigBit */
                        ULONG id_DescTags[22];            /* Information about the opened screen (see below) */
                       };


/* The functions of the .asm File... for SAS/C ... for other compilers it might
   look a bit different, but not much probably */

extern __asm struct InitData *InitIt(void);
extern __asm void CloseIt(register __a0 struct InitData *id);


struct Library *RTGMasterBase;

void main()
{
 void *TheMap;
 int quit=0;
 struct InitData *id=InitIt(); // Init Display
 RTGMasterBase=id->id_RTGMasterBase;  // Get RTGMasterBase
 TheMap=id->id_MapA; // Get Video RAM Base Address
 printf("Width: %i Height: %i PixelLayout: %i ColorSpace: %i Depth: %i PlaneSize: %i BytesPerRow: %i MouseX: %i MouseY: %i BusSystem: %i\n",id->id_DescTags[1],id->id_DescTags[3],id->id_DescTags[5],id->id_DescTags[7],id->id_DescTags[9],id->id_DescTags[11],id->id_DescTags[13],id->id_DescTags[15],id->id_DescTags[17],id->id_DescTags[19]);

 /* Now you can write to TheMap :)
    In ASM for example:

    move.l TheMap,a0
    move.l #$F0F0F0F0,(a0)+

    or something like that.
 */

 /* Now some explanation about "How do we move the video data to the Screen".
    There are several methods to do this :

    a) Do it with your own code (well, i probably do not need to tell something
       about this...)

    b) If you have address of the data to be displayed, in, let's say, MapBack,
       you can do :

       CopyMoveMove(MapBack,id->id_MapA,320*200);

       (for 020/030)

       For 040/060 you can even use the much faster function
       AmigaCC040 that is found in fcopy.s

       AmigaCC040(MapBack,x,y,rowbytes,id->id_MapA,320,200);

       I probably will include that function to rtgmaster.library CopyRtgPixelArray
       soon. The function needs x and rowbytes being divisible by 16 to work.


    c) Use the GFX Board Blitter for this. rtgmaster supports a function to do so.
       Of course the GFX Board Blitter can only access data that is in the Video RAM
       of the Board (it has to be in one of the three Maps that we have defined).
       So you could build the data in one Map, and then move it to the front, using
       the GFX Board Blitter. GFX Board Blitters can move data with about 30 MB/sec.,
       if it is a very fast GFX Board. You might want to test both functions,
       CopyMoveMove and the Blitting function, to see which one is faster. Maybe you
       even could allow the user to configure, which one will be used.

       RtgBlit(id->id_myscreen,1,0,0,0,0,0,320,200,0xc0);

       This call blits MapB to MapA, copying (0,0)-(319,199) from MapB to
       (0,0)-(319,199) of MapA. The Minterm 0xc0 is "Plain Copy". rtgmaster also
       supports the minterms $30,$50,$60 and $80 (but some of those might not
       work under EGS. The Blitter Support of EGS is quite anfinished). 0xc0
       at least works on ANY WB Emulation. So the parameters are :

       Screen,SrcBufferNo,DestBufferNo,SrcX,SrcY,DestX,DestY,Width,Height,Minterm

       NOTE: For RtgBlit the BUFFERNUMBER (0-2) will be used, NOT THE BUFFERADDRESS !!!

    d) Use Double/Triplebuffering

       PRINCIPIALLY this is the fastest method. The problem is only : Even if
       rtgmaster provides a function for this, it can't do else, but internally
       using the functions of the used WB Emulations. And some WB Emulations do
       not support fast Doublebuffering. I am giving you an overview here :

       EGS : Very fast Double/Triplebuffering.
       CyberGraphX : Quite slow Double/Triplebuffering. Might flicker, so try it
                     out, before you use it.
       Probench 3  : The same like CyberGraphX. Could be enhanced by providing
                     a "Probench 3 Native Version", as Probench supports fast
                     Double/Triplebuffering. But as Probench is only supported
                     through CyberGraphX Emulation : Same problems like with
                     CyberGraphX.
       CyberGraphX 3 : Same problems like with CyberGraphX.
       Picasso96 : Currently the same problems like with CyberGraphX. Might change.
       Picasso II Native WB Emu : Same Problems like with CyberGraphX, if you use
       Triplebuffering. Doublebuffering is fast, though.

       So you see : You have to try it out, before you include Doublebuffering.
       This is not a problem of rtgmaster, it is a problem of current Amiga
       WB Emulations. Mail to the authors that you want "ChangeScreenBuffer"
       or at least "ChangeVPBitmap" Support for the WB Emulation. As soon as
       a WB Emulation SUPPORTS a better method, i will include support for it
       in a later version of rtgmaster.

       Use it :

       SwitchScreens(id->id_myscreen,num);

       num can be 0-2, where num is the number on the Map to be displayed (MapA-MapC).

       The best method for displaying would be, that the user can choose, if blitting
       will be used or not, and if doublebuffering will be used or not. Default should
       be blitting turned on, doublebuffering turned on. But tests should be done to
       see which is fastest on typical configurations.


 */

 /* In the following i will explain some more rtgmaster display functions that might
    be useful :

    CallRtgC2P
    ==========

    This is a very high level call for additional ECS/AGA support. It performs a similar
    function like CopyMoveMove (it is a bit slower, as it is more flexible, though) for
    GFX Boards. For ECS/AGA it performs a c2p, instead. The c2p algorithm to be used can
    be changed in the Screenmode-Requester. The docs about the c2p format of rtgmaster
    (c2p is loaded during InitIt()) are available on request from me.

    Calling the function :

    CallRtgC2P(id->id_myscreen,id->id_MapA,id->id_MapB,id->id_Signal,0,0,320,200,mode);

    Screen to be used, Destination buffer, Source Buffer, an exec signal, startx, starty, width, height, mode.

    Only the algorithm "GD" up to now support startx/starty/width/height being anything
    else but 0/0/max_x/max_y. So better use 0/0/max_x/max_y.

    mode is defined in rtgc2p.h (c2p_1x1, c2p_1x2,... i suggest using c2p_Selected, that is the
    user-selected value... if you use rtgmaster for ECS/AGA Support AT ALL... it is not very
    fast in ECS/AGA, so it might be better only to use it for GFX Board Support, where it is
    very fast).

    The signal is for the following : If you use Blitter using c2p, you should Wait for this
    signal after each call of CallRtgC2P. It will let the system wait till the blitter is
    finished, then. But as Blitterusing c2p do not really work currently with rtgmaster (and
    as the Wait slows the thing down quite a bit), you might leave out the Wait...

    CopyRtgPixelArray
    =================

    CopyRtgPixelArray is a function similar to CopyMoveMove, but it is more high level. It is
    quite well optimized, but of course a bit slower than CopyMoveMove. It supports all Screen
    Depths, but it does not do any conversions : It just copies the data to the Screen just
    like it finds it in the source.

    CopyRtgPixelArray(id->id_myscreen,id->id_MapA,id->id_MapB,11,12,200,100,10,20);

    This example copies (10,20)-(200+10-1,100+20-1) of MapB to (11,12)-(200+11-1.100+12-1).
    The Function is a bit faster than CallRtgC2P (because it does not need this signal stuff).

    DrawRtgLine
    ===========

    This is a function to draw a line. There are two functions : DrawRtgLine for 1-8 Bit, and
    DrawRtgLineRGB for 15-24 Bit. The functions use hardware, where hardware is available,
    else Bresenham.

    DrawRtgLine(id->id_myscreen,id->id_MapA,color,x1,y1,x2,y2);

    Draws a line from (x1,y1)-(x2,y2). (x1,y1) HAS TO BE < (x2,y2). Color is the
    color register to be used.

    DrawRtgLineRGB(id->id_myscreen,id->id_MapA,color,x1,y1,x2,y2)

    Same as above, but color is a value in ARGB format.

    FillRtgRect
    ===========

    With this you draw a filled box. It might use the GFX Board Blitter on some
    boards to do so.

    FillRtgRect(id->id_myscreen,id->id_MapA,color,x1,y1,width,height);

    FillRtgRectRGB works exactly the same, only that it takes ARGB color
    values instead of color table number and that it only works for 15-24 Bit
    Screens (FillRtgRect only works for 1-8 Bit Depth).

    LoadRGBRtg
    ==========

    With this call you can change the colortable of a RtgScreen. The colortable
    is in the same format like graphics.library LoadRGB32 (look at the ASM File
    for more details of this format) :

    LoadRGBRtg(id->id_myscreen,colortable);

    RtgBltClear
    ===========

    Another blitting function, that can be used to CLEAR a rectangle.

    RtgBltClear(id->id_myscreen,BufferNo,xpos,ypos,width,height);

    BUFFERNUMBER (0-2) is used here, NOT BUFFERADDRESS !!!

    RtgClearPointer
    ===============

    This function returns the mousepointer to the original pointer, if it
    was changed with RtgSetPointer before.

    This function only works with :

    CyberGraphX
    CyberGraphX 3
    Picasso96
    ECS/AGA

    For the other WB Emulations it is not yet supported. (The Picasso II
    Sublibrary has an invisible pointer, for EGS i did not yet find the
    time to implement the function).

    RtgClearPointer(id->id_myscreen);

    RtgSetPointer
    =============

    This function changes the mousepointer to a different image.

    This function only works with :

    CyberGraphX
    CyberGraphX 3
    Picasso96
    ECS/AGA

    For the other WB Emulations it is not yet supported. (The Picasso II
    Sublibrary has an invisible pointer, for EGS i did not yet find the
    time to implement the function).

    RtgSetPointer(id->id_myscreen,spriteimage,width,height,hotspotx,hotspoty);

    The Spritedata HAS TO BE defined as UWORD spriteimage[36]; No smaller
    or bigger sprites are allowed !!! (it is defined like in the spritedata
    for graphics.library sprites)

    hotspotx/hotspoty define where the Hotspot (the mousesensitive point) is.

 */

 /* In the following i will explain rtgmaster's text-functions :

    RtgOpenFont
    ===========

    With this call you load an Amiga pixelfont from harddrive or RAM (RAM
    in case of topaz.font) :

    It is defined as :

    void *RtgOpenFont(struct RtgScreen *rtgscreen,struct TextAttr *ta);

    RtgScreen is usually our id->id_myscreen, ta is a TextAttr structure,
    like used in graphics.library (rtgmaster uses graphics.library functions
    for Text/Font support, what means that rtgmaster text output is much
    slower than rtgmaster graphics output !!! You might wish to do your
    own text functions...

    Example of a TextAttr structure :

  struct TextAttr Sapphire= {
                             "sapphire.font", //Name
                              14, // Size
                              0,
                              0
                            };
    RtgCloseFont
    ============

    Closes a font again.

    RtgCloseFont(id->id_myscreen,font);

    font is what you got of the RtgOpenFont call.
    You might wonder about the MyScreen parameter. This is only
    because of implementation details of rtgmaster (rtgmaster finds
    out to which WB Emulation a screen belongs to in examining the
    Screen structure).

    RtgSetFont
    ==========

    RtgSetFont(id->id_myscreen,font);

    sets a font to a screen. Parameters are the same like in RtgCloseFont.

    RtgText
    =======

    This function outputs text. It is quite slow. If you want faster
    Textoutput, better code something yourselves (internally this
    function uses simply Text() of graphics.library, which is the reason
    why it is slower than Graphics output. It does not access the Video
    RAM directly, like rtgmaster's other functions...

    Example:

    RtgText(id->id_myscreen,id->id_MapA,"Hello!",strlen("Hello!"),xpos,ypos);

    RtgSetTextMode
    ==============

    This function sets some parameters to the RtgText() function.

    Foreground color, Backgroundcolor and DrawMode. DrawMode can be
    JAM1,JAM2 or COMPLEMENT, like defined in graphics/rastport.i.
    INVERSVID cannot be used, as it is not supported by all GFX Boards.

    Example:

    RtgSetTextMode(id->id_myscreen,fgcolor,bgcolor,JAM1);

    There also exists a RtgSetTextModeRGB for 15-24 Bit deep screens.
    Due to a bug of CyberGraphX, this call won't work as you expect
    on systems using CyberGraphX, Probench3 or Picasso96. (Up to now
    i only tested this with CyberGraphX, but i expect it will behave
    the same way on the other two. It will work fine on EGS).

 */
 while(!quit)
 {
  struct IntuiMessage *imsg;
  if (SetSignal(0,0)&id->id_mpsigbit)
  {
  imsg=(struct IntuiMessage *)RtgGetMsg(id->id_myscreen); // Get the message

  /* Note : Instead of using the IDCMP Port of the RtgScreen, of course, you
     can still directly hit the hardware. The IDCMP method is easier to code,
     though... */

  if (imsg->Class==IDCMP_RAWKEY)
  {
   // A key was pressed
   quit=1;
   printf("RAWKEY CODE : %i\n",imsg->Code);
   RtgReplyMsg(id->id_myscreen,imsg);

   /* In imsg->Code you find the RAWKEY CODE (RAWKEY, NOT ASCII !!!) of the
      key that was pressed. DO NOT access imsg anymore after you did the
      RtgReplyMsg. If the highest Bit in imsg->Code is set this is a Key
      release message, else a key press message.

      BTW: In imsg->Qualifier you gind the Qualifiers (for example,
      if the user presses H and ALT together, ALT is the Qualifier of the keypress.

      Example :

      if (imsg->Qualifier&IEQUALIFIER_CONTROL) checks, if the CONTROL key was pressed.
      You find all Qualifiers in the file include:devices/inputevent.h.
   */
  }
  else if (imsg->Class==IDCMP_MOUSEBUTTONS)
  {
   // a mousebutton was pressed
   GetRtgScreenData(id->id_myscreen,id->id_DescTags);

   /* GetRtgScreenData gets a lot of information about the screen. What information
      is available is described more detailed in the .asm File (Width, Height,
      Depth, Mouseposition,... The initial values of these are already filled
      in by the function InitIt().
   */

   printf("MouseX %i MouseY %i\n",id->id_DescTags[15],id->id_DescTags[17]);
   RtgReplyMsg(id->id_myscreen,imsg);

   /* If you receive a Mousebuttonevent, you will get :

      imsg->Code==SELECTUP : Left Mousebutton was released
      imsg->Code==SELECTDOWN : Left Mousebutton was pressed
      imsg->Code==MENUUP : Right Mousebutton was pressed
      imsg->Code==MENUDOWN : Right Mousebutton was released

      In imsg->MouseX and imsg->MouseY you get the current Mouse-Coordinates.
      (You can also use GetRtgScreenData like in this function, of course,
      but directly reading imsg->MouseX and imsg->MouseY will be a little faster.
   */

  }
  else
  {
   // nothing was pressed
  }
  }
 }
 CloseIt(id);
}
