Jump to content

Aros/Developer/Docs/Libraries/Graphics

From Wikibooks, open books for an open world
Navbar for the Aros wikibook
Aros User
Aros User Docs
Aros User FAQs
Aros User Applications
Aros User DOS Shell
Aros/User/AmigaLegacy
Aros Dev Docs
Aros Developer Docs
Porting Software from AmigaOS/SDL
For Zune Beginners
Zune .MUI Classes
For SDL Beginners
Aros Developer BuildSystem
Specific platforms
Aros x86 Complete System HCL
Aros x86 Audio/Video Support
Aros x86 Network Support
Aros Intel AMD x86 Installing
Aros Storage Support IDE SATA etc
Aros Poseidon USB Support
x86-64 Support
Motorola 68k Amiga Support
Linux and FreeBSD Support
Windows Mingw and MacOSX Support
Android Support
Arm Raspberry Pi Support
PPC Power Architecture
misc
Aros Public License

Introduction

[edit | edit source]

AROS has a line based graphics mode which is useful for polygon and wire-framed based drawing utilities

And has the ability for bitmap manipulation for images (pictures)

  • 8bit (256 colours) graphics.library
  • up 32bit (14m colours) cybergraphics.library (which is an extension of graphics so both are needed to be opened if required)

To clarify that, if all you want to do is blast an RGB image onto a display, then you'll have no problems with Cybergfx chunky pixel functions. If you actually want to do some block polygon fills and rasterize primitives (dots, lines, etc), then you'll need the graphics.library.


You will need to understand the principles behind Window/Screen/BitMaps with RastPort(TmpRas)/ViewPort/...

There are times where screen->ViewPort, not ViewPortAddress(window) is necessary. Functions like ViewPortAddress() are an exception. Many coding for Amiga-like operating systems is done be direct access of the structures.

ViewPortAddress returns the address of the viewport associated with the specified window. The viewport is actually the viewport of the screen within which the window is displayed. If you want to use any of the graphics, text, or animation primitives in your window and that primitive requires a pointer to a viewport, you can use this call.

Returns the address of the viewport of a given window. Use this call, if you want to use any graphics, text or animation functions that require the address of a viewport for your window.
INPUTS       Window - pointer to a Window structure 
RESULT       Address of the Intuition ViewPort structure for the screen that your window is displayed on.


Bitmaps with RastPort (control the number of Pens, Drawing modes and Pattern)

Drawing functions (Data moving, Area operations, Text, Clipping, Color)

Animation, Layers, Display database, Blitter, Copper, Miscellaneous


Line Graphics

[edit | edit source]

AROS like AmigaOS(TM) before has a number of function relating to line graphics using the graphics.library. These include setting color, plotting points (pixels), drawing lines, rectangles, circles, patterns, area filling and so on. Most functions require a pointer to a RastPort which is a special public structure (template) that is created automatically from a Window or a Layer call, referenced by Window->RPort (RastPort address). This value can then be used for the SetAPen(rp,FrontPenNumber), SetOPen(rp,OutlinePenNumber), Move(rp,x,y) and Draw(rp,x,y) and Text(rp,pointer_to_text,ext_length) function commands.

Whenever a window is opened, a drawing surface is also prepared and the information is stored in its own rastport. Every drawing operation involves a rastport. If you want to draw directly into a window, you use the window's rastport.

In some cases, it may be required to replaced the rastport stuff with CloneRastport, and associated functions. Ideally, working with a Clone of the windows rastport - not directly

The internal structure of the RastPort looks like this

struct RastPort
{
    struct  Layer  *Layer;
    struct  BitMap *BitMap;
    UWORD          *AreaPtrn;  /* Ptr to areafill pattern */
    struct  TmpRas *TmpRas;
    struct  AreaInfo *AreaInfo;
    struct  GelsInfo *GelsInfo;
    UBYTE   Mask;              /* Write mask for this raster */
    BYTE    FgPen;             /* Foreground pen for this raster */
    BYTE    BgPen;             /* Background pen  */
    BYTE    AOlPen;            /* Areafill outline pen */
    BYTE    DrawMode;          /* Drawing mode for fill, lines, and text */
    BYTE    AreaPtSz;          /* 2^n words for areafill pattern */
    BYTE    linpatcnt;         /* Current line drawing pattern preshift */
    BYTE    dummy;
    UWORD   Flags;             /* Miscellaneous control bits */
    UWORD   LinePtrn;          /* 16 bits for textured lines */
    WORD    cp_x, cp_y;	       /* Current pen position */
    UBYTE   minterms[8];
    WORD    PenWidth;
    WORD    PenHeight;
    struct  TextFont *Font;    /* Current font address */
    UBYTE   AlgoStyle;         /* The algorithmically generated style */
    UBYTE   TxFlags;           /* Text specific flags */
    UWORD   TxHeight;          /* Text height */
    UWORD   TxWidth;           /* Text nominal width */
    UWORD   TxBaseline;        /* Text baseline */
    WORD    TxSpacing;         /* Text spacing (per character) */
    APTR    *RP_User;
    ULONG   longreserved[2];
#ifndef GFX_RASTPORT_1_2
    UWORD   wordreserved[7];   /* Used to be a node */
    UBYTE   reserved[8];       /* For future use */
#endif
};

WritePixel(rp,x,y) function plots a point with colour already set a separate SetAPen() instruction.

Other instructions available

void SetAPen( struct RastPort *rp, unsigned long pen ) - Set foreground colour using preset colour pens
void SetBPen( struct RastPort *rp, unsigned long pen ) - Set background colour using preset colour pens
void Move(struct RastPort rp, long x, long y) - Move to co-ordinates row x, column y in a Rastport (rp) where 0,0 is the top left of window.
void Draw(struct RastPort rp, long x, long y) - Draws a line from current position to row x, column y.
void DrawEllipse( struct RastPort *rp, long xCenter, long yCenter, long a, long b ) - Draw an Ellipse
ULONG ReadPixel( struct RastPort *rp, long x, long y ) - Read a pixel value
LONG WritePixel( struct RastPort *rp, long x, long y ) - Write a pixel
void PolyDraw( struct RastPort *rp, long count, WORD *polyTable ) - Draw a multi-lined polygon using an array of x,y points.

Refreshing windows can be done via SIMPLE_REFRESH (redraw) or SMART_REFRESH windows or SUPER_BITMAP (GIMMEZEROZERO) window.

/* Grid in a Window */
#include <proto/intuition.h>
#include <proto/gadtools.h>
#include <proto/graphics.h>
#include <proto/layers.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <intuition/intuition.h>

int main() {
    struct Window *myWindow;
    struct RastPort *rp;
    int closewin = FALSE, row, column;
    struct IntuiMessage *msg;
    ULONG msgClass;
    long startx,starty,width;

    myWindow = OpenWindowTags(NULL,
      WA_Left, 0, WA_Top, 0,
      WA_Width, 640, WA_Height, 400,
      WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW,
      WA_Flags, WFLG_SIZEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | 
      WFLG_CLOSEGADGET | WFLG_ACTIVATE | WFLG_SMART_REFRESH,
      WA_Title, "Grid In a Window",
      WA_PubScreenName, "Workbench",
      TAG_DONE);
    /* Get Window's Rastport */
    rp = myWindow->RPort;
 
    /* Draw 8x8 grid of boxes */
    /* Set foreground color */
    SetAPen(rp, 1);
    for(row=1; row<=8; row++) {
      for(column=1; column<=8; column++) {
      /* Move to correct screen position and draw box */
      Move(rp, row*30, column*30);
      Draw(rp, row*30+30, column*30 + 0);
      Draw(rp, row*30+30, column*30 + 30);
      Draw(rp, row*30+0, column*30 + 30);
      Draw(rp, row*30+0, column*30 + 0);
      }
    }
 
    while (closewin == FALSE) {
       Wait(1L << myWindow->UserPort->mp_SigBit);
       msg = GT_GetIMsg(myWindow->UserPort);
       msgClass = msg->Class;
       GT_ReplyIMsg(msg);
       if (msgClass == IDCMP_CLOSEWINDOW) {
          CloseWindow(myWindow);
          closewin = TRUE;
       }
       if (msgClass == IDCMP_REFRESHWINDOW)
          RefreshWindowFrame(myWindow);
    }
 
  return(0);
}

Take a look at amilines for another example and arosbattleships for an ascii version grid.

Set Background Color

[edit | edit source]

If your window is borderless you can just

SetRast(win->RPort, 2);

However, if your window has borders then you need to account for them

{
  LONG l, t, w, h;

  l = win->BorderLeft;
  t = win->BorderTop;
  w = win->Width - win->BorderLeft - win->BorderRight;
  h = win->Height - win->BorderTop - win->BorderBottom;

  if (w > 0 && h > 0)
  {
    /* White background */
    SetAPen(win->RPort, 2);
    RectFill(win->RPort, l, t, l + w - 1, t + h - 1);

    ...
  }
}

Another possibility is using WA_BackFill and a custom backfill hook.

If you are using graphics.library, pens are limited from 0-255 8bit, regardless of what your display is running on.

RectFill always draws into the RastPort. Everything which was in that RastPort before is overwritten. If your window is in the background, only non-hidden parts will be drawn. For SMART_REFRESH windows the hidden parts are stored and shown when the window comes to front. This includes the parts affected by RectFill. RectFill always draws with pen A, so SetBPen has no effect for it. Similarly it does not matter if you use JAM1 or JAM2.

/* beginning of your program */

scr = LockPubScreen (pubscreennname);
red_pen = ObtainBestPen (scr->ViewPort.ColorMap,
           0xffffffff, 0x00000000, 0x00000000,
           OBP_FailIfBad, FALSE,
           OBP_Precision, PRECISION_GUI,
           TAG_END);

/* middle part */

rastPort=MainWindow->RPort;
SetAPen (rastPort,red_pen);
RectFill (rastPort,20,20,150,50);

/* end of your program */

ReleasePen (scr->ViewPort.ColorMap, red_pen);
UnlockPubScreen (NULL,scr);

It doesn't actually matter that you are using a pen in those cases since on an RGB display, you can allocate a pen and change it's colour as often as you want without affecting anything you already rendered.

If you need to set an arbitrary colour for area pens for use on an RGB display, you need to use LoadRGB32 to set the colour of your chosen pen (or pens). On an RGB display, you can keep changing the pen colour without affecting already rendered pixels. On an indexed display, you have to worry about finding a suitable pen that is close to your desired colour in the first place.

If using 'pen 1', and then change the palette value of 'pen 1' by using the values with SetRGB32(). Just allocate a pen, set it's RGB value, render with it, change the RGB value again, render some more and when you are done release the pen. If it's on your own screen, you can just allocate the pen after you open the screen then release it before you close it. You aren't restricted to using just the one pen, you can allocate pens for area, fill etc. Regarding SetRGB32(), the documentation makes it clear that it's slower than LoadRGB32() with a single colour index.

On AFA OS 68k, AROS and MOS you can set RGB foreground and background colors with that Tag

RPTAG_FgColor:
RPTAG_BgColor:

SetRPAttrs( rastport, RPTAG_FgColor:, 0xRRGGBB, TAG_DONE );
/*
    Example for simple drawing routines
*/

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/intuition.h>

#include <graphics/gfxmacros.h>

#include <stdlib.h>

static struct Window *window;
static struct ColorMap *cm;
static struct RastPort *rp;

/*
    ObtainBestPen() returns -1 when it fails, therefore we
    initialize the pen numbers with -1 to simplify cleanup.
*/
static LONG pen1=-1;
static LONG pen2=-1;

static void draw_simple(void);
static void clean_exit(CONST_STRPTR s);
static void handle_events(void);

int main(void)
{
    window = OpenWindowTags(NULL,
        WA_Left,   50,
        WA_Top,    70,
        WA_Width,  400,
        WA_Height, 350,
    
        WA_Title,         "Simple Graphics",
        WA_Activate,      TRUE,
        WA_SmartRefresh,  TRUE,
        WA_NoCareRefresh, TRUE,
        WA_GimmeZeroZero, TRUE,
        WA_CloseGadget,   TRUE,
        WA_DragBar,       TRUE,
        WA_DepthGadget,   TRUE,
        WA_IDCMP,         IDCMP_CLOSEWINDOW,
        TAG_END);
    
    if (! window) clean_exit("Can't open window\n");
    
    rp = window->RPort;
    cm = window->WScreen->ViewPort.ColorMap;

    // Let's obtain two pens
    pen1 = ObtainBestPen(cm, 0xFFFF0000 , 0 , 0 , TAG_END);
    pen2 = ObtainBestPen(cm, 0 , 0 , 0xFFFF0000 , TAG_END);
    if ( !pen1 || !pen2) clean_exit("Can't allocate pen\n");
    
    draw_simple();
    handle_events();

    clean_exit(NULL);

    return 0;
}

static void draw_simple(void)
{
    WORD array[] = {                // Polygon for PolyDraw()
        50, 200,
        80, 180,
        90, 220,
        50, 200,
    };
    
    SetAPen(rp, pen1);              // Set foreground color
    SetBPen(rp, pen2);              // Set background color
    
    WritePixel(rp, 30, 70);         // Plot a point
    
    SetDrPt(rp, 0xFF00);            // Change line pattern. Set pixels are drawn
                                    // with APen, unset with BPen
    
    Move(rp, 20, 50);               // Move cursor to given point
    Draw(rp, 100, 80);              // Draw a line from current to given point
    
    DrawEllipse(rp, 70,30, 15, 10); // Draw an ellipse

    /*
        Draw a polygon. Note that the first line is draw from the
        end of the last Move() or Draw() command.
    */
    PolyDraw(rp, sizeof(array)/sizeof(WORD)/2, array);
    
    SetDrMd(rp, JAM1);             // We want to use only the foreground pen.
    Move(rp, 200, 80);
    Text(rp, "Text in default font", 20);
    
    SetDrPt(rp, 0xFFFF);           // Reset line pattern
}

static void handle_events(void)
{
    /*
        A simple event handler. This will be explained more detailed
        in the Intuition examples.
    */
    struct IntuiMessage *imsg;
    struct MsgPort *port = window->UserPort;
    BOOL terminated = FALSE;
        
    while (!terminated)
    {
        Wait(1L << port->mp_SigBit);
        if ((imsg = (struct IntuiMessage *)GetMsg(port)) != NULL)
        {
            switch (imsg->Class)
            {
                case IDCMP_CLOSEWINDOW:
                    terminated = TRUE;
                    break;
            }
            ReplyMsg((struct Message *)imsg);
        }
    }
}

