Aros/Developer/Docs/Libraries/DataTypes

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

Introduction[edit | edit source]

The datatypes.library was introduced to decode file formats (#?.png #?.jpg etc.) easily using different classes which can be installed as they are needed.

  • V30 Amiga OS 2
  • V40 Amiga OS 3
  • V44 Amiga OS 3.5+

The descriptors in devs/datatypes contain the information how to identify a file type. Usually the file is opened only once by datatypes.library and a small buffer is used for comparisons which contains the first few bytes of the file (64 bytes IIRC).

dt descriptor is related to the struct DataTypeHeader dth_Name, dth_BaseName, etc.

Most datatype descriptors are held very simple, for example "compare the first 12 bytes with the pattern FORM????ILBM". The comparison is done by datatypes.library, there is no foreign code involved.

Only very few descriptors actually contain code. In this code everything can be done, though. For example, the code can close and reopen the file and read it entirely if needed. But this should not be done because identification needs to be very fast.

Dtdesc tool (and accompanied documentation) createdtdesc package is aimed at creating (picture) datatypes (as a whole, including makefiles). dtdescr is aimed at (only) viewing and creating the descriptor.

Once the file type is identified and the application wants to load the file, the class library from classes/datatypes is called. This library contains the code to decode the file contents and to make it available to datatypes.library.

Datatypes consist of a few libraries that exposes a couple of methods to load and save f.e. pictures of a certain type. Internally there is a 'common' storage method of the pixels that is used by the picture datatype, and so each 'library' that can handle its own type is able to 'convert' this common storage method into a specific format or load to this specific format.

The datatypes system itself exposes methods for the developer/user that allows for easy loading and saving by just calling some functions.

So, as long (and in theory) as there are 'libraries' that support a certain file-type (in this case pictures) you can very simply convert from one picture format to another picture format.

First you should learn about BOOPSI. If you understand BOOPSI, it's easy to understand datatypes, ReAction, MUI, ...

The only problem with AmigaOS implementation of datatypes is that they aren't really bidirectional. You can generally only save in IFF.

The ideal implementation would allow each datatype superclass (picture.datatype, sound.datatype etc.) to provide a list of all currently known sub-classes that support encoding. You'd then be able to pick one and encode data for that datatype and write it out to disk in that format.

Wanderer (AROS WB replacement) does not utilise the datatype subsystem directly "except" for loading window background imagery. The datatype system cannot deal with progressive loading and streaming yet.

assume you are trying to manipulate images? Load images using datatypes but read image data to ARGB array using ReadPixelArray methods and dispose source object. For images, to get the raw data use PDTM_READPIXELARRAY (that's the uncompressed data).

concerning Sounds ? Should it be better to use DTMethod to uncompress on a buffer and then use this uncompressed buffer ? For sound, get the data using the SDTA_Sample (or SDTA_LeftSample/SDTA_RightSample) attributes. You can retrieve sample data using SDTA_Sample tag but AmigaOS lacks support for SDTA_SampleType so you can get only 8-bit sample data there. AROS and MorphOS are more advanced there but generally it is better drop datatypes and write your own wave loader.

Setting SDTA_BitsPerSample, 16 will make SDTA_(Left|Right|%) Sample be in 16-bits (32-bit is also supported).

Any applications will query the methods supported by your class. Make sure that if you choose to implement support for the OM_GET/DTA_Methods tag the methods you return should also include the methods supported by your superclass. Otherwise, the user will be unable to use functions such as "Copy" or "Print".


How to[edit | edit source]

create a Datatype Object, use the NewDTObject function ...

gd->gd_DisplayObject = NewDTObject ((IPTR)gd->gd_Unit, DTA_SourceType, DTST_CLIPBOARD, GA_Immediate, TRUE,
                                     GA_RelVerify, TRUE, DTA_TextAttr, (ULONG) & gd->gd_TextAttr, TAG_DONE)) 

The parameters of this functions uses Tags as defined in datatypes/datatypesclasses.h and intuition/gadgetclass.h

gf->gd_Unit = the Clipboard unit number
DTST_Clipboard = the Clipboard is the data source
GA_Immediate = Should the object be active when displayed
GA_RelVerify = Verify that the pointer is over the object when it is selected
gd_->gd_TextAttr = Pointer to text font attributes

Once a datatype object is no longer required, it is disposed of and memory released: e.g.

DisposeDTObject (gd->gd_DisplayObject);

To get attributes from a datatype object, you can use the GetDTAttrs function e.g.

GetDTAttrs (gd->gd_DisplayObject, DTA_DataType, (ULONG)&dtn, TAG_DONE);

and examining the results from the dtn structure you can retrieve:

dtn->dtn_Header->dth_Name = Descriptive name of the datatype
dtn->dtn_Header->dth_GroupID = The group the datatype belongs to

The function GetDTString returns a localised Datatypes string of the id given. This string could be syst, text, docu, soun, inst, musi, pict, anim or movi (see datatypes.h). e.g.

GetDTString (dtn->dtn_Header->dth_GroupID)


Change State - Set/Get[edit | edit source]

what you usually do is, to create an object (initial state), get/set some attributes (attribute change) and then do layout or extract a type.

in that case there many programs that call remap but doesn't have a gpinfo structure.

is there some info what remap have on initial state ?

AROS dt set it to true.

pd->Remap = TRUE;

when a program have no gpinfo with screen, then i think remap should be set to false.maybe AOS do that somewhere.

same can happen on AROS dt too, maybe on AOS dt bitmap (state change and get/set); however it is not clearly defined in which way state changes may affect attributes (screen, colors) or what happens in case some attributes have not been set prior triggering the state change; it's not even exactly clear which states are possible


Refresh[edit | edit source]

Your application can find out when a refresh is appropriate by using the Boopsi ICATarget attribute with the ICTargetIDCMP value. This causes the datatype (gadget) to send an IDCMP_IDCMPUpdate IntuiMessage to the window port on certain status changes. That message carries a pointer to one or more attributes and if DTA_Sync is in that list with a value of 1 then the datatype object is ready for refresh.

You get one of these on attaching the datatype object to your window, and also a stream of them when the window is resized.

Creating datatype object of specified subclass[edit | edit source]

In order to create a jpeg datatype object (jpeg subclass of picture class)

DTImage = NewDTObject(NULL,
DTA_SourceType, DTST_RAM,
DTA_BaseName, "jpeg",
PDTA_DestMode, PMODE_V43,
TAG_DONE);

Examples[edit | edit source]

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

int main (void)

{
struct RDArgs *rdargs;
struct {
	char *file;
	char *pubscreen;
	} args = {0};

int rc = RETURN_FAIL;
struct Screen *scr;
Object *dto;
struct BitMapHeader *bmhd;
struct BitMap *bm;
WORD winw,winh;
struct Window *win;
struct IntuiMessage *imsg;
BOOL cont;

rdargs = ReadArgs ("FILE/A,PUBSCREEN/K",(LONG *)&args,NULL);
if (!rdargs)
	{
	PrintFault (IoErr(),NULL);
	return (RETURN_FAIL);
	}

if (scr = LockPubScreen (args.pubscreen))
	{

	if (dto = NewDTObject (args.file,DTA_GroupID,GID_PICTURE,PDTA_Remap,TRUE,PDTA_Screen,scr,TAG_END))
		{
		DoDTMethod (dto,NULL,NULL,DTM_PROCLAYOUT,NULL,TRUE);
		GetDTAttrs (dto,(ULONG) PDTA_BitMapHeader,&bmhd,(ULONG) PDTA_BitMap,&bm,TAG_END);

		if (bm && bmhd)
			{
			winw = bmhd->bmh_Width + scr->WBorLeft + scr->WBorRight;
			winh = bmhd->bmh_Height + scr->WBorTop + scr->RastPort.TxHeight + 1 + scr->WBorBottom;

			if (win = OpenWindowTags (NULL,
					WA_Left, (scr->Width - winw) / 2,
					WA_Top, (scr->Height - winh) / 2,
					WA_Width, winw,
					WA_Height, winh,
					WA_Title, args.file,
					WA_Flags, WFLG_CLOSEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_ACTIVATE | WFLG_NOCAREREFRESH,
					WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY,
					TAG_END))
				{
				rc = RETURN_OK;

				BltBitMapRastPort (bm,0,0,win->RPort,win->BorderLeft,win->BorderTop,win->GZZWidth,win->GZZHeight,0xc0);

				cont = TRUE;
				do	{
					if (Wait ((1L << win->UserPort->mp_SigBit) | SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
						cont = FALSE;
					while (imsg = (struct IntuiMessage *) GetMsg (win->UserPort))
						{
						switch (imsg->Class)
							{
						case IDCMP_VANILLAKEY:
							if (imsg->Code == 0x1b) /* Esc */
								cont = FALSE;
							break;
						case IDCMP_CLOSEWINDOW:
							cont = FALSE;
							break;
							}
						ReplyMsg ((struct Message *) imsg);
						}
					}
				while (cont);
				CloseWindow (win);
				}

			}
		else
			Printf ("image cannot be rendered into the named pubscreen\n");

		DisposeDTObject (dto);
		}
	else
		{
		Printf (GetDTString (IoErr()),args.file);
		Printf ("\n");
		}

	UnlockPubScreen (NULL,scr);
	}
else
	Printf ("cannot lock pubscreen\n");

return (rc);
}

that's code of diskobjpngio.c.read

icon->iconPNG.handle = PNG_LoadImageMEM(icon->iconPNG.filebuffer, filesize,                                           chunknames, chunkpointer, TRUE);
    if (!icon->iconPNG.handle)
    {
        FreeIconPNG(&icon->dobj, IconBase);
    return FALSE;
    }
   
    {
        LONG width, height;
   
    PNG_GetImageInfo(icon->iconPNG.handle, &width, &height, NULL, NULL);
   
    icon->iconPNG.width  = width;
    icon->iconPNG.height = height;
    icon->iconPNG.transparency  = 0xffffffff;
    PNG_GetImageData(icon->iconPNG.handle, (APTR *)&icon->iconPNG.img1, NULL);

dt2thumb application[edit | edit source]

#include <dos/dos.h>
#include <dos/dosasl.h>
#include <dos/dosextens.h>
#include <dos/exall.h>
#include <dos/rdargs.h>
#include <exec/memory.h>
#include <exec/types.h>
#include <utility/utility.h>

#include <proto/arossupport.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/cybergraphics.h>
#include <proto/datatypes.h>
#include <proto/icon.h>
#include <workbench/workbench.h>
#include <workbench/icon.h>
#include <datatypes/pictureclass.h>

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

#define CTRL_C      (SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
#define  isDir(fib) ((fib)->fib_DirEntryType >= 0)

#define ARG_TEMPLATE    "FILE/A,ALL/S,QUIET/S,W=WIDTH/N,H=HEIGHT/N,F=FORCEASPECT/S,M=METHOD,DEFTOOL"

enum 
{
	ARG_FILE = 0,
	ARG_ALL,
	ARG_QUIET,
	ARG_WIDTH,
	ARG_HEIGHT,
	ARG_FORCEASPECT,
	ARG_METHOD,
	ARG_DEFTOOL,
	NOOFARGS
};

/* Maximum file path length */
#define MAX_PATH_LEN    2048

const TEXT version[] = "$VER: dt2thumb 1.1 (10.12.2010)\n";
static char cmdname[] = "dt2thumb";

typedef struct rgbImage
{
	UWORD Width;
	UWORD Height;
	UBYTE *Data;
}
RGBImage;

int doThumbs(struct AnchorPath *ap, STRPTR files, BOOL all, BOOL quiet,
		ULONG destwidth, ULONG destheight, BOOL keepaspect, STRPTR deftool, STRPTR method);
BOOL CreateThumb(STRPTR infile, ULONG destwidth, ULONG destheight, BOOL keepaspect, STRPTR deftool, STRPTR method);
BOOL readpic_by_datatype(RGBImage *pic, char *file_name);
BOOL savepic_by_datatype(RGBImage *pic, char *file_name);
RGBImage *resizeBilinear(RGBImage *pic, ULONG w2, ULONG h2);
RGBImage *resizeNearest(RGBImage *pic, ULONG w2, ULONG h2);
RGBImage *resizeAverage(RGBImage *pic, ULONG w2, ULONG h2);

int main(void)
{
	struct RDArgs      *rda = NULL;
	struct AnchorPath  *ap = NULL;
	int	   retval = RETURN_OK;
	
	STRPTR files = "#?";
	BOOL   all = FALSE;
	BOOL   quiet = FALSE;
	ULONG  destwidth = 128;
    ULONG  destheight = 128;
    BOOL   keepaspect = TRUE;
    STRPTR method = NULL;
    STRPTR deftool = NULL;
	IPTR   args[NOOFARGS] = { (IPTR)files, all, quiet, (IPTR)&destwidth, (IPTR)&destheight, !keepaspect ,(IPTR)method ,(IPTR)deftool};
	
	ap = AllocVec(sizeof(struct AnchorPath) + MAX_PATH_LEN, MEMF_ANY | MEMF_CLEAR);
	if (ap != NULL)
	{
		ap->ap_Strlen = MAX_PATH_LEN;
		
		rda = ReadArgs(ARG_TEMPLATE, args, NULL);

		if (rda != NULL)
		{
			/* Convert arguments into (less complex) variables */
			if (args[ARG_FILE])			files = (STRPTR)args[ARG_FILE];
			if (args[ARG_ALL])			all = TRUE;
			if (args[ARG_QUIET])		quiet = TRUE;
			if (args[ARG_WIDTH])		destwidth = (ULONG)*((IPTR *)args[ARG_WIDTH]);
			if (args[ARG_HEIGHT])		destheight = (ULONG)*((IPTR *)args[ARG_HEIGHT]);
			if (args[ARG_FORCEASPECT])	keepaspect = FALSE;
			if (args[ARG_METHOD])		method = (STRPTR)args[ARG_METHOD];
			if (args[ARG_DEFTOOL])		deftool = (STRPTR)args[ARG_DEFTOOL];

			if (!all &&IsDosEntryA(files, LDF_VOLUMES | LDF_DEVICES))
			{
				Printf("Can't create thumb for %s - ", files);
				SetIoErr(ERROR_OBJECT_WRONG_TYPE);
				PrintFault(IoErr(), NULL);

				retval = RETURN_FAIL;
			}
			else
				retval = doThumbs(ap, files, all, quiet, destwidth, destheight, keepaspect, deftool, method);
			
			FreeArgs(rda);
		}
		else
		{
			PrintFault(IoErr(), cmdname);
			retval = RETURN_FAIL;
		}
		
		if (ap!=NULL) FreeVec(ap);
	}
	else
	{
		retval = RETURN_FAIL;
	}
	
	return retval;
} /* main */

int doThumbs(struct AnchorPath *ap, STRPTR files, BOOL all, BOOL quiet,
			 ULONG destwidth, ULONG destheight, BOOL keepaspect, STRPTR deftool, STRPTR method)
{
    LONG  match;
    int   retval = RETURN_OK;
    LONG  indent = 0;
    int   i;			/* Loop variable */
    BOOL  error;

    for (match = MatchFirst(files, ap);
    	 match == 0 && retval == RETURN_OK;// && !CTRL_C;
	     match = MatchNext(ap))
    {
		if (isDir(&ap->ap_Info))
		{
			if (ap->ap_Flags & APF_DIDDIR)
			{
				indent--;
				ap->ap_Flags &= ~APF_DIDDIR; /* Should not be necessary */
				continue;
			}
			else if (all)
			{
				ap->ap_Flags |= APF_DODIR;
				indent++;
			}
		}

		error = CreateThumb(ap->ap_Buf, destwidth, destheight, keepaspect, deftool, method);

        if (!quiet)
        {
            /* Fix indentation level */
            for (i = 0; i < indent; i++)
            {
                PutStr("     ");
            }

            if (!isDir(&ap->ap_Info))
            {
                PutStr("   ");
            }

            PutStr(ap->ap_Info.fib_FileName);

            if (isDir(&ap->ap_Info))
            {
                PutStr(" (dir)");
            }

            if (error)
            {
                PutStr(" ..Not a known picture file\n");
            }
            else
            {
                PutStr(" ..Thumbnail created\n");
            }
        }
    }

    MatchEnd(ap);

    return retval;
}

STRPTR get_ext(char *filename)
{
	static char extension[32];
	int position=strlen((char *)filename)-1;

	strcpy(extension,"");
	
	while(position > -1 && filename[position] != '.') position--;

	if (position > -1)
	{
		strncpy(extension,&filename[position+1],32);
	}

	return extension;
}

BOOL CreateThumb(STRPTR infile, ULONG destwidth, ULONG destheight, BOOL keepaspect, STRPTR deftool, STRPTR method)
{
	RGBImage *in_pic = NULL, *out_pic = NULL;
	char outfile[MAX_PATH_LEN];
	BOOL retval = TRUE;

	// do not create thumb for info files
	if (strnicmp(get_ext(infile),"info",4)==0) return retval;

	sprintf(outfile,"%s.info",infile);

	if (in_pic = (RGBImage *)AllocVec(sizeof(RGBImage),MEMF_ANY))
	{
		in_pic->Data = NULL;
		if (readpic_by_datatype(in_pic, infile))
		{
			if (keepaspect)
			{
				int arw = in_pic->Width / destwidth;
				int arh = in_pic->Height / destheight;

				if (arw > arh) destheight = in_pic->Height / arw;
				else if (arh > arw) destwidth = in_pic->Width / arh;
			}
			
			if (method != NULL)
			{
				if (strnicmp(method,"BI",2)==0)
					out_pic = resizeBilinear(in_pic, destwidth, destheight);
				else if (strnicmp(method,"AV",2)==0)
					out_pic = resizeAverage(in_pic, destwidth, destheight);
				else
					out_pic = resizeNearest(in_pic, destwidth, destheight);
			}
			else
				out_pic = resizeNearest(in_pic, destwidth, destheight);
			
			if (out_pic)
			{
				if (savepic_by_datatype(out_pic, outfile))
				{
					// Write default tool
					struct DiskObject *icon = GetIconTags
					(
						infile, ICONGETA_FailIfUnavailable, FALSE, TAG_DONE
					);

					if (icon != NULL)
					{
						STRPTR oldDefaultTool = icon->do_DefaultTool;

						if (deftool)
							icon->do_DefaultTool = deftool;
						else
						{
							static STRPTR tool = "multiview";
							icon->do_DefaultTool = tool;
						}
						if (!PutIconTags(infile, icon, TAG_DONE))
						{
							Printf("ERROR: Failed to write icon.\n");
						}
						icon->do_DefaultTool = oldDefaultTool;
						
						FreeDiskObject(icon);
						
						retval = FALSE;
					}
					else
					{
						Printf("ERROR: Failed to open icon for file\n");
						retval = TRUE;;
					}			
				}
			}
		}
		if (in_pic)
		{
			if (in_pic->Data) FreeVec(in_pic->Data);
			FreeVec(in_pic);
		}
		if (out_pic)
		{
			if (out_pic->Data) FreeVec(out_pic->Data);
			FreeVec(out_pic);
		}
	}
		
	return retval;
}

BOOL readpic_by_datatype(RGBImage *pic, char *file_name)
{
	Object *DTImage = NULL;
	struct BitMapHeader *bmh;
	struct pdtBlitPixelArray bpa;

	DTImage = NewDTObject(	file_name,
							(DTA_SourceType),	DTST_FILE,
							(DTA_GroupID),		GID_PICTURE,
							(PDTA_Remap),		FALSE,
							(OBP_Precision),	PRECISION_EXACT,					
							TAG_DONE);

	if (DTImage)
	{

		if (GetDTAttrs( DTImage,
					PDTA_BitMapHeader, (ULONG)&bmh,
					TAG_END ) == 1)

		{

			/* Picture struct and buffer mem allocation */
			pic->Data = (UBYTE *)AllocVec(bmh->bmh_Width * bmh->bmh_Height * 4, MEMF_ANY);
			if (pic->Data)
			{
				bpa.MethodID = PDTM_READPIXELARRAY;
				bpa.pbpa_PixelData = (APTR)pic->Data;
				bpa.pbpa_PixelFormat = PBPAFMT_ARGB;
				bpa.pbpa_PixelArrayMod = bmh->bmh_Width * 4;
				bpa.pbpa_Left = 0;
				bpa.pbpa_Top = 0;
				bpa.pbpa_Width = bmh->bmh_Width;
				bpa.pbpa_Height = bmh->bmh_Height;

				DoMethodA( DTImage, (Msg)&bpa );

				pic->Width  = bmh->bmh_Width;
				pic->Height = bmh->bmh_Height;
				
				DisposeDTObject( DTImage );

				return TRUE;
			}
		}
		DisposeDTObject( DTImage );
	}
	return FALSE;
}

/**
* Nearest Neighbor resizing algorithm
* In case of thumbnail generation the loss of quality 
* should be minimal vs the bilinear algorithm
*/
RGBImage *resizeNearest(RGBImage *pic, ULONG w2, ULONG h2) 
{
	ULONG *temp = NULL;
	RGBImage *outpic = NULL;
	ULONG *pixels = (ULONG *)pic->Data;
    ULONG x_ratio = (ULONG)((pic->Width<<16)/w2) +1;
    ULONG y_ratio = (ULONG)((pic->Height<<16)/h2) +1;
    ULONG x2,y2,i,j;
	
	if (outpic = (RGBImage *)AllocVec(sizeof(RGBImage),MEMF_ANY))
	{
		outpic->Data = NULL;
		if (outpic->Data = (UBYTE *)AllocVec(w2*h2*4, MEMF_ANY))
		{
			outpic->Width = w2;
			outpic->Height = h2;
			temp = (ULONG *)outpic->Data;
			
			for (i=0;i<h2;i++)
			{
				y2 = ((i*y_ratio)>>16) ;
				for (j=0;j<w2;j++)
				{
					x2 = ((j*x_ratio)>>16) ;
					temp[(i*w2)+j] = pixels[(y2*pic->Width)+x2] ;
				}                
			}
		}
	}
    return outpic;
}

#define max(x,y) (x)>(y)?(x):(y)
#define min(x,y) (x)<(y)?(x):(y)

/**
* Averaging resizing algorithm
*  
* 
*/
RGBImage *resizeAverage(RGBImage *pic, ULONG w2, ULONG h2) 
{
	ULONG *temp = NULL;
	RGBImage *outpic = NULL;
	ULONG *pixels = (ULONG *)pic->Data;
	ULONG xpixels = min(256,max((ULONG)(pic->Width/w2),1));
	ULONG ypixels = min(256,max((ULONG)(pic->Height/h2),1));
    ULONG x_ratio = (ULONG)((pic->Width<<16)/w2) +1;
    ULONG y_ratio = (ULONG)((pic->Height<<16)/h2) +1;
	ULONG r,g,b,a,index;
    ULONG x2,y2,i,j,x,y;
	
	if (outpic = (RGBImage *)AllocVec(sizeof(RGBImage),MEMF_ANY))
	{
		outpic->Data = NULL;
		if (outpic->Data = (UBYTE *)AllocVec(w2*h2*4, MEMF_ANY))
		{
			outpic->Width = w2;
			outpic->Height = h2;
			temp = (ULONG *)outpic->Data;
			
			for (i=0;i<h2;i++)
			{
				y2 = ((i*y_ratio)>>16) ;
				for (j=0;j<w2;j++)
				{
					x2 = ((j*x_ratio)>>16) ;
					
					r = 0;
					g = 0;
					b = 0;
					a = 0;
					
					for (y=0;y<ypixels;y++)
						for (x=0;x<xpixels;x++)
						{
							index = ((y2+y)*pic->Width+(x2+x));
							b += (pixels[index]&0xff);
							g += ((pixels[index]>>8)&0xff);
							r += ((pixels[index]>>16)&0xff);
							a += ((pixels[index]>>24)&0xff);
						}
						
					r /= (ypixels*xpixels);
					g /= (ypixels*xpixels);
					b /= (ypixels*xpixels);
					a /= (ypixels*xpixels);
						
					temp[(i*w2)+j] = 	((((ULONG)a)<<24) & 0xff000000) |
										((((ULONG)r)<<16) & 0x00ff0000) |
										((((ULONG)g)<<8)  & 0x0000ff00) |
										((ULONG)b) ;					
				}                
			}
		}
	}
    return outpic;
}

/**
* Bilinear resize ARGB image.
* pixels is an array of size w * h.
* Target dimension is w2 * h2.
* w2 * h2 cannot be zero.
*/
RGBImage *resizeBilinear(RGBImage *pic, ULONG w2, ULONG h2) 
{
	ULONG *temp = NULL;
	RGBImage *outpic = NULL;
	ULONG *pixels = (ULONG *)pic->Data;
	ULONG a, b, c, d, x, y, index ;
	float x_ratio = ((float)(pic->Width-1))/w2 ;
	float y_ratio = ((float)(pic->Height-1))/h2 ;
	float x_diff, y_diff, blue, red, green, alpha ;
	ULONG offset = 0 ;
	int i,j;
	
	if (outpic = (RGBImage *)AllocVec(sizeof(RGBImage),MEMF_ANY))
	{
		if (outpic->Data = (UBYTE *)AllocVec(w2*h2*4, MEMF_ANY))
		{
			outpic->Width = w2;
			outpic->Height = h2;
			temp = (ULONG *)outpic->Data;
	
			if ((pic->Width==w2) && (pic->Height=h2))
			{
				CopyMem(pixels, temp, pic->Width * pic->Height * 4);
				return outpic;
			}
			
			for (i=0;i<h2;i++) 
			{
				for (j=0;j<w2;j++)
				{
					x = (ULONG)(x_ratio * j) ;
					y = (ULONG)(y_ratio * i) ;
					x_diff = (x_ratio * j) - x ;
					y_diff = (y_ratio * i) - y ;
					index = (y*pic->Width+x) ;                
					a = pixels[index] ;
					b = pixels[index+1] ;
					c = pixels[index+pic->Width] ;
					d = pixels[index+pic->Width+1] ;

					// blue element
					// Yb = Ab(1-w)(1-h) + Bb(w)(1-h) + Cb(h)(1-w) + Db(wh)
					blue = (a&0xff)*(1-x_diff)*(1-y_diff) + (b&0xff)*(x_diff)*(1-y_diff) +
					(c&0xff)*(y_diff)*(1-x_diff)   + (d&0xff)*(x_diff*y_diff);

					// green element
					// Yg = Ag(1-w)(1-h) + Bg(w)(1-h) + Cg(h)(1-w) + Dg(wh)
					green = ((a>>8)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>8)&0xff)*(x_diff)*(1-y_diff) +
					((c>>8)&0xff)*(y_diff)*(1-x_diff)   + ((d>>8)&0xff)*(x_diff*y_diff);

					// red element
					// Yr = Ar(1-w)(1-h) + Br(w)(1-h) + Cr(h)(1-w) + Dr(wh)
					red = ((a>>16)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>16)&0xff)*(x_diff)*(1-y_diff) +
					((c>>16)&0xff)*(y_diff)*(1-x_diff)   + ((d>>16)&0xff)*(x_diff*y_diff);

					// alpha element
					// Yr = Ar(1-w)(1-h) + Br(w)(1-h) + Cr(h)(1-w) + Dr(wh)
					alpha = ((a>>24)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>24)&0xff)*(x_diff)*(1-y_diff) +
					((c>>24)&0xff)*(y_diff)*(1-x_diff)   + ((d>>24)&0xff)*(x_diff*y_diff);

					
					temp[offset++] = 	((((ULONG)alpha)<<24) & 0xff000000) |
										((((ULONG)red)  <<16) & 0x00ff0000) |
										((((ULONG)green)<<8)  & 0x0000ff00) |
										((ULONG)blue) ;
				}
			}
		}
	}
	return outpic ;
}

BOOL savepic_by_datatype(RGBImage *pic, char *file_name)
{
	Object *DTImage = NULL;
	struct BitMapHeader *bmhd;
	struct dtWrite dtw;
	struct pdtBlitPixelArray dtb;
	FILE *file = NULL;
	BOOL retval = FALSE;
	
	DTImage = NewDTObject(	(APTR)NULL,
							DTA_SourceType, DTST_RAM,
							DTA_BaseName, (IPTR)"png",
							PDTA_DestMode, PMODE_V43,
							TAG_DONE);
	if (!DTImage) return(FALSE);

	if (GetDTAttrs(DTImage,PDTA_BitMapHeader,(IPTR)&bmhd,TAG_DONE))
	{
		dtb.MethodID = PDTM_WRITEPIXELARRAY;
		dtb.pbpa_PixelData = pic->Data;
		dtb.pbpa_PixelFormat = PBPAFMT_ARGB;
		dtb.pbpa_PixelArrayMod = pic->Width*4;
		dtb.pbpa_Left = 0;
		dtb.pbpa_Top = 0;
		dtb.pbpa_Width = pic->Width;
		dtb.pbpa_Height = pic->Height;

		bmhd->bmh_Width = pic->Width;
		bmhd->bmh_Height = pic->Height;
		bmhd->bmh_Depth = 24;
		bmhd->bmh_PageWidth = 320;
		bmhd->bmh_PageHeight = 240;
		
		DoMethodA(DTImage, (Msg) &dtb);

		//write datatype object to file
		if (file = Open (file_name,MODE_NEWFILE))
		{
			dtw.MethodID = DTM_WRITE;
			dtw.dtw_GInfo = NULL;
			dtw.dtw_FileHandle = file;
			dtw.dtw_Mode = DTWM_RAW;
			dtw.dtw_AttrList = NULL;

			if (DoMethodA(DTImage, (Msg) &dtw)) retval = TRUE;
		}
	}

	if (file) Close (file);
	if (DTImage) DisposeDTObject(DTImage);
	return retval;
}

sound function[edit | edit source]

void do_sound()
{
    soundnow = "sounds/bingobongo.aiff";

    cout << "do sound!"<<endl;
    int frq, vol, pan, state;

    if (soundobject)DisposeDTObject(soundobject);

    if ((soundobject = NewDTObject(soundnow,
        DTA_SourceType,    DTST_FILE,
        DTA_GroupID,       GID_SOUND,
        DTA_Repeat,        TRUE,
        SDTA_SignalTask,   (ULONG) FindTask(NULL),
        SDTA_SignalBit,    (ULONG) SIGBREAKF_CTRL_C,
        TAG_DONE)))
    {
        
        
            DoDTMethod(soundobject, NULL, NULL, DTM_TRIGGER, NULL, STM_PLAY, NULL);

    }
    else
    {
        cout << "can't create sound"<<endl;
    }
}

STATIC IPTR DT_SetMethod(struct IClass *cl, struct Gadget *g, struct opSet *msg)
{
    struct Picture_Data *pd;
    const struct TagItem *tl = msg->ops_AttrList;
    struct TagItem *ti;
    IPTR RetVal;
    struct RastPort *rp;

    pd=(struct Picture_Data *) INST_DATA(cl, g);
    RetVal=0;

    while((ti=NextTagItem(&tl)))
    {
        switch (ti->ti_Tag)
        {
        case DTA_VisibleHoriz:
        case DTA_VisibleVert:
            RetVal = 1;
        break;
       
            case PDTA_ModeID:
                pd->ModeID = (ULONG) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_ModeID: 0x%lx\n",(long)pd->ModeID));
                break;

            case PDTA_ClassBitMap:
                pd->KeepSrcBM = TRUE;
            DGS(bug("picture.datatype/OM_GET: Tag PDTA_ClassBitMap: Handled as PDTA_BitMap\n"));
            case PDTA_BitMap:
                pd->SrcBM = (struct BitMap *) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_BitMap: 0x%lx\n",(long)pd->SrcBM));
                break;

            case PDTA_Screen:
                pd->DestScreen = (struct Screen *) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_Screen: 0x%lx\n",(long)pd->DestScreen));
                break;

            case PDTA_NumColors:
                pd->NumColors = (UWORD) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_NumColors:%ld\n", (long)pd->NumColors));
                break;

            case PDTA_Grab:
            {
                Point *ThePoint;

                DGS(bug("picture.datatype/OM_SET: Tag PDTA_Grab\n"));
                ThePoint = (Point *) ti->ti_Data;
                if(!ThePoint)
                {
                 break;
                }
                pd->Grab.x = ThePoint->x;
                pd->Grab.y = ThePoint->y;
                break;
            }

        case PDTA_SourceMode:
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_SourceMode (ignored): %ld\n", (long)ti->ti_Data));
            break;

        case PDTA_DestMode:
        pd->DestMode = (BOOL) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_DestMode: %ld\n",(long)pd->DestMode));
            break;

            case PDTA_FreeSourceBitMap:
                pd->FreeSource = (BOOL) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_FreeSourceBitMap:%ld\n", (long)pd->FreeSource));
                break;

        case PDTA_UseFriendBitMap:
                pd->UseFriendBM = (BOOL) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_UseFriendBitMap:%ld\n", (long)pd->UseFriendBM));
            break;

        case PDTA_MaxDitherPens:
                pd->MaxDitherPens = (UWORD) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_MaxDitherPens:%ld\n", (long)pd->MaxDitherPens));
            break;

        case PDTA_DitherQuality:
                pd->DitherQuality = (UWORD) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_DitherQuality:%ld\n", (long)pd->DitherQuality));
            break;

        case PDTA_ScaleQuality:
                pd->ScaleQuality = (UWORD) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_ScaleQuality:%ld\n", (long)pd->ScaleQuality));
            break;

            case PDTA_Remap:               
                pd->Remap = (BOOL) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag ID PDTA_Remap: %ld\n",(long)pd->Remap));
                break;   
       
#ifdef __AROS__
        case PDTA_DelayedRead:
                pd->DelayedRead = (BOOL) ti->ti_Data;
                DGS(bug("picture.datatype/OM_SET: Tag PDTA_DelayedRead:
%ld\n", (long)pd->DelayedRead));
            break;
#endif

#ifdef MYDEBUG
            default:
            {
             register int i;
             int Known;

             Known=FALSE;

             for(i=0; i<NumAttribs; i++)
             {
              if(ti->ti_Tag==KnownAttribs[i])
              {
               Known=TRUE;

               DGS(bug("picture.datatype/OM_SET: Tag %s: 0x%lx (%ld)\n",AttribNames[i], (long)ti->ti_Data, (long)ti->ti_Data));
              }
             }

             if(!Known)
             {
              DGS(bug("picture.datatype/OM_SET: Tag ID 0x%lx: 0x%lx\n",(long)ti->ti_Tag, (long)ti->ti_Data));
             }
            }
#endif /* MYDEBUG */
        }
    }

#if 0
    if(msg->ops_GInfo)
    {
        DoMethod((Object *) g, GM_LAYOUT, msg->ops_GInfo, TRUE);
    }
#endif

    /* Do not call the SuperMethod if you come from OM_NEW! */
    if(!(msg->MethodID == OM_NEW))
    {
        RetVal += (IPTR) DoSuperMethodA(cl, (Object *) g, (Msg) msg);
    }

    if(msg->ops_GInfo)
    {
#if 1
        if (RetVal)
#else
        if(OCLASS((Object *) g) == cl)
#endif
        {
            rp=ObtainGIRPort(msg->ops_GInfo);
            if(rp)
            {
                DoMethod((Object *) g, GM_RENDER, (IPTR) msg->ops_GInfo,(IPTR) rp, GREDRAW_UPDATE);
                ReleaseGIRPort (rp);
            }
        }

#if 0 /* stegerg: ?? */
        if(msg->MethodID == OM_UPDATE)
        {
             DoMethod((Object *) g, OM_NOTIFY, msg->ops_AttrList,
msg->ops_GInfo, 0);
        }
#endif
    }

    return(RetVal);
}

---------------------------------------------------

STATIC IPTR DT_Render(struct IClass *cl, struct Gadget *g, struct gpRender *msg)
{
    struct Picture_Data *pd;
    struct DTSpecialInfo *si;

    struct IBox *domain;
    IPTR TopVert, TopHoriz;

    long SrcX, SrcY, DestX, DestY, SizeX, SizeY;

    pd = (struct Picture_Data *) INST_DATA(cl, g);
    si = (struct DTSpecialInfo *) g->SpecialInfo;

    if(!pd->Layouted)
    {
        D(bug("picture.datatype/GM_RENDER: No layout done yet !\n"));
        return FALSE;
    }

    if(si->si_Flags & DTSIF_LAYOUT)
    {
        D(bug("picture.datatype/GM_RENDER: In layout process !\n"));
        return FALSE;
    }

    if(!(GetDTAttrs((Object *) g, DTA_Domain,    (IPTR) &domain,
                   DTA_TopHoriz,     (IPTR) &TopHoriz,
                   DTA_TopVert,      (IPTR) &TopVert,
                   TAG_DONE) == 3))
    {
        D(bug("picture.datatype/GM_RENDER: Couldn't get dimensions\n"));
        return FALSE;
    }

    ObtainSemaphore(&(si->si_Lock));
    D(bug("picture.datatype/GM_RENDER: Domain: left %ld top %ld width %ld height %ld\n", domain->Left, domain->Top, domain->Width, domain->Height));
    D(bug("picture.datatype/GM_RENDER: TopHoriz %ld TopVert %ld Width %ld Height %ld\n", (long)TopHoriz, (long)TopVert, (long)pd->DestWidth, (long)pd->DestHeight));

    if( pd->DestBM )
    {
    SrcX = MIN( TopHoriz, pd->DestWidth );
    SrcY = MIN( TopVert, pd->DestHeight );
    DestX = domain->Left;
    DestY = domain->Top;
    SizeX = MIN( pd->DestWidth - SrcX, domain->Width );
    SizeY = MIN( pd->DestHeight - SrcY, domain->Height );
    D(bug("picture.datatype/GM_RENDER: SizeX/Y %ld/%ld\n SrcX/Y %ld/%ld DestX/Y %ld/%ld\n",
        SizeX, SizeY, SrcX, SrcY, DestX, DestY));

    render_on_rastport(pd, g, SrcX, SrcY, msg->gpr_RPort, DestX, DestY, SizeX, SizeY);
    }
    else /* if(pd->DestBuffer) || if(pd->DestBM) */
    {
        D(bug("picture.datatype/GM_RENDER: No destination picture present !\n"));
        return FALSE;
    }
    ReleaseSemaphore(&(si->si_Lock));

    return TRUE;
}

How to compile datatypes[edit | edit source]

Build dtdesc tool, this is what you need. The source is located in tools/dtdesc. This tool is used in order to make a datatype descriptor from .dtd file. Class library is built in a usual way, using a usual crosscompiler.

A package so that it will be easy to build datatypes independently of the whole build system. Compiled createdtdesc and examinedtdesc for native AROS. One other tool that is needed is genmodule.

What is needed is a READ/WRITEPIXELARRAY interface, that replaces the former SET PDTA_BitMap and GET PDTA_DestBitMap interface. If a Bitmap was SET (legacy interface), it gets converted to LUT8 format during layout. A destination BitMap is only created, if this is set by Prefs or an applications requests it by GET PDTA_DestBitMap.

RENDER Method chooses one of these functions for displaying

  • cgfx/WritePixelArray: Truecolor pic -> Truecolor screen
  • cgfx/WriteLUTPixelArray: Colormapped pic -> Truecolor screen
  • graphics/WriteChunkyPixels: Colormapped pic -> Colormapped chunky screen
  • graphics/BltBitMapRastPort: Colormapped pic -> Colormapped planar screen

Truecolor pic -> Colormapped screen is handled during layout, with a fixed colormap and some simple but fast dithering algorithm (one dimensional error propagation). Floyd-Steinberg dithering algorithm could be used for slightly better results (two dimensional error propagation). Much better results could be obtained by a calculated colormap (e.g. median cut algorithm), but this is much slower.

Colormapped data is always stored in LUT8 format, or BitMap format for legacy. Truecolor data is always stored in ARGB format. This isn't memory effective, but makes things more simple and faster. Some optimization could be done here.

Created a template for new graphic datatypes here.

/*
    Copyright © 1995-2005, The AROS Development Team. All rights reserved.
    $Id: bmpclass.c 30902 2009-03-14 13:38:20Z mazze $
*/

/**********************************************************************/

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

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dostags.h>
#include <graphics/gfxbase.h>
#include <graphics/rpattr.h>
#include <cybergraphx/cybergraphics.h>
#include <intuition/imageclass.h>
#include <intuition/icclass.h>
#include <intuition/gadgetclass.h>
#include <intuition/cghooks.h>
#include <datatypes/datatypesclass.h>
#include <datatypes/pictureclass.h>

#include <clib/alib_protos.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <proto/iffparse.h>
#include <proto/datatypes.h>

#include <aros/symbolsets.h>

#include "debug.h"

#include "methods.h"

/* Open superclass */
ADD2LIBS("datatypes/picture.datatype", 0, struct Library *, PictureBase);

/**************************************************************************************************/

#define FILEBUFSIZE 65536
#define MAXCOLORS   256

typedef struct {
    struct IFFHandle    *filehandle;

    UBYTE               *filebuf;
    UBYTE               *filebufpos;
    long                filebufbytes;
    long                filebufsize;
    UBYTE               *linebuf;
    UBYTE               *linebufpos;
    long                linebufbytes;
    long                linebufsize;
    
    APTR                codecvars;
} BmpHandleType;

typedef struct
{
    WORD        bfType;             //  0 ASCII "BM"
    ULONG       bfSize;             //  2 Size in bytes of the file
    WORD        bfReserved1;        //  6 Zero
    WORD        bfReserved2;        //  8 Zero
    ULONG       bfOffBits;          // 10 Byte offset in files where image begins
} FileBitMapHeader __attribute__((packed));    // 14

typedef struct
{
    ULONG       biSize;             //  0 Size of this header, 40 bytes
    LONG        biWidth;            //  4 Image width in pixels
    LONG        biHeight;           //  8 Image height in pixels
    WORD        biPlanes;           // 12 Number of image planes, must be 1
    WORD        biBitCount;         // 14 Bits per pixel, 1, 4, 8, 24, or 32
    ULONG       biCompression;      // 16 Compression type, below
    ULONG       biSizeImage;        // 20 Size in bytes of compressed image, or zero
    LONG        biXPelsPerMeter;    // 24 Horizontal resolution, in pixels/meter
    LONG        biYPelsPerMeter;    // 28 Vertical resolution, in pixels/meter
    ULONG       biClrUsed;          // 32 Number of colors used, below
    ULONG       biClrImportant;     // 36 Number of "important" colors
} BitmapInfoHeader __attribute__((packed));    // 40

/* "BM" backwards, due to LE byte order */
#define BITMAP_ID "MB"

/**************************************************************************************************/

static void BMP_Exit(BmpHandleType *bmphandle, LONG errorcode)
{
    D(if (errorcode) bug("bmp.datatype/BMP_Exit() --- IoErr %ld\n", errorcode));
    if (bmphandle->filebuf)
    {
	FreeMem(bmphandle->filebuf, bmphandle->filebufsize);
    }
    if (bmphandle->linebuf)
    {
	FreeMem(bmphandle->linebuf, bmphandle->linebufsize);
    }
    if (bmphandle->codecvars)
    {
	FreeVec(bmphandle->codecvars);
    }
    SetIoErr(errorcode);
}

/**************************************************************************************************/

/* buffered file access, useful for RLE */
BOOL SaveBMP_EmptyBuf(BmpHandleType *bmphandle, long minbytes)
{
    long                bytes, bytestowrite;
    
    bytestowrite = bmphandle->filebufsize - (bmphandle->filebufbytes + minbytes);
    D(bug("bmp.datatype/SaveBMP_EmptyBuf() --- minimum %ld bytes, %ld bytes to write\n", (long)minbytes, (long)bytestowrite));
    bytes = Write(bmphandle->filehandle, bmphandle->filebuf, bytestowrite);
    if ( bytes < bytestowrite )
    {
	D(bug("bmp.datatype/SaveBMP_EmptyBuf() --- writing failed, wrote %ld bytes\n", (long)bytes));
	return FALSE;
    }
    bmphandle->filebufpos = bmphandle->filebuf;
    bmphandle->filebufbytes = bmphandle->filebufsize - minbytes;
    D(bug("bmp.datatype/SaveBMP_EmptyBuf() --- wrote %ld bytes\n", (long)bytes));
    return TRUE;
}

/* buffered file access, useful for RLE */
BOOL LoadBMP_FillBuf(BmpHandleType *bmphandle, long minbytes)
{
    long                i, bytes;
    
    //D(bug("bmp.datatype/LoadBMP_FillBuf() --- minimum %ld bytes of %ld (%ld) bytes\n", (long)minbytes, (long)bmphandle->filebufbytes, (long)(bmphandle->filebufsize-(bmphandle->filebufpos-bmphandle->filebuf)) ));
    if ( bmphandle->filebufbytes >= 0 )
	return TRUE;
    bytes = bmphandle->filebufbytes + minbytes;
    //D(bug("bmp.datatype/LoadBMP_FillBuf() --- %ld bytes requested, %ld bytes left\n", (long)minbytes, (long)bytes));
    if (bytes > 0)
    {
	//D(bug("bmp.datatype/LoadBMP_FillBuf() --- existing %ld old bytes\n", (long)bytes));
	for (i=0; i<bytes; i++)     /* copy existing bytes to start of buffer */
	    bmphandle->filebuf[i] = bmphandle->filebufpos[i];
    }
    bmphandle->filebufpos = bmphandle->filebuf;
    bytes = Read(bmphandle->filehandle, bmphandle->filebuf + bytes, bmphandle->filebufsize - bytes);
    if (bytes < 0 ) bytes = 0;
    bmphandle->filebufbytes += bytes;
    //D(bug("bmp.datatype/LoadBMP_FillBuf() --- read %ld bytes, remaining new %ld bytes\n", (long)bytes, (long)bmphandle->filebufbytes));
    //D(bug("bmp.datatype/LoadBMP_FillBuf() --- >minimum %ld bytes of %ld (%ld) bytes\n", (long)minbytes, (long)bmphandle->filebufbytes, (long)(bmphandle->filebufsize-(bmphandle->filebufpos-bmphandle->filebuf)) ));
    if (bmphandle->filebufbytes >= 0)
	return TRUE;
    return FALSE;
}

static BOOL LoadBMP_Colormap(BmpHandleType *bmphandle, int numcolors,
			    struct ColorRegister *colormap, ULONG *colregs)
{
    unsigned int        i, j;

    if (numcolors && numcolors <= MAXCOLORS)
    {
	j = 0;
	for (i = 0; i < numcolors; i++)
	{
	    if ( (bmphandle->filebufbytes -= 4) < 0 && !LoadBMP_FillBuf(bmphandle, 4) )
	    {
		D(bug("bmp.datatype/LoadBMP_Colormap() --- colormap loading failed\n"));
		return FALSE;
	    }
	    /* BGR0 format for MS Win files, BGR format for OS/2 files */
	    colormap[i].blue = *(bmphandle->filebufpos)++;
	    colormap[i].green = *(bmphandle->filebufpos)++;
	    colormap[i].red = *(bmphandle->filebufpos)++;
	    bmphandle->filebufpos++;
	    colregs[j++] = ((ULONG)colormap[i].red)<<24;
	    colregs[j++] = ((ULONG)colormap[i].green)<<24;
	    colregs[j++] = ((ULONG)colormap[i].blue)<<24;
	    // D(if (i<5) bug("gif r %02lx g %02lx b %02lx\n", colormap[i].red, colormap[i].green, colormap[i].blue));
	}
	D(bug("bmp.datatype/LoadBMP_Colormap() --- %d colors loaded\n", numcolors));
    }
    return TRUE;
}

/**************************************************************************************************/
static BOOL LoadBMP(struct IClass *cl, Object *o)
{
    BmpHandleType           *bmphandle;
    UBYTE                   *filebuf;
    IPTR                    sourcetype;
    ULONG                   bfSize, bfOffBits;
    ULONG                   biSize, biWidth, biHeight, biCompression;
    ULONG                   biClrUsed, biClrImportant;
    UWORD                   biPlanes, biBitCount;
    ULONG                   alignwidth, alignbytes, pixelfmt;
    long                    x, y;
    int                     cont, byte;
    struct BitMapHeader     *bmhd;
    struct ColorRegister    *colormap;
    ULONG                   *colorregs;
    STRPTR                  name;

    D(bug("bmp.datatype/LoadBMP()\n"));

    if( !(bmphandle = AllocMem(sizeof(BmpHandleType), MEMF_ANY)) )
    {
	SetIoErr(ERROR_NO_FREE_STORE);
	return FALSE;
    }
    bmphandle->filebuf = NULL;
    bmphandle->linebuf = NULL;
    bmphandle->codecvars = NULL;
    
    
    if( GetDTAttrs(o,   DTA_SourceType    , (IPTR)&sourcetype ,
			DTA_Handle        , (IPTR)&(bmphandle->filehandle),
			PDTA_BitMapHeader , (IPTR)&bmhd,
			TAG_DONE) != 3 )
    {
	BMP_Exit(bmphandle, ERROR_OBJECT_NOT_FOUND);
	return FALSE;
    }
    
    if ( sourcetype == DTST_RAM && bmphandle->filehandle == NULL && bmhd )
    {
	D(bug("bmp.datatype/LoadBMP() --- Creating an empty object\n"));
	BMP_Exit(bmphandle, 0);
	return TRUE;
    }
    if ( sourcetype != DTST_FILE || !bmphandle->filehandle || !bmhd )
    {
	D(bug("bmp.datatype/LoadBMP() --- unsupported mode\n"));
	BMP_Exit(bmphandle, ERROR_NOT_IMPLEMENTED);
	return FALSE;
    }
    
    /* initialize buffered file reads */
    bmphandle->filebufbytes = 0;
    bmphandle->filebufsize = FILEBUFSIZE;
    if( !(bmphandle->filebuf = bmphandle->filebufpos = AllocMem(bmphandle->filebufsize, MEMF_ANY)) )
    {
	BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	return FALSE;
    }

    /* load FileBitmapHeader from file, make sure, there are at least 14 bytes in buffer */
    if ( (bmphandle->filebufbytes -= 14) < 0 && !LoadBMP_FillBuf(bmphandle, 14) )
    {
	D(bug("bmp.datatype/LoadBMP() --- filling buffer with header failed\n"));
	BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	return FALSE;
    }
    filebuf = bmphandle->filebufpos;    /* this makes things easier */
    bmphandle->filebufpos += 14;
    if( filebuf[0] != 'B' && filebuf[1] != 'M' )
    {
	D(bug("bmp.datatype/LoadBMP() --- header type mismatch\n"));
	BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	return FALSE;
    }
    /* byte-wise access isn't elegant, but it is endianess-safe */
    bfSize = (filebuf[5]<<24) | (filebuf[4]<<16) | (filebuf[3]<<8) | filebuf[2];
    bfOffBits = (filebuf[13]<<24) | (filebuf[12]<<16) | (filebuf[11]<<8) | filebuf[10];
    D(bug("bmp.datatype/LoadBMP() --- bfSize %ld bfOffBits %ld\n", bfSize, bfOffBits));

    /* load BitmapInfoHeader from file, make sure, there are at least 40 bytes in buffer */
    if ( (bmphandle->filebufbytes -= 40) < 0 && !LoadBMP_FillBuf(bmphandle, 40) )
    {
	D(bug("bmp.datatype/LoadBMP() --- filling buffer with header 2 failed\n"));
	BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	return FALSE;
    }
    filebuf = bmphandle->filebufpos;    /* this makes things easier */
    bmphandle->filebufpos += 40;

    /* get image size attributes */
    biSize = (filebuf[3]<<24) | (filebuf[2]<<16) | (filebuf[1]<<8) | filebuf[0];
    biWidth = (filebuf[7]<<24) | (filebuf[6]<<16) | (filebuf[5]<<8) | filebuf[4];
    biHeight = (filebuf[11]<<24) | (filebuf[10]<<16) | (filebuf[9]<<8) | filebuf[8];
    biPlanes = (filebuf[13]<<8) | filebuf[12];
    biBitCount = (filebuf[15]<<8) | filebuf[14];
    biCompression = (filebuf[19]<<24) | (filebuf[18]<<16) | (filebuf[17]<<8) | filebuf[16];
    biClrUsed = (filebuf[35]<<24) | (filebuf[34]<<16) | (filebuf[33]<<8) | filebuf[32];
    biClrImportant = (filebuf[39]<<24) | (filebuf[38]<<16) | (filebuf[37]<<8) | filebuf[36];
    D(bug("bmp.datatype/LoadBMP() --- BMP-Screen %ld x %ld x %ld, %ld (%ld) colors, compression %ld, type %ld\n",
	  biWidth, biHeight, (long)biBitCount, biClrUsed, biClrImportant, biCompression, biSize));
    if (biSize != 40 || biPlanes != 1 || biCompression != 0)
    {
	D(bug("bmp.datatype/LoadBMP() --- Image format not supported\n"));
	BMP_Exit(bmphandle, ERROR_NOT_IMPLEMENTED);
	return FALSE;
    }

    /* check color mode */
    pixelfmt = PBPAFMT_LUT8;
    switch (biBitCount)
    {
	case 1:
	    alignwidth = (biWidth + 31) & ~31UL;
	    alignbytes = alignwidth / 8;
	    break;
	case 4:
	    alignwidth = (biWidth + 7) & ~7UL;
	    alignbytes = alignwidth / 2;
	    break;
	case 8:
	    alignwidth = (biWidth + 3) & ~3UL;
	    alignbytes = alignwidth;
	    break;
	case 24:
	    alignbytes = (biWidth + 3) & ~3UL;
	    alignwidth = alignbytes * 3;
	    pixelfmt = PBPAFMT_RGB;
	    break;
	default:
	    D(bug("bmp.datatype/LoadBMP() --- unsupported color depth\n"));
	    BMP_Exit(bmphandle, ERROR_NOT_IMPLEMENTED);
	    return FALSE;
    }
    D(bug("bmp.datatype/LoadBMP() --- align: pixels %ld bytes %ld\n", alignwidth, alignbytes));

    /* set BitMapHeader with image size */
    bmhd->bmh_Width  = bmhd->bmh_PageWidth  = biWidth;
    bmhd->bmh_Height = bmhd->bmh_PageHeight = biHeight;
    bmhd->bmh_Depth  = biBitCount;

    /* get empty colormap, then fill in colormap to use*/
    if (biBitCount != 24)
    {
	if( !(GetDTAttrs(o, PDTA_ColorRegisters, (IPTR)&colormap,
			    PDTA_CRegs, (IPTR)&colorregs,
			    TAG_DONE ) == 2) ||
	    !(colormap && colorregs) )
	{
	    D(bug("bmp.datatype/LoadBMP() --- got no colormap\n"));
	    BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	    return FALSE;
	}
	if( !LoadBMP_Colormap(bmphandle, biClrUsed, colormap, colorregs) )
	{
	    BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	    return FALSE;
    }
    }
    /* skip offset */
    bfOffBits = bfOffBits - 14 - 40 - biClrUsed*4;
    D(bug("bmp.datatype/LoadBMP() --- remaining offset %ld\n", bfOffBits));
    if ( bfOffBits < 0 ||
	( (bmphandle->filebufbytes -= bfOffBits ) < 0 && !LoadBMP_FillBuf(bmphandle, bfOffBits) ) )
    {
	D(bug("bmp.datatype/LoadBMP() --- cannot skip offset\n"));
	BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	return FALSE;
    }
    bmphandle->filebufpos += bfOffBits;

    /* Pass attributes to picture.datatype */
    GetDTAttrs( o, DTA_Name, (IPTR)&name, TAG_DONE );
    SetDTAttrs(o, NULL, NULL, PDTA_NumColors, biClrUsed,
			      DTA_NominalHoriz, biWidth,
			      DTA_NominalVert , biHeight,
			      DTA_ObjName     , (IPTR)name,
			      TAG_DONE);

    /* Now decode the picture data into a chunky buffer; and pass it to Bitmap line-by-line */
    bmphandle->linebufsize = bmphandle->linebufbytes = alignwidth;
    if (! (bmphandle->linebuf = bmphandle->linebufpos = AllocMem(bmphandle->linebufsize, MEMF_ANY)) )
    {
	BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	return FALSE;
    }

    //D(bug("bmp.datatype/LoadBMP() --- bytes of %ld (%ld) bytes\n", (long)bmphandle->filebufbytes, (long)(bmphandle->filebufsize-(bmphandle->filebufpos-bmphandle->filebuf)) ));
    cont = 1;
    for (y=biHeight-1; y>=0 && cont; y--)
    {
	int r, g, b;
	
	bmphandle->linebufpos = bmphandle->linebuf;
	if (biBitCount == 24)
	{
	    if ( (bmphandle->filebufbytes -= alignwidth) < 0 && !LoadBMP_FillBuf(bmphandle, alignwidth) )
	    {
		D(bug("bmp.datatype/LoadBMP() --- early end of bitmap data, x %ld y %ld\n", x, y));
		//BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
		//return FALSE;
		cont = 0;
	    }
	    for (x=0; x<alignbytes; x++)
	    {
		b = *(bmphandle->filebufpos)++;
		g = *(bmphandle->filebufpos)++;
		r = *(bmphandle->filebufpos)++;
		*(bmphandle->linebufpos)++ = r;
		*(bmphandle->linebufpos)++ = g;
		*(bmphandle->linebufpos)++ = b;
	    }
	}
	else
	{
	    for (x=0; x<alignbytes; x++)
	    {
		if ( (bmphandle->filebufbytes -= 1) < 0 && !LoadBMP_FillBuf(bmphandle, 1) )
		{
		    D(bug("bmp.datatype/LoadBMP() --- early end of bitmap data, x %ld y %ld\n", x, y));
		    //BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
		    //return FALSE;
		    cont = 0;
		    break;              
		}
		byte = *(bmphandle->filebufpos)++;
		switch (biBitCount)
		{
		    case 1:
			for (b=0; b<8; b++)
			{
			    *(bmphandle->linebufpos)++ = (byte & 0x80) ? 1 : 0;
			    byte <<= 1;
			}
			break;
		    case 4:
			*(bmphandle->linebufpos)++ = (byte & 0xf0) >> 4;
			*(bmphandle->linebufpos)++ = (byte & 0x0f);
			break;
		    case 8:
			*(bmphandle->linebufpos)++ = byte;
			break;
		    case 24:
			*(bmphandle->linebufpos)++ = byte;
			break;
		}
	    }
	}
	if
	(
	    !DoSuperMethod(cl, o,
			   PDTM_WRITEPIXELARRAY,	/* Method_ID */
			   (IPTR)bmphandle->linebuf,	/* PixelData */
			   pixelfmt,			/* PixelFormat */
			   alignwidth,			/* PixelArrayMod (number of bytes per row) */
			   0,				/* Left edge */
			   y,				/* Top edge */
			   biWidth,			/* Width */
			   1				/* Height (here: one line) */
	    )
	)
	{
	    D(bug("bmp.datatype/LoadBMP() --- WRITEPIXELARRAY failed !\n"));
	    BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	    return FALSE;
	}
    }
    //D(bug("bmp.datatype/LoadBMP() --- bytes of %ld (%ld) bytes\n", (long)bmphandle->filebufbytes, (long)(bmphandle->filebufsize-(bmphandle->filebufpos-bmphandle->filebuf)) ));

    D(bug("bmp.datatype/LoadBMP() --- Normal Exit\n"));
    BMP_Exit(bmphandle, 0);
    return TRUE;
}

/**************************************************************************************************/

static BOOL SaveBMP(struct IClass *cl, Object *o, struct dtWrite *dtw )
{
    BmpHandleType           *bmphandle;
    UBYTE                   *filebuf;
    unsigned int            width, height, widthxheight, numplanes, numcolors;
    struct BitMapHeader     *bmhd;
    struct BitMap           *bm;
    struct RastPort         rp;
    long                    *colorregs;
    int                     i, j, ret;

    D(bug("bmp.datatype/SaveBMP()\n"));

    if( !(bmphandle = AllocMem(sizeof(BmpHandleType), MEMF_ANY)) )
    {
	SetIoErr(ERROR_NO_FREE_STORE);
	return FALSE;
    }
    bmphandle->filebuf = NULL;
    bmphandle->linebuf = NULL;
    bmphandle->codecvars = NULL;

    /* A NULL file handle is a NOP */
    if( !dtw->dtw_FileHandle )
    {
	D(bug("bmp.datatype/SaveBMP() --- empty Filehandle - just testing\n"));
	BMP_Exit(bmphandle, 0);
	return TRUE;
    }
    bmphandle->filehandle = dtw->dtw_FileHandle;

    /* Get BitMap and color palette */
    if( GetDTAttrs( o,  PDTA_BitMapHeader, (IPTR)&bmhd,
			PDTA_BitMap,       (IPTR)&bm,
			PDTA_CRegs,        (IPTR)&colorregs,
			PDTA_NumColors,    (IPTR)&numcolors,
			TAG_DONE ) != 4UL ||
	!bmhd || !bm || !colorregs || !numcolors)
    {
	D(bug("bmp.datatype/SaveBMP() --- missing attributes\n"));
	BMP_Exit(bmphandle, ERROR_OBJECT_NOT_FOUND);
	return FALSE;
    }
#if 0
    /* Check if this is a standard BitMap */
    if( !( GetBitMapAttr(bm, BMA_FLAGS) & BMF_STANDARD ) )
    {
	D(bug("bmp.datatype/SaveBMP() --- wrong BitMap type\n"));
	BMP_Exit(bmphandle, ERROR_OBJECT_WRONG_TYPE);
	return FALSE;
    }
#endif
    /* initialize buffered file reads */
    bmphandle->filebufsize = FILEBUFSIZE;
    bmphandle->filebufbytes = bmphandle->filebufsize;
    if( !(bmphandle->filebuf = bmphandle->filebufpos = AllocMem(bmphandle->filebufsize, MEMF_ANY)) )
    {
	BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	return FALSE;
    }

    /* write BMP 87a header to file, make sure, there are at least 13 bytes in buffer */
    if ( (bmphandle->filebufbytes -= 13) < 0 && !SaveBMP_EmptyBuf(bmphandle, 13) )
    {
	D(bug("bmp.datatype/SaveBMP() --- filling buffer with header failed\n"));
	BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	return FALSE;
    }
    filebuf = bmphandle->filebufpos;    /* this makes things easier */
    bmphandle->filebufpos += 13;

    /* set screen descriptor attributes (from BitMapHeader) */
    width = bmhd->bmh_PageWidth;
    height = bmhd->bmh_PageHeight;
    numplanes = bmhd->bmh_Depth - 1;
    numcolors = 1 << (numplanes + 1);
    D(bug("bmp.datatype/SaveBMP() --- BMP-Image %d x %d x %d, cols %d\n", width, height, numplanes+1, numcolors));
    filebuf[6] = width & 0xff;
    filebuf[7] = width >> 8;
    filebuf[8] = height & 0xff;
    filebuf[9] = height >> 8;
    filebuf[10] = 0x80 | ((numplanes & 0x07) << 4) | (numplanes & 0x07) ; /* set numplanes, havecolmap=1 */
    filebuf[11] = 0;    /* this is fillcolor */
    filebuf[12] = 0;    /* this is pixel aspect ratio, 0 means unused */

    /* write screen colormap, we don't use an image colormap */
    for (i = 0; i < numcolors*3; i += 3)
    {
	if ( (bmphandle->filebufbytes -= 3) < 0 && !SaveBMP_EmptyBuf(bmphandle, 3) )
	{
	    BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	    return FALSE;
	}
	*(bmphandle->filebufpos)++ = colorregs[i] >> 24;
	*(bmphandle->filebufpos)++ = colorregs[i+1] >> 24;
	*(bmphandle->filebufpos)++ = colorregs[i+2] >> 24;
    }

    /* write image header, image has same size as screen */
    if ( (bmphandle->filebufbytes -= 10) < 0 && !SaveBMP_EmptyBuf(bmphandle, 10) )
    {
	BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	return FALSE;
    }
    filebuf = bmphandle->filebufpos;    /* this makes things easier */
    bmphandle->filebufpos += 10;
    filebuf[0] = ',';       /* header ID */
    filebuf[1] = filebuf[2] = 0;    /* no left edge */
    filebuf[3] = filebuf[4] = 0;    /* no top edge */
    filebuf[5] = width & 0xff;
    filebuf[6] = width >> 8;
    filebuf[7] = height & 0xff;
    filebuf[8] = height >> 8;
    filebuf[9] = numplanes & 0x07; /* set numplanes, havecolmap=0, interlaced=0 */

    /* Now read the picture data from the bitplanes and write it to a chunky buffer */
    /* For now, we use a full picture pixel buffer, not a single line */
    widthxheight = width*height;
    bmphandle->linebufsize = bmphandle->linebufbytes = widthxheight;
    if (! (bmphandle->linebuf = bmphandle->linebufpos = AllocMem(bmphandle->linebufsize, MEMF_ANY)) )
    {
	BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	return FALSE;
    }
    InitRastPort(&rp);
    rp.BitMap=bm;
    for (j=0; j<height; j++)
    {
	for (i=0; i<width; i++)
	{
	    ret = (UBYTE)ReadPixel(&rp, i, j);  /* very slow, to be changed */
	    *(bmphandle->linebufpos)++ = ret;
	}
    }
    bmphandle->linebufpos = bmphandle->linebuf;

    /* write the chunky buffer to file, after encoding */
    
    /* write end-of-BMP marker */
    if ( !bmphandle->filebufbytes-- && !SaveBMP_EmptyBuf(bmphandle, 1) )
    {
	BMP_Exit(bmphandle, ERROR_NO_FREE_STORE);
	return FALSE;
    }
    *(bmphandle->filebufpos)++ = ';';

    /* flush write buffer to file and exit */
    SaveBMP_EmptyBuf(bmphandle, 0);
    D(bug("bmp.datatype/SaveBMP() --- Normal Exit\n"));
    BMP_Exit(bmphandle, 0);
    return TRUE;
}

/**************************************************************************************************/

IPTR BMP__OM_NEW(Class *cl, Object *o, Msg msg)
{
    Object *newobj;
    
    D(bug("bmp.datatype/DT_Dispatcher: Method OM_NEW\n"));
    
    newobj = (Object *)DoSuperMethodA(cl, o, msg);
    if (newobj)
    {
	if (!LoadBMP(cl, newobj))
	{
	    CoerceMethod(cl, newobj, OM_DISPOSE);
	    newobj = NULL;
	}
    }

    return (IPTR)newobj;
}

/**************************************************************************************************/

IPTR BMP__DTM_WRITE(Class *cl, Object *o, struct dtWrite *dtw)
{
    D(bug("bmp.datatype/DT_Dispatcher: Method DTM_WRITE\n"));
    if( (dtw -> dtw_Mode) == DTWM_RAW )
    {
	/* Local data format requested */
	return SaveBMP(cl, o, dtw );
    }
    else
    {
	/* Pass msg to superclass (which writes an IFF ILBM picture)... */
	return DoSuperMethodA( cl, o, (Msg)dtw );
    }
}
/*
    Copyright © 1995-2001, The AROS Development Team. All rights reserved.
    $Id: ppmclass.c 30902 2009-03-14 13:38:20Z mazze $
*/

/**********************************************************************/

#define DEBUGMETHODS 0

/**********************************************************************/

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

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dostags.h>
#include <graphics/gfxbase.h>
#include <graphics/rpattr.h>
#include <intuition/imageclass.h>
#include <intuition/icclass.h>
#include <intuition/gadgetclass.h>
#include <intuition/cghooks.h>
#include <datatypes/datatypesclass.h>
#include <datatypes/pictureclass.h>

#include <clib/alib_protos.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <proto/iffparse.h>
#include <proto/datatypes.h>

#include <aros/symbolsets.h>

ADD2LIBS("datatypes/picture.datatype", 0, struct Library *, PictureBase);

#include "debug.h"

#include "methods.h"

/**************************************************************************************************/

IPTR PPM__OM_NEW(Class *cl, Object *o, struct opSet *msg)
{
 IPTR RetVal;
 char *Title;
 IPTR sourcetype;
 BPTR FileHandle;
 struct BitMapHeader *bmhd;
 char LineBuffer[128];
 long Width, Height, NumChars;
 unsigned int i;
 unsigned char *RGBBuffer;

 D(bug("ppm.datatype/OM_NEW: Entering\n"));

 D(bug("ppm.datatype/OM_NEW: cl: 0x%lx o: 0x%lx msg: 0x%lx\n", (unsigned long) cl, (unsigned long) o, (unsigned long) msg));

 RetVal=DoSuperMethodA(cl, o, (Msg) msg);
 if(!RetVal)
 {
  D(bug("ppm.datatype/OM_NEW: DoSuperMethod failed\n"));
  return(0);
 }

 D(bug("ppm.datatype/OM_NEW: DoSuperMethod: 0x%lx\n", (unsigned long) RetVal));

    if( GetDTAttrs((Object *) RetVal,
			DTA_SourceType    , (IPTR)&sourcetype ,
			DTA_Handle        , (IPTR)&FileHandle,
			DTA_Name          , (IPTR)&Title,
			PDTA_BitMapHeader , (IPTR)&bmhd,
			TAG_DONE) != 4 )
    {
        D(bug("ppm.datatype/OM_NEW: GetDTAttrs(DTA_Handle, DTA_BitMapHeader) error !\n"));
	CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
	SetIoErr(ERROR_OBJECT_NOT_FOUND);
	return FALSE;
    }
    D(bug("ppm.datatype/OM_NEW: GetDTAttrs(DTA_Handle, DTA_BitMapHeader) successful\n"));
    
    if ( sourcetype == DTST_RAM && FileHandle == NULL )
    {
	D(bug("ppm.datatype/OM_NEW: Creating an empty object\n"));
	return TRUE;
    }
    if ( sourcetype != DTST_FILE || !FileHandle || !bmhd )
    {
	D(bug("ppm.datatype/OM_NEW: Unsupported sourcetype mode\n"));
	SetIoErr(ERROR_NOT_IMPLEMENTED);
	return FALSE;
    }

 D(bug("ppm.datatype/OM_NEW: Title: %s\n", Title?Title:"[none]"));

 Seek(FileHandle, 0, OFFSET_BEGINNING);
 D(bug("ppm.datatype/OM_NEW: Seek successful\n"));

 if(!FGets(FileHandle, LineBuffer, 128))
 {
  D(bug("ppm.datatype/OM_NEW: FGets line 1 failed\n"));

  SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  return(0);
 }

 if(!(LineBuffer[0]=='P' && LineBuffer[1]=='6'))
 {
  D(bug("ppm.datatype/OM_NEW: Not a P6 PPM\n"));

  SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  return(0);
 }

 D(bug("ppm.datatype/OM_NEW: It's a P6 PPM\n"));

 if(!FGets(FileHandle, LineBuffer, 128))
 {
  D(bug("ppm.datatype/OM_NEW: FGets line 2 failed\n"));

  SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  return(0);
 }

 if(LineBuffer[0]=='#')
 {
  D(bug("ppm.datatype/OM_NEW: Line 2 is a comment\n"));

  if(!FGets(FileHandle, LineBuffer, 128))
  {
   D(bug("ppm.datatype/OM_NEW: FGets line 3 after comment failed\n"));

   SetIoErr(ERROR_OBJECT_WRONG_TYPE);
   CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
   return(0);
  }
 }

 NumChars=StrToLong(LineBuffer, (LONG *)&Width);

 if(!((NumChars>0) && (Width>0)))
 {
  D(bug("ppm.datatype/OM_NEW: StrToLong(Width) failed\n"));

  SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  return(0);
 }

 D(bug("ppm.datatype/OM_NEW: Width: %ld\n", (long) Width));
 D(bug("ppm.datatype/OM_NEW: NumChars: %ld\n", (long) NumChars));

 NumChars=StrToLong(LineBuffer+NumChars, (LONG *)&Height);

 if(!((NumChars>0) && (Height>0)))
 {
  D(bug("ppm.datatype/OM_NEW: StrToLong(Height) failed\n"));

  SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  return(0);
 }

 D(bug("ppm.datatype/OM_NEW: Height: %ld\n", (long) Height));
 D(bug("ppm.datatype/OM_NEW: NumChars: %ld\n", (long) NumChars));

 if(!FGets(FileHandle, LineBuffer, 128))
 {
  D(bug("ppm.datatype/OM_NEW: FGets line 3 (4) failed\n"));

  SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  return(0);
 }

 if(!(LineBuffer[0]=='2' && LineBuffer[1]=='5' && LineBuffer[2]=='5'))
 {
  D(bug("ppm.datatype/OM_NEW: Wrong depth\n"));

  SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  return(0);
 }

 D(bug("ppm.datatype/OM_NEW: Header successful read\n"));

 bmhd->bmh_Width  = Width;
 bmhd->bmh_Height = Height;
 bmhd->bmh_PageWidth = bmhd->bmh_Width;
 bmhd->bmh_PageHeight = bmhd->bmh_Height;

 D(bug("ppm.datatype/OM_NEW: Using 24 bit colors\n"));
 bmhd->bmh_Depth = 24;

 /* Get a buffer for one line of RGB triples */
 RGBBuffer=AllocVec(Width*3, MEMF_ANY | MEMF_CLEAR);
 if(!RGBBuffer)
 {
  D(bug("ppm.datatype/OM_NEW: AllocVec(RGBBuffer) failed\n"));
  CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
  SetIoErr(ERROR_NO_FREE_STORE);
  return(0);
 }
 D(bug("ppm.datatype/OM_NEW: RGBBuffer successfully allocated\n"));

 /* Flush filehandle, so that unbuffered Read() can be used after buffered FGets() */
 Flush(FileHandle);

 /* Copy picture line by line to picture.datatype using WRITEPIXELARRAY method */
 for(i=0; i<Height; i++)
 {
  if(!(Read(FileHandle, RGBBuffer, (Width*3))==(Width*3)))
  {
   D(bug("ppm.datatype/OM_NEW: Read(RGBBuffer) failed, maybe file too short\n"));
   FreeVec(RGBBuffer);
   CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
   SetIoErr(ERROR_OBJECT_WRONG_TYPE);
   return(0);
  }
  if(!DoSuperMethod(cl, (Object *) RetVal,
		PDTM_WRITEPIXELARRAY,	/* Method_ID */
		(IPTR) RGBBuffer,	/* PixelData */
		PBPAFMT_RGB,		/* PixelFormat */
		Width*3,		/* PixelArrayMod (number of bytes per row) */
		0,			/* Left edge */
		i,			/* Top edge */
		Width,			/* Width */
		1))			/* Height (here: one line) */
   {
	D(bug("ppm.datatype/OM_NEW: WRITEPIXELARRAY failed\n"));
	FreeVec(RGBBuffer);
	CoerceMethod(cl, (Object *) RetVal, OM_DISPOSE);
	return(0);
   }
 }
 D(bug("ppm.datatype/OM_NEW: WRITEPIXELARRAY of whole picture done\n"));

 FreeVec(RGBBuffer);

 SetDTAttrs((Object *) RetVal, NULL, NULL, DTA_ObjName,      (IPTR) Title,
					   DTA_NominalHoriz, Width,
					   DTA_NominalVert,  Height,
					   TAG_DONE);

 D(bug("ppm.datatype/OM_NEW: Leaving. (24 bit mode)\n"));
 return(RetVal);
} /* PPM_New() */

/**************************************************************************************************/

static BOOL PPM_Save(struct IClass *cl, Object *o, struct dtWrite *dtw )
{
    BPTR		    filehandle;
    unsigned int            width, height, numplanes, y;
    UBYTE		    *linebuf;
    struct BitMapHeader     *bmhd;
    long                    *colorregs;

    D(bug("ppm.datatype/PPM_Save()\n"));

    /* A NULL file handle is a NOP */
    if( !dtw->dtw_FileHandle )
    {
	D(bug("ppm.datatype/PPM_Save() --- empty Filehandle - just testing\n"));
	return TRUE;
    }
    filehandle = dtw->dtw_FileHandle;

    /* Get BitMapHeader and color palette */
    if( GetDTAttrs( o,  PDTA_BitMapHeader, (IPTR) &bmhd,
			PDTA_CRegs,        (IPTR) &colorregs,
			TAG_DONE ) != 2UL ||
	!bmhd || !colorregs )
    {
	D(bug("ppm.datatype/PPM_Save() --- missing attributes\n"));
	SetIoErr(ERROR_OBJECT_WRONG_TYPE);
	return FALSE;
    }

    width = bmhd->bmh_Width;
    height = bmhd->bmh_Height;
    numplanes = bmhd->bmh_Depth;
    if( numplanes != 24 )
    {
	D(bug("ppm.datatype/PPM_Save() --- color depth %d, can save only depths of 24\n", numplanes));
	SetIoErr(ERROR_OBJECT_WRONG_TYPE);
	return FALSE;
    }
    D(bug("ppm.datatype/PPM_Save() --- Picture size %d x %d (x %d bit)\n", width, height, numplanes));

    /* Write header to file */
    if( FPrintf( filehandle, "P6\n#Created by AROS ppm.datatype aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n%ld %ld\n255\n",
	(long)width, (long)height ) == -1 )
    {
	D(bug("ppm.datatype/PPM_Save() --- writing header failed\n"));
	return FALSE;
    }

    /* Now read the picture data line by line and write it to a chunky buffer */
    if( !(linebuf = AllocVec(width*3, MEMF_ANY)) )
    {
	SetIoErr(ERROR_NO_FREE_STORE);
	return FALSE;
    }
    D(bug("ppm.datatype/PPM_Save() --- copying picture with READPIXELARRAY\n"));
    for (y=0; y<height; y++)
    {
	if(!DoSuperMethod(cl, o,
			PDTM_READPIXELARRAY,	/* Method_ID */
			(IPTR)linebuf,		/* PixelData */
			PBPAFMT_RGB,		/* PixelFormat */
			width,			/* PixelArrayMod (number of bytes per row) */
			0,			/* Left edge */
			y,			/* Top edge */
			width,			/* Width */
			1))			/* Height */
	{
	    D(bug("ppm.datatype/PPM_Save() --- READPIXELARRAY line %d failed !\n", y));
	    FreeVec(linebuf);
	    SetIoErr(ERROR_OBJECT_WRONG_TYPE);
	    return FALSE;
	}
	if( FWrite( filehandle, linebuf, width*3, 1 ) != 1 )
	{
	    D(bug("ppm.datatype/PPM_Save() --- writing picture data line %d failed !\n", y));
	    FreeVec(linebuf);
	    return FALSE;
	}
    }

    D(bug("ppm.datatype/PPM_Save() --- Normal Exit\n"));
    FreeVec(linebuf);
    SetIoErr(0);
    return TRUE;
}

/**************************************************************************************************/

IPTR PPM__DTM_WRITE(struct IClass *cl, Object *o, struct dtWrite *dtw)
{
    if( (dtw -> dtw_Mode) == DTWM_RAW )
    {
	/* Local data format requested */
	return PPM_Save(cl, o, dtw );
    }
    else
    {
	/* Pass msg to superclass (which writes an IFF ILBM picture)... */
	return DoSuperMethodA( cl, o, (Msg)dtw );
    }
}

/**************************************************************************************************/

#if DEBUGMETHODS

STATIC IPTR DT_NotifyMethod(struct IClass *cl, struct Gadget *g, struct opUpdate *msg)
{
 return(DoSuperMethodA(cl, (Object *) g, (Msg) msg));
}

/**************************************************************************************************/
STATIC IPTR DT_SetMethod(struct IClass *cl, struct Gadget *g, struct opSet *msg)
{
 IPTR RetVal;

 D(bug("ppm.datatype/OM_SET: Entering\n"));

 RetVal=DoSuperMethodA(cl, (Object *) g, (Msg) msg);

 return(RetVal);
}

/**************************************************************************************************/
STATIC IPTR DT_GetMethod(struct IClass *cl, struct Gadget *g, struct opGet *msg)
{
 IPTR RetVal;

 D(bug("ppm.datatype/OM_GET: Entering\n"));

 RetVal=DoSuperMethodA(cl, (Object *) g, (Msg) msg);

 return(RetVal);
}

/**************************************************************************************************/

STATIC IPTR DT_LayoutMethod(struct IClass *cl, struct Gadget *g, struct gpLayout *msg)
{
 IPTR RetVal;
 const char L[]="GM_LAYOUT";
 const char P[]="DTM_PROCLAYOUT";
 const char A[]="DTM_ASYNCLAYOUT";
 const char U[]="Unknown Method";
 char *MethodName;

 RetVal=DoSuperMethodA(cl, (Object *) g, (Msg) msg);

 D(bug("ppm.datatype/%s: RetVal 0x%lx\n", MethodName, (unsigned int) RetVal));

 D(bug("ppm.datatype/%s: Leaving\n", MethodName));

 return(RetVal);
}

#endif /* DEBUGMETHODS */

Creating New Datatypes[edit | edit source]

IPTR DTD__OM_NEW(Class *cl, Object *o, struct opSet *msg)
{

} /* DTD_OM_New() */

/**************************************************************************************************/

static BOOL DTD_Load(struct IClass *cl, Object *o)
{

}

static BOOL DTD_Save(struct IClass *cl, Object *o, struct dtWrite *dtw )
{

}

IPTR DTD__DTM_WRITE(struct IClass *cl, Object *o, struct dtWrite *dtw)
{

}

/**************************************************************************************************/

STATIC IPTR DT_SetMethod(struct IClass *cl, struct Gadget *g, struct opSet *msg)
{

}

STATIC IPTR DT_GetMethod(struct IClass *cl, struct Gadget *g, struct opGet *msg)
{

}

STATIC IPTR DT_LayoutMethod(struct IClass *cl, struct Gadget *g, struct gpLayout *msg)
{

}

init[edit | edit source]

/* Programmheader

	Name:		init.c
	Main:		reko
	Versionstring:	$VER: init.c 1.1 (18.10.1999)
	Author:		SDI
	Distribution:	Freeware
	Description:	all the datatype initialization stuff

 1.0   19.09.99 : first version
 1.1   18.10.99 : fixed the stuff a bit
*/

#include <proto/exec.h>
#include <proto/intuition.h>
#include <dos/dos.h>
#include <exec/resident.h>
#include <exec/initializers.h>
#include <exec/execbase.h>
#include "SDI_compiler.h"

#include "reko.h"

struct LibInitData {
 UBYTE i_Type;     UBYTE o_Type;     UBYTE  d_Type;	UBYTE p_Type;
 UBYTE i_Name;     UBYTE o_Name;     STRPTR d_Name;
 UBYTE i_Flags;    UBYTE o_Flags;    UBYTE  d_Flags;	UBYTE p_Flags;
 UBYTE i_Version;  UBYTE o_Version;  UWORD  d_Version;
 UBYTE i_Revision; UBYTE o_Revision; UWORD  d_Revision;
 UBYTE i_IdString; UBYTE o_IdString; STRPTR d_IdString;
 ULONG endmark;
};

/************************************************************************/

/* First executable routine of this library; must return an error
   to the unsuspecting caller */
LONG ReturnError(void)
{
  return -1;
}

/************************************************************************/

/* The mandatory reserved library function */
ULONG LibReserved(void)
{
  return 0;
}

/************************************************************************/

ASM(struct Library *) LibInit(REG(d0, struct ClassBase *cb), REG(a0, BPTR seglist), REG(a6, struct ExecBase * SysBase))
{
#ifdef _M68060
  if(!(SysBase->AttnFlags & AFF_68060))
    return 0;
#elif defined (_M68040)
  if(!(SysBase->AttnFlags & AFF_68040))
    return 0;
#elif defined (_M68030)
  if(!(SysBase->AttnFlags & AFF_68030))
    return 0;
#elif defined (_M68020)
  if(!(SysBase->AttnFlags & AFF_68020))
    return 0;
#endif
  InitSemaphore(&cb->cb_Lock);

  cb->cb_SegList = seglist;
  cb->cb_SysBase = SysBase;
  if((cb->cb_IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",39)))
  {
    if((cb->cb_GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 39)))
    {
      if((cb->cb_DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 39)))
      {
	if((cb->cb_UtilityBase = (struct UtilityBase *) OpenLibrary ("utility.library", 39)))
	  return (struct Library *) cb;

	CloseLibrary((struct Library *) cb->cb_DOSBase);
      }
      CloseLibrary((struct Library *) cb->cb_GfxBase);
    }
    CloseLibrary((struct Library *) cb->cb_IntuitionBase);
  }

  FreeMem((STRPTR) cb - cb->cb_Lib.lib_NegSize, cb->cb_Lib.lib_NegSize + cb->cb_Lib.lib_PosSize);
  return 0;
}

ASM(struct ClassBase *) LibOpen(REG(a6, struct ClassBase *cb))
{
  struct ExecBase *SysBase = cb->cb_SysBase;
  struct ClassBase *ret = cb;

  ObtainSemaphore(&cb->cb_Lock);

  cb->cb_Lib.lib_Flags &= ~LIBF_DELEXP;
  cb->cb_Lib.lib_OpenCnt++;

  if(!cb->cb_Class)
  {
    if((cb->cb_DataTypesBase = OpenLibrary ("datatypes.library", 39)))
    {
      if((cb->cb_SuperClassBase = OpenLibrary ("datatypes/picture.datatype", 39)))
      {
	if((cb->cb_Class = initClass(cb)))
	{
          ReleaseSemaphore(&cb->cb_Lock);
          return ret;
	}
	CloseLibrary(cb->cb_SuperClassBase);
      }
      CloseLibrary(cb->cb_DataTypesBase);
    }
    cb->cb_Lib.lib_OpenCnt--;
    ret = 0;
  }

  ReleaseSemaphore(&cb->cb_Lock);
  return ret;
}

ASM(LONG) LibExpunge(REG(a6, struct ClassBase *cb))
{
  struct ExecBase *SysBase = cb->cb_SysBase;

  if(!cb->cb_Lib.lib_OpenCnt)
  {
    if(cb->cb_Class) /* security, should never happen */
    {
      struct IntuitionBase *IntuitionBase = cb->cb_IntuitionBase;
      if(FreeClass(cb->cb_Class))
      {
        cb->cb_Class = 0;
        CloseLibrary(cb->cb_SuperClassBase);
        CloseLibrary(cb->cb_DataTypesBase);
      }
    }
    if(!cb->cb_Class)
    {
      BPTR seg = cb->cb_SegList;

      Remove((struct Node *) cb);
      CloseLibrary((struct Library *) cb->cb_UtilityBase);
      CloseLibrary((struct Library *) cb->cb_DOSBase);
      CloseLibrary((struct Library *) cb->cb_GfxBase);
      CloseLibrary((struct Library *) cb->cb_IntuitionBase);

      FreeMem((STRPTR) cb - cb->cb_Lib.lib_NegSize, cb->cb_Lib.lib_NegSize + cb->cb_Lib.lib_PosSize);

      return seg;
    }
  }
  cb->cb_Lib.lib_Flags |= LIBF_DELEXP;
  return 0;
}

ASM(LONG) LibClose(REG(a6, struct ClassBase *cb))
{
  struct ExecBase *SysBase = cb->cb_SysBase;

  ObtainSemaphore(&cb->cb_Lock);

  if(cb->cb_Lib.lib_OpenCnt)
    cb->cb_Lib.lib_OpenCnt--;

  if(!cb->cb_Lib.lib_OpenCnt && cb->cb_Class)
  {
    struct IntuitionBase *IntuitionBase = cb->cb_IntuitionBase;
    if(FreeClass(cb->cb_Class))
    {
      cb->cb_Class = 0;
      CloseLibrary(cb->cb_SuperClassBase);
      CloseLibrary(cb->cb_DataTypesBase);
    }
  }

  ReleaseSemaphore(&cb->cb_Lock);
  /* A bit dangerous, but we cannot release a semaphore after expunging! */
  return (cb->cb_Lib.lib_Flags & LIBF_DELEXP) ? LibExpunge(cb) : 0;
}

/************************************************************************/

ASM(Class *) ObtainEngine(REG(a6, struct ClassBase *cb))
{
  return cb->cb_Class;
}

/************************************************************************/

/* This is the table of functions that make up the library. The first
   four are mandatory, everything following it are user callable
   routines. The table is terminated by the value -1. */

static const APTR LibVectors[] = {
  LibOpen,
  LibClose,
  LibExpunge,
  LibReserved,
  ObtainEngine,
  (APTR)-1
};

static const struct LibInitData LibInitData = {
 0xA0, (UBYTE) OFFSET(Node,    ln_Type),      NT_LIBRARY,		 0,
 0x80, (UBYTE) OFFSET(Node,    ln_Name),      CLASSNAME,
 0xA0, (UBYTE) OFFSET(Library, lib_Flags),    LIBF_SUMUSED|LIBF_CHANGED, 0,
 0x90, (UBYTE) OFFSET(Library, lib_Version),  VERSION,
 0x90, (UBYTE) OFFSET(Library, lib_Revision), REVISION,
 0x80, (UBYTE) OFFSET(Library, lib_IdString), IDSTRING,
 0
};

/* The following data structures and data are responsible for
   setting up the Library base data structure and the library
   function vector. */

static const ULONG LibInitTable[4] = {
  (ULONG)sizeof(struct ClassBase), /* Size of the base data structure */
  (ULONG)LibVectors,             /* Points to the function vector */
  (ULONG)&LibInitData,           /* Library base data structure setup table */
  (ULONG)LibInit                 /* The address of the routine to do the setup */
};

/************************************************************************/

/* The library loader looks for this marker in the memory
   the library code and data will occupy. It is responsible
   setting up the Library base data structure.
*/

static const struct Resident RomTag = {
  RTC_MATCHWORD,                /* Marker value. */
  (struct Resident *)&RomTag,   /* This points back to itself. */
  (struct Resident *)&RomTag+1, /* This points behind this marker. */
  RTF_AUTOINIT,                 /* The Library should be set up according to the given table. */
  VERSION,                      /* The version of this Library. */
  NT_LIBRARY,                   /* This defines this module as a Library. */
  0,                            /* Initialization priority of this Library; unused. */
  CLASSNAME,                    /* Points to the name of the Library. */
  IDSTRING,                     /* The identification string of this Library. */
  (APTR)&LibInitTable           /* This table is for initializing the Library. */
};

Dispatcher[edit | edit source]

/* Programmheader

	Name:		dispatch.c
	Main:		reko
	Versionstring:	$VER: dispatch.c 1.11 (13.07.2003)
	Author:		SDI
	Distribution:	Freeware
	Description:	the real stuff

 1.0   19.09.99 : first version
 1.1   02.10.99 : added PC stuff
 1.2   03.10.99 : some optimizations
 1.3   10.10.99 : added HAM conversion
 1.4   14.10.99 : added ENV variable support
 1.5   17.10.99 : now passes ModeID in HighColor system
 1.6   20.10.99 : added HAM6 mode and card clear
 1.7   11.11.99 : Now the data is told to be 24 bit!
 1.8   10.12.99 : added 16BIT/24BIT keywords
 1.9   04.11.01 : added support for layout of older reko datatypes
 1.10  18.12.01 : fixed Preview for RKP8 and RKP16
 1.11  13.07.03 : added WizSolitaire cardset type
*/

#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/datatypes.h>
#include <proto/utility.h>
#include <clib/alib_protos.h>
#include <datatypes/pictureclass.h>
#include <libraries/iffparse.h>
#include <exec/memory.h>
#include <datatypes/pictureclass.h>

#include "SDI_compiler.h"
#include "reko.h"

#define DOSBase		cb->cb_DOSBase
#define SysBase		cb->cb_SysBase
#define DataTypesBase	cb->cb_DataTypesBase
#define UtilityBase	cb->cb_UtilityBase
#define GfxBase		cb->cb_GfxBase
#define IntuitionBase	cb->cb_IntuitionBase

#define REKOFLAG_SOLITON	(1<<0)
#define REKOFLAG_PREVIEW	(1<<1)
#define REKOFLAG_HAMDIRECT	(1<<2)
#define REKOFLAG_16BIT		(1<<3)
#define REKOFLAG_REKODT39	(1<<4)
#define REKOFLAG_MREKO		(1<<5)

#define REKOFLAG_PCMODE		(1<<6)
#define REKOFLAG_WIZMODE	(1<<7)

struct RekoHeader /* REKO file header */
{
  ULONG rh_ID;
  ULONG rh_BodySize;
  ULONG rh_CardSize;
  UWORD rh_Height;
  UWORD rh_Width;
  ULONG rh_ModeID;
  UBYTE rh_Depth;
  UBYTE rh_CardsCnt;
};

struct PCRekoHeader /* PCREKO file header */
{ /* all in INTEL format */
  UWORD rh_PCID;
  ULONG rh_ID;
  UWORD rh_ID2;
  ULONG rh_BodySize; /* FileSize-22 */
  ULONG rh_CardSize;
  UWORD rh_Width;
  UWORD rh_Height;
  UBYTE rh_Depth;
  UBYTE rh_CardsCnt;
};

struct WizData
{
  ULONG Unknown;
  ULONG Width;
  ULONG Height;
  UBYTE Order; /* 1 to 13 */
  UBYTE Color; /* 0 to 3 */
  ULONG JPEGSize;
};

struct WizHeader
{
  UBYTE ID[16];
  UBYTE Empty[4];
  /* We read 2 bytes too much, as reko header has 2 more bytes */
};

#define ID_REKO			MAKE_ID('R','E','K','O')
#define ID_PC			0x5043
#define ID_WIZ			0x57697A53

#define HEADER_SIZE		sizeof(struct RekoHeader)
#define WIZDATA_SIZE		sizeof(struct WizData)

#define FULLHEIGHT		4  /* Number of cards vertically */
#define NORMWIDTH		14
#define FULLWIDTH               17
#define REKO_I			55 /* Cards in REKO I cardset */
#define REKO_II			59 /* Cards in REKO II cardset */
#define REKO_III		68 /* Cards in REKO III cardset */

#define BORDERCOL	0xF0
#define BACKCOL		0

static const UBYTE Mapping[REKO_III][2] = {
  {13,2}, {13,1}, {13,0},
  { 0,0}, { 0,1}, { 0,2}, { 0,3},
  { 1,0}, { 1,1}, { 1,2}, { 1,3},
  { 2,0}, { 2,1}, { 2,2}, { 2,3},
  { 3,0}, { 3,1}, { 3,2}, { 3,3},
  { 4,0}, { 4,1}, { 4,2}, { 4,3},
  { 5,0}, { 5,1}, { 5,2}, { 5,3},
  { 6,0}, { 6,1}, { 6,2}, { 6,3},
  { 7,0}, { 7,1}, { 7,2}, { 7,3},
  { 8,0}, { 8,1}, { 8,2}, { 8,3},
  { 9,0}, { 9,1}, { 9,2}, { 9,3},
  {10,0}, {10,1}, {10,2}, {10,3},
  {11,0}, {11,1}, {11,2}, {11,3},
  {12,0}, {12,1}, {12,2}, {12,3},
  {13,3}, {14,3}, {15,3}, {16,3},
  {14,0}, {15,0}, {16,0},
  {14,1}, {15,1}, {16,1},
  {14,2}, {15,2}, {16,2}
};

static const UBYTE WizMapping[REKO_III][2] = {
  {13,0},
  { 0,0}, { 1,0}, { 2,0}, { 3,0}, { 4,0}, { 5,0}, { 6,0}, { 7,0}, { 8,0}, { 9,0}, {10,0}, {11,0}, {12,0},
  { 0,1}, { 1,1}, { 2,1}, { 3,1}, { 4,1}, { 5,1}, { 6,1}, { 7,1}, { 8,1}, { 9,1}, {10,1}, {11,1}, {12,1},
  { 0,2}, { 1,2}, { 2,2}, { 3,2}, { 4,2}, { 5,2}, { 6,2}, { 7,2}, { 8,2}, { 9,2}, {10,2}, {11,2}, {12,2},
  { 0,3}, { 1,3}, { 2,3}, { 3,3}, { 4,3}, { 5,3}, { 6,3}, { 7,3}, { 8,3}, { 9,3}, {10,3}, {11,3}, {12,3},
  {13,3}, {14,3}, {15,3}, {16,3},
  {13,1}, /* empty card */
  {13,2}, {14,0}, {14,1}, {14,2}, {15,0}, {15,1}, {15,2}, {16,0}, {16,1}, {16,2}
};

ASM(Object *) Dispatch(REG(a0, Class *cl), REG(a2, Object *o), REG(a1, Msg msg));

Class *initClass(struct ClassBase *cb)
{
  Class *CL;

  /* Create our class (no instance) */
  if((CL=MakeClass(CLASSNAME,PICTUREDTCLASS,NULL,NULL,0)))
  {
    CL->cl_Dispatcher.h_Entry=(HOOKFUNC)Dispatch;
    CL->cl_UserData=(ULONG) cb;
    AddClass(CL);
  }
  return CL;
}

/* Calculate number of cards horizontally */
static ULONG GetFullWidth(ULONG cards)
{
  ULONG HCnt;

  if(cards <= REKO_I) /* REKO-I cardset */
    HCnt=NORMWIDTH;
  else if(cards <= REKO_III) /* REKO-II or REKO-III cardset */
    HCnt=FULLWIDTH;
  else /* Unknown cardset */
    HCnt=cards/FULLHEIGHT+(cards%FULLHEIGHT>0);
  return HCnt;
}

ASM(static void) putfunc(REG(d0, UBYTE data), REG(a3, STRPTR *a))
{
  *((*a)++) = data;
}

static void SPrintF(struct ClassBase *cb, STRPTR buf, STRPTR format, ...)
{
  STRPTR buf2 = buf;

  RawDoFmt(format, (APTR) ((ULONG)&format+sizeof(STRPTR)),
  (void(*)()) putfunc, &buf2);
}

static void MakeBackCard(STRPTR buf, ULONG width, ULONG height)
{
  ULONG j;
  STRPTR b;

  b = buf;
  for(j = width*height*3; j; --j) /* clear background */
    *(b++) = BACKCOL;

  b = buf+3;
  for(j = (width-2)*3; j; --j) /* upper border */
    *(b++) = BORDERCOL;

  b = buf+((width*(height-1))+1)*3;
  for(j = (width-2)*3; j; --j) /* bottom border */
    *(b++) = BORDERCOL;

  b = buf + width*3;
  for(j = height-2; j ; --j) /* side borders */
  {
    b[0] = b[1] = b[2] = BORDERCOL;
    b += width*3;
    *(b-3) = *(b-2) = *(b-1) = BORDERCOL;
  }
  
  b = buf + width*3;
  b[3] = b[4] = b[5] = BORDERCOL;
  b += width*3;
  *(b-6) = *(b-5) = *(b-4) = BORDERCOL;
  b = buf + width*(height-2)*3;
  b[3] = b[4] = b[5] = BORDERCOL;
  b += width*3;
  *(b-6) = *(b-5) = *(b-4) = BORDERCOL;
}

static void GetXY(ULONG num, ULONG *x, ULONG *y, ULONG flags)
{
  if(flags & REKOFLAG_PREVIEW)
  {
    *x = *y = 0;
  }
  else if(flags & REKOFLAG_WIZMODE)
  {
    *x = WizMapping[num][0];
    *y = WizMapping[num][1];
  }
  else if(num < REKO_III)
  {
    *x = Mapping[num][0];
    *y = Mapping[num][1];
    if(num < 3)
    {
      if(flags & REKOFLAG_MREKO)
      {
        switch(num)
        {
        case 0: *y = 1; break;
        case 1: *y = 2; break;
        case 2: *y = 3; break;
        };
      }
      else if(flags & REKOFLAG_REKODT39)
      {
        *y = 1;
        switch(num)
        {
        case 0: *x = 13; break;
        case 1: *x = 14; break;
        case 2: *x = 15; break;
        }
      }
    }
    else if(num >= REKO_I && (flags & (REKOFLAG_MREKO|REKOFLAG_REKODT39)))
    {
      if(num < REKO_II) /* stack cards */
        *y = 0;
      else if((flags & REKOFLAG_REKODT39) && num < REKO_II+2)
      {
        *x = 13; *y = num-REKO_II+2;
      }
      else
        (*y)++;
    }
  }
  else
  {
    *x = num/FULLHEIGHT;
    *y = num%FULLHEIGHT;
  }
}

static void ClearCards(ULONG cnt, struct ClassBase *cb, Class *cl, Object *o, APTR buf, ULONG w, ULONG h, ULONG flags)
{
  ULONG maxcnt, x, y;
  STRPTR b;

  if(flags & REKOFLAG_PREVIEW)
    return;

  b = (STRPTR) buf;
  for(maxcnt = w*h*3; maxcnt; --maxcnt) /* clear card */
    *(b++) = BACKCOL;

  maxcnt = GetFullWidth(cnt)*FULLHEIGHT;

  if(flags & REKOFLAG_PCMODE)
  {
    GetXY(0, &x, &y, flags);
    DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) buf, PBPAFMT_RGB, w*3, x*w, y*h, w, h);
  }

  while(cnt < maxcnt)
  {
    GetXY(cnt++, &x, &y, flags);
    if(!(flags & REKOFLAG_SOLITON) || x <= 13)
      DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) buf, PBPAFMT_RGB, w*3, x*w, y*h, w, h);
  }
}

