跳转到内容

Aros/开发者/文档/库/图形

来自 Wikibooks,开放世界中的开放书籍
Aros 维基百科的导航栏
Aros 用户
Aros 用户文档
Aros 用户常见问题解答
Aros 用户应用程序
Aros 用户 DOS Shell
Aros/用户/AmigaLegacy
Aros 开发文档
Aros 开发者文档
从 AmigaOS/SDL 移植软件
针对 Zune 初学者
Zune .MUI 类
针对 SDL 初学者
Aros 开发者构建系统
特定平台
Aros x86 完整系统 HCL
Aros x86 音频/视频支持
Aros x86 网络支持
Aros Intel AMD x86 安装
Aros 存储支持 IDE SATA 等
Aros Poseidon USB 支持
x86-64 支持
Motorola 68k Amiga 支持
Linux 和 FreeBSD 支持
Windows Mingw 和 MacOSX 支持
Android 支持
Arm Raspberry Pi 支持
PPC Power Architecture
其他
Aros 公共许可证

AROS 具有基于线的图形模式,这对于基于多边形和线框的绘图实用程序非常有用。

它还具有用于图像(图片)的位图操作功能。

  • 8 位(256 色)graphics.library
  • 高达 32 位(1400 万色)cybergraphics.library(它是 graphics 的扩展,因此如果需要,两者都需要打开)。

为了说明这一点,如果您只想将 RGB 图像显示到屏幕上,那么您使用 Cybergfx 块像素函数就不会有任何问题。但是,如果您实际上想进行一些块多边形填充并光栅化基元(点、线等),那么您将需要 graphics.library。


您需要了解 Window/Screen/BitMaps 与 RastPort(TmpRas)/ViewPort/... 背后的原理。

在某些情况下,需要使用 CloneRastport 和相关函数来替换 rastport 内容。理想情况下,应使用窗口 rastport 的克隆,而不是直接操作。

ViewPortAddress 返回与指定窗口关联的视窗的地址。视窗实际上是屏幕上显示窗口的视窗。如果您想在窗口中使用任何图形、文本或动画基元,并且该基元需要指向视窗的指针,则可以使用此调用。

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.


RastPort 的位图(控制笔的数量、绘制模式和图案)。

绘图函数(数据移动、区域操作、文本、裁剪、颜色)。

动画、图层、显示数据库、Blitter、Copper、其他。


线形图形

[编辑 | 编辑源代码]

与早期的 AmigaOS(TM) 一样,AROS 也提供了一些使用 graphics.library 与线形图形相关的函数。这些函数包括设置颜色、绘制点(像素)、绘制线条、矩形、圆形、图案、区域填充等等。大多数函数都需要一个指向 RastPort 的指针,RastPort 是一个特殊的公共结构(模板),它由 Window 或 Layer 调用自动创建,并由 Window->RPort(RastPort 地址)引用。该值可用于 SetAPen(rp,FrontPenNumber)、SetOPen(rp,OutlinePenNumber)、Move(rp,x,y) 和 Draw(rp,x,y) 以及 Text(rp,pointer_to_text,ext_length) 函数命令。

每当打开一个窗口时,也会准备一个绘制表面,并将信息存储在其自己的 rastport 中。每个绘图操作都涉及一个 rastport。如果您想直接绘制到窗口中,请使用窗口的 rastport。

在某些情况下,可能需要使用 CloneRastport 和相关函数来替换 rastport 内容。理想情况下,应使用窗口 rastport 的克隆,而不是直接操作。

RastPort 的内部结构如下所示。

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) 函数使用单独的 SetAPen() 指令设置的颜色绘制一个点。

其他可用的指令

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.

可以使用 SIMPLE_REFRESH(重绘)或 SMART_REFRESH 窗口或 SUPER_BITMAP(GIMMEZEROZERO)窗口来刷新窗口。