static void clean_exit(CONST_STRPTR s)
{
    if (s) PutStr(s);

    // Give back allocated resourses
    if (pen1 != -1) ReleasePen(cm, pen1);
    if (pen2 != -1) ReleasePen(cm, pen2);
    if (window) CloseWindow(window);

    exit(0);
}



ColorMap

[edit | edit source]

So far we have only used the SetXPen() functions to select the drawing pens. Now we look how we can change the red, green blue values of the pens.

If the colormap belongs us

  • We can change the colors as we like with the LoadRGB..., SetRGB... functions. We'll get a private colormap when we open a private screen.

We want draw into a window on a public Screen.

  • We have to query a shared pen with the ObtainBestPenA() function. Otherwise we would change the colors used by other applications.

ColorMap Index 0. (the 'light grey' on Amiga 4-color mode) Runs the fastest!


Drawing with Polygon Areas

[edit | edit source]

Area operations are area functions allowing a fast drawing of filled polygons and ellipses.

In order to use this functions you need a struct AreaInfo which must be connected to the rastport. The area buffer must be WORD-aligned (it must have an even address). You need five bytes per vertex:

#define AREA_SIZE 200
WORD areaBuffer[AREA_SIZE];
struct AreaInfo areaInfo = {0};
memset(areabuffer, 0, sizeof(areabuffer));
InitArea(&areaInfo, areaBuffer, sizeof(areaBuffer)/5);
rastPort->AreaInfo = &areaInfo;

The AreaInfo structure list the points that make up the filled shape.

struct AreaInfo
{
    WORD   *VctrTbl;	     /* ptr to start of vector table */
    WORD   *VctrPtr;	     /* ptr to current vertex */
    BYTE    *FlagTbl;	      /* ptr to start of vector flag table */
    BYTE    *FlagPtr;	      /* ptrs to areafill flags */
    WORD   Count;	     /* number of vertices in list */
    WORD   MaxCount;	     /* AreaMove/Draw will not allow Count>MaxCount*/
    WORD   FirstX,FirstY;    /* first point for this polygon */
};

Additionally, you need a TmpRas structure. It should have the same width and height as the bitmap you want to draw into. The graphics workspace is served by a data structure called

struct TmpRas
{
    BYTE *RasPtr;
    LONG Size;
};
/* unoptimized for 32bit alignment of pointers */


#define WIDTH 400
#define HEIGHT 300
PLANEPTR rasplane = AllocRaster(WIDTH, HEIGHT);
struct TmpRas tmpRas = {0};
InitTmpRas(&tmpRas, rasPlane, WIDTH * HEIGHT);
rastPort->TmpRas = &tmpRas;

It is now possible to produce filled polygon 'areas' using the InitArea, AreaMove, AreaDraw and AreaEnd functions as long as a TmpRas struct is set up which can plot out an outline of a shape and flood fill it with a specified color.

struct TmpRas *InitTmpRas( struct TmpRas *tmpRas, PLANEPTR buffer, long size )
void InitArea( struct AreaInfo *areaInfo, APTR vectorBuffer, long maxVectors )
ULONG SetOutlinePen( struct RastPort *rp, unsigned long pen )

LONG AreaMove( struct RastPort *rp, long x, long y )
LONG AreaDraw( struct RastPort *rp, long x, long y )
LONG AreaEnd( struct RastPort *rp )

InitArea() 	Initializes the AreaInfo
AreaMove() 	Closes open polygon and sets start point for a new one. You don't have to connect the end point to the start point.
AreaDraw() 	Add point to vector buffer
AreaEllipse() 	Add filled ellipse to vector buffer
AreaEnd() 	Start filling operation

An area is initialised with the InitTmpRas which sets up a working area for areas and flood fills in the Raster and InitArea which sets up a vector buffer to store area co-ordinates, the pointers are then associated with the Window's Raster structure to be eventually rendered on the screen. To create an area, use AreaMove to set the start position, then each subsequent position is then drawn with AreaDraw using absolute x,y co-ordinates, you do not need to join the last co-ordinate with the first position, as AreaEnd will do this for you. Notice that I have used SetAPen and SetOutlinePen to set the colour of the area and the lines around the shapes. The InitTmpRas requires a pointer to a TmpRas structure, a pointer to a buffer in Chip memory (which is allocated using AllocMem) for the area of the window (width height x 8) and the size of the buffer. AreaInfo requires a pointer to a AreaInfo structure, a buffer to store x,y vectors and a max number of vectors (buffer * 2 /5) which uses Word values rather than UBYTE as it has to be word aligned. The structures are then assigned to the Rastport e.g. rp->AreaInfo and rp->TmpRas before using the areas.

Flood(rp,mode,x,y)

If negative coordinates are passed to these AreaMove() AreaDraw() functions the display gets corrupted. Moreover, even for further calls with no negative coordinates the new drawings are also corrupted.

Drawing functions

A line is drawn by setting the pen position with Move() to the start position and with Draw() to the end position.

For the Flood() function you have to attach a TmpRas to the rastport

Move() 	Change pen position
Draw() 	Draw line from pen position to given coordinates
DrawEllipse() 	Draw an ellipse
DrawCircle() 	Draw a circle (macro in graphics/gfxmacros.h)
PolyDraw() 	Draw connected lines from an array of points
WritePixel() 	Write a single pixel
ReadPixel() 	Read the pen value of a pixel
EraseRect() 	Fill rectangular area with current backfill hook (TODO: what's this?)
SetRast() 	Fill entire drawing area with given pen
RectFill() 	Fill rectangular area with current rastport settings
Flood() 	Flood fill an arbitrary shape

Data moving
BltBitMap() 	Copy rectangular area
BltBitMapRastPort() 	Copy rectangular area
BltRastPortBitMap() 	Copy rectangular area (AROS extension)
ClipBlit() 	Copy rectangular area with layers and clip rects. Use this if you want to blit into a window
BltClear() 	Set a memory block to zero. On classic Amigas this block has to be in chip ram.
BltMaskBitMapRastPort() 	Copy rectangular area with using a mask
BltPattern() 	Draw a rectangular pattern into a bitmap
BltTemplate() 	Draw a rectangular pattern into a bitmap
BitMapScale() 	Copy a rectangular area and change its size
ScalerDiv() 	Helper function for BitMapScale()
ScrollRaster() 	Move rectangular area within a bitmap
ScrollRasterBF() 	Move rectangular area, the vacated space is filled with EraseRect()
WriteChunkyPixels() 	Write rectangular area from array with pen values
WritePixelArray8() 	Write rectangular area from array with pen values
ReadPixelArray8() 	Read rectangular area into memory
WritePixelLine8() 	Write horiz. line from an array with pen values
ReadPixelLine8() 	Read horiz. line from an array into memory



Filling 2D polygon area

[edit | edit source]
/*
    Copyright � 1995-2014, The AROS Development Team. All rights reserved.
    $Id$
*/

#include <intuition/intuition.h>
#include <graphics/gfxmacros.h>
#include <graphics/gfx.h>
#include <devices/rawkeycodes.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <aros/debug.h>

#define MAX_POINTS 50

#define MODE_ADDPOINTS 1
#define MODE_MOVEPOINTS 2

#define MSGMOUSEX ( ((msg->MouseX - win->BorderLeft) < 0) ? 0 : \
    	    	    ((msg->MouseX - win->BorderLeft) >= win->GZZWidth) ? win->GZZWidth - 1 : \
		    (msg->MouseX - win->BorderLeft) )

#define MSGMOUSEY ( ((msg->MouseY - win->BorderTop) < 0) ? 0 : \
    	    	    ((msg->MouseY - win->BorderTop) >= win->GZZHeight) ? win->GZZHeight - 1 : \
		    (msg->MouseY - win->BorderTop) )

static struct Window *win;
static struct RastPort *winrp, *drawrp;
static struct BitMap *drawbm;
static struct AreaInfo ai;
static struct TmpRas tr;
static void *trbuf;
static UBYTE aibuf[(MAX_POINTS + 1) * 5];
static WORD mode, actpoint, hipoint, numpoints;
static WORD outlinepen = -1, testfillpen = -1;
static BOOL outlinemode, testfill;
static WORD points[MAX_POINTS + 1][2];
static char wintitle[256];

#include "areatest2_fillpoly.h"

static void cleanup(char *msg)
{
    if (msg) printf("areatest2: %s\n", msg);
    
    if (outlinepen != -1) ReleasePen(win->WScreen->ViewPort.ColorMap, outlinepen);
    if (testfillpen != -1) ReleasePen(win->WScreen->ViewPort.ColorMap, testfillpen);
    if (drawbm) FreeBitMap(drawbm);
    if (drawrp) FreeRastPort(drawrp);
    
    if (trbuf)
    {
    	FreeRaster(trbuf, win->GZZWidth, win->GZZHeight);
    }
    
    if (win) CloseWindow(win);
    exit(0);    
}

static void updatetitle(void)
{
    char *title = "AreaTest2";
    
    switch(mode)
    {
    	case MODE_ADDPOINTS:
	    snprintf(wintitle,
	    	     sizeof(wintitle),
		     "Create points [%2d/%2d]. Press RETURN when done.",
		     actpoint + 1, MAX_POINTS);
	    title = wintitle;
	    break;

    	case MODE_MOVEPOINTS:
	    snprintf(wintitle,
	    	     sizeof(wintitle),
		     "Move points. Press RETURN to make new shape.");
	    title = wintitle;
	    break;
	    
    }
    
    SetWindowTitles(win, title, (char *)~0);
    
}

static void makewin(void)
{
    win = OpenWindowTags(0, WA_Title, (IPTR)"AreaTest2",
    	    	    	    WA_InnerWidth, 320,
			    WA_InnerHeight, 256,
			    WA_GimmeZeroZero, TRUE,
			    WA_CloseGadget, TRUE,
			    WA_DepthGadget, TRUE,
    	    	    	    WA_DragBar, TRUE,
			    WA_IDCMP, IDCMP_MOUSEBUTTONS |
			    	      IDCMP_MOUSEMOVE |
				      IDCMP_CLOSEWINDOW |
				      IDCMP_VANILLAKEY |
				      IDCMP_RAWKEY,
			    WA_Activate, TRUE,
			    WA_ReportMouse, TRUE,
			    TAG_DONE);
    if (!win) cleanup("Can't open window!");
    
    winrp = win->RPort;
     
    InitArea(&ai, aibuf, sizeof(aibuf) / 5);
    trbuf = AllocRaster(win->GZZWidth, win->GZZHeight);
    if (!trbuf) cleanup("TmpRas buffer allocation failed!");
    InitTmpRas(&tr, trbuf, RASSIZE(win->GZZWidth, win->GZZHeight));
    
    drawbm = AllocBitMap(win->GZZWidth, win->GZZHeight, 0, BMF_MINPLANES, win->RPort->BitMap);
    if (!drawbm) cleanup("Can't allocate draw bitmap!");
    
    drawrp = CreateRastPort();
    if (!drawrp) cleanup("Can't allocate draw rastport!");
    drawrp->BitMap = drawbm;
    
    drawrp->AreaInfo = &ai;
    drawrp->TmpRas = &tr;

    outlinepen = ObtainBestPen(win->WScreen->ViewPort.ColorMap, 0xFFFFFFFF,
    	    	    	    	    	    	    	    	0x00000000,
							     	0x00000000,
								OBP_FailIfBad, FALSE,
								TAG_DONE);
    
    testfillpen = ObtainBestPen(win->WScreen->ViewPort.ColorMap, 0x44444444,
    	    	    	    	    	    	    	    	 0x44444444,
							     	 0x44444444,
								 OBP_FailIfBad, FALSE,
								 TAG_DONE);

}

static void hilightpoint(WORD point)
{
    WORD x = points[point][0];
    WORD y = points[point][1];
    
    //kprintf("hilightpoint %d,%d\n", x, y);
    
    SetABPenDrMd(winrp, 2, 0, COMPLEMENT);
    Move(winrp, x - 3, y - 3);
    Draw(winrp, x + 3, y - 3),
    Draw(winrp, x + 3, y + 3);
    Draw(winrp, x - 3, y + 3),
    Draw(winrp, x - 3, y - 3);
}

static void clear(struct RastPort *rp)
{
    SetABPenDrMd(rp, 2, 0, JAM1);
    RectFill(rp, 0, 0, win->GZZWidth - 1, win->GZZHeight - 1);
}

static void paint(void)
{
    int i;
    
    if (numpoints == 0) return;
    
    switch(mode)
    {
    	case MODE_ADDPOINTS:
	    SetABPenDrMd(winrp, 1, 0, JAM1);
	    Move(winrp, points[0][0], points[0][1]);
	    PolyDraw(winrp, numpoints, (WORD *)points);	    
	    break;
	    
	case MODE_MOVEPOINTS:
	    clear(drawrp);
	    SetABPenDrMd(drawrp, testfill ? testfillpen : 1, 0, JAM1);
	    if (outlinemode)
	    {
	    	SetOutlinePen(drawrp, outlinepen);
	    }
	    else
	    {
	    	drawrp->Flags &= ~AREAOUTLINE;
	    }
	    
	    if (!testfill)
	    {
		AreaMove(drawrp, points[0][0], points[0][1]);
		for(i = 1; i < numpoints; i++)
		{
	    	    AreaDraw(drawrp, points[i][0], points[i][1]);
		}
		AreaEnd(drawrp);
	    }
	    else
	    {
	    	MyFillPolygon(drawrp, points, numpoints);
	    }
	    
	    BltBitMapRastPort(drawbm, 0, 0, winrp, 0, 0, win->GZZWidth, win->GZZHeight, 192);
	    break;
    }
}

static WORD pointundermouse(LONG x, LONG y)
{
    LONG i, dist;
    LONG best_i = 0, best_dist = 0x7fffffff;

    for(i = 0; i < numpoints; i++)
    {
	dist = (points[i][0] - x) * (points[i][0] - x) +
	       (points[i][1] - y) * (points[i][1] - y);

	if (dist < best_dist)
	{
	    best_dist = dist;
	    best_i = i;
	}
    }

    return (best_dist < 200) ? best_i : -1;
}