#define EndConvI32(a)	(((a)>>24)|(((a)>>8)&0xFF00)|(((a)<<8)&0xFF0000)|((a)<<24))
#define EndConvI16(a)	((UWORD)(((a)>>8)|((a)<<8)))

static LONG GetPCREKO(struct ClassBase *cb, Class *cl, Object *o, BPTR fh,
struct BitMapHeader *bmhd, struct PCRekoHeader *h, STRPTR Title, ULONG flags)
{
  register ULONG CSize;
  LONG result = ERROR_OBJECT_WRONG_TYPE;

  flags |= REKOFLAG_PCMODE;
  h->rh_CardSize = EndConvI32(h->rh_CardSize);
  h->rh_Width = EndConvI16(h->rh_Width);
  h->rh_Height = EndConvI16(h->rh_Height);
  if(flags & REKOFLAG_SOLITON)
  {
    if(h->rh_CardsCnt > REKO_I-2)
      h->rh_CardsCnt = REKO_I-2;
  }
  else if(flags & REKOFLAG_PREVIEW)
    h->rh_CardsCnt = 5;
  /* Calculate sizes */
  CSize = h->rh_Width*h->rh_Height*(h->rh_Depth>>3);
  if(h->rh_CardsCnt && CSize && (h->rh_Depth == 8 || h->rh_Depth == 16) && h->rh_CardSize == CSize)
  {
    LONG ErrorLevel = 0, ErrorNumber = 0;
    ULONG ModeID;

     /* Fill in BitMapHeader information */
    bmhd->bmh_Width = bmhd->bmh_PageWidth = h->rh_Width*(flags & REKOFLAG_PREVIEW ? 1 : GetFullWidth(h->rh_CardsCnt));
    bmhd->bmh_Height = bmhd->bmh_PageHeight = h->rh_Height*(flags & REKOFLAG_PREVIEW ? 1 : FULLHEIGHT);
    bmhd->bmh_Depth = flags & REKOFLAG_16BIT ? 16 : 24;

    ModeID=BestModeID(BIDTAG_DesiredWidth, bmhd->bmh_Width, BIDTAG_DesiredHeight, bmhd->bmh_Height,
    BIDTAG_Depth, bmhd->bmh_Depth, TAG_DONE);

    SetDTAttrs(o, 0, 0, DTA_ObjName, Title, DTA_NominalHoriz, bmhd->bmh_Width, DTA_NominalVert, bmhd->bmh_Height,
    PDTA_SourceMode, PMODE_V43, PDTA_ModeID, ModeID, DTA_ErrorLevel, &ErrorLevel, DTA_ErrorNumber, &ErrorNumber, TAG_DONE);

    if(ErrorLevel)
      result = ErrorNumber;
    else if(h->rh_Depth == 16)
    {
      register UBYTE *d, *e;

      CSize = h->rh_Width*h->rh_Height*2+4;

      if((d = (UBYTE *) AllocVec(CSize+h->rh_Width*h->rh_Height*3, MEMF_PUBLIC)))
      {
	ULONG x, y;
        register ULONG i, j, card = 0;

	result = 0;
        e = d + CSize;
	  
	while(!result && card < h->rh_CardsCnt)
	{
	  if(Read(fh, d, CSize) != CSize)
	    result = ERROR_OBJECT_WRONG_TYPE;
	  else
	  {
	    j = 0;
	    for(i = 4; i < CSize; i += 2)
	    {
	      e[j++] = (d[i+1]<<1)&0xF8;		/* red */
	      e[j++] = (d[i+1]<<6 | d[i]>>2)&0xF8;	/* green */
	      e[j++] = (d[i]<<3)&0xF8;			/* blue */
	    }

	    GetXY(card+2, &x, &y, flags);
            DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) e, PBPAFMT_RGB,
            h->rh_Width*3, x*h->rh_Width, y*h->rh_Height, h->rh_Width, h->rh_Height);
          }
          ++card;
        }
        if(!result && !(flags & REKOFLAG_PREVIEW))
        {
	  MakeBackCard(e, h->rh_Width, h->rh_Height);
	  GetXY(1, &x, &y, flags);
          DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) e, PBPAFMT_RGB,
          h->rh_Width*3, x*h->rh_Width, y*h->rh_Height, h->rh_Width, h->rh_Height);
	  ClearCards(h->rh_CardsCnt+2, cb, cl, o, e, h->rh_Width, h->rh_Height, flags);
	}
	FreeVec(d);
      } /* AllocVec */
      else
	result = ERROR_NO_FREE_STORE;
    }
    else if(h->rh_Depth == 8)
    {
      register UBYTE *d, *e, *f, *g;

      CSize = h->rh_Width*h->rh_Height;

      if((d = (UBYTE *) AllocVec(CSize+256*3+h->rh_Width*h->rh_Height*3, MEMF_PUBLIC)))
      {
	ULONG x, y;
        register ULONG i, j, card = 0;

	result = 0;
        e = d + 256*3 + CSize;
        f = d + CSize;
	  
	while(!result && card < h->rh_CardsCnt)
	{
	  if(Read(fh, d, 256*2+4) != 256*2+4)
	    result = ERROR_OBJECT_WRONG_TYPE;
	  else
	  {
	    j = 0;
	    for(i = 4; i < (256)*2+4; i += 2)
	    {
	      f[j++] = (d[i+1]<<1)&0xF8;		/* red */
	      f[j++] = (d[i+1]<<6 | d[i]>>2)&0xF8;	/* green */
	      f[j++] = (d[i]<<3)&0xF8;			/* blue */
	    }
	    if(Read(fh, d, CSize) != CSize)
	      result = ERROR_OBJECT_WRONG_TYPE;
	    else
	    {
	      for(i = j = 0; i < CSize; ++i)
	      {
	        g = f + 3*d[i];
	        e[j++] = *(g++);
	        e[j++] = *(g++);
	        e[j++] = *g;
	      }

	      GetXY(card+2, &x, &y, flags);
              DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) e, PBPAFMT_RGB,
              h->rh_Width*3, x*h->rh_Width, y*h->rh_Height, h->rh_Width, h->rh_Height);
            }
          }
          ++card;
        } /* while */
        if(!result && !(flags & REKOFLAG_PREVIEW))
	{
	  MakeBackCard(e, h->rh_Width, h->rh_Height);
	  GetXY(1, &x, &y, flags);
          DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) e, PBPAFMT_RGB,
          h->rh_Width*3, x*h->rh_Width, y*h->rh_Height, h->rh_Width, h->rh_Height);
	  ClearCards(h->rh_CardsCnt+2, cb, cl, o, e, h->rh_Width, h->rh_Height, flags);
	}
	FreeVec(d);
      } /* AllocVec */
      else
        result = ERROR_NO_FREE_STORE;
    } /* Error ? */
  } /* data checks */
  return result;
}

