# Aros/Developer/Docs/Libraries/Graphics

* 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

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.
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
WritePixel(rp,x,y) function plots a point with colour already set a separate SetAPen instruction.
Other instructions available
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
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.
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

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

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

### Filling 2D polygon area
## 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.
* 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:
Installing a layer:
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:
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:
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
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.
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

## 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.
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...
Simple Sprites are always 16 bits wide (sprite.h)
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.

#### Bobs

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

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

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.

## References

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).
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:
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 * );
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:
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.
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
TODO: check whether the drawing modes are really available.
Pattern