/* 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);
}

请查看 amilines 获取另一个示例,并查看 arosbattleships 获取一个 ASCII 版本的网格。

设置背景颜色

[编辑 | 编辑源代码]

如果您的窗口没有边框,您只需

SetRast(win->RPort, 2);

但是,如果您的窗口有边框,则需要考虑它们。

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

    ...
  }
}

另一种方法是使用 WA_BackFill 和自定义的 backfill hook。

如果您使用的是 graphics.library,那么无论您的显示器运行什么,笔都限制在 0-255 8 位范围内。

RectFill 始终绘制到 RastPort 中。之前在 RastPort 中的所有内容都将被覆盖。如果您的窗口在后台,则只会绘制未隐藏的部分。对于 SMART_REFRESH 窗口,隐藏的部分将被存储起来,并在窗口移至前台时显示。这包括受 RectFill 影响的部分。RectFill 始终使用笔 A 绘制,因此 SetBPen 对其没有影响。类似地,使用 JAM1 或 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);

在这些情况下,实际上并不重要您是否使用笔,因为在 RGB 显示器上,您可以分配一个笔并尽可能频繁地更改其颜色,而不会影响您已经渲染的任何内容。

如果您需要为 RGB 显示器上的区域笔设置任意颜色,则需要使用 LoadRGB32 来设置您选择的笔(或多支笔)的颜色。在 RGB 显示器上,您可以不断更改笔的颜色,而不会影响已渲染的像素。在索引显示器上,您必须担心首先找到与您所需颜色接近的合适笔。

如果您使用的是“笔 1”,然后使用 SetRGB32() 中的值更改“笔 1”的调色板值,只需分配一个笔,设置其 RGB 值,用它进行渲染,再次更改 RGB 值,再渲染一些内容,并在完成后释放该笔即可。您并不局限于使用单一笔,您可以分配用于区域、填充等的笔。关于 SetRGB32(),文档明确指出它比使用单个颜色索引的 LoadRGB32() 更慢。

在 AFA OS 68k、AROS 和 MOS 上,可以使用该标签来设置 RGB 前景和背景颜色。

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



调色板

[编辑 | 编辑源代码]

到目前为止,我们只使用了 SetXPen() 函数来选择绘图笔。现在,我们来看看如何更改笔的红、绿、蓝值。

如果调色板属于我们

  • 我们可以使用 LoadRGB...、SetRGB... 函数随意更改颜色。当我们打开一个私有屏幕时,我们将获得一个私有调色板。

我们想要绘制到公共屏幕上的窗口中。

  • 我们必须使用 ObtainBestPenA() 函数查询一个共享笔。否则,我们将更改其他应用程序使用的颜色。

调色板索引 0(Amiga 4 色模式下的“浅灰色”)。运行速度最快!


使用多边形区域绘制

[编辑 | 编辑源代码]

区域操作是区域函数,允许快速绘制填充的多边形和椭圆。

要使用这些函数,你需要一个 AreaInfo 结构体,它必须连接到 rastport。区域缓冲区必须是 WORD 对齐的(必须具有偶数地址)。每个顶点需要五个字节。

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

AreaInfo 结构体列出了构成填充形状的点。

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

此外,你还需要一个 TmpRas 结构体。它应该与你想要绘制的位图具有相同的宽度和高度。图形工作区由一个名为

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;

现在可以使用 InitArea、AreaMove、AreaDraw 和 AreaEnd 函数来生成填充的多边形“区域”,只要设置一个 TmpRas 结构体,它可以绘制形状的轮廓并用指定颜色填充它。

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

区域使用 InitTmpRas 初始化,它为区域设置一个工作区域并用 Raster 和 InitArea 进行填充,它设置一个向量缓冲区来存储区域坐标,然后将指针与窗口的 Raster 结构体关联,最终渲染到屏幕上。要创建区域,使用 AreaMove 设置起始位置,然后使用 AreaDraw 使用绝对 x,y 坐标绘制每个后续位置,不需要将最后一个坐标与第一个位置连接,因为 AreaEnd 会为你完成此操作。请注意,我使用 SetAPen 和 SetOutlinePen 设置区域的颜色和形状周围的线条。InitTmpRas 需要一个指向 TmpRas 结构体的指针,一个指向 Chip 内存中缓冲区的指针(使用 AllocMem 分配)用于窗口的区域(宽度高度 x 8)以及缓冲区的大小。AreaInfo 需要一个指向 AreaInfo 结构体的指针,一个用于存储 x,y 向量的缓冲区,以及一个最大向量数(缓冲区 * 2 /5),它使用 Word 值而不是 UBYTE,因为它必须是字对齐的。然后将结构体分配给 Rastport,例如 rp->AreaInfo 和 rp->TmpRas,然后再使用区域。

Flood(rp,mode,x,y)

如果将负坐标传递给这些 AreaMove() AreaDraw() 函数,则显示屏会损坏。此外,即使对没有负坐标的进一步调用,新的绘图也会损坏。

绘图函数

通过使用 Move() 将笔位置设置为起始位置,并使用 Draw() 将其设置为结束位置来绘制一条线。

对于 Flood() 函数,你必须将 TmpRas 附加到 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



填充 2D 多边形区域

[编辑 | 编辑源代码]
/*
    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;
}


虽然打开屏幕或窗口会自动设置 RastPort,但 BitMap 结构体需要你自己设置。BitMap 告诉图形库绘图区域位于内存中的哪个位置以及它是如何排列的。

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;
  • 分配一个窗口。
  • 创建一个与你的窗口可见区域大小相同的辅助位图,作为屏幕外缓冲区。
  • 创建一个第二个辅助位图,其大小是瓷砖大小的合理倍数。
  • 将你的瓷砖渲染到第二个位图中。

如果绘制到屏幕外位图,则创建自己的临时 rastport,然后将临时位图 blit 到窗口的 rastport 中。

创建屏幕外位图时,确保它拥有自己的 rastport,该 rastport 具有与窗口使用的 rastport 相同的属性(例如调色板等)。

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

如果你希望它完全无闪烁,你可能需要将其绘制到屏幕外位图中,更新文本,然后将整个内容 blit 到窗口中。

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

分配一个位图,其辅助位图设置为除 NULL 之外的其他值。否则,将在常规内存中创建具有缓冲区的位图 - 这种位图无法锁定(特别是操作系统托管模式)。在托管显示驱动程序上,位图根本不是像素数组。它只是一个底层操作系统的 blob。它可以被模拟(临时分配像素数组,复制数据,然后在解锁时复制回来)。

如果你的窗口有尺寸工具或进行简单的刷新,最好将图片放在后台缓冲区中,这样你就可以轻松地重新绘制暴露的区域。

始终使用 GetBitMapAttr() 查询深度,例如 ULONG depth = GetBitMapAttr(screen->RastPort.BitMap, BMA_DEPTH); 否则,即使对于 24 位和 32 位屏幕,你也会得到“8”。不确定超级位图是否已准备好用于真彩色屏幕,或者 AROS 中超级位图窗口的实现是否已损坏,需要额外的测试。我的建议是,不要使用超级位图窗口。你可以使用 ClipBlit() 将内容 blit 到窗口中。

你使用 RectFill() 填充背景或使用 WritePixelArray() 在文本后面绘制图像的代码需要移动/复制/放入一个函数,并从你的内部循环调用。或者,你可以在两种情况下都安装一个后台填充钩子,并在其中执行 EraseRect()。

钩子是你在代码中编写的自定义函数,用于处理从拦截主代码(例如处理消息)时出现的特定情况。该函数必须被设计为接受三个参数,其顺序和类型已给出。

避免使用直接渲染到屏幕的 struct BitMap 中的技巧。你将盲目地覆盖显示屏的内容。RastPort 是用于正确绘图的,它们负责裁剪和将隐藏的部分存储在单独的位图中。但是,只有在它完全是你的屏幕并且操作系统没有在上面显示任何东西(即使是标题栏)的情况下,才允许直接在 BitMap 上绘制。或者它是你自己内存中的 BitMap。

使用 AllocBitMap() 创建的位图没有裁剪矩形。这意味着当你绘制到位图之外时,你正在破坏内存。你可以处理你的绘制操作,或者你可以安装裁剪矩形。有两种可能性:

在 SetRPAttrsA() 中使用标签 RPTAG_ClipRectangle

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

安装一个层

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

    ...

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

后者与 AmigaOS 兼容。

有几种不同的方法可以将一个位图复制到另一个位图。BltBitMap(位图到位图 - 最容易崩溃)、ClipBlit(rastport 到 rastport - 销毁目标的部分)和 BltBitmapRastPort(位图到 rastport)。

一个最小项值(ABC、ABNC 和 ANBC),描述了图像必须如何复制

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

最小项 0xC0 将是 ABC|ABNC,最小项 0xE0 将是 ABC|ABNC|ANBC

但是,在使用图形卡时,这并不明显,只有某些非常特定的工作值。0xE0(不支持 0xC0)的值用于对图像进行一次无修改的复制。

BltBitMapRastPort 支持 0xC0,BltMaskBitMapRastPort 忽略它。

以下是绘制图像的调用方法

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

请记住,在使用函数 FreeBitMap () 退出程序之前,先释放位图。

请注意,AutoDoc FreeBitMap () 建议在释放位图之前调用 WaitBlit (),以确保没有写入它。

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

使用 256 色 IFF 到 C,调色板主要是黑色,但屏幕处于真彩色模式?图像数据仅包含笔号。IFF2C 不会创建颜色表吗?这只是一个关于框的图片。PPaint 为我提供了一个包含 256 个值的数组,标记为“调色板”。如何将其放入屏幕调色板?

是否需要分别从图像中提取调色板,如果是,如何设置我的屏幕以使用它?你可以使用 OpenScreenTags() 的 SA_Colors 属性。或者,你可以使用 graphics.library 中的 LoadRGB32()。另外:图像数据必须是 (UBYTE *) 而不是 (UWORD *),否则由于端序错误会导致图像损坏。

我的思路是否正确?是否有更简单的方法来实现?这取决于你真正想做什么。如果你想加载图像并将其 blit 到屏幕上,使用 Datatype 系统可能更好。

从技术上讲,struct BitMap 应该在 MEMF_PUBLIC 中分配,而位平面应该在 MEMF_CHIP 中分配。这样,指向位平面的指针就可以位于快速 RAM 中,而位平面本身不会位于快速 RAM 中。作为临时解决方法,建议在 pc-i386 上使用 MEMF_ANY 分配位平面。无论如何,是否有必要从 chipmem 分配位平面,因为据我所知,可显示的位图是在 68k 上通过 HIDD 分配的?struct BitMap 不应该与其位平面获得相同的内存类型吗?

你将 bltmask 设置为芯片 RAM 中与要 blit 的位图大小相同的字对齐的单比特平面。掩码中的 0 表示不复制任何内容,而 1 表示将源位图复制到目标位图。

可以使用掩码(BltMaskBitMapRastPort(),它通过掩码将矩形区域从位图移动到 RastPort - 软件渲染)实现透明效果。

只需将一个“无层”rastport指向它,开销就会很低。某些簿记将得到尊重,例如rastport掩码。大多数rastport例程首先要做的事情是检查rastport上是否挂着层,如果有,它们就会进入一种剪切类型的东西。BltMaskBitMapRastPort()以非最佳方式执行其功能,因此它可以执行分层操作。为层掩码或其他内容保留一个源操作数。

描述如何复制图像的最小项值(支持的值为 ABC、ABNC 和 ANBC)

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

将一个通道指定为“切换”源和背景的最小项必须包含 4 个项。(2 个包含“掩码设置” && 源,2 个包含“掩码清除” && 背景)

但是,在使用图形卡时,这并不明显,只有某些非常特定的工作值。0xE0(不支持 0xC0)的值用于对图像进行一次无修改的复制。

最小项 0xC0 将是 ABC|ABNC,最小项 0xE0 将是 ABC|ABNC|ANBC。BltBitMapRastPort 支持 0xC0,BltMaskBitMapRastPort 忽略它。0xC0 是一个“与”最小项 - 结果是通道 A 和 B 的“与”运算。

您不能相信函数使用的“最小项”与实际 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;
}

交错 blit 仅影响不透明 blit,因为掩码必须与交错透明 blit 上的源图像一样大。无论透明 blit 如何存储,都会以非交错模式执行。此外,在分配位图/屏幕时,必须使用特定标志请求交错模式。

如果源和目标位图是交错的,则 BltMaskBitMapRastPort() 的掩码 也必须是交错/重复的。目前尚不清楚这是否是错误或功能。如果您尝试从交错 blit 到交错 blit,则必须使用这些可怕的重复掩码之一。使掩码也交错,即在下一行之前重复掩码中的所有行 次(这意味着包含与源位图一样多的平面),依此类推。

这意味着我必须创建一个大小为 word_aligned_width*height*depth 位的块作为掩码吗?是的,但前提是源位图是交错的。基本上,您必须在掩码中重复每行 次。解决此问题的变通方法

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

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

动画

[edit | edit source]

Amiga 的特殊之处在于,与其他操作系统相比,它的操作系统更紧密地适应了硬件的工作方式(与硬件的抽象程度更低)。因此,现在很多后续内容仅为了向后兼容。

精灵

[edit | edit source]

大多数精灵内容(鼠标指针 #0)已几乎完全从 graphics.library 的处理中移除。为了提供代码重用,仅保留了 AllocSpriteData()。其余部分在 monitorclass 中完成,它更适合在那里,并且可以用比使用 graphics.library 精灵处理更简单的方式完成很多事情。

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) 获取精灵数据并在您的程序初始化时将其复制到其中,然后当您需要移动或显示它们时,您请求操作系统使用一些精灵,使用 GetSprite;当不再需要看到它们时,您释放精灵,当不再需要精灵图形时,您释放精灵数据。

AmigaOS(TM) FreeSprite 释放了您为 Viewport 使用 GetSprite 保留的 8 个硬件精灵中的一个;将其返回以供操作系统(或需要使用精灵的其他程序)使用。FreeSpriteData 应释放包含精灵结构数据的内存 - 精灵的像素数据等。

硬件

[edit | edit source]

AmigaOS(TM) 曾经有一个名为 InitGels() 的函数,它启动 VSprite,但目前在 AROS 中没有实现...

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

简单精灵始终为 16 位宽(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() 和 freeVSprite() 函数

虚拟

[edit | edit source]

AROS 有 VSprites (gels.h),但它们仅供鼠标指针 (精灵 #0) 使用,它将它们转换为简单精灵并显示它们。

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

与 Amiga 的 Blitter 芯片相关,因此实际上只在 AROS m68k 端口中实现...

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

碰撞

[edit | edit source]

AROS 有 SetCollision() 函数....

字体渲染

[edit | edit source]
这里

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

需要在写入文本之前使用 SetDrMd(rp,mode) 设置绘制模式。但是,如果我使用 SetRPAttrs 设置和 SetDrMd 绘制,则背景不会显示,但文本不会刷新,并且会反复重绘,最终变得无法阅读。必须在绘制新文本之前刷新背景。

为了渲染字体,我们使用 BlitColorExpansion() 方法。为了加速,传递给此方法的源位图必须通过相同的驱动程序分配。第一个可能的(也是最简单的方法)是为每个驱动程序存储一个单独的字体位图。我真的很不喜欢它,因为它会浪费大量的内存。

如果位图是使用 PutTemplate() 方法创建的。那么为什么不能直接使用 PutTemplate() 生成文本呢?如果我们仔细观察,会发现 BltTemplate() 在某些情况下已经使用(用于软件生成的斜体和下划线样式)。所以也许只需实现加速的 PutTemplate() 和 PutAlphaTemplate() 并完全放弃 BlitColorExpansion() 就可以了?

已删除 font->bitmap 转换和 BlitColorExpansion() 支持。现在 BltTemplate() 用于字体渲染。

BltTemplate — 在 RastPort 中的矩形中绘制形状。

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

此函数以当前颜色和绘制模式在指定位置将模板中的图像绘制到 RastPort 中。假设模板不与目标重叠。

如果模板超出 RastPort 边界,则将其截断到该边界。

注意:SrcTemplate 指针应指向模板掩码的“最近”字(向下取整)。掩码的精细对齐是通过在 0 到 15 十进制范围内设置 SrcX 位偏移量来实现的。

 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() 设置前景颜色 SetBPen() 设置背景颜色 SetDrMd() 设置绘制模式 Text() 将一些文本写入窗口 TextLength() 估计文本块的像素长度 RectFill() 绘制一个矩形 SetFont() 将字体设置为 rastport SetSoftStyle() 设置字体的样式(粗体、斜体等) Move() 将某种不可见的“海龟”设置为 rastport Draw() 从最后一个“海龟”点绘制一条线到此点

在文本框中滚动时,您可以重新绘制所有内容,也可以使用 ScrollWindowRaster() 仅刷新滚入的内容。当然,滚动只有在滚动事件滚动的距离小于可见页面时才有意义。

将窗口层回填钩子设置为 NULL。然后,AmigaOS 将不会用当前背景颜色(通常为笔 #0)填充损坏的区域。如果您始终注意刷新,则可以通过这种方式完全避免闪烁。

w:Aros/Developer/Docs/Examples/GfxLibraryExample

文本编辑器

[edit | edit source]

通常,您将整个文本存储在内部缓冲区中,然后仅绘制可见的缓冲区部分。您分别绘制每个部分,并在绘制部分之前设置字体和颜色。

您应该做的是根据存储在内存中的文本和指示您滚动距离的值绘制文本。稍后,您可以添加优化措施,以避免重新绘制整个窗口,方法是使用 blitter 滚动已经可见的部分。

我是否需要使用窗口的 rastport?是的,并使用 WFLG_GIMMEZEROZERO 标志窗口。使用 ClearEOL() 和 ClearScreen() 清除行尾和屏幕的其余部分。这些是来自 graphics.library 的函数,非常适合与文本编辑器一起使用。

如何在窗口中获得光标?您可以使用 SetAPen() 和 SetBPen() 键入字母,或者使用 SetDrMd() 和 COMPLEMENT。

如何保存从窗口中滚出的文本?您将文本保存在逻辑文本部分的缓冲区中(显示的是物理部分)。在文本编辑器中存储缓冲区的最佳方法是将其存储在字符串列表中。

如何在文本的同一行/行中使用不同的颜色?这很简单。使用 Text() 写入文本,RastPort 的内部光标将使您移动到单词/单词的末尾。使用 SetAPen() 和 SetBPen() 更改颜色,然后写入行的其余部分。

文字处理器

[edit | edit source]

如何在文本的同一行/行中使用不同的字体?这很棘手!然后您想制作 Word 或 WordWorth 类型的程序。您必须编写适当的函数来涵盖这一点。它比简单的文本编辑器(非文字处理器)需要更多努力。

坦白说,我认为显示的细节与程序的其余部分相比并不重要——从键盘、鼠标和 GUI 输入接收输入,维护当前文本数据库,决定如何处理窗口大小的变化。例如,文本是换行还是在右边缘被截断?如果是换行,那么您需要在每侧的行的之间显示额外的行,并且您必须将该新的部分行插入数据库中。

如果您认真对待这项工作,可以先设计和实现数据库。您可以始终使用现有的工具和类显示内容。然后,稍后您可以编写所有 WYSIWYG 函数以很好地显示它。

文本完全存储在一个文本缓冲区中。您在窗口上绘制文本缓冲区中可见的部分,以满足需求。请不要引入一个包含可见文本的第二个缓冲区的概念。

您需要快速访问文本,逐行访问。一个建议是使用一个指向字符串的指针数组。每个指针都指向一行文本。当您插入或删除一行时,您只需要移动指针数组,而不需要移动整个文本。即使文本的大小为 GB,这也非常快,并且开销非常低。当您将文本加载到内存时,它也非常快。您可以将所有内容加载到一个块中(如果需要,也可以加载到几个大块中),并只设置索引数组中的指针。然后用 0 字节替换返回值,或者编写您的可视化内容,以表示您尊重返回值。如果一行被编辑并且变大,它会从内存池中分配自己的内存缓冲区。

但是,在 AmigaOS 环境中,一个更简洁的方法是为每一行文本使用一个 Exec List 节点。在重新绘制显示时,遍历 List 的速度与遍历表格一样快。另一方面,插入/删除(行)操作变得微不足道,因为您不必更改指向其他行的任何指针。缓冲区中的所有文本都可以存储在一个单一列表中,每行一个节点。要显示列表的一部分,您只需要维护几个指针,一个指向窗口中第一行的节点,另一个指向最后一行的节点。每当文本滚动时,您就使用 Prev() 和 Next() 调用一次移动一个指针。困难的部分是保持对跨越两行或多行的文本行的控制。每当窗口宽度或字体大小发生改变,或者用户在某一行插入文本时,您必须重新访问文本在受影响行之间的分割。无论您使用查找表还是 List,问题都是一样的。

但是,列表的开销更大。当编辑小文本文件时,所有方法都没有问题。当文本文件非常大时,问题就开始了。许多文本编辑器在这里速度很慢,例如,如果您加载一个 1 GB 的文本文件。构建这样的链表所花费的时间比数组要多。在数组中的插入或删除成本没有那么高,请记住,现在的 CPU 每秒可以移动 GB 级别的内存,并且与键入字符相比,插入删除操作很少见。

需要一些与文本一起的格式化信息。格式化信息直接存储在行的文本中。

额外的函数应该首先保留/锁定当前由 MOS/OS4 扩展使用的 LVO,然后在最后保留一个 LVO 块(100 个?)。在这个块之后,可以添加 AROS 函数。

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

除了最后一个之外,我认为其他函数都是公共扩展/改进,而不是私有函数。例如,“ND”代表“非破坏性”。原始的区域函数都会将结果区域“返回”到源区域之一(即它们修改/破坏它)。

AndRegionRegion():

   R2 = R1 intersected with R2;

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

   R3 = R1 intersected with R2;

当然,您可以使用标准(旧的)区域函数来模拟这一点,但是仅仅因为您可以使用大量的 WritePixel() 来模拟 RectFill(),并不意味着移除 RectFill() 是一个好主意。

DPaint(1-3)使用 RectFill() 在 JAM2 模式下手动填充工具区域。这毫无意义,JAM2 应该覆盖所有内容。经过多次测试后,我终于找到了原因:DPaint 直接指向 RastPort 并修改了 RastPort->mintern[0] 值,以便位平面 0 被反转,但位平面 1 按正常方式绘制。AOS 显然在每次 SetAPen()、BPen、DrMd 调用后重新计算所有 mintern 值,这些值随后被使用 blitter 的任何绘图例程使用。(mintern[0] = plane0, mintern[1] = plane1 等)可能不值得麻烦去实现,但它是一个有趣的实现默认值。(这甚至在 OS39 上也能工作)。

以不影响 MOS/OS4 未来兼容性的方式扩展 3.x 库的主题已列入 ABI V1 的议程。

建议将尽可能多的内容从核心库中移出,并放入一些新的组件中。例如,这些区域操作函数可以移动到类似 gfxutils.library 的东西中。此外,这将减小 Kickstart 的大小。

我认为,所有 API 扩展都应该经过仔细设计,而不是仅仅因为某个应用程序的作者说这将是一件好事就将其作为黑客来实现。如果我们仔细研究这些函数,我们可以注意到它们 99% 的代码是重复的。例如,AndRegionRegionND() 事实上仅仅是

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

查看内部结构,我们可以认为 CopyRegion() 是一个非常有用的函数,因为它不仅仅是两三行代码,而且没有真正的替代方案。所以应该保留。这样,我们可以减少扩展的数量。

另一个例子是 dos.library 的 SetError() 函数。在内部,它是两行代码。此外,它恰好被启动代码使用。目前这还不错,但是当 m68k AROS 出现时,这意味着在 m68k AROS 下构建的应用程序将无法在例如经典 AmigaOS 上运行,即使使用版本检查也是如此。这个函数完全可以移到 libamiga.a 中。此外,它可以被重命名为 SetErrorOutput() 以实现 AmigaOS4 兼容性。

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

看一下 struct MonitorSpec 中的 ms_transform() 和 ms_translate() 回调。名称暗示了它们的目的是以某种方式转换屏幕坐标。这意味着我们的图形子系统可以在一些其他的坐标(而不是像素)中工作,自动处理屏幕纵横比等?查看了 MorphOS 代码,ms_translate() 是一个存根,它只是将一个 Rectangle 结构复制到另一个 Rectangle 结构。ms_transform() 只是返回。

在实现 GetMonitorList() 和 FreeMonitorList() 时,注意到它们的原始 LVO 已经被 StartScreenNotifyTagList() 和 EndScreenNotify() 函数使用。LVO 不会与任何东西发生冲突,除了两个私有的 AmigaOS v3 函数,它们用于将 DisplayInfo 添加到系统中。它们被基于磁盘的视频模式驱动程序使用(DEVS:Monitors 的内容)。

  • monitorclass 是一个 BOOPSI 类,不是我发明的。
  • 为了创建一个 BOOPSI 对象,我们必须调用 intuition.library/NewObject()。
  • 在 AROS 中,添加显示驱动程序是通过 graphics.library/AddDisplayDriverA() 完成的,这是一个 AROS 特定的函数(因为在其他操作系统中没有这个函数的公共等效项)。
  • monitorclass 对象的创建需要以某种方式与 AddDisplayDriverA() 绑定。
  • 如果我们实现一些其他的 AROS 特定的 API,那么我们实际上不需要 monitorclass,我们可以直接基于这个 API。

在以前的版本中,同步对象和 MonitorSpec 是独立的实体。graphics.library 枚举所有同步对象,并为它们创建相应的 MonitorSpec。存在以下缺陷

  • 在 MonitorSpec 或同步发生改变后,需要同步数据。
  • 数据重复(50% 的同步对象数据重复了 MonitorSpec 数据)。
  • 需要大量的代码来复制重复的数据。
  • 由于(2),内存碎片过多。

此外,存在严格的关系“一个同步 == 一个 MonitorSpec”。同步对象需要知道相关的 MonitorSpec,而 MonitorSpec 需要知道相关的同步对象。这进一步让我想到,MonitorSpec 可以完全合并在一起。这样,它将以更好的方式进行管理(例如,更好地实现可变/常量同步对象,以及更好地处理没有 SpecialMonitor 添加的 MonitorSpec)。使 MonitorSpec 自注册的解决方案变得非常明显。这允许摆脱添加/删除代码。当一个显示驱动程序被释放时,它的同步对象会被释放,这会导致关联的 MonitorSpec 从 graphics.library 列表中自动移除。

监视器驱动程序是另一个令人沮丧的章节——关于它们的文档一无所有,只有一组 gfx 库中的钩子和视窗结构(IIRC),颜色表完全没有文档,并带有大量有效负载,这些有效负载被塞入其中,因为视图和视窗被完全记录并且无法扩展。

现在移到了 monitorclass

GfxNew() 和 GfxFree() 也是由 Commodore 发明的。事实上,可以使用 AllocMem()/FreeMem(),但由于存在一些代码重复,决定不这样做。

但是,用户界面上的操作在内部会转换为位图上的操作。屏幕上的操作会转换为视窗上的操作。graphics.library 中缺少一些功能,但在 HIDD API 中存在,并且可以安全地使用它(这些是信息查询调用,而不是渲染调用)。

GetDisplayInfoData() 不提供这种合成能力信息。GetDisplayInfoData() 在保留字段中返回所需的指针(这最初是为 CGX 实现的)。然而,这里我们有一个小问题...

显示驱动程序使用 graphics.library/AddDisplayDriverA() 注册自己。但是,Intuition 如何知道注册了一个新驱动程序(以便创建 monitorclass 对象)呢?

再次有以下解决方案

  • 驱动程序可以调用 Intuition 的函数(反过来将调用图形函数)。
  • 图形可以调用 Intuition 的一些函数来创建一个 monitorclass 对象。
  • Intuition 可以修补 AddDisplayDriverA() 以添加自己的代码。
  • 显示驱动程序可以自己创建 BOOPSI 对象。

我对它们的看法

  • 这将真正使图形在没有 Intuition 的情况下无法运行(无法添加显示驱动程序)。此外,它不会减少 AROS 特定扩展的数量(看看 include/graphics/driver.h - 这些是绝对需要的,并且它们的数量会增加)。
  • 这就是我打算做的事情。
  • 讨厌操作系统自我修补!!!尤其是在没有补丁的情况下可以做到这一点时。此外,graphics.library 需要在它的 DisplayInfoDataBase 中保留一个指向 monitorclass 对象的指针(以便 Intuition 可以通过模式 ID 来查找它)。
  • 这会导致每个驱动程序中的代码重复,这很糟糕。这种方法倾向于变成 OS 3.1 中使用显示驱动程序的方式。

此外,我必须将这段代码添加到每个显示驱动程序中,这是一个费时费力并且破坏了向后兼容性的工作。

相信在 MorphOS 中,所有这些都是由 cgxsystem.library 管理的。在那里(就像在经典的 AmigaOS 中一样),DisplayInfoDataBase 只是一个静态列表,而 Intuition 似乎还有一个静态列表。CGX 只创建所需的项目,并将它们全部推入各自的列表中。我们只在一个地方有所不同——我们没有 cgxsystem.library(它完全是 CGX 的私有库),并且此功能已合并到 graphics.library 中。

AROS 并没有添加新的公共库函数。它添加了一个新的公共 BOOPSI 类,它更容易避免冲突,特别是如果决定实现 MorphOS 二进制兼容性的话。

看起来图形库的故事并不比 dos 库的故事逊色。一些迹象表明,Amiga graphics.library API 只是对底层东西的封装。例如,GetDisplayInfoData() 的内部实现很可能是基于标签列表的,并且看起来还有更多选项可以查询。

了解更多信息,请点击这里

关于 graphics.library 代码,有两点需要注意:

  • 已经支持 RAM(包括 ChipRAM)中的平面位图。
  • graphics.library 从池中分配临时平面位图 HIDD 对象,并将位图附加到它们以对它们进行操作。

这意味着你可以

  • 为 planarbm 类添加一些属性来处理可显示的位图(那些具有铜列表的位图)。除了位图之外,还应该将铜列表附加到临时对象。
  • 实现一个驱动程序,它能够使用 Show 或 ShowViewPorts 方法来显示这些对象。

对于 ABI v1,graphics/displayinfo.h 中 struct QueryHeader 中的所有字段应该从 ULONG 更改为 IPTR。这是因为最初这个结构是两个 TagItems。在某些情况下,它可以使用 utility.library 中的标签列表函数进行处理。

背后的想法是,我们为每个 RastPort 附加了一个 GC(图形上下文)HIDD 对象。这个对象需要分配/释放。在早期,CreateRastPort() 和 DeleteRastPort() 做了这件事。如今,GC 对象在第一次尝试使用 RastPort 时自动分配。然后,这个对象被缓存,并附带一个使用计数器。当一些绘图操作开始时,使用计数器会递增。当操作结束时,它会递减。这些对象应该被一些垃圾收集器销毁,但还没有实现。一个 DeInitRastPort() 函数存在,它强制进行 GC 销毁。因此,实际上,CreateRastPort() 和 DeleteRastPort() 已过时。

与 AOS 不同,AROS 需要一个 rastport 清理函数 (DeInitRastPort()),否则可能会发生内存泄漏。这就是为什么代码为尚未存在的 rastport 垃圾收集器做好准备的原因。对于在移植代码中忘记使用 DeinitRastPort() 的情况(或者理论上对于具有理论 68k 仿真器的 68k 二进制文件)。但是垃圾收集器永远无法确定一个 rastport 是否确实已死,并且永远不会再次使用。因此,即使在杀死 driverdata/gc_object 之后,也可能在一段时间后再次使用 rastport。在这种情况下,必须从 RastPort 结构中的信息重新创建 driverdata/gc_object。

driverdata/gc_object 垃圾收集可能会有一些负面影响,所以想法是只对手动创建(或克隆)的 rastport 使用它。但不是对使用 CreateRastPort() 或 CloneRastPort() 创建的 rastport 使用,因为在这种情况下,程序员会知道他们必须使用 DeleteRastPort() 来释放它。其中一个负面影响可能是速度,但也可能是使用了一些新的 AROS rastport 功能(如裁剪矩形),这些功能没有存储在 RastPort 结构中(而是存储在 DriverData 结构中),因此在 driverdata/gc_object 被垃圾收集杀死但 rastport 稍后再次使用的情况下无法重新创建。所以在这种情况下,应用程序必须使用 CreateRastPort() 或 CloneRastPort() 来防止垃圾收集发生。

RastPort 清理和 DeinitRastPort() 的要求正在开发中。

当你想要添加一些新功能并且私有空间已满时该怎么办?与现在使用 ClipRect 一样。设置扩展属性会分配扩展空间。在此之后,是的,你需要 deinit。在 x86-64 上添加了更多私有空间。!!! 二进制兼容性已破坏 !!! 删除了 PatOrigin 属性以释放 RastPort 中可用的空间。没有找到它们背后的理由,只需调整图案起始地址即可。

图案大小假定等于源位图。所以,如果位图的大小为 (x, y),而我们不是从 (0, 0) 开始,而是从某个偏移量开始,它将从哪里获取额外的像素呢?好吧,这样的功能可以更好地作为具有额外参数的独立函数来实现。Origin 用于图案的对齐方式 == 就像图案的循环滚动。例如,如果你有一个棋盘格图案,你可能希望它以这样的方式对齐,使其“开始”正好位于内部窗口区域的 (x,y) 处,这取决于窗口边框大小,因为大多数窗口是非 GZZ 的,(0,0) 在窗口边框上方。

考虑按设计破坏的 ClipRect 删除。在很多情况下都不可用,并且维护它会带来很多麻烦。也许我说得太苛刻了。但是,第一个问题。添加它的理由是什么?因为在很多情况下,拥有像这样的裁剪支持比 layers.library/InstallClipRegion() 更加容易和快速。因为当你在一个部分隐藏的智能刷新层中安装裁剪区域时,这甚至可能导致在层裁剪矩形位图之间来回 blit。

我脑海中的主要用途是用于在多列列表视图中裁剪 Text() 之类的东西,即在短时间内可能进行大量裁剪的地方。其他操作系统也有它。但 IMHO 它们有它是因为绘图的理念截然不同。这些操作系统中没有后台存储。实际上,没有类似于 Layers 的东西;当一个窗口打开时,它只是占据了屏幕位图的一部分,而隐藏的部分就消失不见了(是的,程序员每次都必须重新绘制它)。就像 AOS 中的简单刷新窗口(这也是在 AROS 中运行效果最好的窗口,因为智能刷新窗口缺乏一些优化,以避免诸如备份/恢复屏幕外裁剪矩形位图之类的事情,即使层操作根本没有影响它们)。但如今,即使是这些操作系统都支持后台存储,因为它们需要它来进行合成。

如果我们在一个部分覆盖的智能刷新窗口上安装 ClipRegion,就会创建两组遮挡的 ClipRects。第一组是从整个窗口创建的,第二组表示第一组与 ClipRegion 的交集。因此,第二组中的 ClipRects 是第一组的子裁剪矩形,并且它们具有重复的存储位图。每次移动窗口时,我们都必须将这些片段重新组合,这需要两组 blit。这很慢。但如果我们扩展 ClipRects,使其能够引用已存在位图的一部分呢?这样,第二组(裁剪)中的 ClipRects 就可以重复使用第一组的存储位图。这将消除不必要的 blit 并减少内存使用量。这种优化将使它对现有应用程序透明地工作,除非其中一些应用程序通过手动遍历 ClipRects 来进行渲染。此外,ClipRegion 允许使用比一个矩形更复杂的形状。

为什么很麻烦?因为让它正常工作需要大量的新增内容。你知道 layers.library 的 DoHookClipRect() 函数吗?它应该做与 do_render_func() 目前做的一样。只是它忽略了这个 ClipRect,它不知道它。希望在 RastPort 上实现一些复杂操作的公众,预计会使用它。并且,如果有人想在 RastPort 上设置一个 ClipRect,这将使其无法正常工作。对于这样的特殊情况,我可能会使用 SetRPAttrs() 使 rastport 标志可变,该标志告诉像 DoHookClipRects() 这样的函数是否应用 rastport 裁剪矩形。回调函数本身不应该处理 rastport 裁剪矩形本身。在编写 RPTAG_ClipRectangle 之后的一段时间添加了它,因为它是一个简单的扩展(没有裁剪矩形?-> 假设位图边界是裁剪矩形),我发现应用程序可以在位图之外渲染总是很愚蠢。

  • RastPort 变得自包含。不再需要额外的数据,这些数据需要显式释放。GC 对象内置在 RastPort 中。因此,GC 操作快得多。
  • CreateRastPort()、CloneRastPort()、FreeRastPort()、DeinitRastPort() 已移至 libarossupport,主要是为了支持旧代码。如果在 RastPort 上安装了 ClipRect,仍然需要进行 RastPort 清理。这可以通过 FreeVec(rp->RP_Extra) 来完成。
  • 正确实现了 RPTAG_PenMode,与 MorphOS 兼容。

AROS 有一个特殊功能,允许为 rastport 设置一个裁剪矩形,该裁剪矩形也可以用于(连接到)屏幕外位图。使用它可以防止在位图边界之外进行渲染(= AROS 原生中的内存损坏/崩溃和 AROS 托管/X11 中的 X11 错误消息)。也许很久以前就发生了?我在启用了 mungwall 的 Darwin 托管环境中测试了这个更改。对于 X11 驱动程序,你可能会使用一个 X11 像素图作为位图,所以不会出现内存损坏 - 只有 X11 错误会显示。

方法 HIDD_BM_PutPixel 应该使用 HIDDT_Pixel 类型作为最后一个参数。如果 64 位编译器抱怨由于 64 位 (IPTR) 到 32 位 (HIDD_Pixel) 的缩放而丢失了一些数据,那么你需要以其他方式修复函数体。

将 Point ExtendedNode.xln_Init 指向虚拟函数。防止 WB2.0+ 监视器驱动程序崩溃。这个 xln_Init() 函数的作用。它获取两个参数:节点指针和标志。对于 MONITOR_SPEC_TYPE 节点,标志值被放入 ms_Flags 成员中。然后,如果设置了 MSF_REQUEST_SPECIAL 位,将分配 SpecialMonitor 结构并附加它。因此,这个初始化函数负责在结构中设置一些默认值。我可以实现它,但我决定不这样做,因为对 AROS 来说它无论如何都是无用的。

现在关于“驱动程序”本身。这个程序可以被视为 graphics.library 的一部分,放在磁盘上。它所做的只是将显示模式的信息插入 graphics.library 的模式数据库中。数据库是一个结构,指向由 GfxBase->DisplayInfoDataBase 指向的结构。我开始记录我发现的东西,但没有时间做太多。DisplayInfoDataBase 文档在这里。MonitorSpecs 和模式 ID 属性中的所有值都是硬编码常量。它们中的一些具有不同的变体,具体取决于 GfxBase->ChipRevBits 指定的芯片组。GfxBase->Bugs 中还有魔法位号 5。实际上,这个变量是一些内部标志。如果设置了位 5,VGA 驱动程序将选择略微不同的常量集。我猜这个位是由 VGAOnly 程序设置的。还有 GfxBase->ProgData 指向一些东西,我猜是某些芯片组常量。显示驱动程序扫描这段内存,搜索其中的某些东西,并将它们复制到它们创建的每个显示模式 ID 的 VecInfo->Data 指向的结构中。我没有理解这些操作的确切目的。

实际上,我认为如果 GfxBase->DisplayInfoDataBase 为 NULL,驱动程序将优雅地失败,并且不会执行任何操作。要么我错了,要么是出了问题。我认为你只需要提供驱动程序失败的条件。它不应该插入自己的 MonitorSpec,也不应该尝试插入数据库记录。使用两个私有的 graphics.library 函数填充模式 DB:AddDisplayInfoData() 和 SetDisplayInfoData()。它们的 LVO 被 AROS 特定的函数占据。我不记得值,但你可以搜索函数名称,很容易找到它们。我也考虑过让这些驱动程序工作的可能性,但是

  • 这需要反向工程并重新实现 AmigaOS graphics.library 的大部分内容,这可能是版权侵权。
  • 用 AROS 自己的方式重新实现整个东西要容易得多。使用 AROS 自己的基础设施。如果你看一下 AmigaOS 中模式数据库的实现,你就会明白 AROS 的实现要好得多。

AROS PolyDraw,rkm 说,计数是一个字值,但在 AROS 中它是一个长值。在 MOS 和 OS4 上,它似乎也是一个字值,因为 amiblitz 在 MOS 和 OS4 上运行良好。Amiblitz 在 AROS 68k 上失败,会无限绘制线条,因为高位寄存器包含随机高值。也许是包含文件中的错误,但在 amiga 开发者 CD 文件中是这么写的。例如,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;
};


位图

位图是 AROS 的绘图板。它们的坐标系原点位于左上角。x 轴从左到右,y 轴从上到下。可能的颜色数量取决于位图的深度。

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

1 到 8 的深度是 LUT(查找表)模式。这意味着每种颜色的红色、绿色和蓝色(RGB)值存储在表中。然后索引将作为笔号存储在位图中。

15 和 16 的深度称为高颜色,24 称为真彩色。与 LUT 模式不同,RGB 值直接存储在位图中。

图形库对高/真彩色模式的支持有限。一些绘图函数仅适用于 LUT 模式。要完全访问,您需要使用 cybergraphics 库中的函数。

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

位图与大多数绘图函数之间的连接通过一个 rastport 完成。rastport 包含有关绘图笔、线和区域图案、绘图模式和文本字体的信息。

您可以将多个 rastport 连接到一个位图。这允许在不同的绘图配置之间快速切换。但是,在 AROS 中无法简单地复制 rastport;您必须使用 CloneRastPort() 函数。

一些 Intuition 元素,例如屏幕和窗口,已经有一个 RastPort 元素。您可以立即将其用于绘图操作。对象结构 RastPort 屏幕 struct Screen RastPort 窗口 struct Window *RPort

如果您创建了一个位图并想要在其中绘图,您必须自己创建 rastport。警告:此示例已简化,缺少返回值检查

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

rastport 包含 3 支笔。A(前景色,主色)笔,B(背景色,副色)笔和 O(区域轮廓)笔。后者由区域填充和填充填充函数使用。


绘图模式

    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.

待办事项:检查绘图模式是否真的可用。


模式

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
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()
华夏公益教科书