static LONG GetWiz(struct ClassBase *cb, Class *cl, Object *o, BPTR fh,
struct BitMapHeader *bmhd, STRPTR Title, ULONG flags)
{
  LONG result = 0;

  flags |= REKOFLAG_WIZMODE;

  if(Seek(fh, -2, OFFSET_CURRENT) == -1)
    result = IoErr();
  else
  {
    int i;
    ULONG width=0, height=0, add = 0, x, y;
    struct Task* t;
    STRPTR e = 0;
    STRPTR mem;
    struct WizData wd;
 
    t = FindTask(0);
    for(i = 0; i < 13*4+1+add && !result; ++i)
    {
      if(Read(fh, &wd, WIZDATA_SIZE) == WIZDATA_SIZE)
      {
        wd.Width = EndConvI32(wd.Width);
        wd.Height = EndConvI32(wd.Height);
        wd.JPEGSize = EndConvI32(wd.JPEGSize);
        if(!i)
        {
          LONG ErrorLevel = 0, ErrorNumber = 0;
          ULONG ModeID;

          width = wd.Width;
          height = wd.Height;

          if(!(e = (STRPTR) AllocVec(width*height*3, MEMF_PUBLIC)))
            result = ERROR_NO_FREE_STORE;
          else
          {
            /* Fill in BitMapHeader information */
            bmhd->bmh_Width = bmhd->bmh_PageWidth = width*(flags & REKOFLAG_PREVIEW ? 1 :
            (flags & REKOFLAG_SOLITON ? NORMWIDTH : FULLWIDTH));
            bmhd->bmh_Height = bmhd->bmh_PageHeight = height*(flags & REKOFLAG_PREVIEW ? 1 : FULLHEIGHT);
            bmhd->bmh_Depth = flags & REKOFLAG_16BIT ? 16 : 24;

            ModeID=BestModeID(BIDTAG_DesiredWidth, bmhd->bmh_Width, BIDTAG_DesiredHeight, bmhd->bmh_Height,
            BIDTAG_Depth, bmhd->bmh_Depth, TAG_DONE);

            SetDTAttrs(o, 0, 0, DTA_ObjName, Title, DTA_NominalHoriz, bmhd->bmh_Width, DTA_NominalVert,
            bmhd->bmh_Height, PDTA_SourceMode, PMODE_V43, PDTA_ModeID, ModeID, DTA_ErrorLevel, &ErrorLevel,
            DTA_ErrorNumber, &ErrorNumber, TAG_DONE);
            if(ErrorLevel)
            {
              result = ErrorNumber;
              break;
            }
          }
        }
        if(!(flags & REKOFLAG_PREVIEW) || i == 1+3*13)
        {
          if(!(mem = AllocVec(wd.JPEGSize+30, MEMF_ANY)))
            result = ERROR_NO_FREE_STORE;
          else /* uses temporary file, does MEM-access work for all JPEG datatypes? */
          {
            if(Read(fh, mem+30, wd.JPEGSize) == wd.JPEGSize)
            {
              BPTR fh2;

              SPrintF(cb, mem, "T:REKODT_%08lx.jpg", t);
              if((fh2 = Open(mem, MODE_NEWFILE)))
              {
                if((Write(fh2, mem+30, wd.JPEGSize) == wd.JPEGSize))
                {
                  Object *obj;
                  struct BitMap *bmp;

                  Close(fh2); fh2 = 0;
                  if((obj = NewDTObject(mem,
                  DTA_GroupID           , GID_PICTURE,
                  OBP_Precision         , PRECISION_IMAGE,
                  DTA_SourceType        , DTST_FILE,
                  PDTA_DestMode         , PMODE_V43,
                  TAG_DONE)))
                  {
                    DoMethod(obj, DTM_PROCLAYOUT, NULL, 1);
                    GetDTAttrs(obj, PDTA_DestBitMap, &bmp, TAG_DONE);

	            GetXY(i, &x, &y, flags);

                    DoMethod(obj, PDTM_READPIXELARRAY, (ULONG) e, PBPAFMT_RGB,
                    width*3, 0, 0, width, height);

                    DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) e, PBPAFMT_RGB,
                    width*3, x*width, y*height, width, height);

                    DisposeDTObject(obj);
                  }
                  else
                    result = IoErr();
                }
                else
                  result = IoErr();

                if(fh2)
                  Close(fh2);
                DeleteFile(mem); /* remove the temporary file */
              }
              else
                result = IoErr();
            }
            else
              result = IoErr();

            FreeVec(mem);
          }
        } /* preview card? */
        else
        {
          if(Seek(fh, wd.JPEGSize, OFFSET_CURRENT) == -1)
            result = IoErr();
        }

        if(!result && i == 13*4 && !(flags & REKOFLAG_SOLITON)) /* additional cards */
        {
          if(Read(fh, &add, 4) == 4)
          {
            add = EndConvI32(add);
            if(add > 4)
              add = 0;
          }
          else
            add = 0;
        }
      } /* read header */
      else
        result = IoErr();
    }
    if(!result && !(flags & REKOFLAG_PREVIEW))
    {
      MakeBackCard(e, width, height);
      GetXY(57, &x, &y, flags);
      DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) e, PBPAFMT_RGB,
      width*3, x*width, y*height, width, height);
      ClearCards(58, cb, cl, o, e, width, height, flags);
    }
    if(e)
      FreeVec(e);
  }
  return result;
}