static void savepoly(WORD n)
{
    char s[200];
    BPTR fh;
    BOOL ok = FALSE;
    LONG err;
    
    snprintf(s, sizeof(s), "PROGDIR:polygon%d.dat", n);
    
    if ((fh = Open(s, MODE_NEWFILE)))
    {
    	WORD i = numpoints;
	
	if (Write(fh, &i, sizeof(i)) == sizeof(i))
	{
	    for(n = 0; n < numpoints; n++)
	    {
	    	i = points[n][0];		
		if (Write(fh, &i, sizeof(i)) != sizeof(i)) break;
		
		i = points[n][1];
		if (Write(fh, &i, sizeof(i)) != sizeof(i)) break;
		
	    }
	    
	    if (n == numpoints) ok = TRUE;
	}
	
	err = IoErr();
	
    	Close(fh);
    }
    else
    {
    	err = IoErr();
    }
    
    if (!ok) 
    {
    	Fault(err, "Saving failed", s, sizeof(s));
    }
    else
    {
    	strcpy(s, "Saved polygon");
    }

    SetWindowTitles(win, s, (char *)~0);
    Delay(75);
    updatetitle();

}

static BOOL loadpoly(WORD n)
{
    char s[200];
    BPTR fh;
    BOOL ok = FALSE;
    LONG err;
    WORD *temppoints;
    
    snprintf(s, sizeof(s), "PROGDIR:polygon%d.dat", n);
    
    if ((fh = Open(s, MODE_OLDFILE)))
    {
    	WORD i;
	
	if (Read(fh, &i, sizeof(i)) == sizeof(i))
	{
	    if ((temppoints = malloc(sizeof(WORD) * 2 * i)))
	    {	    
		for(n = 0; n < i; n++)
		{
		    if (Read(fh, &temppoints[n * 2], sizeof(WORD)) != sizeof(WORD)) break;
		    if (Read(fh, &temppoints[n * 2 + 1], sizeof(WORD)) != sizeof(WORD)) break;

		}

		if (n == i)
		{
		    numpoints = i;
		    for(i = 0; i < n; i++)
		    {
		    	points[i][0] = temppoints[i * 2];
		    	points[i][1] = temppoints[i * 2 + 1];
		    }
		    
		    ok = TRUE;
		}
		
		free(temppoints);
	    }
	    
	}
	
	err = IoErr();
	
    	Close(fh);
    }
    else
    {
    	err = IoErr();
    }
    
    if (!ok) 
    {
    	Fault(err, "Loading failed", s, sizeof(s));
    	SetWindowTitles(win, s, (char *)~0);
    	Delay(75);
    	updatetitle();
    }
  
    return ok;

}

