Aros/Developer/Docs/Libraries/Graphics

Introduction
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
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]; UWORD  wordreserved[7];   /* Used to be a node */ UBYTE  reserved[8];       /* For future use */ };
 * 1) ifndef GFX_RASTPORT_1_2
 * 1) 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.

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

Set Background Color
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

Another possibility is using WA_BackFill and a custom backfill hook.

Pens
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 );

ColorMap
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 want draw into a window on a public Screen.
 * 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 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
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:

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 */

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

BitMaps
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 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.).

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.

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
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.

Copy
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:
 * 1) define ABC 0x80
 * 2) define ABNC 0x40
 * 3) define ANBC 0x20
 * 4) define ANBNC 0x10
 * 5) define NABC 0x08
 * 6) define NABNC 0x04
 * 7) define NANBC 0x02
 * 8) 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.

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
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


 * 1) define ABC 0x80
 * 2) define ABNC 0x40
 * 3) define ANBC 0x20
 * 4) define ANBNC 0x10
 * 5) define NABC 0x08
 * 6) define NABNC 0x04
 * 7) define NANBC 0x02
 * 8) 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 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 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
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
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
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
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; };

Bobs
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
AROS has SetCollision function....

Font Rendering

 * 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 Aros/Developer/Docs/Examples/GfxLibraryExample

TextEditor
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
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.