static LONG MakeHAM(struct ClassBase *cb, Class *cl, Object *o, BPTR fh,
struct BitMapHeader *bmhd, struct RekoHeader *h, STRPTR Title, ULONG flags)
{
  ULONG CSize;
  LONG result = ERROR_OBJECT_WRONG_TYPE;

  /* Calculate sizes */
  CSize = (h->rh_Width*h->rh_Height*h->rh_Depth)>>3;
  if(h->rh_CardsCnt && CSize && h->rh_CardSize == CSize)
  {
    LONG ErrorLevel = 0, ErrorNumber = 0;
    ULONG ModeID;

     /* Fill in BitMapHeader information */
    bmhd->bmh_Width = bmhd->bmh_PageWidth = h->rh_Width*(flags & REKOFLAG_PREVIEW ? 1 : GetFullWidth(h->rh_CardsCnt));
    bmhd->bmh_Height = bmhd->bmh_PageHeight = h->rh_Height*(flags & REKOFLAG_PREVIEW ? 1 : FULLHEIGHT);
    bmhd->bmh_Depth = flags & REKOFLAG_16BIT ? 16 : 24;

    ModeID=BestModeID(BIDTAG_DesiredWidth, bmhd->bmh_Width, BIDTAG_DesiredHeight, bmhd->bmh_Height,
    BIDTAG_Depth, bmhd->bmh_Depth, TAG_DONE);

    SetDTAttrs(o, 0, 0, DTA_ObjName, Title, DTA_NominalHoriz, bmhd->bmh_Width, DTA_NominalVert, bmhd->bmh_Height,
    PDTA_SourceMode, PMODE_V43, PDTA_ModeID, ModeID, DTA_ErrorLevel, &ErrorLevel, DTA_ErrorNumber, &ErrorNumber, TAG_DONE);

    if(ErrorLevel)
      result = ErrorNumber;
    else if(h->rh_Depth == 8 || h->rh_Depth == 6)
    {
      UBYTE *Cr;
      ULONG i, dep;

      dep = h->rh_Depth;
      i = (1<<(dep-2))*3;
      if((Cr = (UBYTE *) AllocVec(i, MEMF_PUBLIC)))
      {
        if(Read(fh, Cr, i) == i)
        {
          register UBYTE *d, *e;

          if((d = (UBYTE *) AllocVec(CSize+h->rh_Width*h->rh_Height*3, MEMF_PUBLIC)))
          {
            ULONG j, k, l, m, card = 0, u;

	    result = 0;
	  
            l = h->rh_Width >> 3;
            u = dep*l;
	    while(!result && card < h->rh_CardsCnt)
	    {
	      if(Read(fh, d, CSize) != CSize)
	        result = ERROR_OBJECT_WRONG_TYPE;
	      else
	      {
	        ULONG x, y, v;
	        UBYTE *planar[8], image, last[3];

                e = d + CSize;

	        for(j = v = 0; j < h->rh_Height; ++j, v += u)
	        {
	          for(k = m = 0; k < dep; ++k, m += l)
	            planar[k] = d + m + v;

		  last[0] = Cr[0];
		  last[1] = Cr[1];
		  last[2] = Cr[2];
		  for(m = l; m; --m)
		  {
		    for(i = (1<<7); i; i >>= 1)
		    {
		      image = 0;
		      for(k = 0; k < dep; ++k)
		      {
		        image >>= 1;
		        image |= (*planar[k] & i) ? (1<<7) : 0;
		      }
		      k = image >> 6;
		      image <<= 2;
		      switch(k)
		      {
		      case 0: image >>= (8-dep+2); last[0] = Cr[image*3]; last[1] = Cr[image*3+1]; last[2] = Cr[image*3+2]; break;
		      case 1: last[2] = image; break;
		      case 2: last[0] = image; break;
		      case 3: last[1] = image; break;
		      }
		      *(e++) = last[0];
		      *(e++) = last[1];
		      *(e++) = last[2];
		    }
		    for(k = 0; k < dep; k++)
		      planar[k]++;
	          }
                }

	        GetXY(card, &x, &y, flags);
                DoSuperMethod(cl, o, PDTM_WRITEPIXELARRAY, (ULONG) (d+CSize), PBPAFMT_RGB,
                h->rh_Width*3, x*h->rh_Width, y*h->rh_Height, h->rh_Width, h->rh_Height);
              }
              ++card;
            }
            if(!result)
	      ClearCards(h->rh_CardsCnt, cb, cl, o, d+CSize, h->rh_Width, h->rh_Height, flags);
            
	    FreeVec(d);
          } /* AllocVec */
          else
	    result = ERROR_NO_FREE_STORE;
	} /* Read */
      } /* AllocVec */
      else
        result = ERROR_NO_FREE_STORE;
    }
  } /* data checks */
  return result;
}

