mirror of
https://git.code.sf.net/p/newrpl/sources
synced 2024-11-16 19:51:25 +01:00
1104 lines
30 KiB
C
1104 lines
30 KiB
C
/*
|
|
* Copyright (c) 2016, Claudio Lapilli and the newRPL Team
|
|
* All rights reserved.
|
|
* This file is released under the 3-clause BSD license.
|
|
* See the file LICENSE.txt that shipped with this distribution.
|
|
*/
|
|
|
|
#include "newrpl.h"
|
|
#include "libraries.h"
|
|
#include "ui.h"
|
|
#include "render.h"
|
|
|
|
|
|
// *****************************
|
|
// *** COMMON LIBRARY HEADER ***
|
|
// *****************************
|
|
|
|
|
|
|
|
// REPLACE THE NUMBER
|
|
#define LIBRARY_NUMBER 80
|
|
|
|
//@TITLE=Bitmaps
|
|
|
|
// LIST OF COMMANDS EXPORTED,
|
|
// INCLUDING INFORMATION FOR SYMBOLIC COMPILER
|
|
// IN THE CMD() FORM, THE COMMAND NAME AND ITS
|
|
// ENUM SYMBOL ARE IDENTICAL
|
|
// IN THE ECMD() FORM, THE ENUM SYMBOL AND THE
|
|
// COMMAND NAME TEXT ARE GIVEN SEPARATEDLY
|
|
|
|
#define COMMAND_LIST \
|
|
ECMD(TOSYSBITMAP,"→SYSBITMAP",MKTOKENINFO(10,TITYPE_NOTALLOWED,1,2))
|
|
|
|
#define ERROR_LIST \
|
|
ERR(BITMAPEXPECTED,0), \
|
|
ERR(UNSUPPORTEDBITMAP,1), \
|
|
ERR(INVALIDCHECKSUM,2), \
|
|
ERR(UNEXPECTEDENDOFDATA,3)
|
|
|
|
|
|
|
|
// ADD MORE OPCODES HERE
|
|
|
|
// LIST ALL LIBRARY NUMBERS THIS LIBRARY WILL ATTACH TO
|
|
#define LIBRARY_ASSIGNED_NUMBERS \
|
|
LIBRARY_NUMBER, \
|
|
LIBRARY_NUMBER+1, \
|
|
LIBRARY_NUMBER+2, \
|
|
LIBRARY_NUMBER+3, \
|
|
LIBRARY_NUMBER+4, \
|
|
LIBRARY_NUMBER+5, \
|
|
LIBRARY_NUMBER+6, \
|
|
LIBRARY_NUMBER+7
|
|
|
|
|
|
|
|
// THIS HEADER DEFINES MANY COMMON MACROS FOR ALL LIBRARIES
|
|
#include "lib-header.h"
|
|
|
|
|
|
#ifndef COMMANDS_ONLY_PASS
|
|
|
|
// ************************************
|
|
// *** END OF COMMON LIBRARY HEADER ***
|
|
// ************************************
|
|
|
|
|
|
INCLUDE_ROMOBJECT(LIB_MSGTABLE);
|
|
INCLUDE_ROMOBJECT(LIB_HELPTABLE);
|
|
INCLUDE_ROMOBJECT(lib80_menu);
|
|
|
|
|
|
// EXTERNAL EXPORTED OBJECT TABLE
|
|
// UP TO 64 OBJECTS ALLOWED, NO MORE
|
|
const WORDPTR const ROMPTR_TABLE[]={
|
|
(WORDPTR)LIB_MSGTABLE,
|
|
(WORDPTR)LIB_HELPTABLE,
|
|
(WORDPTR)lib80_menu,
|
|
|
|
0
|
|
};
|
|
|
|
const char * const bitmap_modes[]={
|
|
"MONO",
|
|
"16GR",
|
|
"256G",
|
|
"64KC",
|
|
"ARGB",
|
|
"OTHR",
|
|
"INVA",
|
|
"INVA"
|
|
};
|
|
|
|
// CONVERT RGB 0-255 TO GRAY 0-255 PER BT.709 HDTV FORMULA FOR LUMINANCE
|
|
|
|
#define LUMINANCE(r,g,b) ((((r)*55+(g)*183+(b)*18)+128)>>8)
|
|
#define RGB5TO8(comp) (((BINT)(comp)*2106)>>8)
|
|
#define RGB6TO8(comp) (((BINT)(comp)*1036)>>8)
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
// ADD OTHER INFO HERE
|
|
DRAWSURFACE srf;
|
|
BINT npoints,ptalloc;
|
|
CURVEPT points[1];
|
|
|
|
|
|
} BMP_RENDERSTATE;
|
|
|
|
|
|
#define RENDERSTATE_SIZE(npoints) ((sizeof(BMP_RENDERSTATE)+(npoints-1)*sizeof(((BMP_RENDERSTATE *)0)->points))>>2)
|
|
|
|
|
|
|
|
// CONVERT A BITMAP FROM ANY FORMAT INTO THE DEFAULT DISPLAY FORMAT
|
|
|
|
WORDPTR rplBmpToDisplay(WORDPTR bitmap)
|
|
{
|
|
if(!ISBITMAP(*bitmap)) {
|
|
rplError(ERR_BITMAPEXPECTED);
|
|
return 0;
|
|
}
|
|
|
|
|
|
BINT type=LIBNUM(*bitmap)&7;
|
|
|
|
if(type==DEFAULTBITMAPMODE) return bitmap; // NO CONVERSION NEEEDED
|
|
|
|
BINT width=(BINT)bitmap[1];
|
|
BINT height=(BINT)bitmap[2];
|
|
|
|
BINT totalsize=(width*height*DEFAULTBITSPERPIXEL)+31;
|
|
|
|
totalsize>>=5; // BITMAP SIZE IN WORDS
|
|
|
|
|
|
WORDPTR newbmp=rplAllocTempOb(totalsize+2);
|
|
if(!newbmp) return 0;
|
|
|
|
BINT npixels=width*height;
|
|
|
|
|
|
|
|
// THIS IS FOR THE 50G HARDWARE, BUT FUTURE-PROOF FOR 16-BIT COLOR DISPLAYS AS WELL
|
|
|
|
#if DEFAULTBITMAPMODE == BITMAP_RAW16G
|
|
switch(type)
|
|
{
|
|
case BITMAP_RAWMONO:
|
|
|
|
{
|
|
BYTEPTR destptr,srcptr;
|
|
|
|
BINT mask=1,destmask=0;
|
|
BINT pixel;
|
|
|
|
srcptr=(BYTEPTR)(bitmap+3);
|
|
destptr=(BYTEPTR)(newbmp+3);
|
|
|
|
while(npixels) {
|
|
|
|
// READ A PIXEL FROM SOURCE
|
|
pixel=*srcptr&mask;
|
|
// CONVERT TO PROPER FORMAT
|
|
if(pixel) pixel=0xf; else pixel=0;
|
|
|
|
// WRITE TO DESTINATION
|
|
if(!destmask) *destptr=(BYTE)pixel;
|
|
else *destptr|=(BYTE)(pixel<<4);
|
|
|
|
//INCREASE SOURCE POINTER
|
|
mask<<=1;
|
|
if(mask>128) { ++srcptr; mask>>=8; }
|
|
|
|
// INCREASE DEST PTR
|
|
destmask^=1;
|
|
if(!destmask) ++destptr;
|
|
|
|
--npixels;
|
|
}
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
case BITMAP_RAW16G:
|
|
break;
|
|
case BITMAP_RAW256G:
|
|
|
|
{
|
|
|
|
BYTEPTR destptr,srcptr;
|
|
|
|
BINT destmask=0;
|
|
BINT pixel;
|
|
|
|
srcptr=(BYTEPTR)(bitmap+3);
|
|
destptr=(BYTEPTR)(newbmp+3);
|
|
|
|
while(npixels) {
|
|
|
|
// READ A PIXEL FROM SOURCE
|
|
pixel=*srcptr;
|
|
// CONVERT TO PROPER FORMAT
|
|
pixel=((255-pixel)+128)>>4;
|
|
|
|
// WRITE TO DESTINATION
|
|
if(!destmask) *destptr=(BYTE)pixel;
|
|
else *destptr|=(BYTE)(pixel<<4);
|
|
|
|
//INCREASE SOURCE POINTER
|
|
++srcptr;
|
|
|
|
// INCREASE DEST PTR
|
|
destmask^=1;
|
|
if(!destmask) ++destptr;
|
|
|
|
--npixels;
|
|
}
|
|
break;
|
|
}
|
|
case BITMAP_RAW64KC:
|
|
|
|
{
|
|
|
|
BYTEPTR destptr,srcptr;
|
|
|
|
BINT destmask=0;
|
|
BINT pixel;
|
|
|
|
srcptr=(BYTEPTR)(bitmap+3);
|
|
destptr=(BYTEPTR)(newbmp+3);
|
|
|
|
while(npixels) {
|
|
|
|
// READ A PIXEL FROM SOURCE
|
|
pixel=srcptr[0]+256*srcptr[1];
|
|
|
|
// CONVERT TO PROPER FORMAT
|
|
pixel=LUMINANCE(RGB5TO8(pixel>>11),RGB6TO8((pixel>>5)&0x3f),RGB5TO8(pixel&0x1f));
|
|
pixel=((255-pixel)+128)>>4;
|
|
|
|
// WRITE TO DESTINATION
|
|
if(!destmask) *destptr=(BYTE)pixel;
|
|
else *destptr|=(BYTE)(pixel<<4);
|
|
|
|
//INCREASE SOURCE POINTER
|
|
srcptr+=2;
|
|
|
|
// INCREASE DEST PTR
|
|
destmask^=1;
|
|
if(!destmask) ++destptr;
|
|
|
|
--npixels;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case BITMAP_RAWARGB:
|
|
|
|
{
|
|
|
|
BYTEPTR destptr,srcptr;
|
|
|
|
BINT destmask=0;
|
|
BINT pixel;
|
|
|
|
srcptr=(BYTEPTR)(bitmap+3);
|
|
destptr=(BYTEPTR)(newbmp+3);
|
|
|
|
while(npixels) {
|
|
|
|
// READ A PIXEL FROM SOURCE
|
|
//pixel=srcptr[0]+256*srcptr[1];
|
|
|
|
// CONVERT TO PROPER FORMAT
|
|
pixel=LUMINANCE(srcptr[2],srcptr[1],srcptr[0]);
|
|
pixel=((255-pixel)+128)>>4;
|
|
|
|
// WRITE TO DESTINATION
|
|
if(!destmask) *destptr=(BYTE)pixel;
|
|
else *destptr|=(BYTE)(pixel<<4);
|
|
|
|
//INCREASE SOURCE POINTER
|
|
srcptr+=4;
|
|
|
|
// INCREASE DEST PTR
|
|
destmask^=1;
|
|
if(!destmask) ++destptr;
|
|
|
|
--npixels;
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
// ALL PIXELS CONVERTED
|
|
|
|
return newbmp;
|
|
|
|
}
|
|
|
|
|
|
// CREATE A BITMAP OF THE REQUESTED SIZE AND TYPE
|
|
|
|
WORDPTR rplBmpCreate(BINT type,BINT width,BINT height,BINT clear)
|
|
{
|
|
BINT bitspixel;
|
|
|
|
switch(type)
|
|
{
|
|
case BITMAP_RAWMONO:
|
|
bitspixel=1;
|
|
break;
|
|
case BITMAP_RAW16G:
|
|
bitspixel=4;
|
|
break;
|
|
case BITMAP_RAW256G:
|
|
bitspixel=8;
|
|
break;
|
|
case BITMAP_RAW64KC:
|
|
bitspixel=16;
|
|
break;
|
|
case BITMAP_RAWARGB:
|
|
bitspixel=32;
|
|
break;
|
|
default:
|
|
rplError(ERR_UNSUPPORTEDBITMAP);
|
|
return 0;
|
|
}
|
|
|
|
BINT totalsize=(width*height*bitspixel)+31;
|
|
|
|
totalsize>>=5; // BITMAP SIZE IN WORDS
|
|
|
|
|
|
WORDPTR newbmp=rplAllocTempOb(totalsize+2);
|
|
if(!newbmp) return 0;
|
|
|
|
newbmp[0]=MKPROLOG(DOBITMAP+type,totalsize+2);
|
|
newbmp[1]=width;
|
|
newbmp[2]=height;
|
|
if(clear) memsetw(newbmp+3,0,totalsize); // CLEAR THE BITMAP
|
|
|
|
return newbmp;
|
|
|
|
}
|
|
|
|
// QUICKLY RETRIEVE THE RENDERER STATUS BEFORE EACH COMMAND IS PROCESSED
|
|
// RECEIVES rstatus LIST IN STACK LEVEL 2
|
|
void rplBMPRenderUdateState(WORDPTR *rstatusptr,BMP_RENDERSTATE **renderstptr)
|
|
{
|
|
WORDPTR rstatus=rplPeekData(2);
|
|
BMP_RENDERSTATE *renderst;
|
|
|
|
*rstatusptr=rstatus; // UPDATE rstatus LIST
|
|
renderst=(BMP_RENDERSTATE *) (PERSISTPTR(rstatus)+1);
|
|
*renderstptr=renderst; // UPDATE render STATUS STRUCTURE
|
|
|
|
renderst->srf.addr=(BINT *)(ROBJPTR(rstatus)+3); // UPDATE BITMAP ADDRESS IN CASE IT MOVED!
|
|
|
|
}
|
|
|
|
// ALLOCATE MORE SPACE FOR PATH POINTS IN THE BMP_RENDERSTATE STRUCTURE
|
|
// UPDATE STACK LEVELS 1 AND 2 AS NEEDED IF THINGS MOVE
|
|
void rplBMPRenderAllocPoint(WORDPTR *rstatusptr,BMP_RENDERSTATE **renderstptr,BINT npoints)
|
|
{
|
|
WORDPTR rstatus=*rstatusptr;
|
|
BMP_RENDERSTATE *renderst=*renderstptr;
|
|
|
|
if(renderst->ptalloc>=renderst->npoints+npoints) return; // NO NEED TO ALLOCATE MORE MEMORY
|
|
|
|
BINT need=renderst->npoints+npoints;
|
|
|
|
need=(need+7)/8; // ALLOCATE IN BLOCKS OF 8 POINTS FOR SPEED
|
|
|
|
BINT wordsneed=need*sizeof(renderst->points)*2; // TOTAL WORDS NEEDED AT THE STRUCTURE
|
|
|
|
wordsneed+=rplObjSize(rstatus)-1-sizeof(renderst->points)/4*renderst->ptalloc;
|
|
|
|
WORDPTR newobj=rplAllocTempOb(wordsneed);
|
|
if(!newobj) return;
|
|
|
|
rstatus=rplPeekData(2); // RELOAD IN CASE IT MOVED
|
|
|
|
memmovew(newobj,rstatus,OBJSIZE(*rstatus));
|
|
|
|
// STRETCH THE BINDATA OBJECT
|
|
WORDPTR libdata=PERSISTPTR(newobj);
|
|
*libdata=MKPROLOG(DOBINDATA, RENDERSTATE_SIZE(need*8));
|
|
renderst=(BMP_RENDERSTATE *) (libdata+1);
|
|
libdata=rplSkipOb(libdata);
|
|
*libdata=CMD_ENDLIST;
|
|
|
|
// STRETCH THE CONTAINER LIST OBJECT
|
|
*newobj=MKPROLOG(DOLIST,libdata-newobj);
|
|
|
|
// UPDATE ALLOCATION COUNT
|
|
renderst->ptalloc=need*8;
|
|
|
|
// UPDATE POINTERS
|
|
*rstatusptr=newobj; // UPDATE rstatus LIST
|
|
*renderstptr=renderst; // UPDATE render STATUS STRUCTURE
|
|
|
|
renderst->srf.addr=(BINT *) (ROBJPTR(rstatus)+3); // UPDATE BITMAP ADDRESS IN CASE IT MOVED!
|
|
|
|
rplOverwriteData(2,newobj);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void LIB_HANDLER()
|
|
{
|
|
if(ISPROLOG(CurOpcode)) {
|
|
// JUST PUSH THE OBJECT ON THE STACK
|
|
rplPushData(IPtr);
|
|
return;
|
|
}
|
|
|
|
|
|
if( (OPCODE(CurOpcode)>CMD_PLTBASE) && (OPCODE(CurOpcode)<MIN_OVERLOAD_OPCODE))
|
|
{
|
|
// SAME LIBRARY CAN WORK AS A RENDERER FOR PLOTS
|
|
|
|
// PLOT RENDERER RECIEVES ON STACK LEVEL 1 = CURRENT PLOT OBJECT BEING PROCESSED
|
|
// STACK LEVEL 2 = RENDERING STATUS LIST OBJECT
|
|
// PLOT RENDERER MUST NOT LEAVE ANYTHING ON THE STACK OR REMOVE ANY PARAMETERS
|
|
|
|
switch(OPCODE(CurOpcode))
|
|
{
|
|
|
|
case CMD_PLTRESET:
|
|
{
|
|
// RESET ENGINE, NOTHING TO DO IN THIS CASE
|
|
// THE ABSENCE OF INVALID OPCODE ERROR IS USED TO DETECT A VALID RENDERER
|
|
return;
|
|
}
|
|
case CMD_PLTRENDERSIZE:
|
|
{
|
|
// USE THE INFORMATION IN THE RENDERER STATUS, NOT ARGUMENTS
|
|
WORDPTR rstatus=rplPeekData(2);
|
|
|
|
// NO CHECKS, RENDERER HAS TO BE CALLED WITH PROPER ARGUMENTS
|
|
BINT64 w=(*WIDTHPTR(rstatus))>>24;
|
|
BINT64 h=(*HEIGHTPTR(rstatus))>>24;
|
|
|
|
BINT bitmaptype=LIBNUM(CurOpcode)-LIBRARY_NUMBER;
|
|
|
|
|
|
// CREATE A GROB THE RIGHT SIZE INSIDE rstatus AND APPEND A RENDER STATUS STRUCTURE
|
|
|
|
BINT wordsneeded=ROBJPTR(rstatus)-rstatus; // INCLUDES AN EXTRA WORD FOR CMD_ENDLIST
|
|
wordsneeded+=RENDERSTATE_SIZE(1)+1;
|
|
|
|
BINT bitspixel;
|
|
|
|
switch(bitmaptype)
|
|
{
|
|
case BITMAP_RAWMONO:
|
|
bitspixel=1;
|
|
break;
|
|
case BITMAP_RAW16G:
|
|
bitspixel=4;
|
|
break;
|
|
case BITMAP_RAW256G:
|
|
bitspixel=8;
|
|
break;
|
|
case BITMAP_RAW64KC:
|
|
bitspixel=16;
|
|
break;
|
|
case BITMAP_RAWARGB:
|
|
bitspixel=32;
|
|
break;
|
|
default:
|
|
rplError(ERR_UNSUPPORTEDBITMAP);
|
|
return;
|
|
}
|
|
|
|
BINT totalsize=(w*h*bitspixel)+31;
|
|
|
|
totalsize>>=5; // BITMAP SIZE IN WORDS
|
|
|
|
wordsneeded+=totalsize+3;
|
|
|
|
|
|
|
|
WORDPTR newrst=rplAllocTempOb(wordsneeded),ptr;
|
|
|
|
if(!newrst) return;
|
|
|
|
memmovew(newrst,rstatus,ROBJPTR(rstatus)-rstatus);
|
|
ptr=ROBJPTR(newrst);
|
|
ptr[0]=MKPROLOG(DOBITMAP+bitmaptype,totalsize+2);
|
|
ptr[1]=w;
|
|
ptr[2]=h;
|
|
memsetw(ptr+3,0,totalsize); // CLEAR NEW BITMAP BACKGROUND
|
|
ptr=PERSISTPTR(newrst);
|
|
ptr[0]=MKPROLOG(DOBINDATA,RENDERSTATE_SIZE(1));
|
|
|
|
// INITIALIZE THE RENDERING STRUCTURE
|
|
BMP_RENDERSTATE *renderst=(BMP_RENDERSTATE *)(ptr+1);
|
|
|
|
// INITIALIZE THE RENDERING INTERNAL STATUS
|
|
|
|
renderst->ptalloc=1;
|
|
renderst->npoints=0;
|
|
renderst->srf.clipx=0;
|
|
renderst->srf.clipx2=w-1;
|
|
renderst->srf.clipy=0;
|
|
renderst->srf.clipy2=h-1;
|
|
renderst->srf.addr=(BINT *)(ROBJPTR(rstatus)+3);
|
|
renderst->srf.width=w;
|
|
renderst->srf.x=0;
|
|
renderst->srf.y=0;
|
|
renderst->points[0].type=0;
|
|
renderst->points[0].x=0;
|
|
renderst->points[0].y=0;
|
|
ptr=rplSkipOb(ptr);
|
|
ptr[0]=CMD_ENDLIST; // CLOSE THE LIST
|
|
|
|
newrst[0]=MKPROLOG(DOLIST,wordsneeded);
|
|
|
|
rplOverwriteData(1,newrst);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
case CMD_PLTBASE+PLT_MOVETO:
|
|
{
|
|
// UPDATE RENDER STATUS
|
|
WORDPTR rstatus;
|
|
BMP_RENDERSTATE *renderst;
|
|
rplBMPRenderUdateState(&rstatus,&renderst);
|
|
|
|
renderst->npoints=0; // END ANY PREVIOUS PATH
|
|
|
|
*CXPTR(rstatus)=*ARG1PTR(rstatus);
|
|
*CYPTR(rstatus)=*ARG2PTR(rstatus);
|
|
return;
|
|
|
|
}
|
|
case CMD_PLTBASE+PLT_LINETO:
|
|
{
|
|
// UPDATE RENDER STATUS
|
|
WORDPTR rstatus;
|
|
BMP_RENDERSTATE *renderst;
|
|
rplBMPRenderUdateState(&rstatus,&renderst);
|
|
|
|
if(renderst->npoints<1) {
|
|
// ADD THE STARTING POINT, STORAGE IS GUARANTEED TO EXIST!
|
|
|
|
renderst->points[0].type=TYPE_STARTPOINT; // STARTING POINT
|
|
renderst->points[0].x=*CXPTR(rstatus);
|
|
renderst->points[0].y=*CYPTR(rstatus);
|
|
renderst->npoints=1;
|
|
}
|
|
|
|
rplBMPRenderAllocPoint(&rstatus,&renderst,1);
|
|
if(Exceptions) return; // RETURN IF OUT OF MEMORY
|
|
|
|
renderst->points[renderst->npoints].type=TYPE_LINE; // STARTING POINT
|
|
renderst->points[renderst->npoints].x=*ARG1PTR(rstatus);
|
|
renderst->points[renderst->npoints].y=*ARG2PTR(rstatus);
|
|
renderst->npoints++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case CMD_PLTBASE+PLT_STROKE:
|
|
{
|
|
// UPDATE RENDER STATUS
|
|
WORDPTR rstatus;
|
|
BMP_RENDERSTATE *renderst;
|
|
rplBMPRenderUdateState(&rstatus,&renderst);
|
|
// DRAW THE PERIMETER OF THE PATH
|
|
|
|
// TODO: ACTUALLY DRAW THE LINE TO THE BITMAP
|
|
// USING A REAL SCAN-LINE RENDERER
|
|
BINT k;
|
|
for(k=0;k<renderst->npoints;++k) {
|
|
ggl_cliphline(&(renderst->srf),renderst->points[k].y>>24,renderst->points[k].x,renderst->points[k].x,0xf);
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
}
|
|
// RETURN QUIETLY ON UNKNOWN OPERATIONS, JUST DO NOTHING.
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch(OPCODE(CurOpcode))
|
|
{
|
|
|
|
|
|
case OVR_SAME:
|
|
// COMPARE AS PLAIN OBJECTS, THIS INCLUDES SIMPLE COMMANDS IN THIS LIBRARY
|
|
{
|
|
BINT same=rplCompareObjects(rplPeekData(1),rplPeekData(2));
|
|
rplDropData(2);
|
|
if(same) rplPushTrue(); else rplPushFalse();
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
case OVR_ISTRUE:
|
|
{
|
|
rplOverwriteData(1,(WORDPTR)one_bint);
|
|
return;
|
|
}
|
|
|
|
|
|
case OVR_FUNCEVAL:
|
|
case OVR_EVAL:
|
|
case OVR_EVAL1:
|
|
case OVR_XEQ:
|
|
// ALSO EXECUTE THE OBJECT
|
|
if(!ISPROLOG(*rplPeekData(1))) {
|
|
// EXECUTE THE COMMAND BY CALLING THE HANDLER DIRECTLY
|
|
WORD saveOpcode=CurOpcode;
|
|
CurOpcode=*rplPopData();
|
|
// RECURSIVE CALL
|
|
LIB_HANDLER();
|
|
CurOpcode=saveOpcode;
|
|
return;
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
// STANDARIZED OPCODES:
|
|
// --------------------
|
|
// LIBRARIES ARE FORCED TO ALWAYS HANDLE THE STANDARD OPCODES
|
|
|
|
case OPCODE_COMPILE:
|
|
// COMPILE RECEIVES:
|
|
// TokenStart = token string
|
|
// TokenLen = token length
|
|
// BlankStart = token blanks afterwards
|
|
// BlanksLen = blanks length
|
|
// CurrentConstruct = Opcode of current construct/WORD of current composite
|
|
|
|
// COMPILE RETURNS:
|
|
// RetNum = enum CompileErrors
|
|
{
|
|
if((TokenLen==10) && (!utf8ncmp2((char *)TokenStart,(char *)BlankStart,"BITMAPDATA",10))) {
|
|
|
|
ScratchPointer4=CompileEnd;
|
|
rplCompileAppend(MKPROLOG(LIBRARY_NUMBER,0));
|
|
RetNum=OK_NEEDMORE;
|
|
return;
|
|
}
|
|
|
|
|
|
// THIS STANDARD FUNCTION WILL TAKE CARE OF COMPILATION OF STANDARD COMMANDS GIVEN IN THE LIST
|
|
// NO NEED TO CHANGE THIS UNLESS CUSTOM OPCODES
|
|
|
|
libCompileCmds(LIBRARY_NUMBER,(char **)LIB_NAMES,NULL,LIB_NUMBEROFCMDS);
|
|
return;
|
|
}
|
|
case OPCODE_COMPILECONT:
|
|
{
|
|
if((LIBNUM(*ScratchPointer4)&~7)!=LIBRARY_NUMBER) {
|
|
// SOMETHING BAD HAPPENED, THERE'S NO BMPDATA HEADER
|
|
RetNum=ERR_SYNTAX;
|
|
return;
|
|
}
|
|
|
|
if(!(*ScratchPointer4&0x10000)) {
|
|
// NEED TO INPUT THE BITMAP TYPE IN 4-LETTERS: MONO,16GR,256G,64KC,ARGB,OTHR
|
|
if(((BINT)TokenLen!=(BYTEPTR)BlankStart-(BYTEPTR)TokenStart)||(TokenLen!=4)) {
|
|
// THERE'S UNICODE CHARACTERS IN BETWEEN, THAT MAKES IT AN INVALID STRING
|
|
// OR THERE'S NOT 4 CHARACTERS
|
|
rplError(ERR_UNSUPPORTEDBITMAP);
|
|
RetNum=ERR_SYNTAX;
|
|
return;
|
|
}
|
|
if(!utf8ncmp2((char *)TokenStart,(char *)BlankStart,"MONO",4)) *ScratchPointer4|=BITMAP_RAWMONO|0x10000;
|
|
else if(!utf8ncmp2((char *)TokenStart,(char *)BlankStart,"16GR",4)) *ScratchPointer4|=BITMAP_RAW16G|0x10000;
|
|
else if(!utf8ncmp2((char *)TokenStart,(char *)BlankStart,"256G",4)) *ScratchPointer4|=BITMAP_RAW256G|0x10000;
|
|
else if(!utf8ncmp2((char *)TokenStart,(char *)BlankStart,"64KC",4)) *ScratchPointer4|=BITMAP_RAW64KC|0x10000;
|
|
else if(!utf8ncmp2((char *)TokenStart,(char *)BlankStart,"ARGB",4)) *ScratchPointer4|=BITMAP_RAWARGB|0x10000;
|
|
else if(!utf8ncmp2((char *)TokenStart,(char *)BlankStart,"OTHR",4)) *ScratchPointer4|=BITMAP_EXTERNAL|0x10000;
|
|
else {
|
|
rplError(ERR_UNSUPPORTEDBITMAP);
|
|
RetNum=ERR_SYNTAX;
|
|
return;
|
|
}
|
|
RetNum=OK_NEEDMORE;
|
|
return;
|
|
}
|
|
|
|
// HERE WE ALREADY HAVE THE TYPE OF BITMAP
|
|
|
|
|
|
|
|
if(!(*ScratchPointer4&0x20000)) {
|
|
// NEED TO CAPTURE THE WIDTH AND HEIGHT AS INTEGERS
|
|
WORD value=0;
|
|
BINT digit;
|
|
BYTEPTR ptr=(BYTEPTR)TokenStart;
|
|
|
|
while(ptr<(BYTEPTR)BlankStart) {
|
|
if((*ptr>='0')&&(*ptr<='9')) digit=*ptr-'0';
|
|
else {
|
|
RetNum=ERR_SYNTAX;
|
|
return;
|
|
}
|
|
value*=10;
|
|
value+=digit;
|
|
++ptr;
|
|
}
|
|
|
|
rplCompileAppend(value);
|
|
|
|
// IF THERE WERE 2 NUMBERS ALREADY, THEN MARK THE SIZE AS DONE
|
|
if(CompileEnd-ScratchPointer4>=3) *ScratchPointer4|=0x20000;
|
|
RetNum=OK_NEEDMORE;
|
|
return;
|
|
}
|
|
|
|
|
|
// HERE WE ALREADY HAVE THE BITMAP TYPE, WIDTH AND HEIGHT
|
|
|
|
|
|
// WE HAVE A SIZE
|
|
WORD totalsize;
|
|
|
|
if((*ScratchPointer4&0xff)==BITMAP_EXTERNAL) {
|
|
// THE SIZE IS IN THE FIRST WORD, GET A MINIMAL OF 1 WORDS
|
|
totalsize=CompileEnd-ScratchPointer4-3;
|
|
if(LIBNUM(*ScratchPointer4)&1) totalsize-=2;
|
|
if(totalsize>=1) {
|
|
// WE ALREADY RECOVERED THE SIZE OF THE OBJECT
|
|
totalsize=ScratchPointer4[3];
|
|
}
|
|
else totalsize=0xffffffff;
|
|
}
|
|
else {
|
|
totalsize=ScratchPointer4[1]*ScratchPointer4[2];
|
|
switch(*ScratchPointer4&0xff)
|
|
{
|
|
case BITMAP_RAWMONO:
|
|
break;
|
|
case BITMAP_RAW16G:
|
|
totalsize*=4;
|
|
break;
|
|
case BITMAP_RAW256G:
|
|
totalsize*=8;
|
|
break;
|
|
case BITMAP_RAW64KC:
|
|
totalsize*=16;
|
|
break;
|
|
case BITMAP_RAWARGB:
|
|
default:
|
|
totalsize*=32;
|
|
break;
|
|
}
|
|
totalsize+=31;
|
|
totalsize>>=5;
|
|
}
|
|
|
|
|
|
// DO WE NEED ANY MORE DATA?
|
|
|
|
BYTEPTR ptr=(BYTEPTR)TokenStart;
|
|
|
|
WORD value=0;
|
|
WORD checksum=0;
|
|
BINT ndigits=0;
|
|
BINT dig;
|
|
|
|
if(LIBNUM(*ScratchPointer4)&1) {
|
|
// CONTINUE WHERE WE LEFT OFF
|
|
--CompileEnd;
|
|
ndigits=(*CompileEnd)&0xffff;
|
|
checksum=(*CompileEnd)>>16;
|
|
--CompileEnd;
|
|
value=*CompileEnd;
|
|
*ScratchPointer4&=~0x00100000;
|
|
}
|
|
|
|
do {
|
|
if((*ptr>='0')&&(*ptr<='9')) dig=(*ptr+4);
|
|
else if((*ptr>='A')&&(*ptr<='Z')) dig=(*ptr-65);
|
|
else if((*ptr>='a')&&(*ptr<='z')) dig=(*ptr-71);
|
|
else if(*ptr=='+') dig=62;
|
|
else if(*ptr=='/') dig=63;
|
|
else {
|
|
// INVALID CHARACTER!
|
|
RetNum=ERR_SYNTAX;
|
|
return;
|
|
}
|
|
|
|
// STILL NEED MORE WORDS, KEEP COMPILING
|
|
if(ndigits==5) {
|
|
value<<=2;
|
|
value|=dig&3;
|
|
checksum+=dig&3;
|
|
if((checksum&0xf)!=((dig>>2)&0xf)) {
|
|
rplError(ERR_INVALIDCHECKSUM);
|
|
RetNum=ERR_INVALID;
|
|
return;
|
|
}
|
|
// CHECKSUM PASSED, IT'S A VALID WORD
|
|
rplCompileAppend(value);
|
|
value=0;
|
|
ndigits=0;
|
|
checksum=0;
|
|
}
|
|
else {
|
|
value<<=6;
|
|
value|=dig;
|
|
checksum+=(dig&3)+((dig>>2)&3)+((dig>>4)&3);
|
|
++ndigits;
|
|
}
|
|
++ptr;
|
|
} while(ptr!=(BYTEPTR)BlankStart);
|
|
|
|
if(ndigits) {
|
|
// INCOMPLETE WORD, PREPARE FOR RESUME ON NEXT TOKEN
|
|
rplCompileAppend(value);
|
|
rplCompileAppend(ndigits | (checksum<<16));
|
|
*ScratchPointer4|=0x00100000;
|
|
}
|
|
else {
|
|
if((CompileEnd-ScratchPointer4-3)==totalsize) {
|
|
// DONE! FIX THE PROLOG WITH THE RIGHT LIBRARY NUMBER AND SIZE
|
|
*ScratchPointer4=MKPROLOG(DOBITMAP+(*ScratchPointer4&0xff),totalsize+2);
|
|
RetNum=OK_CONTINUE;
|
|
return;
|
|
}
|
|
RetNum=OK_NEEDMORE;
|
|
return;
|
|
}
|
|
|
|
// END OF TOKEN, NEED MORE!
|
|
RetNum=OK_NEEDMORE;
|
|
return;
|
|
|
|
}
|
|
case OPCODE_DECOMPEDIT:
|
|
|
|
case OPCODE_DECOMPILE:
|
|
// DECOMPILE RECEIVES:
|
|
// DecompileObject = Ptr to prolog of object to decompile
|
|
// DecompStringEnd = Ptr to the end of decompile string
|
|
|
|
//DECOMPILE RETURNS
|
|
// RetNum = enum DecompileErrors
|
|
if(ISPROLOG(*DecompileObject)) {
|
|
// DECOMPILE BITMAP
|
|
|
|
rplDecompAppendString((BYTEPTR)"BITMAPDATA ");
|
|
|
|
// TYPE
|
|
rplDecompAppendString((BYTEPTR)bitmap_modes[LIBNUM(*DecompileObject)&7]);
|
|
|
|
rplDecompAppendChar(' ');
|
|
|
|
// SIZE
|
|
BYTE buffer[50];
|
|
BINT len=rplIntToString((BINT64)DecompileObject[1],DECBINT,buffer,buffer+50);
|
|
|
|
rplDecompAppendString2(buffer,len);
|
|
|
|
rplDecompAppendChar(' ');
|
|
|
|
len=rplIntToString((BINT64)DecompileObject[2],DECBINT,buffer,buffer+50);
|
|
|
|
rplDecompAppendString2(buffer,len);
|
|
|
|
rplDecompAppendChar(' ');
|
|
|
|
BINT size=OBJSIZE(*DecompileObject)-2;
|
|
|
|
// OUTPUT THE DATA BY WORDS, WITH FOLLOWING ENCODING:
|
|
// 32-BIT WORDS GO ENCODED IN 6 TEXT CHARACTERS
|
|
// EACH CHARACTER CARRIES 6-BITS IN BASE64 ENCONDING
|
|
// MOST SIGNIFICANT 6-BIT PACKET GOES FIRST
|
|
// LAST PACKET HAS 2 LSB BITS TO COMPLETE THE 32-BIT WORDS
|
|
// AND 4-BIT CHECKSUM. THE CHECKSUM IS THE SUM OF THE (16) 2-BIT PACKS IN THE WORD, MODULO 15
|
|
|
|
|
|
|
|
BYTE encoder[7];
|
|
|
|
encoder[6]=0;
|
|
|
|
WORDPTR ptr=DecompileObject+3;
|
|
BINT nwords=0;
|
|
|
|
while(size) {
|
|
// ENCODE THE 6 CHARACTERS
|
|
int k;
|
|
BINT chksum=0;
|
|
for(k=0;k<5;++k) { encoder[k]=((*ptr)>>(26-6*k))&0x3f; chksum+=(encoder[k]&3)+((encoder[k]>>2)&3)+((encoder[k]>>4)&3); }
|
|
encoder[5]=(*ptr)&3;
|
|
chksum+=*ptr&3;
|
|
encoder[5]|=(chksum&0xf)<<2;
|
|
|
|
// NOW CONVERT TO BASE64
|
|
for(k=0;k<6;++k)
|
|
{
|
|
if(encoder[k]<26) encoder[k]+=65;
|
|
else if(encoder[k]<52) encoder[k]+=71;
|
|
else if(encoder[k]<62) encoder[k]-=4;
|
|
else if(encoder[k]==62) encoder[k]='+';
|
|
else encoder[k]='/';
|
|
}
|
|
|
|
rplDecompAppendString(encoder);
|
|
if(Exceptions) {
|
|
RetNum=ERR_INVALID;
|
|
return;
|
|
}
|
|
|
|
++nwords;
|
|
if(nwords==8) { rplDecompAppendChar(' '); nwords=0; }
|
|
|
|
++ptr;
|
|
--size;
|
|
|
|
}
|
|
|
|
RetNum=OK_CONTINUE;
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
// THIS STANDARD FUNCTION WILL TAKE CARE OF DECOMPILING STANDARD COMMANDS GIVEN IN THE LIST
|
|
// NO NEED TO CHANGE THIS UNLESS THERE ARE CUSTOM OPCODES
|
|
libDecompileCmds((char **)LIB_NAMES,NULL,LIB_NUMBEROFCMDS);
|
|
return;
|
|
case OPCODE_VALIDATE:
|
|
// VALIDATE RECEIVES OPCODES COMPILED BY OTHER LIBRARIES, TO BE INCLUDED WITHIN A COMPOSITE OWNED BY
|
|
// THIS LIBRARY. EVERY COMPOSITE HAS TO EVALUATE IF THE OBJECT BEING COMPILED IS ALLOWED INSIDE THIS
|
|
// COMPOSITE OR NOT. FOR EXAMPLE, A REAL MATRIX SHOULD ONLY ALLOW REAL NUMBERS INSIDE, ANY OTHER
|
|
// OPCODES SHOULD BE REJECTED AND AN ERROR THROWN.
|
|
// Library receives:
|
|
// CurrentConstruct = SET TO THE CURRENT ACTIVE CONSTRUCT TYPE
|
|
// LastCompiledObject = POINTER TO THE LAST OBJECT THAT WAS COMPILED, THAT NEEDS TO BE VERIFIED
|
|
|
|
// VALIDATE RETURNS:
|
|
// RetNum = OK_CONTINUE IF THE OBJECT IS ACCEPTED, ERR_INVALID IF NOT.
|
|
|
|
|
|
RetNum=OK_CONTINUE;
|
|
return;
|
|
|
|
case OPCODE_PROBETOKEN:
|
|
// PROBETOKEN FINDS A VALID WORD AT THE BEGINNING OF THE GIVEN TOKEN AND RETURNS
|
|
// INFORMATION ABOUT IT. THIS OPCODE IS MANDATORY
|
|
|
|
// COMPILE RECEIVES:
|
|
// TokenStart = token string
|
|
// TokenLen = token length
|
|
// BlankStart = token blanks afterwards
|
|
// BlanksLen = blanks length
|
|
// CurrentConstruct = Opcode of current construct/WORD of current composite
|
|
|
|
// COMPILE RETURNS:
|
|
// RetNum = OK_TOKENINFO | MKTOKENINFO(...) WITH THE INFORMATION ABOUT THE CURRENT TOKEN
|
|
// OR RetNum = ERR_NOTMINE IF NO TOKEN WAS FOUND
|
|
{
|
|
libProbeCmds((char **)LIB_NAMES,(BINT *)LIB_TOKENINFO,LIB_NUMBEROFCMDS);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
case OPCODE_GETINFO:
|
|
// THIS OPCODE RECEIVES A POINTER TO AN RPL COMMAND OR OBJECT IN ObjectPTR
|
|
// NEEDS TO RETURN INFORMATION ABOUT THE TYPE:
|
|
// IN RetNum: RETURN THE MKTOKENINFO() DATA FOR THE SYMBOLIC COMPILER AND CAS
|
|
// IN DecompHints: RETURN SOME HINTS FOR THE DECOMPILER TO DO CODE BEAUTIFICATION (TO BE DETERMINED)
|
|
// IN TypeInfo: RETURN TYPE INFORMATION FOR THE TYPE COMMAND
|
|
// TypeInfo: TTTTFF WHERE TTTT = MAIN TYPE * 100 (NORMALLY THE MAIN LIBRARY NUMBER)
|
|
// FF = 2 DECIMAL DIGITS FOR THE SUBTYPE OR FLAGS (VARIES DEPENDING ON LIBRARY)
|
|
// THE TYPE COMMAND WILL RETURN A REAL NUMBER TypeInfo/100
|
|
// FOR NUMBERS: TYPE=10 (REALS), SUBTYPES = .01 = APPROX., .02 = INTEGER, .03 = APPROX. INTEGER
|
|
// .12 = BINARY INTEGER, .22 = DECIMAL INT., .32 = OCTAL BINT, .42 = HEX INTEGER
|
|
|
|
if(ISPROLOG(*ObjectPTR)) {
|
|
TypeInfo=LIBRARY_NUMBER*100;
|
|
DecompHints=0;
|
|
RetNum=OK_TOKENINFO | MKTOKENINFO(0,TITYPE_NOTALLOWED,0,1);
|
|
}
|
|
else {
|
|
TypeInfo=0; // ALL COMMANDS ARE TYPE 0
|
|
DecompHints=0;
|
|
libGetInfo2(*ObjectPTR,(char **)LIB_NAMES,(BINT *)LIB_TOKENINFO,LIB_NUMBEROFCMDS);
|
|
}
|
|
return;
|
|
|
|
case OPCODE_GETROMID:
|
|
// THIS OPCODE RECEIVES A POINTER TO AN RPL OBJECT IN ROM, EXPORTED BY THIS LIBRARY
|
|
// AND CONVERTS IT TO A UNIQUE ID FOR BACKUP PURPOSES
|
|
// ObjectPTR = POINTER TO ROM OBJECT
|
|
// LIBBRARY RETURNS: ObjectID=new ID, RetNum=OK_CONTINUE
|
|
// OR RetNum=ERR_NOTMINE IF THE OBJECT IS NOT RECOGNIZED
|
|
|
|
libGetRomptrID(LIBRARY_NUMBER,(WORDPTR *)ROMPTR_TABLE,ObjectPTR);
|
|
return;
|
|
case OPCODE_ROMID2PTR:
|
|
// THIS OPCODE GETS A UNIQUE ID AND MUST RETURN A POINTER TO THE OBJECT IN ROM
|
|
// ObjectID = ID
|
|
// LIBRARY RETURNS: ObjectPTR = POINTER TO THE OBJECT, AND RetNum=OK_CONTINUE
|
|
// OR RetNum= ERR_NOTMINE;
|
|
|
|
libGetPTRFromID((WORDPTR *)ROMPTR_TABLE,ObjectID);
|
|
return;
|
|
|
|
case OPCODE_CHECKOBJ:
|
|
// THIS OPCODE RECEIVES A POINTER TO AN OBJECT FROM THIS LIBRARY AND MUST
|
|
// VERIFY IF THE OBJECT IS PROPERLY FORMED AND VALID
|
|
// ObjectPTR = POINTER TO THE OBJECT TO CHECK
|
|
// LIBRARY MUST RETURN: RetNum=OK_CONTINUE IF OBJECT IS VALID OR RetNum=ERR_INVALID IF IT'S INVALID
|
|
if(ISPROLOG(*ObjectPTR)) { RetNum=ERR_INVALID; return; }
|
|
|
|
RetNum=OK_CONTINUE;
|
|
return;
|
|
|
|
case OPCODE_AUTOCOMPNEXT:
|
|
libAutoCompleteNext(LIBRARY_NUMBER,(char **)LIB_NAMES,LIB_NUMBEROFCMDS);
|
|
return;
|
|
|
|
case OPCODE_LIBMENU:
|
|
// LIBRARY RECEIVES A MENU CODE IN MenuCodeArg
|
|
// MUST RETURN A MENU LIST IN ObjectPTR
|
|
// AND RetNum=OK_CONTINUE;
|
|
{
|
|
if(MENUNUMBER(MenuCodeArg)>0) { RetNum=ERR_NOTMINE; return; }
|
|
// WARNING: MAKE SURE THE ORDER IS CORRECT IN ROMPTR_TABLE
|
|
ObjectPTR=ROMPTR_TABLE[MENUNUMBER(MenuCodeArg)+2];
|
|
RetNum=OK_CONTINUE;
|
|
return;
|
|
}
|
|
|
|
case OPCODE_LIBHELP:
|
|
// LIBRARY RECEIVES AN OBJECT OR OPCODE IN CmdHelp
|
|
// MUST RETURN A STRING OBJECT IN ObjectPTR
|
|
// AND RetNum=OK_CONTINUE;
|
|
{
|
|
libFindMsg(CmdHelp,(WORDPTR)LIB_HELPTABLE);
|
|
return;
|
|
}
|
|
case OPCODE_LIBMSG:
|
|
// LIBRARY RECEIVES AN OBJECT OR OPCODE IN LibError
|
|
// MUST RETURN A STRING OBJECT IN ObjectPTR
|
|
// AND RetNum=OK_CONTINUE;
|
|
{
|
|
|
|
libFindMsg(LibError,(WORDPTR)LIB_MSGTABLE);
|
|
return;
|
|
}
|
|
|
|
case OPCODE_LIBINSTALL:
|
|
LibraryList=(WORDPTR)libnumberlist;
|
|
RetNum=OK_CONTINUE;
|
|
return;
|
|
case OPCODE_LIBREMOVE:
|
|
return;
|
|
|
|
}
|
|
// UNHANDLED OPCODE...
|
|
|
|
// IF IT'S A COMPILER OPCODE, RETURN ERR_NOTMINE
|
|
if(OPCODE(CurOpcode)>=MIN_RESERVED_OPCODE) {
|
|
RetNum=ERR_NOTMINE;
|
|
return;
|
|
}
|
|
// BY DEFAULT, ISSUE A BAD OPCODE ERROR
|
|
rplError(ERR_INVALIDOPCODE);
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|