static void handleall(void)
{
    struct IntuiMessage *msg;
    WORD    	    	 i;
    BOOL    	    	 quitme = FALSE, lmbdown = FALSE;
    
    mode = MODE_ADDPOINTS;
    updatetitle();
    clear(winrp);
    
    while(!quitme)
    {
    	WaitPort(win->UserPort);
    	while((msg = (struct IntuiMessage *)GetMsg(win->UserPort)))
	{
	    switch(msg->Class)
	    {
	    	case IDCMP_CLOSEWINDOW:
		    quitme = TRUE;
		    break;
		    
		case IDCMP_MOUSEBUTTONS:
		    if (msg->Code == SELECTDOWN)
		    {
		    	lmbdown = TRUE;
			
			switch(mode)
			{
		    	    case MODE_ADDPOINTS:
				points[actpoint][0] = MSGMOUSEX;
				points[actpoint][1] = MSGMOUSEY;
				actpoint++;
				numpoints++;
				if (numpoints == MAX_POINTS)
				{
			    	    mode = MODE_MOVEPOINTS;
				    actpoint = -1;
				    hipoint = -1;
				}
				paint();
				updatetitle();
				break;
				
			    case MODE_MOVEPOINTS:
			    	actpoint = pointundermouse(MSGMOUSEX, MSGMOUSEY);
			    	break;
				
			}
		    }
		    else if (msg->Code == SELECTUP)
		    {
		    	lmbdown = FALSE;
			
			switch(mode)
			{
			    case MODE_MOVEPOINTS:
			    	actpoint = -1;
				hipoint = -1;
				break;
			}
		    }
		    
		    break;
		    
		case IDCMP_MOUSEMOVE:
		    switch(mode)
		    {
		    	case MODE_MOVEPOINTS:
			    if ((actpoint >= 0) && lmbdown)
			    {
			    	points[actpoint][0] = MSGMOUSEX;
				points[actpoint][1] = MSGMOUSEY;
				paint();
			    }
			    else if (!lmbdown)
			    {
			    	WORD new_hipoint = pointundermouse(MSGMOUSEX, MSGMOUSEY);
				
				if (new_hipoint != hipoint)
				{
				    if (hipoint >= 0) hilightpoint(hipoint);
				    hipoint = new_hipoint;
				    if (hipoint >= 0) hilightpoint(hipoint);
				}
			    }
			    
			    break;
		    }
		    break;
		    
		case IDCMP_VANILLAKEY:
		    switch(msg->Code)
		    {
		    	case 27:
			    quitme = TRUE;
			    break;
			    
		    	case 13:
			    switch(mode)
			    {
			    	case MODE_ADDPOINTS:
				    if (numpoints >= 2)
				    {
			    	    	mode = MODE_MOVEPOINTS;
				    	actpoint = -1;
					hipoint = -1;
					paint();
					updatetitle();
				    }
				    break;
				    
				case MODE_MOVEPOINTS:
				    actpoint = numpoints = 0;
				    mode = MODE_ADDPOINTS;
				    clear(winrp);
				    updatetitle();
				    break;
			    }
			    break;

    	    	    	case '4':
			    if (mode == MODE_MOVEPOINTS)
			    {
				for(i = 0; i < numpoints; i++)
				{
			    	    if (points[i][0] > 0) points[i][0]--;				
				}
				hipoint = -1;
				paint();
			    }
			    break;

    	    	    	case '6':
			    if (mode == MODE_MOVEPOINTS)
			    {
				for(i = 0; i < numpoints; i++)
				{
			    	    if (points[i][0] < win->GZZWidth - 1) points[i][0]++;				
				}
				hipoint = -1;
				paint();
			    }
			    break;

    	    	    	case '8':
			    if (mode == MODE_MOVEPOINTS)
			    {
				for(i = 0; i < numpoints; i++)
				{
			    	    if (points[i][1] > 0) points[i][1]--;				
				}
				hipoint = -1;
				paint();
			    }
			    break;

    	    	    	case '2':
			    if (mode == MODE_MOVEPOINTS)
			    {
				for(i = 0; i < numpoints; i++)
				{
			    	    if (points[i][1] < win->GZZHeight - 1) points[i][1]++;				
				}
				hipoint = -1;
				paint();
			    }
			    break;
			
			case 'o':
			case 'O':
			    outlinemode = !outlinemode;
			    if (mode == MODE_MOVEPOINTS)
			    {
			    	hipoint = -1;
				paint();
				SetWindowTitles(win, outlinemode ? "Outline Mode: ON" : "Outline Mode: OFF", (char *)~0);
				Delay(30);
				updatetitle();
			    }
			    break;
			    
			case 'f':
			case 'F':
			case 'R':
			case 'r':
			    testfill = !testfill;
			    if (mode == MODE_MOVEPOINTS)
			    {
			    	hipoint = -1;
				paint();
				SetWindowTitles(win, testfill ? "Test Fillroutine: ON" : "Test Fillroutine: OFF", (char *)~0);
				Delay(30);
				updatetitle();
			    }
			    break;
		    }
		    break;
		    
		case IDCMP_RAWKEY:
		    switch(mode)
		    {
		    	case MODE_MOVEPOINTS:
			    if (lmbdown && actpoint >= 0)
			    {
			    	BOOL changed = FALSE;
				
			    	switch(msg->Code)
				{
				    case CURSORLEFT:
				    	if (points[actpoint][0] > 0)
					{
					    points[actpoint][0]--;
					    changed = TRUE;
					}
					break;
					
				    case CURSORRIGHT:
				    	if (points[actpoint][0] < win->GZZWidth - 1)
					{
					    points[actpoint][0]++;
					    changed = TRUE;
					}
				    	break;
					
				    case CURSORUP:
				    	if (points[actpoint][1] > 0)
					{
					    points[actpoint][1]--;
					    changed = TRUE;
					}
					break;
					
				    case CURSORDOWN:
				    	if (points[actpoint][1] < win->GZZHeight - 1)
					{
					    points[actpoint][1]++;
					    changed = TRUE;
					}
				    	break;
				    	
				} /* switch(msg->Code) */
				
				if (changed) paint();
				
			    } /* if (!lmbdown && hipoint >= 0) */
			    else
			    {
			    	switch(msg->Code)
				{
				    case RAWKEY_F1:
				    case RAWKEY_F2:
				    case RAWKEY_F3:
				    case RAWKEY_F4:
				    case RAWKEY_F5:
				    case RAWKEY_F6:
				    case RAWKEY_F7:
				    case RAWKEY_F8:
				    case RAWKEY_F9:
				    case RAWKEY_F10:
				    	if (msg->Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
					{
				    	    savepoly(msg->Code - RAWKEY_F1 + 1);
					}
					else
					{
					    loadpoly(msg->Code - RAWKEY_F1 + 1);
					    hipoint = -1;
					    paint();
					}
					break;
				    
				}
			    }
			    break;
			    			    
			case MODE_ADDPOINTS:
			    switch(msg->Code)
			    {
				    case RAWKEY_F1:
				    case RAWKEY_F2:
				    case RAWKEY_F3:
				    case RAWKEY_F4:
				    case RAWKEY_F5:
				    case RAWKEY_F6:
				    case RAWKEY_F7:
				    case RAWKEY_F8:
				    case RAWKEY_F9:
				    case RAWKEY_F10:
				    	if (!(msg->Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
					{
					    if (loadpoly(msg->Code - RAWKEY_F1 + 1))
					    {
					    	hipoint = -1;
						actpoint = -1;
						mode = MODE_MOVEPOINTS;
					    	paint();
					    }
					}
					break;
			    }
			    break;
			    
		    } /* switch(mode) */
		    break;
		    
	    } /* switch(msg->Class) */
	    ReplyMsg((struct Message *)msg);
	    
	} /* while((msg = (struct IntuiMessage *)GetMsg(win->UserPort))) */
	
    } /*while(!quitme) */
    
}

int main(void)
{
    makewin();
    handleall();
    cleanup(0);    
    return 0;
}


BitMaps

[edit | edit source]

Whilst opening a screen or window sets up a RastPort automatically, a BitMap struct has to be setup by yourself. A BitMap tells the graphics library where in memory the drawing area is located and how it is arranged.

struct BitMap
{
    UWORD   BytesPerRow;
    UWORD   Rows;
    UBYTE   Flags;
    UBYTE   Depth;
    UWORD   pad;
    PLANEPTR Planes[8];
};
static struct Window *win;
static struct BitMap *drawbm;
static struct RastPort *winrp, *drawrp;
static struct AreaInfo ai;
static struct TmpRas tr;
static void *trbuf;

/* Initialize the RastPort and link the BitMap to it. */
InitRastPort(&rastPort);
rastPort.BitMap = &bitMap;
struct RastPort *offscreen_buffer_rp;
offscreen_buffer_rp &myBufferRP;
  • Allocate a window.
  • Create a friend bitmap the same size as your windows visible area as an offscreen buffer.
  • Create a second friend bitmap that is some sensible multiple of your tile size.
  • Render your tiles into the second bitmap.

If you draw to an off-screen bitmap you create your own temporary rastport and then blit the temporary bitmap into the window's rastport.

When you create your offscreen bitmap, make sure it has a rastport of its own that has the same properties as that used by the window (things like palette etc.).

    screen = LockPubScreen(NULL);
    if (screen)
    {
        printf("screen bitmap %p\n", screen->RastPort.BitMap);
        bitmap = AllocBitMap(400, 300, 32, BMF_MINPLANES | /*BMF_DISPLAYABLE | */ BMF_SPECIALFMT | SHIFT_PIXFMT(PIXFMT_ABGR32), screen->RastPort.BitMap);

If you want it completely flicker free you may instead want to do that to an off screen bitmap, update the text, and then blit the whole thing to the window.

 struct RastPort rp;
 struct * Bitmap PBM, ULONG screenDepth, flags, BOOL isStandardBM; 
 InitRastPort (& rp); 
 screenDepth GetBitMapAttr = (pWin-> WScreen-> RastPort.BitMap, BMA_DEPTH); 
 isStandardBM GetBitMapAttr = (pWin-> WScreen-> RastPort . BitMap, BMA_FLAGS) & BMF_STANDARD; 
 flags = (FindPort ("FBlit")?0:BMF_DISPLAYABLE) | (isStandardBM? 0: BMF_MINPLANES);

/* friend_bitmap clones the existing bitmap's pixel format in graphics RAM and has all the correct alignment for blitting and stuff */
 PBM = AllocBitMap (IMAGE_WIDTH, IMAGE_HEIGHT, screenDepth, flags, pWin-> WScreen-> RastPort.BitMap)
if (! PBM) return / * quit if allocation failed * /
 = rp.BitMap PBM, / * binds to BitMap RastPort * / 
 WriteChunkyPixels (& rp, 0, 0, IMAGE_WIDTH-1 IMAGE_HEIGHT-1 Image IMAGE_WIDTH);

 /* draw the Bitmap in the window */
 BltBitMapRastPort (struct Bitmap * bitmap_source, src_x WORD, WORD src_y,
                    struct * RastPort rastport_dest, dest_x WORD, WORD dest_y,
                    WORD width, WORD height UBYTE minterm); bitmap_source
static struct RastPort *Alloctemprp(struct RastPort *rp)
{
   struct Layer_Info *li;
   struct Layer *l;
   struct BitMap *tempbm;
   ULONG bmwidth, bmheight, bmdepth;

   bmwidth  = GetBitMapAttr(rp->BitMap,BMA_WIDTH);
   bmheight = GetBitMapAttr(rp->BitMap,BMA_HEIGHT);
   bmdepth  = GetBitMapAttr(rp->BitMap,BMA_DEPTH);

   if(tempbm = AllocBitMap(bmwidth,bmheight,bmdepth,BMF_MINPLANES,rp->BitMap))
   {
       if (rp && rp->Layer)
       {
          if ((li = NewLayerInfo()) != NULL)
          {
              if ((l = CreateUpfrontHookLayer(li,
                                             tempbm,
                                             rp->Layer->bounds.MinX,
                                             rp->Layer->bounds.MinY,
                                             rp->Layer->bounds.MaxX,
                                             rp->Layer->bounds.MaxY,
                                             LAYERSIMPLE,
                                             LAYERS_NOBACKFILL,
                                             NULL)) != NULL)
             {
                InstallLayerHook(l,(struct Hook *)rp->Layer->BackFill);
                return (l->rp);
             }
             DisposeLayerInfo(li);
          }
       }
       FreeBitMap(tempbm);
   }
   return (NULL);
}

static void Freetemprp(struct RastPort *rp)
{
    struct Layer_Info *li;
    struct BitMap *bm = NULL;
    if(rp)
    {
        bm = rp->BitMap;
    }
    if (rp && rp->Layer)
    {
       li = rp->Layer->LayerInfo;
//       InstallLayerInfoHook(li,LAYERS_NOBACKFILL);
       InstallLayerHook(rp->Layer,LAYERS_NOBACKFILL);
       DeleteLayer(0,rp->Layer);
       DisposeLayerInfo(li);
    }
    if(bm)
    {
        FreeBitMap(bm);
    }
}

Allocate a bitmap with friend bitmap set to something else than NULL. Otherwise, bitmap with buffers in regular memory will be created - such thing cannot be locked (especially os-hosted modes). On hosted display driver's bitmap is not a pixel array at all. It's some underlying OS' blob instead. It could be emulated (temporarily allocate pixel array, copy data, then copy back upon unlock).

It is better to have the picture in a back buffer if your window has a size gadget or does simple refreshing so that you can easily redraw exposed areas.

Always use GetBitMapAttr() to query the depth, e.g. ULONG depth = GetBitMapAttr(screen->RastPort.BitMap, BMA_DEPTH); Otherwise you'll get "8" even for 24 and 32 bit screens. Not sure if superbitmap is prepared for true color screens or if AROS implementation of superbitmap windows is broken requires additional tests. My suggestion is that you leave out superbitmap windows. You can use ClipBlit() to blit into a window.

The code where you either RectFill() the background or WritePixelArray() the image behind the text needs to be moved/duplicated/put into a function and called from your inner loop. Alternatively you could install a backfill hook and do EraseRect() in both cases.

A hook is a custom function you write in order to be able to handle a specific situation that arises from intercepting the main code (such as, processing a message). The function must be designed to accept three arguments, whose order and type is given.

Clipping

[edit | edit source]

Avoid hacks such as direct rendering into a screen's struct BitMap. You'll blindly overwrite display's contents. RastPorts are needed for PROPER drawing, they are responsible for clipping and storing hidden parts in separate bitmaps. Though, direct drawing on a BitMap is allowed ONLY if it's completely your screen and OS doesn't display anything on it, even titlebar. Or of its your own BitMap in memory.

Bitmaps which you have created with AllocBitMap() don't have a clipping rectangle. This means that you trash memory when you draw outside the bitmap. You can either take care about your drawing operations or you can install a clipping rectangle. There are two possibilities:

Using the tag RPTAG_ClipRectangle in SetRPAttrsA():

    struct Rectangle rect = {0, 0, 399, 299};
    SetRPAttrs(&rastPort, RPTAG_ClipRectangle, &rect, TAG_DONE);

Installing a layer:

    li = NewLayerInfo())
    rastPort.Layer = CreateUpfrontLayer(li, rastPort->BitMap, 0, 0, width - 1, height - 1, 0, NULL))

    ...

    DeleteLayer(0,rastPort.Layer)
    DisposeLayerInfo(li)

The latter is compatible with AmigaOS.

There are few different ways to copy one bitmap to another. BltBitMap (bitmap to bitmap - most prone to crashes), ClipBlit (rastport to rastport - destroy parts of destination) and BltBitmapRastPort (bitmap to rastport).

A minterm value (ABC, ABNC and ANBC) describing how the image must be copied

from blit.h:

#define ABC 0x80
#define ABNC 0x40
#define ANBC 0x20
#define ANBNC 0x10
#define NABC 0x08
#define NABNC 0x04
#define NANBC 0x02
#define NANBNC 0x01

minterm 0xC0 would be ABC|ABNC and minterm 0xE0 being ABC|ABNC|ANBC

However, this is not apparent when using a graphics card, and only some very specific work values. The value of 0xE0 (0xC0 is not supported) is to be used for a single copy of the image without modification.

BltBitMapRastPort supports 0xC0, BltMaskBitMapRastPort ignores it.

Here is the call to do to draw your image:

BltBitMapRastPort (PBM, 0, 0, pWin-> RPORT, dest_x, dest_y, IMAGE_WIDTH, IMAGE_HEIGHT, 0xE0);

Remember to release the Bitmap before leaving the program with the function FreeBitMap ().

Note that the AutoDoc FreeBitMap () recommends calling WaitBlit () before releasing the Bitmap to be sure that nothing is being written in it.

 
/* Spy is a toy to view the next screen as "iconified" in a window on the current screen (using graphics library BitMapScale function). */

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>

#include <graphics/scale.h>

#include <stdio.h>

static const char version[] = "$VER: Spy 41.1.2 (29.08.2008) by Olivier Tigréat";

void redraw(struct Window *spy_window, struct BitMap *wbm, struct Screen *observed_screen);

void redraw(struct Window *spy_window, struct BitMap *wbm, struct Screen *observed_screen)
{
    
    struct RastPort temprp;
    InitRastPort(&temprp);
    temprp.BitMap = wbm;

    struct BitScaleArgs bms_args;
    bms_args.bsa_SrcBitMap = observed_screen->RastPort.BitMap;
    bms_args.bsa_DestBitMap = temprp.BitMap;
    
    bms_args.bsa_Flags = 0;

    bms_args.bsa_SrcWidth = observed_screen->Width;
    bms_args.bsa_SrcHeight = observed_screen->Height;

    bms_args.bsa_SrcX = 0;
    bms_args.bsa_SrcY = 0;
    bms_args.bsa_DestX = 0;
    bms_args.bsa_DestY = 0;
    bms_args.bsa_XSrcFactor = observed_screen->Width;
    bms_args.bsa_XDestFactor = spy_window->GZZWidth;
    bms_args.bsa_YSrcFactor = observed_screen->Height;
    bms_args.bsa_YDestFactor = spy_window->GZZHeight;

    BitMapScale(&bms_args);

    ClipBlit(             &temprp,                      0,                     0,
                spy_window->RPort, spy_window->BorderLeft, spy_window->BorderTop,
             spy_window->GZZWidth,  spy_window->GZZHeight,                0x00C0);

    DeinitRastPort(&temprp);

}

int main()
{
    int retval   = 0;                           /* Return code for main() (Shell error code) */
    int closewin = FALSE;                       /* Flag used to end program */
    struct IntuiMessage *imsg;                  /* Structure to store Intuition message data */
    ULONG signals;                              /* User interaction reported by signals */
    struct Screen *screen = NULL, *observed_screen = NULL;
    struct Window *spy_window = NULL;           /* Our Spy window  */
    struct BitMap *scaledBitMap = NULL;         /* BitMap structure for scaled representation */
    IPTR depth = 0 ;

        
    if (NULL == (screen = LockPubScreen(NULL)))
    {
        retval = RETURN_ERROR;
        puts("LockPubScreen() failed to lock current screen");
    }
    
    else
        depth = GetBitMapAttr(screen->RastPort.BitMap, BMA_DEPTH);
        
    if (depth == 0)
    {
        retval = RETURN_ERROR;
        puts("GetBitMapAttr() failed to get depth of screen");
    }
    
    else
        observed_screen = screen->NextScreen;
        
    if (!(scaledBitMap = AllocBitMap(                   screen->Width,
                                                       screen->Height,
                                                                depth,
                                                      BMF_DISPLAYABLE,
                                     observed_screen->RastPort.BitMap) ) )
    {
        UnlockPubScreen(NULL,screen);
        retval = RETURN_ERROR;
        puts("AllocBitMap() failed to allocate/initialise BitMap");
    }
    
    else
    {
        struct TagItem initial_tags[] = 
        {
            {          WA_Width , 160                                  },
            {         WA_Height , 120                                  },
            {           WA_Left , 400                                  },
            {            WA_Top , screen->BarHeight + 1                },
            {       WA_BackFill , (IPTR)LAYERS_NOBACKFILL              },
            {  WA_GimmeZeroZero , FALSE                                },
            {    WA_SizeBBottom , TRUE                                 },
            {        WA_DragBar , TRUE                                 },
            {        WA_RMBTrap , TRUE                                 },
            {    WA_DepthGadget , TRUE                                 },
            {    WA_CloseGadget , TRUE                                 },
            {     WA_SizeGadget , TRUE                                 },
            {  WA_NoCareRefresh , TRUE                                 },
            {          WA_IDCMP , IDCMP_CLOSEWINDOW|IDCMP_CHANGEWINDOW },
            {       WA_MinWidth , 80                                   },
            {      WA_MinHeight , 80                                   },
            {       WA_MaxWidth , -1                                   },
            {      WA_MaxHeight , -1                                   },
            {          WA_Title , (IPTR)"Spy"                          },
            {       WA_BackFill , (IPTR)LAYERS_NOBACKFILL              },
            {                     TAG_DONE                             }
        };
        
        
        if ( !(spy_window = OpenWindowTagList(NULL,initial_tags)))
        {
            UnlockPubScreen(NULL,screen);
            closewin = TRUE;
            retval = RETURN_ERROR;
            puts("OpenWindowTags() failed to open spy window");
        }
        
        else
        {
            UnlockPubScreen(NULL,screen);
            redraw(spy_window,scaledBitMap,observed_screen);
    
            while((closewin == FALSE))
            {
                signals = Wait(1L << spy_window->UserPort->mp_SigBit | SIGBREAKF_CTRL_C); /* Wait for an event! */
                if (signals & (1L << spy_window->UserPort->mp_SigBit))
                {
                    while ((imsg = (struct IntuiMessage *)GetMsg(spy_window->UserPort)))
                    {
                        switch (imsg->Class)
                        {
                            case IDCMP_CLOSEWINDOW:                     /* Check here if Close Window selected */
                                closewin = TRUE;                        /* so while loop will end there */
                                break;
                            case IDCMP_CHANGEWINDOW:
                                redraw(spy_window,scaledBitMap,observed_screen);
                                break;
                            case IDCMP_REFRESHWINDOW:
                                redraw(spy_window,scaledBitMap,observed_screen);
                                break;
                            default:
                                puts("Unknown IDCMP message");
                        } /* switch (imsg->Class) */
                           ReplyMsg((struct Message *)imsg);
                       } /* while ((imsg = (struct IntuiMessage *)GetMsg(spy_window->UserPort))) */
                } /* if(signals & (1L << spy_window->UserPort->mp_SigBit)) */
                if (signals & SIGBREAKF_CTRL_C)
                {
                    puts("Spy execution aborted with CTRL_C signal");
                    closewin = TRUE;
                } /* if (signals & SIGBREAKF_CTRL_C) */
            } /* while((closewin == FALSE)) */
        } /* else after if( !(spy_window... */
    } /* else after else if (!(scaledBitMap... */
    
    if (closewin == TRUE)
    {
        if (scaledBitMap) FreeBitMap(scaledBitMap);
        if (spy_window) CloseWindow(spy_window);             /* Close window */
        spy_window = NULL;
    }

    if(retval)
    {
        PrintFault(IoErr(), "spy");
    }
    return retval;
}

using a 256 colour IFF to C, the palette is mostly black, but the screen is in a truecolour mode? Image data contains just pen numbers. Doesn't IFF2C create a color table? Its just a picture for an about box. PPaint gives me an array of 256 values, labelled 'palette'. How do I get this into the screen palette?

Do I need to extract the palette from the image separately and if so, how do I set my screen to use it? You can use SA_Colors attribute for OpenScreenTags() Or you can use LoadRGB32() from graphics.library Another thing: image data must be (UBYTE *) rather than (UWORD *) or you'll get a corrupt image because of wrong endianness.

Am I thinking about this the right way? Is there an easier way to do it? It depends what you really want to do. If you want to load an image and blit it to the screen it's likely better to use the Datatype system.

Technically, a struct BitMap should be allocated in MEMF_PUBLIC while the bitplanes should be MEMF_CHIP. This way the pointers to the bitplanes can be in Fast RAM while the bitplanes themselves will not be. As a temporary workaround, propose allocating bitplanes with MEMF_ANY on pc-i386. Is it even necessary to allocate bitplanes from chipmem anyway, since AFAIK displayable bitmaps are allocated through HIDDs on 68k? And should struct BitMap not get the same type of memory as its bitplanes?

Masks

[edit | edit source]

You set the bltmask to a word aligned single bit plane in chip ram the same size as the bitmap to be blitted. A 0 in the mask means nothing is copied and a 1 means the source bitmap is copied through to the destination.

Transparency effects are possible with Masks (BltMaskBitMapRastPort() which moves a rectangular region from a BitMap to a RastPort through a mask - software rendered).

Just point an "unlayered" rastport at it and the overhead will be low. Certain bookkeeping will be respected, such as the rastport mask. The first thing most of the rastport routines do is check to see if there is a layer hanging off of the rastport, and if there is they get into a clipping kind of thing. BltMaskBitMapRastPort() performs its function in a non-optimal way, so that it CAN do layered operations. Reserving one of the source operands for layer masking or something.

A minterm value (supported are ABC, ABNC and ANBC) describing how the image must be copied

#define ABC 0x80
#define ABNC 0x40
#define ANBC 0x20
#define ANBNC 0x10
#define NABC 0x08
#define NABNC 0x04
#define NANBC 0x02
#define NANBNC 0x01

A minterm that specifies one channel as a 'switch' between source and background must contain 4 terms. (2 that include 'mask set' && source, 2 that include 'mask clear' && background)

However, this is not apparent when using a graphics card, and only some very specific work values. The value of 0xE0 (0xC0 is not supported) is to be used for a single copy of the image without modification.

minterm 0xC0 would be ABC|ABNC and minterm 0xE0 being ABC|ABNC|ANBC. BltBitMapRastPort supports 0xC0, BltMaskBitMapRastPort ignores it. 0xC0 is an 'AND' minterm - the result is the ANDing of channels A and B.

You just cannot trust the 'minterm' as used by a function to be the same 'minterm' as used in an actual blit.

{
/* printf("%s: mask= %p\n", __FUNCTION__, mask); */
if (mask) {
BltMaskBitMapRastPort(bm, 0, 0, _rp(obj), dst_x, dst_y, w, h, ABC|ABNC|ANBC, mask);
} 
else 
{
BltBitMapRastPort(bm, 0, 0, _rp(obj), dst_x, dst_y, w, h, ABC|ABNC);
}
}
 	
if (scaled_bm) {
WaitBlit();
FreeBitMap(scaled_bm);
}
 	
return 0;
}

Interleaved blits only affect opaque blits because the masks would have to be as large as the source image on an interleaved transparent blit. The transparent blits are executed in non-interleaved mode regardless of how it is stored. Also, you have to request interleaved mode with a specific flag when you allocate the bitmap/screen.

If source and dest bitmaps are interleaved, mask for BltMaskBitMapRastPort() must be interleaved/repeated too. It's not clear if this is a bug or a feature. If you try to blit from interleaved to interleaved then you must use one of those horrible repeating masks. Make the mask interleaved too, ie. repeat all lines in the mask <depth> times (which means also contain as much planes as the source bitmap) before the next line and so on.

Does this mean that i have to create the mask as a block which is word_aligned_width*height*depth bits large? Yes, but only if source bitmap is interleaved. Basically you then must repeat each line in the mask <numplane> times. Workaround for the problem

1-plane mask         interleaved mask in case of 3-plane source bm

11110000             11110000
11001100             11110000
00001111             11110000
                     11001100
                     11001100
                     11001100
                     00001111
                     00001111
                     00001111

Animation

[edit | edit source]

Amiga was special in that its OS is more closely adapted to how the hardware works than other OSes (less abstracted from hw). So much so that a lot of what follows is for backwards compatibility only now.

Sprites

[edit | edit source]

Most sprite stuff (mouse pointer #0) is almost completely moved away from graphics.library's handling. Only AllocSpriteData() is still used, in order to provide code reuse. The rest is done in monitorclass, it fits much better there, and many things can be done there in a simpler way than when using graphics.library sprite handling.

struct GelsInfo
{
    BYTE sprRsrvd;                     /* flag of which sprites to reserve from vsprite system */
    UBYTE Flags;                       /* system use */
    struct VSprite *gelHead, *gelTail; /* dummy vSprites for list management*/
    WORD *nextLine;                    /* pointer to array of 8 WORDS for sprite available lines */ 
    WORD **lastColor;                  /* pointer to array of 8 pointers for color-last-assigned to vSprites */ 
    struct collTable *collHandler;     /* addresses of collision routines */
    WORD leftmost, rightmost, topmost, bottommost;
    APTR firstBlissObj,lastBlissObj;    /* system use only */
};

AmigaOS(TM) GetSpriteData and copy the sprite graphics into it at your program init, then when you need to move them around or show them you ask the OS to use some sprites with GetSprite; when they don't need to be seen anymore you FreeSprite and when you don't need the spritegraphics anymore you FreeSpriteData.

AmigaOS(TM) FreeSprite frees 1 of the 8 hardware sprites that you reserved for use with GetSprite for your Viewport; returns it to be used by the OS (or another program that needs to use a sprite). FreeSpriteData should free the memory containing the sprite structure data - sprite's pixeldata etc.

Hardware

[edit | edit source]

AmigaOS(TM) used to have a function InitGels() which starts VSprite but not implemented in AROS atm...

   struct VSprite  *vsHead;
   struct VSprite  *vsTail;
   struct GelsInfo *gInfo;
   InitGels(vsHead, vsTail, gInfo);

Simple Sprites are always 16 bits wide (sprite.h)

GetSprite()  Attempts to allocates a sprite for exclusive use
ChangeSprite()  Modifies a Simple Sprite's image data
MoveSprite()  Changes a Simple Sprite's position
FreeSprite()  Relinquishes a sprite so it can be used by others

makeVSprite() and freeVSprite() functions

Virtual

[edit | edit source]

AROS has VSprites (gels.h) but are only used by the mouse pointer (sprite #0) which converts them to simple sprites and displays them.

struct VSprite {
    struct VSprite *NextVSprite;  /* system only */
    struct VSprite *PrevVSprite;
    struct VSprite *DrawPath;
    struct VSprite *ClearPath;
    WORD            OldY, OldX;
    WORD            Flags;        /* */
    WORD            Y, X;         /* */
    WORD            Height;
    WORD            Width;
    WORD            Depth;
    WORD            MeMask;       /* */
    WORD            HitMask;
    WORD           *ImageData;
    WORD           *BorderLine;
    WORD           *CollMask;
    WORD           *SprColors;
    struct Bob     *VSBob;
    BYTE            PlanePick;    /* */
    BYTE            PlaneOnOff;
    VUserStuff      VUserExt;
    };

Associated with the Amiga's Blitter chip so really only implemented in AROS m68k port...

struct Bob
  {
  WORD               Flags;     /* general purpose flags                 */
  WORD              *SaveBuffer;/* buffer for background save            */
  WORD              *ImageShadow; /* shadow mask of image                */
  struct Bob        *Before;   /* draw this Bob before Bobs on this list */
  struct Bob        *After;     /* draw this Bob after Bobs on this list */
  struct VSprite    *BobVSprite;/* this Bob's VSprite definition         */
  struct AnimComp   *BobComp;   /* pointer to this Bob's AnimComp def    */
  struct DBufPacket *DBuffer;   /* pointer to this Bob's dBuf packet     */
  BUserStuff         BUserExt;  /* Bob user extension                    */
  };

Collisions

[edit | edit source]

AROS has SetCollision() function....

Font Rendering

[edit | edit source]
see here

void Text(struct RastPort *rp, CONST_STRPTR string, ULONG count)

void SetFont(struct RastPort *rp, struct TextFont *textFont)

struct TextFont {
    struct Message tf_Message; /* reply message for font removal */
                               /* font name in LN       | used in this */
    UWORD   tf_YSize;          /* font height           | order to best */
    UBYTE   tf_Style;          /* font style            | match a font */
    UBYTE   tf_Flags;          /* preferences and flags / request. */
    UWORD   tf_XSize;      /* nominal font width */
    UWORD   tf_Baseline;   /* distance from the top of char to baseline */
    UWORD   tf_BoldSmear;  /* smear to affect a bold enhancement */

    UWORD   tf_Accessors;  /* access count */

    UBYTE   tf_LoChar;     /* the first character described here */
    UBYTE   tf_HiChar;     /* the last character described here */
    APTR    tf_CharData;   /* the bit character data */

    UWORD   tf_Modulo;     /* the row modulo for the strike font data */
    APTR    tf_CharLoc;    /* ptr to location data for the strike font */
                           /*   2 words: bit offset then size */
    APTR    tf_CharSpace;  /* ptr to words of proportional spacing data */
    APTR    tf_CharKern;   /* ptr to words of kerning data */
};

It is required to use SetDrMd(rp,mode) to set the drawing mode before writing the text. But if I use SetRPAttrs setting and SetDrMd drawing, the background does not show, but the text is not refreshing and it redraws again and again, and in the end it is unreadable. the background has to be refreshed before drawing the new text.

For rendering fonts we use BlitColorExpansion() method. In order to be accelerated, source bitmap passed to this method must be allocated via the same driver. The first possible (and the simplest) way to solve this problem is to store a separate font bitmap per driver. I really don't like it because it would be a huge waste of memory.

If the bitmap is created using PutTemplate() method. So why can't we use PutTemplate() directly to produce a text? If we look more carefully, we'll see that BltTemplate() is already used in some cases (for software-generated italic and underline styles). So may be just implement accelerated PutTemplate() and PutAlphaTemplate() and completely drop BlitColorExpansion() ?

Removed font->bitmap conversion and BlitColorExpansion() support. BltTemplate() is used for font rendering from now on.

BltTemplate—Draw a shape in a rectangle to the RastPort.

BltTemplate(SrcTemplate, SrcX, SrcMod, rp, DstX, DstY, SizeX, SizeY)

This function draws the image in the template into the RastPort in the current color and drawing mode at the specified position. The template is assumed not to overlap the destination.

If the template falls outside the RastPort boundary, it is truncated to that boundary.

Note: the SrcTemplate pointer should point to the "nearest" word (rounded down) of the template mask. Fine alignment of the mask is achieved by setting the SrcX bit offset within the range of 0 to 15 decimal.

 SrcTemplate  - pointer to the first (nearest) word of the template mask.
 SrcX         - x bit offset into the template mask (range 0..15).
 SrcMod       - number of bytes per row in template mask.
 rp           - pointer to destination RastPort.
 DstX, DstY   - x and y coordinates of the upper left corner of the destination for the blit.
 SizeX, SizeY - size of the rectangle to be used as the template.

SetAPen() sets the forground color SetBPen() sets the background color SetDrMd() sets the drawing mode Text() writes some text to the window TextLength() estimates the pixel length of a chunk of text RectFill() draws a rectangle SetFont() sets the font to the rastport SetSoftStyle() sets the style of the font (bold, italic, etc.) Move() sets some kind of invisible "turtle" to the rastport Draw() draws a line from the last "turtle" point to this one

When you scroll in your Textbox, you can either redraw everything or you can use ScrollWindowRaster() and refresh only what is scrolled-in. Scrolling makes only sense of course, if the scroll event scrolls less that a visible page.

Set the window layers backfill hook to NULL. AmigaOS will then NOT fill damaged areas with the current background color (usually pen #0). If you are taking always care of refreshing, you avoid flickering this way completely.

See w:Aros/Developer/Docs/Examples/GfxLibraryExample

TextEditor

[edit | edit source]

Usually one stores the entire text in an internal buffer and then draws only the part of the buffer which is visible. You draw each section separately and set font and color before you draw a section.

What you should be doing is drawing your text based upon the text stored in memory & a value indicating how far you have scrolled. Later on you can add optimisations that avoid redrawing the whole window, by using the blitter to scroll the already-visible part.

Do I need to use the rastport of windows? Yes, and use WFLG_GIMMEZEROZERO flag windows. Use ClearEOL() and ClearScreen() to clear end-of-line and the rest of the screen. These are functions from graphics.library great to use with text-editors.

How do I get the cursor in a window? You type in letter with SetAPen() and SetBPen() or use SetDrMd() with COMPLEMENT.

How do I save the text that scrolls out of the window? You save the text in buffers that is logic part of the text (the displayed is physic part). The best method to store buffers in text editors is to store it in list of strings.

How do I do to have different colours on the same row/line of text? That's simple. Write the text with Text() and the inner cursor of RastPort will move you to the end of the word/words. You change colors with SetAPen() and SetBPen() then write the rest of the line.

Word Processor

[edit | edit source]

How do I have different fonts in the same row/line of text? That's tricky! Then you want to make Word or WordWorth type program. You must write proper function that covers that. It requires more effort than simple text editor (not word processor).

Frankly, think the nitty-gritty of the display is nothing compared to the rest of the program - receiving input from keyboard, mouse and GUI inputs, maintaining the current text database, deciding how you are going to handle changes in window size. For instance, does text wrap or is it cut off at the right hand edge? If it wraps, you then have an extra line to display between the line on each side and you have to insert that new partial line into the database.

If you are serious about the job, you could start by designing and implementing the database first. You can always display the content using existing gadgets and classes. Then, later, you could write all the WYSIWYG functions to display it nicely.

The text is stored entirely in one textbuffer. You draw on the window the part of the text buffer that is visible on demand. Please do not introduce a concept of a second buffer that holds visible text.

You need to access the text fast, line by line. One recommendation is to have an array of pointers to a string. Each pointer points to a line of text. When you insert or delete a line, you only need to move the array of pointers, not the entire text. This is pretty fast, even if the text is a GB of size, and the overhead is pretty low. It is also very fast when you load the text to ram. You can load everything into one block (or several large blocks, if needed), and just set the pointers in the index array. Return code is then replaced by the 0-byte, or you write your visualization like this that you respect the return code. If a line is edited and gets larger, it gets its own memory buffer allocated from a memory pool.

However, in an AmigaOS environment, a far neater method is to use an Exec List node for each row of text. It is just as quick to run through a List when redrawing a display as it is to run through a table. On the other hand, Insert/Delete (row) operations become trivial, since you don't have to change any pointers to other rows. The entire text in the buffer can be stored in a single List with one Node per row. To display portion of the List, you only have to maintain a couple of pointers, one to the Node for the first row in the window, another to the last. Whenever the text is scrolled, you move the pointers one row at a time, using Prev() and Next() calls. The difficult part is maintaining control of lines of text that span two or more rows. Whenever the window width or font size is changed, or the user inserts text into a row, you have to revisit the split of text between the affected rows. It doesn't matter whether you use a lookup table or a List, the problem is the same.

but a list has more overhead. when editing small text files, none of the methods is a problem. The problem begins when the text file is very large. Many texteditors are really slow here, e.g. if you load a 1GB text file. Building such a linked list simply costs more time than an array. The insert or delete costs are not that drastic in an array, remember that nowadays CPUs can move gigabytes of memory in a second, and insert delete operations are rare compared to typing characters.

Need some formatting information along with the text. The formatting information is stored directly in the text of the line.

References

[edit | edit source]

Extra functions should be first to reserve/lock on LVOs used currently by MOS/OS4 extensions moving around AROS extensions and then reserve a block of LVOs (100?) at the end. After this block, AROS functions could be added.

OrRectRegionND() ClearRectRegionND() OrRegionRegionND() ClearRegionRegionND() XorRegionRegionND() XorRectRegionND() AreRegionsEqual() ScrollRegion() (*) SwapRegions() BltRastPortBitMap() (*) ShowImminentReset() (**)

Apart from the last one, I see the others as public extensions/improvements, not private functions. For example "ND" stands for "non destructive". The original region functions all "return" the resulting region in one of the source regions (i.e. they modify/destroy it).

AndRegionRegion():

   R2 = R1 intersected with R2;

The ND versions don't do that. AndRegionRegionND():

   R3 = R1 intersected with R2;

Of course you can simulate this with the standard (old) region functions, but just because you can simulate a RectFill() with tons of WritePixel() doesn 't mean it's a good idea to remove RectFill().

DPaint (1-3) uses RectFill() to fill the gadget area manually using JAM2 mode. Which does not make any sense, JAM2 should overwrite everything. After more test much later I finally found out the reason: DPaint pokes directly to RasPort and modifies RastPort->mintern[0] value so that bitplane 0 is inverted but bitplane 1 is drawn normally. AOS apparently recalculates all mintern values after each SetAPen(),BPen,DrMd call which are then used by any drawing routine that uses blitter. (mintern[0] = plane0, mintern[1] = plane1 etc..) Not probably worth the trouble to implement but it is interesting implementation default. (this even works on OS39).

The topic of extending 3.x libraries in a way not to hurt MOS/OS4 future compatibility is on the list of ABI V1

It was proposed to move as much as possible out of core libraries and place into some new components. For example these region manipulation functions could be moved into something like gfxutils.library. In addition this would decrease size of kickstart.

IMHO all API extensions should be carefully designed, and not implemented as hacks just because some single application's author says that it would be a nice thing. If we examine these functions carefully, we can note that they are 99% duplication of code. And for example AndRegionRegionND() is in fact just:

struct Region *r3 = CopyRegion(r1);
AndRegionRegion(r3, r2);

Looking at the internals we can consider CopyRegion() a really useful function because it's not just two or three lines of code and there's really no replacement. So should stay. This way we can decrease number of extensions.

Another example of this is SetError() function of dos.library. Internally it's two lines of code. Additionally it happens to be used by startup code. Currently it's not bad, but when m68k AROS appears, this means that applications built under m68k AROS will have no chance to run on for example classic AmigaOS, even with version checks. This function could be moved to libamiga.a at all. Additionally it could be renamed to SetErrorOutput() for AmigaOS4 compatibility.

http://www.amigacoding.com/index.php/Graphics.library

Taking a look at ms_transform() and ms_translate() callbacks in struct MonitorSpec. Names give a clue that their purpose is to translate screen coordinates somehow. Does this mean that our graphics subsystem can work in some another coordinates (not in pixels), automatically dealing with screen aspects and such? Looked at MorphOS code there, ms_translate() is a stub which just copy one Rectangle structure to another. ms_transform() simply returns.

When implementing GetMonitorList() and FreeMonitorList(), noticed that their original LVOs are already in use by StartScreenNotifyTagList() and EndScreenNotify() functions. LVOs do not conflict with anything except two private AmigaOS v3 functions, which are used for adding DisplayInfo to the system. They are used by disk-based video mode drivers (contents of DEVS:Monitors).

  • monitorclass is a BOOPSI class, it's not my invention.
  • In order to create a BOOPSI object, we have to call intuition.library/NewObject().
  • In AROS adding a display driver is done by graphics.library/AddDisplayDriverA(), which is AROS-specific function (since there's no public equivalent of this function in other OSes).
  • Creation of monitorclass object needs to be tied somehow with AddDisplayDriverA().
  • If we implement some another, AROS-specific API, then we in fact don't need monitorclass, we can directly base on this API.

Previous versions, the sync objects and MonitorSpecs were separate entities. graphics.library enumerated all syncs and created corresponding MonitorSpecs for them. There were following flaws:

  • A need to sync up data every time after some change in MonitorSpec or sync.
  • Data duplication (50% of sync object data duplicated MonitorSpec data).
  • Need for excessive code to copy duplicated data forth and back.
  • Excessive memory fragmentation due to (2).

Additionally, there was strict relation "one sync == one MonitorSpec". Sync object needed to know about associated MonitorSpec and MonitorSpec needed to know about associated sync. This further gave me an idea that MonitorSpec could be completely merged together. This way it would be managed in much better way (for example better implementation of variable/constant sync objects and better handling of MonitorSpecs without SpecialMonitor addition). The solution to make MonitorSpecs self-registering became quite obvious. This allowed to get rid of addition/removal code. When a display driver is disposed, its sync objects are disposed, and this causes automatic removal of associated MonitorSpecs from graphics.library list.

Monitor drivers is another sad chapter - there is no documentation on them whatsoever, only a set of hooks in the gfx library and the viewport structure (IIRC), the colormap is completely undocumented and carries a lot of payload around that was fitted into it because view and viewport were fully documented and could not be extended.

now moved to monitorclass

GfxNew() and GfxFree() are also invented by Commodore. In fact could use AllocMem()/FreeMem(), but with some code duplication, decided not to do it.

However internally operations on user interface are turned into operations on bitmaps. Operations on screens are turned into operations on ViewPorts. Some functionality is missing from graphics.library but is present in HIDD API, and it's safe to use it (these are information query calls, not rendering calls).

GetDisplayInfoData() doesn't provide this composition capability information. GetDisplayInfoData() returns needed pointers in reserved fields (this originally was implemented for CGX). However here we have one little quirk...

A display driver registers itself using graphics.library/AddDisplayDriverA(). But how will Intuition know that a new driver was registered (in order to create a monitorclass object) ?

There are again the following solutions:

  • Drivers could call Intuition's function (which in turn will call graphics function).
  • Graphics could call some Intuition's function in order to create a monitorclass object.
  • Intuition could patch AddDisplayDriverA() in order to add own code.
  • Display drivers can create BOOPSI objects themselves.

My opinions on them:

  • This would really make graphics inoperative without Intuition (no way to add a display driver). In addition it would not decrease amount of AROS-specific extensions (look at include/graphics/driver.h - these are absolutely needed things, and their amount will grow).
  • This is what i was going to do.
  • Hate OS patching itself!!! Especially when this can be done without patches. Additionally graphics.library needs to keep a pointer to monitorclass object in its DisplayInfoDataBase (in order for Intuition to be able to look it up by mode ID).
  • This causes code duplication in every driver and this sucks. This approach tends to turn into what is done in OS 3.1 with display driver.

In addition i would have to add this code to every display driver, this is time-consuming work breaking backwards compatibility.

Believe in MorphOS all this is managed by cgxsystem.library. There (like in classic AmigaOS) DisplayInfoDataBase is just a static list, and Intuition seems to have another static list. CGX just creates needed items and pushes all them into respective lists. We differ only in one place - we have no cgxsystem.library (which is entirely private to the CGX anyway) and this functionality is merged into graphics.library.

AROS is not adding new public library functions. It's adding a new public BOOPSI class, which is quite less prone to conflicts, especially if it is decided to implement MorphOS binary compatibility.

It looks like graphics' story is no less interesting than dos' one. Some things tell me that Amiga graphics.library API is just a wrapper on top of something. For example internal implementation of GetDisplayInfoData() is likely taglist-based, and looks like there are more options to query.

Read more here

There are two things about graphics.library code,

  • there is already support planar bitmaps in RAM (including ChipRAM)
  • graphics.library allocates temporary planarbm hidd objects from the pool and attaches bitmaps to them for doing operations on them.

This means that you could:

  • Add some attributes to planarbm class for processing displayable bitmaps (those which have copperlists). Not only bitmap but also a copperlist should be attached to temporary objects then.
  • Implement a driver which would be able to display such objects using Show or ShowViewPorts method.

For ABI v1 all fields in struct QueryHeader in graphics/displayinfo.h should be changed from ULONG to IPTR. This is because originally this structure is two TagItems. Under certain conditions it can be processed using taglist functions from utility.library.

The idea behind this is that we have GC (graphics context) HIDD object attached to every RastPort. This object has to be allocated/deallocated. In early days CreateRastPort() and DeleteRastPort() did this. Nowadays, GC object is allocated automagically on first attempt to use the RastPort. This object is then cached with usage counter attached. When some drawing operation begins, usage counter is incremented. It's decremented when the operation ends. These objects are supposed to be destroyed by some garbage collector which is not implemented yet. A DeInitRastPort() function exists which forces GC destruction. So, in fact, CreateRastPort() and DeleteRastPort() are obsolete.

Unlike AOS, AROS needs a rastport cleanup function (DeInitRastPort()), otherwise there may be a memory leak. That's why code is prepared for non-yet-existing rastport garbage collector. For cases where coders forget to use DeinitRastPort() in ported code (or theoretically for 68k binaries with a theoretical 68k emu). But the garbage collector would never know for sure if a rastport is definitely dead and will never be used again. Therefore even after killing driverdata/gc_object it's possible that some time later rastport is used again. In this case the driverdata/gc_object must be re-created from the info in the RastPort structure.

driverdata/gc_object garbage collection may have some negative effect, so the idea would be to use it only for rastports created (or cloned) manually. But not for rastports created with CreateRastPort() or CloneRastPort(), because coders in this cases would know that they have to free it with DeleteRastPort(). One such negative effect may be speed, but also the case where some new AROS rastport features are used (like the clip rectangle), which is not stored in the RastPort structure (instead in DriverData struct) and can therefore not be re-created in case the driverdata/gc_object got killed by garbage collection but rastport is used again later on. So in this case the app must use CreateRastPort() or CloneRastPort() to prevent garbage collection from ever happening.

RastPort cleanup and DeinitRastPort() de-mandation W.I.P.:

What do you do when you want to add some new feature and private space is full? The same as done now with ClipRect. Setting extended attribute allocates extension space. After this, yes, you need deinit. Added more private space on x86-64. !!! BINARY COMPATIBILITY BROKEN !!! Removed PatOrigin attributes to free up usable space in RastPort. See no rationale behind them, simply adjust pattern start address instead.

Pattern size is assumed to be equal to source bitmap. So, if the bitmap has size of (x, y), and we start not from (0, 0), but from some offset, where would it take extra pixels from? Well, such a feature could be implemented better as a separate function with extra arguments. Origin is for alignment of the pattern == like wraparound scrolling of the pattern. If for example you have a checkerfield pattern you may want to have it aligned in such a way that it "starts" exactly at the inner window area's (x,y) which depends on window border size because most windows are non-GZZ and (0,0) is over the window border.

Consider broken-by-design ClipRect removal. Nonfunctional in many cases, and gives lots of headache maintaining it. May be i was too harsh saying it. But, the first question. What was the rationale behind adding it ? Because in many cases having clipping support like this is easier and faster layers.libary/InstallClipRegion() sucks because when you for example install a clip region in a smart refresh layer which is partly hidden then this even may result in forth&back blits between layer cliprect bitmaps.

The main use I had in mind was for things like clipping Text() in multi column listviews, ie. where a lot of clippings may be done in a short time. Other OSes have it. But IMHO they have it because the philosophy of drawing is quite different. There's no backing store in those OSes. There is effectively no analog to Layers; when a window opens, it simply occupies part of the screen bitmap, and the hidden part goes to nowhere (yes, and the programmer has to redraw it every time). Like simple refresh windows in AOS (which are also the ones which work best in AROS, because smart refresh ones lack some optimization to avoid things like backing up/Restoring offscreen cliprect bitmaps even if a layer operation does not affect them at all). But nowadays even this OSes all support backing store because they need it for compositing.

if we install ClipRegion over a partially cover smart refresh window, two sets of obscured ClipRects are created. The first set is created from the whole window, and the second set represents first set intersected with ClipRegion. So, ClipRects from the second set are sub-clip-rects of the first one, and they have duplicated storage bitmaps. And every time the window is moved, we have to reassemble the pieces back, which requires two sets of blits. This is slow. But what if we extend ClipRects, making it possible to refer to a part of already existing bitmap? This way ClipRects from the second (clipped) set could reuse storage bitmaps from the first set. This would eliminate unneeded blits and reduce memory usage. Such optimization would make it working transparently for existing applications, unless some of them do rendering by manual walking through ClipRects. Additionally, ClipRegion allows to use more complex shapes than one rectangle.

Why headache? Because making it working correctly requires tons of new additions. Do you know about layers.library's DoHookClipRect() function? It's supposed to do the same as do_render_func() currently does. Just it ignores this ClipRect, it doesn't know about it. The general public, wishing to implement some complex operation on the RastPort, is expected to use it. And, if someone wants to set a ClipRect on the RastPort, this will make it working incorrectly. For special cases like this I would probably make a rastport flag changeable by SetRPAttrs() which tells a function like DoHookClipRects() whether to apply the rastport cliprect or not. The callback function itself is not supposed to have to deal with the rastport cliprect itself. added that some time after writing RPTAG_ClipRectangle stuff because it was an easy extension (no cliprectangle? -> assume bitmap bounds is cliprectangle) and I found it always stupid that apps could render outside bitmap.

  • RastPort made self-contained. There's no more mandatory extra data which needs to be explicitly freed. GC objects are built inside the RastPort. Consequently, GC operations are much faster.
  • CreateRastPort(), CloneRastPort(), FreeRastPort(), DeinitRastPort() moved to libarossupport, mainly to support old code. RastPort cleanup is still needed if ClipRect has been installed on it. This can be accomplished by FreeVec(rp->RP_Extra).
  • Correctly implemented RPTAG_PenMode, MorphOS-compatible.

AROS has a special feature which allows setting a clip rectangle for a rastport which can be also used for (rastports connected to) offscreen bitmaps. Use that to prevent rendering outside bitmap bounds (= memtrash/crash in AROS native and X11 error msg in AROS hosted/X11). May be it happened long time ago? I tested the change on Darwin-hosted with mungwall enabled. With X11 driver you will likely have an X11 pixmap being used for the bitmap, so no mem trashes - only X11 errors showing up.

The method HIDD_BM_PutPixel should use HIDDT_Pixel type as last argument. If 64bit compiler complains about loosing some portion of data due to 64bit (IPTR) to 32bit (HIDD_Pixel) scaling, then you need to fix body of your function in other way.

Point ExtendedNode.xln_Init to dummy function. Prevents WB2.0+ monitor driver crash. this xln_Init() function does. It gets two arguments: node pointer and flags. For MONITOR_SPEC_TYPE nodes flags value is put into ms_Flags member. Then, if MSF_REQUEST_SPECIAL bit is set, SpecialMonitor structure will be allocated and attached. So, this init function is responsible for setting some default values in the structure. I could implement it but decided not to do it because for AROS it's useless anyway.

Now about the "driver" itself. This program can be treated as part of graphics.library placed on disk. All it does is inserting data about display modes into graphics.library's mode database. The database is a structure pointed to by GfxBase->DisplayInfoDataBase. I started documenting things i figured out, bit had no time do to much. DisplayInfoDataBase documented here. All values in MonitorSpecs and mode ID properties are hardcoded constants. Some of them have different variants based on what chipset is specified by GfxBase->ChipRevBits. There's also a magic bit number 5 in GfxBase->Bugs. In fact this variable is some internal flags. If bit 5 is set, VGA drivers choose slightly different sets of constants. I guess this bit is set by VGAOnly program. There's also GfxBase->ProgData pointing to some stuff, i guess some chipset constants. Display drivers scan this memory, search for something in it, and copy into structure pointed to by VecInfo->Data of every display mode ID they create. I did not understand the exact purpose of these manipulations.

In fact i thought that if GfxBase->DisplayInfoDataBase is NULL, the driver will fail gracefully and will not do anything. Either i've mistaken or something is wrong. I think you just need to provide conditions for the driver to fail. It should neither insert own MonitorSpec nor attempt to insert database records. Populating mode DB is done using two private graphics.library functions: AddDisplayInfoData() and SetDisplayInfoData(). Their LVOs are occupied by AROS-specific functions. I don't remember values but you can google for function names, you'll find them easily. I also thought about a possibility to make these drivers working, but:

  • It requires to reverse engineer and to reimplement a major part of AmigaOS graphics.library which can be a copyright breach.
  • It's much easier to reimplement the whole thing in AROS own way. using AROS own infrastructure. If you look at AmigaOS implementation of mode database, you'll understand that AROS implementation is way better.

AROS PolyDraw, the rkm say, count is a word value, but on AROS its a long value. On MOS and OS4 it seem too a word value, because amiblitz work ok on MOS and OS4. Amiblitz fail on AROS 68k with endless drawing lines, because upper register contain high random value. Maybe its wrong in the includes then, but in the amiga developer CD file stand this. e.g. void PolyDraw( struct RastPort *, WORD, WORD * );

struct ViewPort {
   struct   ViewPort *Next;
   struct   ColorMap  *ColorMap;    /* table of colors for this viewport, if nil MakeVPort assumes default */
   struct   CopList  *DspIns;       /* user by MakeView() */
   struct   CopList  *SprIns;       /* used by sprite stuff */
   struct   CopList  *ClrIns;       /* used by sprite stuff */
   struct   UCopList *UCopIns;      /* User copper list */
   WORD     DWidth,DHeight;
   WORD     DxOffset,DyOffset;
   UWORD    Modes;
   UBYTE    SpritePriorities;       /* used by makevp */
   UBYTE    ExtendedModes;
   struct   RasInfo *RasInfo;
};

struct View {
   struct ViewPort *ViewPort;
   struct cprlist *LOFCprList;   /* used for interlaced and noninterlaced */
   struct cprlist *SHFCprList;   /* only used during interlace */
   WORD DyOffset,DxOffset;       /* complete View positioning offsets are +- adjustments to standard #s */
   UWORD   Modes;                /* such as INTERLACE, GENLOC */
};

/* these structures are obtained via GfxNew */
/* and disposed by GfxFree */

struct ViewExtra {
    struct ExtendedNode n;
    struct View *View;           /* backwards link */
    struct MonitorSpec *Monitor; /* monitors for this view */
};
/* this structure is obtained via GfxNew */
/* and disposed by GfxFree */

struct ViewPortExtra {
    struct   ExtendedNode n;
    struct   ViewPort *ViewPort;       /* backwards link */
    struct   Rectangle DisplayClip;    /* makevp display clipping information */
};
#define EXTEND_VSTRUCT	0x1000	/* unused bit in Modes field of View */
/* defines used for Modes in IVPargs */
#define GENLOCK_VIDEO	0x0002
#define LACE		0x0004
#define SUPERHIRES	0x0020
#define PFBA		0x0040
#define EXTRA_HALFBRITE 0x0080
#define GENLOCK_AUDIO	0x0100
#define DUALPF		0x0400
#define HAM		0x0800
#define EXTENDED_MODE	0x1000
#define VP_HIDE	0x2000
#define SPRITES	0x4000
#define HIRES		0x8000
#define VPF_A2024		0x40
#define VPF_AGNUS		0x20
#define VPF_TENHZ		0x20

struct RasInfo	/* used by callers to and InitDspC() */ {
   struct   RasInfo *Next;          /* used for dualpf */
   struct   BitMap *BitMap;
   WORD     RxOffset,RyOffset;      /* scroll offsets in this BitMap */
};

struct ColorMap {
    UBYTE    Flags;
    UBYTE    Type;
    UWORD    Count;
    APTR     ColorTable;
    struct   ViewPortExtra *cm_vpe;
    UWORD    *TransparencyBits;
    UBYTE    TransparencyPlane;
    UBYTE    reserved1;
    UWORD    reserved2;
    struct   ViewPort *cm_vp;
    APTR     NormalDisplayInfo;
    APTR     CoerceDisplayInfo;
    struct   TagItem *cm_batch_items;
    ULONG    VPModeID;
};

/* if Type == 0 then ColorMap is V1.2/V1.3 compatible */
/* if Type != 0 then ColorMap is V36	   compatible */
#define COLORMAP_TYPE_V1_2	0x00
#define COLORMAP_TYPE_V1_4	0x01
#define COLORMAP_TYPE_V36 COLORMAP_TYPE_V1_4	/* use this definition */

/* Flags variable */
#define COLORMAP_TRANSPARENCY	0x01
#define COLORPLANE_TRANSPARENCY	0x02
#define BORDER_BLANKING		0x04
#define BORDER_NOTRANSPARENCY	0x08
#define VIDEOCONTROL_BATCH	0x10
#define USER_COPPER_CLIP	0x20
struct	ExtendedNode	{
   struct      Node  *xln_Succ;
   struct      Node  *xln_Pred;
   UBYTE       xln_Type;
   BYTE        xln_Pri;
   char        *xln_Name;
   UBYTE       xln_Subsystem;
   UBYTE       xln_Subtype;
   LONG        xln_Library;
   LONG        (*xln_Init)();
};

#define SS_GRAPHICS          0x02
#define	VIEW_EXTRA_TYPE	        1
#define	VIEWPORT_EXTRA_TYPE     2
#define	SPECIAL_MONITOR_TYPE    3
#define	MONITOR_SPEC_TYPE       4

struct	MonitorSpec {
    struct      ExtendedNode  ms_Node;
    UWORD       ms_Flags;
    LONG        ratioh;
    LONG        ratiov;
    UWORD       total_rows;
    UWORD       total_colorclocks;
    UWORD       DeniseMaxDisplayColumn;
    UWORD       BeamCon0;
    UWORD       min_row;
    struct      SpecialMonitor  *ms_Special;
    UWORD       ms_OpenCount;
    LONG        (*ms_transform)();
    LONG        (*ms_translate)();
    LONG        (*ms_scale)();
    UWORD       ms_xoffset;
    UWORD       ms_yoffset;
    struct      Rectangle  ms_LegalView;
    LONG        (*ms_maxoscan)();            /* maximum legal overscan */
    LONG        (*ms_videoscan)();           /* video display overscan */
    UWORD       DeniseMinDisplayColumn;
    ULONG       DisplayCompatible;
    struct      List DisplayInfoDataBase;
    struct      SignalSemaphore DisplayInfoDataBaseSemaphore;
    ULONG       ms_reserved00;
    ULONG       ms_reserved01;
};

struct	SpecialMonitor {
    struct      ExtendedNode   spm_Node;
    UWORD       spm_Flags;
    int	(*do_monitor)();
    int	(*reserved1)();
    int	(*reserved2)();
    int	(*reserved3)();
    struct      AnalogSignalInterval hblank;
    struct      AnalogSignalInterval vblank;
    struct      AnalogSignalInterval hsync;
    struct      AnalogSignalInterval vsync;
};


Bitmaps

Bitmaps are the drawing sheets of AROS. Their coordinate systems have the zero point in the upper left corner. The x-axis goes from left to right, the y-axis from top to bottom. The number of possible colors depends on the depth of the bitmap:

Depth 	Colors
1 	2
2 	4
3 	8
4 	16
5 	32
6 	64
7 	128
8 	256
15 	32,768
16 	65,536
24 	16,777,216

The depths from 1 to 8 are LUT (look-up-table) modes. This means the red, green, and blue (RGB) value for each color is stored in a table. The index will then be stored as pen number in the bitmap.

The depths 15 and 16 are called high color, 24 is called true color. Unlike LUT mode the RGB value is stored directly in the bitmap.

The graphics library has only a limited support for high/true color modes. Some of the drawing functions work only with LUT modes. For full access you need the functions from the cybergraphics library.

GetBitMapAttr() Query bitmap attributes. (Don't peek at bitmap.)
AllocBitMap() 	Allocate and initialize bitmap
InitBitMap() 	Initialize bitmap
FreeBitMap() 	Free resources allocated by a bitmap
AllocRaster() 	Allocate a single bitplane
FreeRaster() 	Free a single bitplane
CopySBitMap() 	Syncronize super-bitmap (see Intuition)
SyncSBitMap() 	Syncronize super-bitmap
RastPort

The connection between the bitmaps and most drawing functions is done by a rastport. The rastport contains information about drawing pens, line and area patterns, drawing mode and text font.

You can connect more than one rastport to a bitmap. This allows a fast switch between different drawing configurations. Just copying a rastport is not possible in AROS, however; you have to use the function CloneRastPort().

Some Intuition elements, like screens and windows, already have a RastPort element. You can immediately use that for your drawing operations. Object Structure RastPort screen struct Screen RastPort window struct Window *RPort

If you create a bitmap and want to draw into it you have to create the rastport by yourself. Warning: this example is simplified and lacks checks of return values:

struct BitMap *bm = AllocBitMap(400, 300, 8, BMF_CLEAR, NULL); struct RastPort *rp = CreateRastPort(); rp->BitMap = bm; ... WritePixel(rp, 50, 30); ... FreeRastPort(rp); FreeBitMap(bm);

Pens

A rastport contains 3 pens. The A (foreground, primary) pen, B (background, secondary) pen and the O (area outline) pen. The latter is used by the area fill and flood fill functions.


Drawing modes

    JAM1: draw only with A pen.

    JAM2: draw bit 1 in a pattern with A pen, bit 0 with B pen

    COMPLEMENT: for each set bit, the state in the target is reversed

    INVERSVID: is used for text rendering
            JAM1|INVERSVID: transparent letters outlined in foreground color
            JAM2|INVERSVID: like previous, but letter in background color.

TODO: check whether the drawing modes are really available.


Pattern

The line pattern can be set with the macro SetDrPt(). The second parameter is a 16 bit pattern:

SetDrPt(&rastPort, 0xCCCC);

The pattern can be reset with:

SetDrPt(&rastPort, ~0);

For area patterns a macro SetAfPt() exists. The width is 16 bit, the height a power of two (2, 4, 8, 16, ...). The third parameter is the n in 2^n=height:

UWORD areaPattern[] =
{
    0x5555, 0xAAAA
};
SetAfPt(&rastPort, areaPattern, 1);

Colored patterns are possible with a negative value for the height. The number of bitplanes in the pattern must be the same as in the target bitmap.

Reset of area pattern:

SetAfPt(&rastPort, NULL, 0);

CloneRastPort() 	Copy rastport
CreateRastPort() 	Create rastport
InitRastPort() 	Initialize rastport
DeinitRastPort() 	Deinitialize rastport
FreeRastPort() 	Free rastport
SetAPen() 	Set primary pen
GetAPen() 	Get primary pen
SetBPen() 	Set secondary pen
GetBPen() 	Get secondary pen
SetOPen() 	Set area outline pen and switch outline mode on *
SetOutlinePen() 	Get area outline pen
GetOutlinePen() 	Get area outline pen
BNDRYOFF() 	Switch off area outline mode *
SetDrMd() 	Set drawing mode
GetDrMd() 	Get drawing mode
SetDrPt() 	Set line pattern *
SetAfPt() 	Set area pattern *
SetABPenDrMd() 	Set primary & secondary pen and drawing mode in one step
SetRPAttrsA() 	Set misc. drawing attributes
GetRPAttrsA() 	Get misc. drawing attributes
InitTmpRas() 	Initialize a TmpRas structure.
SetWriteMask() 	Set write mask

* Macro in graphics/gfxmacros.h

Functions

[edit | edit source]
LONG BltBitMap(struct BitMap *srcBitMap, LONG xSrc, LONG ySrc, struct BitMap *destBitMap, LONG xDest,      
               LONG yDest, LONG xSize, LONG ySize, ULONG minterm, ULONG mask, PLANEPTR tempA)
void BltTemplate(PLANEPTR source, LONG xSrc, LONG srcMod, struct RastPort *destRP, LONG xDest, 
                 LONG yDest, LONG xSize, LONG ySize) 
void BltBitMapRastPort(struct BitMap *srcBitMap, LONG xSrc, LONG ySrc, struct RastPort *destRP, 
                   LONG xDest, LONG yDest, LONG xSize, LONG ySize, ULONG minterm) 
void BltMaskBitMapRastPort(struct BitMap *srcBitMap, LONG xSrc, LONG ySrc, struct RastPort *destRP, 
                   LONG xDest, LONG yDest, LONG xSize, LONG ySize, ULONG minterm, PLANEPTR bltMask) 
void BltRastPortBitMap(struct RastPort *srcRastPort, LONG xSrc, LONG ySrc, struct BitMap *destBitMap, 
              LONG xDest, LONG yDest, ULONG xSize, ULONG ySize, ULONG minterm)

BOOL InitRastPort(struct RastPort *rp) 
void InitVPort(struct ViewPort *vp) 
ULONG MrgCop(struct View *view) 
ULONG MakeVPort(struct View *view, struct ViewPort *viewport) 
void LoadView(struct View *view) 
void WaitBlit() 
void SetRast(struct RastPort *rp, ULONG pen)

void Move(struct RastPort *rp, WORD x, WORD y) 
void Draw(struct RastPort *rp, LONG x, LONG y) 
ULONG AreaMove(struct RastPort *rp, WORD x, WORD y) 
ULONG AreaDraw(struct RastPort *rp, WORD x, WORD y) 
LONG AreaEnd(struct RastPort *rp)
void WaitTOF() 
void QBlit(struct bltnode *bn) 
void InitArea(struct AreaInfo *areainfo, void *buffer, WORD maxvectors) 
void SetRGB4(struct ViewPort *vp, ULONG n, ULONG r, ULONG g, ULONG b) 
void QBSBlit(struct bltnode *bn) 
void BltClear(void *memBlock, ULONG bytecount, ULONG flags) 
void RectFill(struct RastPort *rp, LONG xMin, LONG yMin, LONG xMax, LONG yMax) 
void BltPattern(struct RastPort *rp, PLANEPTR mask, LONG xMin, LONG yMin, LONG xMax, LONG yMax, ULONG byteCnt) 
void DrawEllipse(struct RastPort *rp, LONG xCenter, LONG yCenter, LONG a, LONG b) 
ULONG AreaEllipse(struct RastPort *rp, WORD cx, WORD cy, WORD a, WORD b) 
void LoadRGB4(struct ViewPort *vp, UWORD *colors, LONG count)

LONG ReadPixel(struct RastPort *rp, LONG x, LONG y) 
LONG WritePixel(struct RastPort *rp, LONG x, LONG y) 
BOOL Flood(struct RastPort *rp, ULONG mode, LONG x, LONG y) 
void PolyDraw(struct RastPort *rp, LONG count, WORD *polyTable) 
void SetAPen(struct RastPort *rp, ULONG pen) 
void SetBPen(struct RastPort *rp, ULONG pen) 
void SetDrMd(struct RastPort *rp, ULONG drawMode) 
void InitView(struct View *view) 
void InitBitMap(struct BitMap *bm, BYTE depth, UWORD width, UWORD height) 
void ScrollRaster(struct RastPort *rp, LONG dx, LONG dy, LONG xMin, LONG yMin, LONG xMax, LONG yMax)

PLANEPTR AllocRaster(ULONG width, ULONG height) (D0, D1)
void FreeRaster(PLANEPTR p, ULONG width, ULONG height) (A0, D0, D1)

BOOL AttemptLockLayerRom(struct Layer *l) (A5)
struct ExtendedNode *GfxNew(ULONG node_type) (D0)
void GfxFree(struct ExtendedNode *node) (A0)
void GfxAssociate(void *pointer, struct ExtendedNode *node) (A0, A1)

void BitMapScale(struct BitScaleArgs *bitScaleArgs) (A0)
UWORD ScalerDiv(UWORD factor, UWORD numerator, UWORD denominator) (D0, D1, D2)

void TextExtent(struct RastPort *rp, CONST_STRPTR string, ULONG count, struct TextExtent *textExtent) 
ULONG TextFit(struct RastPort *rp, CONST_STRPTR string, ULONG strLen, struct TextExtent *textExtent, struct TextExtent *constrainingExtent, LONG strDirection, ULONG constrainingBitWidth, ULONG constrainingBitHeight)

struct ExtendedNode *GfxLookUp(void *pointer) (A0)
ULONG VideoControl(struct ColorMap *cm, struct TagItem *tags) (A0, A1)
struct MonitorSpec *OpenMonitor(STRPTR monitor_name, ULONG display_id) (A1, D0)
LONG CloseMonitor(struct MonitorSpec *monitor_spec) (A0)
DisplayInfoHandle FindDisplayInfo(ULONG ID) (D0)
ULONG NextDisplayInfo(ULONG last_ID) (D0)

ULONG GetDisplayInfoData(DisplayInfoHandle handle, UBYTE *buf, ULONG size, ULONG tagID, ULONG ID) 
void FontExtent(struct TextFont *font, struct TextExtent *fontExtent) (A0, A1)

LONG ReadPixelLine8(struct RastPort *rp, LONG xstart, LONG ystart, ULONG width, UBYTE *array, struct RastPort *tempRP) (A0, D0, D1, D2, A2, A1)
LONG WritePixelLine8(struct RastPort *rp, LONG xstart, LONG ystart, ULONG width, UBYTE *array, struct RastPort *tempRP) (A0, D0, D1, D2, A2, A1)
LONG ReadPixelArray8(struct RastPort *rp, LONG xstart, LONG ystart, LONG xstop, LONG ystop, UBYTE *array, struct RastPort *temprp) (A0, D0, D1, D2, D3, A2, A1)
LONG WritePixelArray8(struct RastPort *rp, ULONG xstart, ULONG ystart, ULONG xstop, ULONG ystop, UBYTE *array, struct RastPort *temprp) (A0, D0, D1, D2, D3, A2, A1)

ULONG GetVPModeID(struct ViewPort *vp) 
ULONG ModeNotAvailable(ULONG modeID) 
WORD WeighTAMatch(struct TextAttr *reqTextAttr, struct TextAttr *targetTextAttr, struct TagItem *targetTags) 
void EraseRect(struct RastPort *rp, LONG xMin, LONG yMin, LONG xMax, LONG yMax) 
ULONG ExtendFont(struct TextFont *font, struct TagItem *fontTags) 
void StripFont(struct TextFont *font) 
UWORD CalcIVG(struct View *View, struct ViewPort *ViewPort) 
LONG AttachPalExtra(struct ColorMap *cm, struct ViewPort *vp) 
LONG ObtainBestPenA(struct ColorMap *cm, ULONG r, ULONG g, ULONG b, struct TagItem *tags) 
struct Region *ClearRegionRegionND(struct Region *R1, struct Region *R2)

void SetRGB32(struct ViewPort *vp, ULONG n, ULONG r, ULONG g, ULONG b) 
ULONG GetAPen(struct RastPort *rp) 
ULONG GetBPen(struct RastPort *rp) 
ULONG GetDrMd(struct RastPort *rp) 
ULONG GetOutlinePen(struct RastPort *rp) 
void LoadRGB32(struct ViewPort *vp, const ULONG *table) 
ULONG SetChipRev(ULONG ChipRev) 
void SetABPenDrMd(struct RastPort *rp, ULONG apen, ULONG bpen, ULONG drawMode) 
void GetRGB32(struct ColorMap *cm, ULONG firstcolor, ULONG ncolors, ULONG *table)

struct BitMap *AllocBitMap(ULONG sizex, ULONG sizey, ULONG depth, ULONG flags, struct BitMap *friend_bitmap) (D0, D1, D2, D3, A0)
void FreeBitMap(struct BitMap *bm) (A0)
LONG GetExtSpriteA(struct ExtSprite *sprite, struct TagItem *tags) (A2, A1)
ULONG CoerceMode(struct ViewPort *RealViewPort, ULONG MonitorID, ULONG Flags) (A0, D0, D1)
void ChangeVPBitMap(struct ViewPort *vp, struct BitMap *bm, struct DBufInfo *db) (A0, A1, A2)
void ReleasePen(struct ColorMap *cm, ULONG n) (A0, D0)
LONG ObtainPen(struct ColorMap *cm, ULONG n, ULONG r, ULONG g, ULONG b, ULONG flags) (A0, D0, D1, D2, D3, D4)
IPTR GetBitMapAttr(struct BitMap *bitmap, ULONG attribute) (A0, D1)
struct DBufInfo *AllocDBufInfo(struct ViewPort *vp) (A0)
void FreeDBufInfo(struct DBufInfo *db) (A1)
ULONG SetOutlinePen(struct RastPort *rp, ULONG pen) (A0, D0)
ULONG SetWriteMask(struct RastPort *rp, ULONG mask) (A0, D0)
void SetMaxPen(struct RastPort *rp, ULONG maxpen) (A0, D0)
void SetRGB32CM(struct ColorMap *cm, ULONG n, ULONG r, ULONG g, ULONG b) (A0, D0, D1, D2, D3)
void ScrollRasterBF(struct RastPort *rp, LONG dx, LONG dy, LONG xMin, LONG yMin, LONG xMax, LONG yMax) (A1, D0, D1, D2, D3, D4, D5)
ULONG FindColor(struct ColorMap *cm, ULONG r, ULONG g, ULONG b, ULONG maxpen) (A3, D1, D2, D3, D4)

struct ExtSprite *AllocSpriteDataA(struct BitMap *bitmap, struct TagItem *tagList) (A2, A1)
LONG ChangeExtSpriteA(struct ViewPort *vp, struct ExtSprite *oldsprite, struct ExtSprite *newsprite, struct TagItem *tags) (A0, A1, A2, A3)
void FreeSpriteData(struct ExtSprite *extsp) (A2)
void SetRPAttrsA(struct RastPort *rp, struct TagItem *tags) (A0, A1)
void GetRPAttrsA(struct RastPort *rp, struct TagItem *tags) (A0, A1)
ULONG BestModeIDA(struct TagItem *TagItems) (A0)
void WriteChunkyPixels(struct RastPort *rp, LONG xstart, LONG ystart, LONG xstop, LONG ystop, UBYTE *array, LONG bytesperrow) (A0, D0, D1, D2, D3, A2, D4)

struct RastPort *CreateRastPort() ()
struct RastPort *CloneRastPort(struct RastPort *rp) (A1)
void DeinitRastPort(struct RastPort *rp) (A1)
void FreeRastPort(struct RastPort *rp) (A1)
LONG AddDisplayDriverA(APTR gfxhidd, struct TagItem *tags) (A0, A1)

LONG WritePixels8(struct RastPort *rp, UBYTE *array, ULONG modulo, LONG xstart, LONG ystart, LONG xstop, LONG ystop, HIDDT_PixelLUT *pixlut, BOOL do_update)

LONG FillRectPenDrMd(struct RastPort *rp, LONG x1, LONG y1, LONG x2, LONG y2, HIDDT_Pixel pix, HIDDT_DrawMode drmd, BOOL do_update)

LONG DoRenderFunc(struct RastPort *rp, Point *src, struct Rectangle *rr, RENDERFUNC render_func, APTR funcdata, BOOL do_update) 
LONG DoPixelFunc(struct RastPort *rp, LONG x, LONG y, PIXELFUNC render_func, APTR funcdata, BOOL do_update)

struct Region *XorRegionRegionND(struct Region *R1, struct Region *R2) 
struct Region *XorRectRegionND(struct Region *Reg, struct Rectangle *Rect) 
BOOL ClearRegionRegion(struct Region *R1, struct Region *R2) 
struct Region *CopyRegion(struct Region *region) 
BOOL AreRegionsEqual(struct Region *R1, struct Region *R2) 
BOOL IsPointInRegion(struct Region *Reg, WORD x, WORD y) 
BOOL ScrollRegion(struct Region *region, struct Rectangle *rect, WORD dx, WORD dy) 
void SwapRegions(struct Region *region1, struct Region *region2) 
BOOL AndRectRect(struct Rectangle *rect1, struct Rectangle *rect2, struct Rectangle *intersect) 
struct Region *NewRectRegion(WORD MinX, WORD MinY, WORD MaxX, WORD MaxY) 
BOOL SetRegion(struct Region *src, struct Region *dest) 
void AndRectRegion(struct Region *Reg, struct Rectangle *Rect) (A0, A1)
BOOL OrRectRegion(struct Region *Reg, struct Rectangle *Rect) (A0, A1)
struct Region *NewRegion() ()
BOOL ClearRectRegion(struct Region *Reg, struct Rectangle *Rect) (A0, A1)
void ClearRegion(struct Region *region) (A0)
void DisposeRegion(struct Region *region) (A0)
BOOL XorRectRegion(struct Region *Reg, struct Rectangle *Rect) (A0, A1)
struct Region *OrRectRegionND(struct Region *Reg, struct Rectangle *Rect) (A0, A1)
struct Region *ClearRectRegionND(struct Region *Reg, struct Rectangle *Rect) (A0, A1)
struct Region *OrRegionRegionND(struct Region *R1, struct Region *R2) (A0, A1)
BOOL OrRegionRegion(struct Region *R1, struct Region *R2) (A0, A1)
BOOL XorRegionRegion(struct Region *R1, struct Region *R2) (A0, A1)
BOOL AndRegionRegion(struct Region *R1, struct Region *R2) (A0, A1)
struct Region *AndRectRegionND(struct Region *Reg, struct Rectangle *Rect) (A0, A1)
struct Region *AndRegionRegionND(struct Region *R1, struct Region *R2) (A0, A1)

WORD TextLength(struct RastPort *rp, CONST_STRPTR string, ULONG count) 
void Text(struct RastPort *rp, CONST_STRPTR string, ULONG count) 
void SetFont(struct RastPort *rp, struct TextFont *textFont) 
struct TextFont *OpenFont(struct TextAttr *textAttr) 
void CloseFont(struct TextFont *textFont) 
ULONG AskSoftStyle(struct RastPort *rp) 
ULONG SetSoftStyle(struct RastPort *rp, ULONG style, ULONG enable) 
void ClearEOL(struct RastPort *rp) 
void ClearScreen(struct RastPort *rp) 
void AskFont(struct RastPort *rp, struct TextAttr *textAttr) 
void AddFont(struct TextFont *textFont) 
void RemFont(struct TextFont *textFont)

void AddBob(struct Bob *bob, struct RastPort *rp) 
void AddVSprite(struct VSprite *vs, struct RastPort *rp) 
void DoCollision(struct RastPort *rp) 
void DrawGList(struct RastPort *rp, struct ViewPort *vp) 
void InitGels(struct VSprite *head, struct VSprite *tail, struct GelsInfo *GInfo) 
void InitMasks(struct VSprite *vs) 
void RemIBob(struct Bob *bob, struct RastPort *rp, struct ViewPort *vp) 
void RemVSprite(struct VSprite *vs) 
void SetCollision(ULONG num, VOID_FUNC routine, struct GelsInfo *GInfo) 
void SortGList(struct RastPort *rp) 
void AddAnimOb(struct AnimOb *anOb, struct AnimOb **anKey, struct RastPort *rp) 
void Animate(struct AnimOb **anKey, struct RastPort *rp) 
BOOL GetGBuffers(struct AnimOb *anOb, struct RastPort *rp, BOOL db) 
void InitGMasks(struct AnimOb *anOb) 
WORD GetSprite(struct SimpleSprite *sprite, WORD pick) 
void FreeSprite(WORD pick) 
void ChangeSprite(struct ViewPort *vp, struct SimpleSprite *s, void *newdata) 
void MoveSprite(struct ViewPort *vp, struct SimpleSprite *sprite, WORD x, WORD y) 
void LockLayerRom(struct Layer *l) 
void UnlockLayerRom(struct Layer *l) 
void SyncSBitMap(struct Layer *l) 
void CopySBitMap(struct Layer *l) 
void OwnBlitter() 
void DisownBlitter() 
struct TmpRas *InitTmpRas(struct TmpRas *tmpras, void *buffer, ULONG size) 
void SetRGB4CM(struct ColorMap *cm, WORD n, UBYTE r, UBYTE g, UBYTE b) (A0, D0, D1, D2, D3)

void FreeVPortCopLists(struct ViewPort *vp) 
void FreeCopList(struct CopList *coplist) 
void ClipBlit(struct RastPort *srcRP, LONG xSrc, LONG ySrc, struct RastPort *destRP, LONG xDest, 
              LONG yDest, LONG xSize, LONG ySize, UBYTE minterm) 
void FreeCprList(struct cprlist *cprList) 
struct ColorMap *GetColorMap(ULONG entries) 
void FreeColorMap(struct ColorMap *colormap) 
ULONG GetRGB4(struct ColorMap *colormap, LONG entry) 
void ScrollVPort(struct ViewPort *vp) (A0) 
struct CopList *UCopperListInit(struct UCopList *ucl, WORD n) 
void FreeGBuffers(struct AnimOb *anOb, struct RastPort *rp, BOOL db) 
void CBump(struct UCopList *ucl) 
void CMove(struct UCopList *ucl, void *reg, WORD value) 
void CWait(struct UCopList *ucl, WORD v, WORD h) 
LONG VBeamPos() 
void WaitBOVP(struct ViewPort *vp) 
void ShowImminentReset()