static LONG GetREKO(struct ClassBase *cb, Class *cl, Object *o, struct TagItem *attrs, ULONG flags)
{
  struct RekoHeader Header;
  LONG result = ERROR_OBJECT_WRONG_TYPE;
  struct BitMapHeader *bmhd = 0;
  BPTR fh = 0;
  STRPTR Title; /* Picture name */
  ULONG LSize, CSize, NumCol, ModeID;
  ULONG *MethodArray;

  Title = (STRPTR)GetTagData(DTA_Name, 0, attrs);
  GetDTAttrs(o, DTA_Handle, &fh, PDTA_BitMapHeader, &bmhd, DTA_Methods, &MethodArray, TAG_DONE);

  /* Now we search for the new PDTM_WRITEPIXELARRAY method to determine
     if it's the new V43 picture.datatype */
  while(*MethodArray != ~0 && *MethodArray != PDTM_WRITEPIXELARRAY)
    ++MethodArray;

  if(fh && bmhd)
  {
    if(Seek(fh, 0, OFFSET_BEGINNING)>=0)
    {
      if(Read(fh, &Header, HEADER_SIZE) == HEADER_SIZE)
      {
        if((((struct PCRekoHeader *) &Header)->rh_PCID == ID_PC) && (((struct PCRekoHeader *) &Header)->rh_ID == ID_REKO)
        && (*MethodArray == PDTM_WRITEPIXELARRAY))
	  result = GetPCREKO(cb, cl, o, fh, bmhd, (struct PCRekoHeader *) &Header, Title, flags);
	else if(Header.rh_ID == ID_WIZ)
	  result = GetWiz(cb, cl, o, fh, bmhd, Title, flags);
	else if(Header.rh_ID == ID_REKO)
	{
	  if(flags & REKOFLAG_SOLITON)
	  {
            if(Header.rh_CardsCnt > REKO_I)
              Header.rh_CardsCnt = REKO_I;
          }
          else if(flags & REKOFLAG_REKODT39)
          {
            if(Header.rh_CardsCnt > REKO_II)
              Header.rh_CardsCnt = REKO_II;
          }
          else if(flags & REKOFLAG_PREVIEW)
            Header.rh_CardsCnt = 7;
	  if(Header.rh_ModeID & HAM_KEY)
	  {
	    if((*MethodArray == PDTM_WRITEPIXELARRAY) && !(flags & REKOFLAG_HAMDIRECT))
	      return MakeHAM(cb, cl, o, fh, bmhd, &Header, Title, flags);
	    else if(flags & REKOFLAG_SOLITON)
	      return 0;
	  }
	  /* Calculate sizes */
	  NumCol = 1<<((Header.rh_ModeID & HAM_KEY) ? Header.rh_Depth-2 : Header.rh_Depth);
	  LSize = Header.rh_Width>>3; /* Width in bytes */
	  CSize = LSize*Header.rh_Height*Header.rh_Depth; /* Card size in bytes */
	  if(Header.rh_CardsCnt && CSize && Header.rh_Depth>=3 && Header.rh_CardSize == CSize)
	  {
	    /* Fill in BitMapHeader information */
	    bmhd->bmh_Width = bmhd->bmh_PageWidth = Header.rh_Width*(flags & REKOFLAG_PREVIEW ? 1 :
	    GetFullWidth(Header.rh_CardsCnt));
	    bmhd->bmh_Height = bmhd->bmh_PageHeight = Header.rh_Height*(flags & REKOFLAG_PREVIEW ? 1 : FULLHEIGHT);
	    bmhd->bmh_Depth = Header.rh_Depth;

	    /* Get display mode id */
	    if((ModeID=BestModeID(Header.rh_ModeID & HAM_KEY ? BIDTAG_DIPFMustHave : TAG_IGNORE, DIPF_IS_HAM,
	    BIDTAG_DesiredWidth, bmhd->bmh_Width, BIDTAG_DesiredHeight, bmhd->bmh_Height,
	    BIDTAG_Depth, Header.rh_Depth, TAG_DONE)) != INVALID_ID)
	    {
  	      UBYTE *CMap = 0;		/* in real "struct ColorRegister *" */
	      ULONG *CRegs = 0;

	      /* Set colors */
	      SetDTAttrs(o,NULL,NULL,PDTA_NumColors,NumCol,TAG_DONE);
	      GetDTAttrs(o,PDTA_ColorRegisters,&CMap,PDTA_CRegs,&CRegs,TAG_DONE);
	      if(CMap && CRegs)
	      {
	        NumCol *= 3;
	        if(Read(fh,CMap,NumCol)==NumCol)
	        {
	          register ULONG i;
		  struct BitMap *bm;
		  register ULONG *a;
		  register UBYTE *b;
		  
		  a = CRegs;
		  b = CMap;

		  while(NumCol--)
  		  {
		    i = *(b++);
		    i = (i<<8)+i;
		    *(a++) = (i<<16)+i;
		  }

	          /* Prepare bitmap */
	          if((bm=AllocBitMap(bmhd->bmh_Width, bmhd->bmh_Height, Header.rh_Depth,
	          (BMF_CLEAR | BMF_INTERLEAVED | BMF_DISPLAYABLE), 0)))
	          {
		    STRPTR Buffer;

	            /* Allocate temporary buffer */
		    if((Buffer = (STRPTR) AllocVec(CSize, MEMF_PUBLIC)))
		    {
		      result = 0;
		      /* Read data in 1-card chunks */
		      for(i=0; !result && i < Header.rh_CardsCnt; ++i)
		      {
			if(Read(fh,Buffer,CSize) != CSize)
			  result = ERROR_OBJECT_WRONG_TYPE;
			else
			{
			  ULONG x,y;
			  register ULONG k, j, DstOffs, bpr, h;

  			  bpr = bm->BytesPerRow;
  			  b = Buffer;
  			  h = Header.rh_Height;

  			  GetXY(i,&x,&y, flags);
  			  DstOffs=y*h*bpr+x*LSize;
			  while(h--)
			  {
			    for(k=0; k < Header.rh_Depth; k++)
    			    {
      			      for(j = 0; j < LSize; ++j)
        			bm->Planes[k][DstOffs+j] = *(b++);
    			    }
    			    DstOffs += bpr;
			  }
			}
		      }
	              FreeVec(Buffer);

		      /* Set attributes of destination picture */
		      if(!result)
		        SetDTAttrs(o, 0, 0, DTA_ObjName, Title, DTA_NominalHoriz, bmhd->bmh_Width,
			DTA_NominalVert, bmhd->bmh_Height, PDTA_BitMap, bm, PDTA_ModeID, ModeID,
			PDTA_SourceMode, PMODE_V42, PDTA_DestMode, PMODE_V42, TAG_DONE);
		    } /* AllocVec */
		    else
		      result = ERROR_NO_FREE_STORE;
		    if(result)
	              FreeBitMap(bm);
	          } /* AllocBitmap */
	        } /* Read colortable */
	      } /* CMap && CRegs */
	    } /* BestModeID */
	  } /* data checks */
	} /* ID_REKO ? */
      } /* read header */
    } /* seek to begin */
  } /* fh && bmhd */
  return result;
}

ASM(Object *) Dispatch(REG(a0, Class *cl), REG(a2, Object *o), REG(a1, Msg msg))
{
  struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
  Object *Obj;

  switch(msg->MethodID)
  {
    case OM_NEW: /* We know this method */
      if((Obj = (Object *)DoSuperMethodA(cl,o,msg)))
      {
        UBYTE dtmode[50] = "NORMAL", *ptr;
        ULONG flags = 0;

        GetVar("REKODTMODE", (STRPTR) &dtmode, 50, GVF_GLOBAL_ONLY);
        ptr = dtmode;
        while(*ptr)
        {
          switch(*ptr)
          {
          case 'm': case 'M': flags |= REKOFLAG_MREKO; break;           /* MREKOMODE */
          case 'r': case 'R': flags |= REKOFLAG_REKODT39; break;        /* REKODT39MODE */
          case 'p': case 'P': flags |= REKOFLAG_PREVIEW; break;		/* PREVIEW */
          case 's': case 'S': flags |= REKOFLAG_SOLITON; break;		/* SOLITON */
          case 'h': case 'H': flags |= REKOFLAG_HAMDIRECT; break;	/* HAMDIRECT */
          case '1':	      flags |= REKOFLAG_16BIT; break;		/* 16BIT */
       /* case '2': */							/* 24BIT */
       /* case 'n': case 'N': */					/* NORMAL */
          }
          while(*ptr && *(ptr++) != ',')
            ;
        }
        if(flags & REKOFLAG_SOLITON)
          flags &= ~(REKOFLAG_HAMDIRECT|REKOFLAG_MREKO|REKOFLAG_REKODT39|REKOFLAG_PREVIEW);
        else if(flags & REKOFLAG_PREVIEW)
          flags &= ~(REKOFLAG_REKODT39|REKOFLAG_MREKO);
        else if(flags & REKOFLAG_MREKO)
          flags &= ~(REKOFLAG_REKODT39);

        if((flags = GetREKO(cb, cl, Obj, ((struct opSet *)msg)->ops_AttrList, flags)))
        {
          SetIoErr(flags);
          CoerceMethod(cl, Obj, OM_DISPOSE);
          return 0;
        }
        else
          SetIoErr(0);
      }
      break;
    default: /* Let the superclass handle it */
      Obj = (Object *)DoSuperMethodA(cl, o, msg);
      break;
  }
  return Obj;
}

Decoder[edit | edit source]

References[edit | edit source]

datatypes

Index AddDTObject() CopyDTMethods() CopyDTTriggerMethods() DisposeDTObject() DoAsyncLayout() DoDTDomainA() DoDTMethodA() DrawDTObjectA() FindMethod() FindToolNodeA() FindTriggerMethod() FreeDTMethods() GetDTAttrsA() GetDTMethods() GetDTString() GetDTTriggerMethodDataFlags() GetDTTriggerMethods() LaunchToolA() LockDataType() NewDTObjectA() ObtainDataTypeA() ObtainDTDrawInfoA() PrintDTObjectA() RefreshDTObjectA() ReleaseDataType() ReleaseDTDrawInfo() RemoveDTObject() SaveDTObjectA() SetDTAttrsA() StartDragSelect()


AddDTObject()

LONG AddDTObject(

        struct Window    * win,
        struct Requester * req,
        Object           * obj,
        LONG pos );

Function

Add an object to the window 'win' or requester 'req' at the position in the gadget list specified by the 'pos' argument.

Inputs

win -- window the object should be added to; may be NULL in which case

        nothing is done

req -- requester the object should be added to obj -- the object to add; may be NULL in which case nothing is done pos -- the position of the object in the list

Result

The position where the object was added (may be different from what you asked for).

Notes

The object will receice a GM_LAYOUT message with the gpl_Initial field set to 1 when the object is added.

See also RemoveDTObject() intuition.library/AddGList()


CopyDTMethods()

ULONG * CopyDTMethods(

        ULONG * methods,
        ULONG * include,
        ULONG * exclude );

Function

Copy and modify an array of methods. This is used by subclass implementors who want to add supported methods to an existing class.

Inputs

methods -- array of methods; may be NULL include -- array of methods to include terminated with ~0UL; may be NULL method -- array of methods to exclude terminated with ~0UL; may be NULL.

Result

The new array of methods or NULL if something went wrong (like out of memory).

See also

FindMethod() CopyDTTriggerMethods() FreeDTMethods()


CopyDTTriggerMethods()

struct DTMethod * CopyDTTriggerMethods(

        struct DTMethod * methods,
        struct DTMethod * include,
        struct DTMethod * exclude );

Function

Copy and modify an array of DTMethod:s. This is used by subclass implementors who want to add supported methods to an existing class.

Inputs

methods -- array of methods; may be NULL include -- array of methods to include terminated with ~0UL; may be NULL method -- array of methods to exclude terminated with ~0UL; may be NULL

            the dtm_Command and dtm_Method fields may have the options
            described in the FindTriggerMethod to filter out the given
            entries

Result

The new array of methods or NULL if something went wrong (like out of memory).

Notes

dtm_Label and dtm_Command must be valid as long as the object exists as they are not copied.

   A subclass that implment DTM_TRIGGER must send unknown trigger

methods to its superclass.

See also

FindTriggerMethod() CopyDTMethods() FreeDTMethods()


DisposeDTObject()

void DisposeDTObject(

        Object * o );

Function

Dispose a data type object obtained by NewDTObjectA().

Inputs

o -- The data type object to dispose of; may be NULL.

See also

NewDTObjectA() DoAsyncLayout() Synopsis

ULONG DoAsyncLayout(

        Object * object,
        struct gpLayout * gpl );

Function

Perform an object's DTM_ASYNCLAYOUT method -- doing it asynchronously off loads the input.device. The method should exit when a SIGBREAK_CTRL_C is received; this signal means that the data is obsolete and the method will be called again.

Inputs

object -- pointer to data type object gpl -- gpLayout message pointer

DoDTDomainA() Synopsis

ULONG DoDTDomainA(

        Object           * o,
        struct Window    * win,
        struct Requester * req,
        struct RastPort  * rport,
        ULONG which,
        struct IBox      * domain,
        struct TagItem   * attrs );

ULONG DoDTDomain(

        Object           * o,
        struct Window    * win,
        struct Requester * req,
        struct RastPort  * rport,
        ULONG which,
        struct IBox      * domain,
        TAG tag, ... );

Function

Obtain the maximum/minimum/nominal domains of a data type object.

Inputs

o -- data type object in question win -- window that the object is attached to req -- requester the object is attached to rport -- rastport; used for domain calculations which -- the domain to obtain (GDOMAIN_, see <intuition/gadgetclass.h> domain -- the result will be put here attrs -- additional attributes (subclass specific)

Result

The return value of GM_DOMAIN or 0 if an error occurred. The 'domain' IBox will be filled with the requested values as a side effect.

Notes

This function requires an object to perform the GM_DOMAIN method. To achieve similar results without an object, you must use CoerceMethodA() manually.

See also intuition/gadgetclass.h


DoDTMethodA()

IPTR DoDTMethodA(

        Object           * o,
        struct Window    * win,
        struct Requester * req,
        Msg msg );

IPTR DoDTMethod(

        Object           * o,
        struct Window    * win,
        struct Requester * req,
        TAG tag, ... );

Function

Perform a specific datatypes methodl.

Inputs

o -- pointer to data type object win -- window the object is attached to req -- requester the object is attached to msg -- the message to send to the object

Result

The value returned by the specified method.

See also

intuition.library/DoGadgetMethodA()


DrawDTObjectA()

LONG DrawDTObjectA(

        struct RastPort * rp,
        Object          * o,
        LONG x,
        LONG y,
        LONG w,
        LONG h,
        LONG th,
        LONG tv,
        struct TagItem  * attrs );

LONG DrawDTObject(

        struct RastPort * rp,
        Object          * o,
        LONG x,
        LONG y,
        LONG w,
        LONG h,
        LONG th,
        LONG tv,
        TAG tag, ... );

Function

Draw a data type object into a RastPort. You must have successfully called ObtainDTDrawInfoA before calling this function; it invokes the object's DTM_DRAW method.

Inputs

rp -- pointer to the RastPort to draw the object into o -- pointer to the data type object to draw x -- left edge of drawing area y -- top edge of drawing area w -- width of drawing area h -- height of drawing area th -- horizontal top in units tv -- vertical top in units attrs -- additional attributes

Tags

ADTA_Frame for animationclass objects (selects the frame that should be drawn.

Result

TRUE if rendering went OK, FALSE if failure.

Notes

The RastPort in question must support clipping, i.e. have a valid layer structure attached to it; if not, some datatypes can't draw and FALSE will be returned.

See also ObtainDataTypeA()


FindMethod()

ULONG * FindMethod(

        ULONG * methods,
        ULONG searchmethodid );

Function

Search for a specific method in a array of methods.

Inputs

methods -- array of methods; may be NULL searchmethodid -- method to search for

Result

Pointer to method table entry or NULL if the method wasn't found.

See also

GetDTMethods() CopyDTMethods()


FindToolNodeA()

struct ToolNode * FindToolNodeA(

        struct List    * toollist,
        struct TagItem * attrs );

struct ToolNode * FindToolNode(

        struct List    * toollist,
        TAG tag, ... );

Function

Search for a specific tool in a list of given tool nodes.

Inputs

toollist -- a list or a struct ToolNode * (which will be skipped) to

             search in; may be NULL.

attrs -- search tags; if NULL, the result of the function will

             simply be the following node.

Tags

TOOLA_Program -- name of the program to search for

TOOLA_Which -- one of the TW_#? types

TOOLA_LaunchType -- launch mode: TF_SHELL, TF_WORKBENCH or TF_RX

Result

A pointer to a ToolNode describing the search result (NULL for failure).

Notes

The entries in dt->dtn_ToolList are valid as long as a lock is kept on the data type 'dt' (ObtainDataTypeA() or LockDataType()).

See also LaunchToolA()


FindTriggerMethod()

struct DTMethod * FindTriggerMethod(

        struct DTMethod * methods,
        STRPTR command,
        ULONG method );

Function

Search for a specific trigger method in a array of trigger methods (check if either 'command' or 'method' matches).

Inputs

methods -- array of trigger methods; may be NULL command -- name of trigger method (may be NULL; if so, 'command'

                   is not matched against)

method -- id of trigger method to search for (may be ~0; if so, don't

            match against 'method'.

Result

Pointer to trigger method table entry (struct DTMethod *) or NULL if the method wasn't found.

See also GetDTTriggerMethods() CopyDTTriggerMethods()


FreeDTMethods()

VOID FreeDTMethods(

        APTR methods );

Function

Free array obtained from CopyDTMethods() or CopyDTTriggerMethods().

Inputs

methods -- array of methods; may be NULL

See also

CopyDTMethods() CopyDTTriggerMethods() GetDTAttrsA() Synopsis

ULONG GetDTAttrsA(

        Object         * o,
        struct TagItem * attrs );

ULONG GetDTAttrs(

        Object         * o,
        TAG tag, ... );

Function

Get the attributes of a specific data type object.

Inputs

o -- pointer to a data type object; may be NULL attrs -- the attributes to get terminated with TAG_DONE; each Tag's

          data element should contain the address of the respective
          storage element; may be NULL
          <base attribs>
          DTA_DataType (#1)
          DTA_ObjName
          DTA_ObjAuthor
          DTA_ObjAnnotation
          DTA_ObjCopyright
          DTA_ObjVersion
          DTA_ObjectID

Result

The number of attributes obtained.

Notes

(#1) - On AROS, the "DataType" an object returns may be a clone of

      the real entry, so that the subclass can override
      subformat information.

See also SetDTAttrsA() intuition.library/GetAttr()


GetDTMethods()

ULONG * GetDTMethods(

        Object * object );

Function

Get a list of the methods an object supports.

Inputs

object -- pointer to a data type object

Result

Pointer to a ULONG array which is terminated ~0; the array is only valid until the object is disposed of.

See also GetDTTriggerMethods()


GetDTString()

CONST_STRPTR GetDTString(

        ULONG id );

Function

Get a pointer to a localized datatypes string.

Inputs

id -- ID of the string to get

Result

Pointer to a NULL terminated string.


GetDTTriggerMethodDataFlags()

ULONG GetDTTriggerMethodDataFlags(

        ULONG method );

Function

Get the kind of data that may be attached to the stt_Data field in the dtTrigger method body. The data type can be specified by or:ing the method id (within the STMF_METHOD_MASK value) with one of the STMD_ identifiers.

STMD_VOID -- stt_Data must be NULL STMD_ULONG -- stt_Data contains an unsigned value STMD_STRPTR -- stt_Data is a pointer to a string STMD_TAGLIST -- stt_Data points to an array of struct TagItem terminated

                 with TAG_DONE

The trigger methods below STM_USER are explicitly handled as described in <datatypes/datatypesclass.h>.

Inputs

method -- dtt_Method ID from struct DTMethod

Result

One of the STMD_ identifiers defined in <datatypes/datatypesclass.h>

See also CopyDTTriggerMethods() FindTriggerMethod()


GetDTTriggerMethods()

struct DTMethod * GetDTTriggerMethods(

        Object * object );

Function

Get a list of the trigger methods an object supports.

Inputs

object -- pointer to a data type object

Result

A pointer to a STM_DONE terminated DTMethod list. This list in only valid until the object is disposed of.

Example

To call the specific method, do the following:

DoMethod(object, DTM_TRIGGER, myMethod);

Notes

Some trigger methods requires an argument (calling these with a NULL argument is wrong). Use GetDTTriggerMethodDataFlags() to obtain the type of the requested argument.

See also GetDTMethods()


LaunchToolA()

ULONG LaunchToolA(

        struct Tool * tool,
        STRPTR project,
        struct TagItem * attrs );

ULONG LaunchTool(

        struct Tool * tool,
        STRPTR project,
        TAG tag, ... );

Function

Launch an application with a particular project.

Inputs

tool -- tool to use (may be NULL in which case this function

            returns 0)

project -- name of the project to execute or NULL attrs -- additional attributes

Tags

NP_Priority (BYTE) -- priority of the launched tool (default is the

                     priority of the currect process except for
                     Workbench applications where the default priority
                     is 0 if not overridden by the TOOLPRI tooltype).

NP_Synchronous (BOOL) -- don't return until lauched application process

                        finishes (defaults to FALSE).

Result

Zero for failure, non-zero otherwise.

See also NewDTObjectA()


LockDataType()

VOID LockDataType(

        struct DataType * dt );

Function

Lock a DataType structure obtained from ObtainDataTypeA() or a data type object (DTA_DataType).

Inputs

dt -- DataType structure; may be NULL

Notes

Calls to LockDataType() and ObtainDataTypeA() must have a corresponding ReleaseDataType() call or else problems will arise.

See also ObtainDataTypeA() ReleaseDataType()


NewDTObjectA()

Object * NewDTObjectA(

        APTR name,
        struct TagItem * attrs );

Object * NewDTObject(

        APTR name,
        TAG tag, ... );

Function

Create a data type object from a BOOPSI class.

Inputs

name -- name of the data source; generally an existing file name attrs -- pointer to a TagList specifying additional arguments

Tags

DTA_SourceType -- The type of source data (defaults to DTST_FILE).

                   If the source is the clipboard the name field
                   contains the numeric clipboard unit.

DTA_Handle -- Can be used instead of the 'name' field. If the

                   source is DTST_FILE, ths must be a valid FileHandle;
                   must be a valid IFFHandle if source is DTST_CLIPBOARD.

DTA_DataType -- The class of the data. Data is a pointer to a valid

                   DataType; only used when creating a new object that
                   doens't have any source data.

DTA_GroupID -- If the object isn't of this type, fail with an IoErr()

                   of ERROR_OBJECT_WRONG_TYPE.

GA_Left GA_RelRight GA_Top GA_RelBottom GA_Width GA_RelWidth GA_Height GA_RelHeight -- Specify the position of the object relative to the

                   window.

GA_ID -- ID of the object.

GA_UserData -- Application specific data for the object.

GA_Previous -- Previous object / gadget in the list.

Result

A BOOPSI object. This may be used in different contexts such as a gadget or image. NULL indicates failure -- in that case IoErr() gives more information:

ERROR_REQUIRED_ARG_MISSING -- A required attribute wasn't specified.

ERROR_BAD_NUMBER -- The group ID specified was invalid.

ERROR_OBJECT_WRONG_TYPE -- Object data type doesn't match DTA_GroupID.

Notes

This function invokes the method OM_NEW for the specified class.

The object should (eventually) be freed by DisposeDTObject() when no longer needed.

See also AddDTObject() DisposeDTObject() RemoveDTObject() intuition.library/NewObjectA()


ObtainDataTypeA()

struct DataType * ObtainDataTypeA(

        ULONG type,
        APTR handle,
        struct TagItem * attrs );

struct DataType * ObtainDataType(

        ULONG type,
        APTR handle,
        TAG tag, ... );

Function

Examine the data pointed to by 'handle'.

Inputs

type -- specifies the stream-type of 'handle', using one of the following types;

           DTST_FILE - 'handle' is a BPTR lock
           DTST_CLIPBOARD - 'handle' is a struct IFFHandle *
           DTST_RAM - (v45) 'handle' is a STRPTR datatype-name

handle -- handle to return a datatype for. attrs -- additional attributes.

           DTA_GroupID  -  (v45) (ULONG)
                           the group (GID_#?) to match.
                           0 is used as a wildcard value.
           DTA_DataType -  (v45) (struct DataType *)
                           starts/continues search from the specified
                           DataType. NULL has the same effect as not
                           using DTA_DataType.

Result

A pointer to a DataType or NULL if failure. IoErr() gives more information in the latter case:

ERROR_NO_FREE_STORE -- Not enough memory available ERROR_OBJECT_NOT_FOUND -- Unable to open the data type object ERROR_NOT_IMPLEMENTED -- Unknown handle type

See also ReleaseDataType()


ObtainDTDrawInfoA()

APTR ObtainDTDrawInfoA(

        Object         * o,
        struct TagItem * attrs );

APTR ObtainDTDrawInfo(

        Object         * o,
        TAG tag, ... );

Function

Prepare a data type object for drawing into a RastPort; this function will send the DTM_OBTAINDRAWINFO method the object using an opSet message.

Inputs

o -- pointer to the data type object to obtain the drawinfo for;

          may be NULL in which case nothing is done

attrs -- additional attributes

Tags

None defined so far.

Result

A private handle that must be passed to ReleaseDTDrawInfo when the application is done drawing the object, or NULL if failure.

See also DrawDTObjectA() ReleaseDTDrawInfo()


PrintDTObjectA()

ULONG PrintDTObjectA(

        Object           * object,
        struct Window    * window,
        struct Requester * requester,
        struct dtPrint   * msg );

ULONG PrintDTObject(

        Object           * object,
        struct Window    * window,
        struct Requester * requester,
        TAG tag, ... );

Function

Perform an object's DTM_PRINT method in an asynchronous manner.

Inputs

object -- pointer to the data type object window -- pointer to the window the object has been added to requester -- pointer to the requester the object has been added to

Result

TRUE on success, FALSE otherwise.

Notes

When an application has called PrintDTObjectA() it must not touch the printerIO union until a IDCMP_IDCMPUPDATE is received which contains the DTA_PrinterStatus tag.

   To abort a print, send the DTM_ABORTPRINT method to the object.

This will signal the print process with a SIGBREAK_CTRL_C.


RefreshDTObjectA()

void RefreshDTObjectA(

        Object           * object,
        struct Window    * window,
        struct Requester * req,
        struct TagItem   * attrs );

void RefreshDTObject(

        Object           * object,
        struct Window    * window,
        struct Requester * req,
        TAG tag, ... );

Function

Refresh a specified object sending the GM_RENDER message to the object.

Inputs

object -- pointer to the data type object to refresh; may be NULL window -- pointer to the window; may be NULL req -- must be NULL attrs -- additional attributes (currently none defined)

See also AddDTObject() RemoveDTObject() intuition.library/RefreshGList()


ReleaseDataType()

VOID ReleaseDataType(

        struct DataType * dt );

Function

Release a DataType structure aquired by ObtainDataTypeA().

Inputs

dt -- DataType structure as returned by ObtainDataTypeA(); NULL is

       a valid input.

See also

ObtainDataTypeA() ReleaseDTDrawInfo() Synopsis

VOID ReleaseDTDrawInfo(

        Object * o,
        APTR handle );

Function

Release the handle obtained from ObtainDTDrawInfoA(); invokes the object's DTM_RELEASEDRAWINFO method sending the dtReleaseDrawInfo message.

Inputs

o -- pointer to the data type object the drawinfo of which to

           release; may be NULL

handle -- handle got from ObtainDTDrawInfoA()

Result

A private handle that must be passed to ReleaseDTDrawInfo when the application is done drawing the object, or NULL if failure.

See also DrawDTObjectA() ObtainDTDrawInfoA()


RemoveDTObject()

LONG RemoveDTObject(

        struct Window * window,
        Object        * object );

Function

Remove an object from the specified window's object list; this will wait until the AsyncLayout process is ready. The object will receive a message of type DTM_REMOVEDTOBJECT as a sign of it having been removed.

Inputs

window -- pointer to the window in question object -- pointer to the object to remove

Result

The position of the object in the list before it was removed; if the object wasn't found -1 is returned.

See also AddDTObject() intuition.library/RemoveGList()


SaveDTObjectA()

ULONG SaveDTObjectA(

        Object           * o,
        struct Window    * win,
        struct Requester * req,
        STRPTR file,
        ULONG mode,
        BOOL saveicon,
        struct TagItem   * attrs );

ULONG SaveDTObject(

        Object           * o,
        struct Window    * win,
        struct Requester * req,
        STRPTR file,
        ULONG mode,
        BOOL saveicon,
        TAG tag, ... );

Function

Save the contents of an object to a file using DTM_WRITE.

Inputs

o -- data type object to write to a file win -- window the object is attached to req -- requester the object is attached to file -- name of the file to save the object to mode -- save mode (RAW, IFF etc.), one of the DTWM_ identifiers saveicon -- should an icon be saved together with the file attrs -- additional attributes (these are subclass specific)

Result

The return value of DTM_WRITE.

Notes

If DTM_WRITE returns 0, the file will be deleted.


SetDTAttrsA()

ULONG SetDTAttrsA(

        Object * o,
        struct Window    * win,
        struct Requester * req,
        struct TagItem   * attrs );

ULONG SetDTAttrs(

        Object * o,
        struct Window    * win,
        struct Requester * req,
        TAG tag, ... );

Function

Set the attributes of a data type object.

Inputs

o -- pointer to the data type object the attributes of which to set win -- window that the object has been added to attrs -- attributes to set (terminated with TAG_DONE)

          tags are specified in <datatypes/datatypesclass.h>

See also GetDTAttrsA() intuition.library/SetGadgetAttrsA() datatypes/datatypesclass.h


StartDragSelect()

ULONG StartDragSelect(

        Object * o );

Function

Start drag-selection by the user; the drag selection will only start if the object in question supports DTM_SELECT, is in a window or requester and no layout-process is working on the object.

Inputs

o -- data type object in question; may be NULL

Result

TRUE if all went OK, FALSE otherwise. If FALSE, IoErr() gives further information:

ERROR_ACTION_NOT_KNOWN -- the object doesn't support DTM_SELECT ERROR_OBJECT_IN_USE -- the object is currently occupied


Picture.class 41.00[edit | edit source]

OM_DISPOSE function DT_DisposeMethod
OM_GET function DT_GetMethod
OM_NEW function DT_NewMethod
OM_SET alias OM_UPDATE or function DT_SetMethod
GM_GOACTIVE function DT_GoActiveMethod
GM_HANDLEINPUT function DT_HandleInputMethod
GM_LAYOUT function DT_Layout
GM_RENDER function DT_Render
DTM_ASYNCLAYOUT function DT_AsyncLayout
DTM_DRAW function DT_Draw
DTM_FRAMEBOX function DT_FrameBox
DTM_OBTAINDRAWINFO function DT_ObtainDrawInfo
DTM_PROCLAYOUT function DT_ProcLayout
DTM_RELEASEDRAWINFO function DT_ReleaseDrawInfo
PDTM_READPIXELARRAY function PDT_ReadPixelArray
PDTM_SCALE function PDT_Scale
PDTM_WRITEPIXELARRAY function PDT_WritePixelArray

sound.class 41.11[edit | edit source]

OM_DISPOSE function Sound_DISPOSE
OM_GET function Sound_GET
OM_NEW function Sound_NEW
OM_SET function Sound_SET
OM_UPDATE function Sound_UPDATE
GM_DOMAIN function Sound_DOMAIN
GM_GOINACTIVE function Sound_GOINACTIVE
GM_HANDLEINPUT function Sound_HANDLEINPUT alias GM_GOACTIVE 
GM_HITTEST function Sound_HITTEST alias GM_HELPTEST
GM_LAYOUT function Sound_LAYOUT alias DTM_PROCLAYOUT
GM_RENDER function Sound_RENDER
DTM_CLEARSELECTED function Sound_CLEARSELECTED
DTM_WRITE function Sound_WRITE alias DTM_COPY
DTM_DRAW function Sound_DRAW
DTM_OBTAINDRAWINFO function Sound_OBTAINDRAWINFO
DTM_RELEASEDRAWINFO function Sound_RELEASEDRAWINFO
DTM_REMOVEDTOBJECT function Sound_REMOVEDTOBJECT
DTM_SELECT function Sound_SELECT
DTM_TRIGGER function Sound_TRIGGER


animation.class[edit | edit source]

Implement the animation.datatype (including boopsi control gadget). Must also provide a child datatype (ie avi, mpeg, divx or any other usable format) and a basic application to demonstrate functionality animation.datatype -- root data type for animations. The animation.datatype is the super-class for any animation related classes.

This class creates the controls, scaling, remapping and synchronization.


LONG DrawDTObjectA(
         struct RastPort * rp,
         Object          * o,
         LONG x,
         LONG y,
         LONG w,
         LONG h,
         LONG th,
         LONG tv,
         struct TagItem  * attrs );

LONG DrawDTObject(
         struct RastPort * rp,
         Object          * o,
         LONG x,
         LONG y,
         LONG w,
         LONG h,
         LONG th,
         LONG tv,
         TAG tag, ... );

Draw a data type object into a RastPort. You must have successfully called ObtainDTDrawInfoA before calling this function; it invokes the object's DTM_DRAW method.

rp     --  pointer to the RastPort to draw the object into
o      --  pointer to the data type object to draw
x      --  left edge of drawing area
y      --  top edge of drawing area
w      --  width of drawing area
h      --  height of drawing area
th     --  horizontal top in units
tv     --  vertical top in units
attrs  --  additional attributes

ADTA_Frame Tag for animationclass objects (selects the frame that should be drawn.

TRUE if rendering went OK, FALSE if failure. The RastPort in question must support clipping, i.e. have a valid layer structure attached to it; if not, some datatypes can't draw and FALSE will be returned.


/*
    Copyright � 2015-2020, The AROS Development	Team. All rights reserved.
    $Id$
*/

#include <graphics/gfx.h>
#include <datatypes/pictureclass.h>
#include <datatypes/animationclass.h>
#include <datatypes/animationclassext.h>

#define	MIN(a,b) (((a) < (b)) ?	(a) : (b))
#define	MAX(a,b) (((a) > (b)) ?	(a) : (b))

/*
    api flags
 */
#define	ANIMDF_CONTROLPANEL     (1 << 0)
#define	ANIMDF_IMMEDIATE        (1 << 1)
#define	ANIMDF_REPEAT           (1 << 2)
#define	ANIMDF_REMAP            (1 << 3)
#define	ANIMDF_ADJUSTPALETTE    (1 << 4)
#define	ANIMDF_ADAPTFPS         (1 << 5)
#define	ANIMDF_FRAMESKIP        (1 << 6)
#define	ANIMDF_SMARTSKIP        (1 << 7)

/*
    special flags used by rendering/layout code
 */
#define ANIMDF_LAYOUT           (1 << 29)               
#define ANIMDF_REMAPPEDPENS     (1 << 30)               
#define ANIMDF_SHOWPANEL        (1 << 31)

#define ANIMPLAYER_TICKFREQ     ((struct RealTimeBase *)RealTimeBase)->rtb_Reserved1

struct ProcessPrivate;
struct Animation_Data;
struct AnimFrame;
BOOL ProcEnabled(struct ProcessPrivate *, volatile ULONG *, ULONG);
void cacheFrame(struct Animation_Data *, struct AnimFrame *);
void freeFrame(struct Animation_Data *, struct AnimFrame *);

struct AnimColor_Data
{
    struct SignalSemaphore      acd_PenLock;
    struct ColorMap             *acd_ColorMap;
    struct ColorRegister        *acd_ColorRegs;
    ULONG			*acd_CRegs;
    ULONG                       *acd_GRegs;

    UWORD                       acd_NumColors;
    UWORD                       acd_NumAlloc;

    UBYTE			*acd_ColorTable[2];
    UBYTE			*acd_Allocated;          /* pens we have actually allocated      */
    ULONG                       acd_PenPrecison;         /* precision to use allocating pens     */
};

struct AnimFrame_Data
{
    struct SignalSemaphore      afd_AnimFramesLock;
    struct List                 afd_AnimFrames;

    UWORD                       afd_Frames;              /* # of frames                          */
    UWORD                       afd_FrameCurrent;        /* # of current frame                   */
    UWORD                       afd_FramesStep;          /* how much to skip back/fwd            */
};

struct AnimTimer_Data
{
    UWORD                       atd_FramesPerSec;        /* Playback rate                        */
    UWORD                       atd_TicksPerFrame;       /* realtime.libraries tick frequency /
                                                           ad_FramesPerSec */
    UWORD                       atd_Tick;
};

/* our nodes used to play the anim! */
struct AnimFrame
{
    struct Node                 af_Node;
#define af_CacheBM af_Node.ln_Name
    ULONG                       af_Flags;
    struct adtNewFormatFrame    af_Frame;
};

#define AFFLAGB_READY      0
#define AFFLAGF_READY      (1 << 0)

/* for sanity, we embed the frame number in the ln_type/ln_pri fields */
static inline UWORD GetNODEID(struct AnimFrame *node) {
    UWORD *id_ptr = (UWORD *)&node->af_Node.ln_Type;
    return *id_ptr;
}

static inline void SetNODEID(struct AnimFrame *node, UWORD id) {
    UWORD *id_ptr = (UWORD *)&node->af_Node.ln_Type;
    *id_ptr = id;
}

struct Animation_Data
{
    ULONG                       ad_Flags;               /* object control flags                 */
    char                        *ad_BaseName;

    struct Window               *ad_Window;

    struct AnimFrame_Data       ad_FrameData;
    struct AnimTimer_Data       ad_TimerData;

    struct BitMap               *ad_FrameBM;        /* currently displayed frame            */
    struct BitMap               *ad_CacheBM;        /* .. */
    struct AnimFrame            *ad_KeyFrame;       /* animations key (first) frame         */

    UWORD                       ad_VertTop;             /* Y offset of visible rectangle        */
    UWORD                       ad_VertTotal;           
    UWORD                       ad_VertVis;
    UWORD                       ad_HorizTop;            /* X offset of visible rectangle        */
    UWORD                       ad_HorizTotal;
    UWORD                       ad_HorizVis;

    UWORD                       ad_RenderLeft;
    UWORD                       ad_RenderTop;
    UWORD                       ad_RenderWidth;
    UWORD                       ad_RenderHeight;

    IPTR                        ad_ModeID;
    struct BitMapHeader         ad_BitMapHeader;        /* objects embedded bitmap header       */

    struct AnimColor_Data       ad_ColorData;

    IPTR                        ad_ProcStack;
    struct ProcessPrivate       *ad_ProcessData;
    struct Process              *ad_BufferProc;         /* buffering process */
    struct Process              *ad_PlayerProc;         /* playback process */
    struct Player               *ad_Player;
    struct Hook                 ad_PlayerHook;

    struct Gadget               *ad_Tapedeck;
    ULONG                       ad_BufferTime;         /* (prefs) how many seconds to buffer  */
    ULONG                       ad_BufferStep;         /* (prefs) no of frames to try to load in one go */
    UBYTE                       ad_PlayerSourceLastState;
};

struct ProcessPrivate
{
    Object                      *pp_Object;
    struct Animation_Data       *pp_Data;
    char                        *pp_PlayBackName;
    char                        *pp_BufferingName;
    volatile ULONG              pp_PlayerFlags;
    volatile ULONG              pp_BufferFlags;
    ULONG                       pp_BufferFrames;       /* no of frames to buffer in total       */
    ULONG                       pp_BufferLevel;        /* no of frames buffered                 */
    IPTR                        pp_BufferSpecific;     /* specific frame to load                */
    struct AnimFrame            *pp_BufferFirst;       /* starting point to load from           */
    struct AnimFrame            *pp_PlaybackFrame;

    ULONG                       pp_BufferSigMask;
    BYTE                       pp_BufferEnable;
    BYTE                       pp_BufferDisable;
    BYTE                       pp_BufferFill;
    BYTE                       pp_BufferPurge;

    ULONG                       pp_PlaybackSigMask;
    BYTE                       pp_PlaybackEnable;
    BYTE                       pp_PlaybackDisable;
    BYTE                       pp_PlaybackTick;          /* signal frames needs to change      */
    BYTE                       pp_PlaybackSync;          /* signal position changed            */
};

#define PRIVPROCF_ENABLED       (1 << 0)
#define PRIVPROCF_RUNNING       (1 << 1)
#define PRIVPROCF_ACTIVE        (1 << 2)
#define PRIVPROCF_BUSY          (1 << 3)

#define TAG_PRIVATE             	(ADTA_Dummy + 100)
#define PRIVATE_INITPLAYER              (TAG_PRIVATE - 1)
#define PRIVATE_ALLOCCOLORTABLES        (TAG_PRIVATE - 2)
#define PRIVATE_MAPFRAMEPENS            (TAG_PRIVATE - 3)     
#define PRIVATE_FREECOLORTABLES         (TAG_PRIVATE - 4) 
#define PRIVATE_FREEPENS                (TAG_PRIVATE - 5)             
#define PRIVATE_ALLOCBUFFER             (TAG_PRIVATE - 6)
#define PRIVATE_RENDERFRAME             (TAG_PRIVATE - 7)
#define PRIVATE_REMAPFRAME              (TAG_PRIVATE - 8)

struct privAllocColorTables
{
    STACKED ULONG MethodID;
    STACKED ULONG NumColors;
};

struct privMapFramePens
{
    STACKED ULONG MethodID;
    STACKED struct AnimFrame *Frame;
};

struct privAllocBuffer
{
    STACKED ULONG MethodID;
    STACKED struct BitMap *Friend;
    STACKED UBYTE Depth;
};

struct privRenderFrame
{
    STACKED ULONG MethodID;
    STACKED struct AnimFrame *Frame;
    STACKED struct BitMap *Target;
};

#if DEBUG > 0
#define DFRAMES(...) bug(__VA_ARGS__);
#else
#define DFRAMES(...)
#endif


/*
    Copyright � 2016-2020, The AROS Development	Team. All rights reserved.
    $Id$
*/

#ifndef DEBUG
#   define DEBUG 0
#endif
#include <aros/debug.h>

#include <clib/alib_protos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/utility.h>

#include "animationclass.h"

/*
 *  converts/remaps a frame to a bitmap suitable for display..
 */

void cacheFrame(struct Animation_Data *animd, struct AnimFrame *frame)
{
    struct privRenderFrame rendFrameMsg;
    
    DFRAMES("[animation.datatype/CACHE]: %s()\n", __func__)

    if (frame->af_Frame.alf_CMap)
    {
        DFRAMES("[animation.datatype/CACHE]: %s:      CMap @ 0x%p\n", __func__, frame->af_Frame.alf_CMap)
        rendFrameMsg.MethodID = PRIVATE_MAPFRAMEPENS;
        rendFrameMsg.Frame = frame;
        DoMethodA(animd->ad_ProcessData->pp_Object, (Msg)&rendFrameMsg);
    }

    rendFrameMsg.MethodID = PRIVATE_RENDERFRAME;
    rendFrameMsg.Frame = frame;
    if ((rendFrameMsg.Target = (struct BitMap *)frame->af_CacheBM) == NULL)
    {
        frame->af_CacheBM = (char *)AllocBitMap(animd->ad_BitMapHeader.bmh_Width, animd->ad_BitMapHeader.bmh_Height, 24,
                                  BMF_CLEAR, animd->ad_CacheBM);
        rendFrameMsg.Target = (struct BitMap *)frame->af_CacheBM;
        frame->af_Flags = 0;
        DFRAMES("[animation.datatype/CACHE]: %s: allocated frame cache bm @ 0x%p (friend @ 0x%p)\n", __func__, frame->af_CacheBM, animd->ad_CacheBM)
    }
    DoMethodA(animd->ad_ProcessData->pp_Object, (Msg)&rendFrameMsg);
}

void freeFrame(struct Animation_Data *animd, struct AnimFrame *frame)
{
    DFRAMES("[animation.datatype/CACHE]: %s()\n", __func__)
    if (frame->af_CacheBM)
    {
        FreeBitMap((struct BitMap *)frame->af_CacheBM);
        frame->af_CacheBM = NULL;
    }
}


/*
    Copyright � 2015-2020, The AROS Development	Team. All rights reserved.
    $Id$
*/

#ifndef DEBUG
#   define DEBUG 0
#endif
#include <aros/debug.h>

#include <clib/alib_protos.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <proto/realtime.h>
#include <proto/layers.h>
#include <proto/datatypes.h>

#include <intuition/gadgetclass.h>
#include <libraries/realtime.h>
#include <gadgets/tapedeck.h>

#include "animationclass.h"

AROS_UFH3(ULONG, playerHookFunc, 
    AROS_UFHA(struct    Hook *,     hook, A0), 
    AROS_UFHA(struct Player *, obj, A2), 
    AROS_UFHA(struct pmTime *, msg, A1))
{ 
    AROS_USERFUNC_INIT
 
    struct Animation_Data *animd = (struct Animation_Data *)hook->h_Data;
    IPTR buffSigs = 0, playbacksigs = 0;

#if (0)
    // only enable if you like spam.
    bug("[animation.datatype]: %s(%08x)\n", __func__, msg->pmt_Method);
#endif

    switch (msg->pmt_Method)
    {
	case PM_TICK:
            animd->ad_TimerData.atd_Tick++;

            if (animd->ad_TimerData.atd_Tick >= animd->ad_TimerData.atd_TicksPerFrame)
            {
                animd->ad_TimerData.atd_Tick = 0;
                // increment the frame counter if we are supposed to...
                if (!(animd->ad_ProcessData->pp_PlayerFlags & PRIVPROCF_BUSY) || (animd->ad_Flags & ANIMDF_FRAMESKIP))
                {
                    animd->ad_FrameData.afd_FrameCurrent++;
                    if (animd->ad_FrameData.afd_FrameCurrent >= animd->ad_FrameData.afd_Frames)
                    {
                        if (animd->ad_Flags & ANIMDF_REPEAT)
                            animd->ad_FrameData.afd_FrameCurrent = 1;
                        else
                            animd->ad_FrameData.afd_FrameCurrent = animd->ad_FrameData.afd_Frames - 1;
                    }
                }
                if (animd->ad_ProcessData->pp_PlaybackTick != -1)
                    playbacksigs |=  (1 << animd->ad_ProcessData->pp_PlaybackTick);
            }
            if (animd->ad_TimerData.atd_Tick == 0)
            {
                // flush unused buffers...
                if (animd->ad_ProcessData->pp_BufferPurge != -1)
                    buffSigs |= (1 << animd->ad_ProcessData->pp_BufferPurge);
            }
	    break;

	case PM_SHUTTLE:
            D(bug("[animation.datatype] %s: PM_SHUTTLE\n", __func__);)
            animd->ad_FrameData.afd_FrameCurrent = msg->pmt_Time/animd->ad_TimerData.atd_TicksPerFrame;
            animd->ad_TimerData.atd_Tick = 0;
            if (animd->ad_ProcessData->pp_PlaybackSync != -1)
                playbacksigs |=  (1 << animd->ad_ProcessData->pp_PlaybackSync);
	    break;

	case PM_STATE:
	    break;
    }

    if (buffSigs && (animd->ad_BufferProc))
        Signal((struct Task *)animd->ad_BufferProc, buffSigs);
    if (playbacksigs && (animd->ad_PlayerProc))
        Signal((struct Task *)animd->ad_PlayerProc, playbacksigs);

    return 0;

    AROS_USERFUNC_EXIT
}
    
void FreePlaybackSignals(struct ProcessPrivate *priv)
{
    D(bug("[animation.datatype/PLAY]: %s()\n", __func__);)

    if (priv->pp_PlaybackTick != -1)
        FreeSignal(priv->pp_PlaybackTick);
    if (priv->pp_PlaybackEnable != -1)
        FreeSignal(priv->pp_PlaybackEnable);
    if (priv->pp_PlaybackDisable != -1)
        FreeSignal(priv->pp_PlaybackDisable);
}

BOOL AllocPlaybackSignals(struct ProcessPrivate *priv)
{
    if ((priv->pp_PlaybackEnable = AllocSignal(-1)) != -1)
    {
        D(bug("[animation.datatype/PLAY]: %s: allocated enable signal (%x)\n", __func__, priv->pp_PlaybackEnable);)
        if ((priv->pp_PlaybackDisable = AllocSignal(-1)) != -1)
        {
            D(bug("[animation.datatype/PLAY]: %s: allocated disable signal (%x)\n", __func__, priv->pp_PlaybackDisable);)
            if ((priv->pp_PlaybackTick = AllocSignal(-1)) != -1)
            {
                D(bug("[animation.datatype/PLAY]: %s: allocated tick signal (%x)\n", __func__, priv->pp_PlaybackTick);)
                if ((priv->pp_PlaybackSync = AllocSignal(-1)) != -1)
                {
                    D(bug("[animation.datatype/PLAY]: %s: allocated sync signal (%x)\n", __func__, priv->pp_PlaybackSync);)

                    priv->pp_PlaybackSigMask = (1 << priv->pp_PlaybackEnable) | (1 << priv->pp_PlaybackDisable) | (1 << priv->pp_PlaybackTick) | (1 << priv->pp_PlaybackSync);

                    D(bug("[animation.datatype/PLAY]: %s: signal mask (%x)\n", __func__, priv->pp_PlaybackSigMask);)

                    return TRUE;
                }
            }
        }
    }
    return FALSE;
}

struct AnimFrame *NextFrame(struct ProcessPrivate *priv, struct AnimFrame *frameCurrent, UWORD *frame)
{
    struct AnimFrame *frameFound = NULL,
                     *frameFirst = NULL, *framePrev = NULL;
    UWORD frameID = 0;

    DFRAMES("[animation.datatype/PLAY]: %s(0x%p, %d)\n", __func__, frameCurrent, *frame)

    ObtainSemaphoreShared(&priv->pp_Data->ad_FrameData.afd_AnimFramesLock);

    if ((!frameCurrent) ||
        (*frame < GetNODEID(frameCurrent)))
        frameCurrent = frameFound = (struct AnimFrame *)&priv->pp_Data->ad_FrameData.afd_AnimFrames;
    else
        frameFound = frameCurrent;

    while ((frameFound->af_Node.ln_Succ) && (frameFound->af_Node.ln_Succ->ln_Succ))
    {
        frameFound = (struct AnimFrame *)frameFound->af_Node.ln_Succ;

        DFRAMES("[animation.datatype/PLAY] %s:   frame #%d @ 0x%p\n", __func__, GetNODEID(frameFound), frameFound)
        if (!frameFirst)
            frameFirst = frameFound;

        if (GetNODEID(frameFound) >= *frame)
        {
            break;
        }
        framePrev = frameFound;
    }

    if (!(frameFound) ||
        (frameCurrent == frameFound) ||
        (frameFound == (struct AnimFrame *)&priv->pp_Data->ad_FrameData.afd_AnimFrames) ||
        (GetNODEID(frameFound) > *frame))
    {
        frameFound = NULL;

        if (!(priv->pp_Data->ad_Flags & ANIMDF_FRAMESKIP))
        {
            if ((frameFirst) && (GetNODEID(frameFirst) == (GetNODEID(frameCurrent) + 1)))
                frameFound = frameFirst;
        }
        else if ((framePrev) && (GetNODEID(framePrev) > 0))
            frameFound = framePrev;

        if (!(frameFound) &&
            (frameCurrent) &&
            (GetNODEID(frameCurrent) < priv->pp_Data->ad_FrameData.afd_Frames))
            frameFound = frameCurrent;
    }

    if (frameFound)
    {
        frameID = GetNODEID(frameFound);
        if (frameFound != frameCurrent)
            priv->pp_PlaybackFrame = frameFound;
        else
            frameFound = NULL;
    }
    *frame = frameID;

    DFRAMES("[animation.datatype/PLAY] %s: found #%d @ 0x%p\n", __func__, *frame, frameFound)

    ReleaseSemaphore(&priv->pp_Data->ad_FrameData.afd_AnimFramesLock);

    return frameFound;
}

BOOL GetFrameCacheBitmap(struct BitMap **frameBM,  struct AnimFrame *frame)
{
    if (frame->af_Flags & AFFLAGF_READY)
    {
        *frameBM = (struct BitMap *)frame->af_CacheBM;
        return TRUE;
    }
    return FALSE;
}

AROS_UFH3(void, playerProc,
        AROS_UFHA(STRPTR,              argPtr, A0),
        AROS_UFHA(ULONG,               argSize, D0),
        AROS_UFHA(struct ExecBase *,   SysBase, A6))
{
    AROS_USERFUNC_INIT

    struct ProcessPrivate *priv = FindTask(NULL)->tc_UserData;
    struct AnimFrame *curFrame = NULL;
    struct gpRender gprMsg;
    struct TagItem attrtags[] =
    {
        { TAG_IGNORE,   0},
        { TAG_IGNORE,   0},
        { TAG_DONE,     0}
    };
    UWORD frame = 0;
    ULONG signal, buffsigs;

    D(bug("[animation.datatype/PLAY]: %s()\n", __func__);)

    if (priv)
    {
        D(
            bug("[animation.datatype/PLAY] %s: private data @ 0x%p\n", __func__, priv);
            bug("[animation.datatype/PLAY] %s: dt obj @ 0x%p, instance data @ 0x%p\n", __func__, priv->pp_Object, priv->pp_Data);
        )

        priv->pp_PlaybackFrame = NULL;
        priv->pp_PlayerFlags |= PRIVPROCF_RUNNING;

        if (AllocPlaybackSignals(priv))
        {
            D(bug("[animation.datatype/PLAY]: %s: entering main loop ...\n", __func__);)
            while (TRUE)
            {
                priv->pp_PlayerFlags &= ~PRIVPROCF_ACTIVE;

                signal = priv->pp_PlaybackSigMask | SIGBREAKF_CTRL_C;
                signal = Wait(signal);

                D(bug("[animation.datatype/PLAY]: %s: signalled (%08x)\n", __func__, signal);)

                if (signal & SIGBREAKF_CTRL_C)
                    break;

                priv->pp_PlayerFlags |= PRIVPROCF_ACTIVE;

                if (signal & (1 << priv->pp_PlaybackEnable))
                    priv->pp_PlayerFlags |= PRIVPROCF_ENABLED;
                else if (signal & (1 << priv->pp_PlaybackDisable))
                    priv->pp_PlayerFlags &= ~PRIVPROCF_ENABLED;

                if ((priv->pp_PlayerFlags & PRIVPROCF_ENABLED) && ((signal & ((1 << priv->pp_PlaybackTick)|(1 << priv->pp_PlaybackSync))) != 0))
                {
                    priv->pp_PlayerFlags |= PRIVPROCF_BUSY;
                    frame = priv->pp_Data->ad_FrameData.afd_FrameCurrent;
                    buffsigs = 0;

                    DFRAMES("[animation.datatype/PLAY] %s: Frame #%d\n", __func__, frame)

                    curFrame = NextFrame(priv, priv->pp_PlaybackFrame, &frame);

                    if ((priv->pp_BufferFrames > priv->pp_BufferLevel) &&
                        (priv->pp_BufferLevel < priv->pp_Data->ad_FrameData.afd_Frames))
                    {
                        buffsigs |= (1 << priv->pp_BufferFill);
                    }

                    if (!(curFrame))
                    {
                        ObtainSemaphore(&priv->pp_Data->ad_FrameData.afd_AnimFramesLock);
                        if ((signal & (1 << priv->pp_PlaybackSync)) ||
                            (priv->pp_Data->ad_Flags & ANIMDF_FRAMESKIP))
                        {
                            priv->pp_BufferSpecific = frame;
                        }

                        if ((priv->pp_PlaybackFrame) &&
                            ((GetNODEID(priv->pp_PlaybackFrame) < frame) ||
                            (!(priv->pp_Data->ad_Flags & ANIMDF_FRAMESKIP) && (GetNODEID(priv->pp_PlaybackFrame) < (priv->pp_Data->ad_FrameData.afd_Frames - 1)))))
                        {
                            priv->pp_BufferFirst = priv->pp_PlaybackFrame;
                        }
                        else if (priv->pp_Data->ad_Flags & ANIMDF_FRAMESKIP)
                            priv->pp_BufferFirst = NULL;

                        ReleaseSemaphore(&priv->pp_Data->ad_FrameData.afd_AnimFramesLock);

                        buffsigs |= ((1 << priv->pp_BufferPurge) | (1 << priv->pp_BufferFill));
                    }

                    if ((buffsigs) && (priv->pp_Data->ad_BufferProc))
                    {
                        Signal((struct Task *)priv->pp_Data->ad_BufferProc, buffsigs);
                        if (buffsigs & (1 << priv->pp_BufferPurge))
                            SetTaskPri((struct Task *)priv->pp_Data->ad_PlayerProc, -2);
                    }

                    // frame has changed ... render it ..
                    if ((curFrame) && GetFrameCacheBitmap(&priv->pp_Data->ad_FrameBM,  curFrame))
                    {
                        D(
                            bug("[animation.datatype/PLAY]: %s: Rendering Frame #%d\n", __func__,  GetNODEID(curFrame));
                            bug("[animation.datatype/PLAY]: %s:      BitMap @ 0x%p\n", __func__, priv->pp_Data->ad_FrameBM);
                        )

                        priv->pp_PlayerFlags &= ~PRIVPROCF_BUSY;

                        if ((priv->pp_Data->ad_Window) && !(priv->pp_Data->ad_Flags & ANIMDF_LAYOUT))
                        {
                            if (priv->pp_Data->ad_Tapedeck)
                            {
                                // update the tapedeck gadget..
                                attrtags[0].ti_Tag = TDECK_CurrentFrame;
                                attrtags[0].ti_Data = GetNODEID(curFrame);
                                attrtags[1].ti_Tag = TAG_IGNORE;

                                SetAttrsA((Object *)priv->pp_Data->ad_Tapedeck, attrtags);
                            }

                            // tell the top level gadget to redraw...
                            gprMsg.MethodID   = GM_RENDER;
                            gprMsg.gpr_RPort  = priv->pp_Data->ad_Window->RPort;
                            gprMsg.gpr_GInfo  = NULL;
                            gprMsg.gpr_Redraw = GREDRAW_UPDATE;
                            DoGadgetMethodA((struct Gadget *)priv->pp_Object, priv->pp_Data->ad_Window, NULL, (Msg)&gprMsg);
                        }
                    }
                }
            }
            FreePlaybackSignals(priv);
        }
        priv->pp_PlayerFlags &= ~PRIVPROCF_RUNNING;
        priv->pp_Data->ad_PlayerProc = NULL;
    }

    D(bug("[animation.datatype/PLAY]: %s: exiting ...\n", __func__);)

    return;

    AROS_USERFUNC_EXIT
}






//
//  animationclass.h
//

Const

  ANIMATIONDTCLASS      : PChar =       'animation.datatype';

  //* Tags */
  ADTA_Dummy            =  (DTA_Dummy + 600);
  ADTA_ModeID           =  PDTA_ModeID;
  ADTA_KeyFrame         =  PDTA_BitMap;
  ADTA_ColorRegisters   =  PDTA_ColorRegisters;
  ADTA_CRegs            =  PDTA_CRegs;
  ADTA_GRegs            =  PDTA_GRegs;
  ADTA_ColorTable       =  PDTA_ColorTable;
  ADTA_ColorTable2      =  PDTA_ColorTable2;
  ADTA_Allocated        =  PDTA_Allocated;
  ADTA_NumColors        =  PDTA_NumColors;
  ADTA_NumAlloc         =  PDTA_NumAlloc;
  ADTA_Remap            =  PDTA_Remap;
  ADTA_Screen           =  PDTA_Screen;
  ADTA_Width            =  (ADTA_Dummy + 1);
  ADTA_Height           =  (ADTA_Dummy + 2);
  ADTA_Depth            =  (ADTA_Dummy + 3);
  ADTA_Frames           =  (ADTA_Dummy + 4);
  ADTA_Frame            =  (ADTA_Dummy + 5);
  ADTA_FramesPerSecond  =  (ADTA_Dummy + 6);
  ADTA_FrameIncrement   =  (ADTA_Dummy + 7);

  ADTA_Sample           =  SDTA_Sample;
  ADTA_SampleLength     =  SDTA_SampleLength;
  ADTA_Period           =  SDTA_Period;
  ADTA_Volume           =  SDTA_Volume;
  ADTA_Cycles           =  SDTA_Cycles;

  //* New in V44 */
  // NOTE: nowhere in MorpOS SDK are SDTA_xxx constants below defined.
  //       i fixed it above.
  ADTA_PreloadFrameCount= (ADTA_Dummy + 8);     { (V44) }
  ADTA_LeftSample       =  SDTA_LeftSample;     { (V44) }
  ADTA_RightSample      =  SDTA_RightSample;    { (V44) }
  ADTA_SamplesPerSec    =  SDTA_SamplesPerSec;  { (V44) }


  //* IFF ANIM chunks */
  ID_ANIM   = ord('A') shl 24 + ord('N')  shl 16 + ord('I') shl 8 + ord('M'); // 1095649613;
  ID_ANHD   = ord('A') shl 24 + ord('N')  shl 16 + ord('H') shl 8 + ord('D'); // 1095649348;
  ID_DLTA   = ord('D') shl 24 + ord('L')  shl 16 + ord('T') shl 8 + ord('A'); // 1145852993;


Type
  PAnimHeader = ^TAnimHeader;
  TAnimHeader = record
    ah_Operation    : UBYTE;
    ah_Mask         : UBYTE;
    ah_Height       : UWORD;
    ah_Width        : UWORD;
    ah_Left         : SWORD;
    ah_Top          : SWORD;
    ah_AbsTime      : ULONG;
    ah_RelTime      : ULONG;
    ah_Interleave   : UBYTE;
    ah_Pad0         : UBYTE;
    ah_Flags        : ULONG;
    ah_Pad          : packed array[0..16-1] of UBYTE;
  end;


const

  //* Methods */

  ADTM_Dummy                = ($700);
  ADTM_LOADFRAME            = ($701);
  ADTM_UNLOADFRAME          = ($702);
  ADTM_START                = ($703);
  ADTM_PAUSE                = ($704);
  ADTM_STOP                 = ($705);
  ADTM_LOCATE               = ($706);

  //* New on V44 */
  ADTM_LOADNEWFORMATFRAME   = ($707);
  ADTM_UNLOADNEWFORMATFRAME = ($708);


Type
  PadtFrame = ^TadtFrame;
  TadtFrame = record
    MethodID        : ULONG;
    alf_TimeStamp   : ULONG;
    alf_Frame       : ULONG;
    alf_Duration    : ULONG;
    alf_BitMap      : PBitMap;
    alf_CMap        : PColorMap;
    alf_Sample      : PSBYTE;
    alf_SampleLength: ULONG;
    alf_Period      : ULONG;
    alf_UserData    : APTR;
  end;


  PadtNewFormatFrame = ^TadtNewFormatFrame;
  TadtNewFormatFrame = record
    MethodID            : ULONG;
    alf_TimeStamp       : ULONG;
    alf_Frame           : ULONG;
    alf_Duration        : ULONG;
    alf_BitMap          : PBitMap;
    alf_CMap            : PColorMap;
    alf_Sample          : PSBYTE;
    alf_SampleLength    : ULONG;
    alf_Period          : ULONG;
    alf_UserData        : APTR;
    alf_Size            : ULONG;
    alf_LeftSample      : PSBYTE;
    alf_RightSample     : PSBYTE;
    alf_SamplesPerSec   : ULONG;
  end;

  PadtStart = ^tadtStart;
  TadtStart = record
    MethodID            : ULONG;
    asa_Frame           : ULONG;
  end;