/*********************************************************************************************************************** PicoMite MMBasic Draw.c Geoff Graham, Peter Mather Copyright (c) 2021, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name MMBasic be used when referring to the interpreter in any documentation and promotional material and the original copyright message be displayed on the console at startup (additional copyright messages may be added). 4. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by the . 5. Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ************************************************************************************************************************/ /** * @file Draw.c * @author Geoff Graham, Peter Mather * @brief Source for Graphics MMBasic commands and functions */ /* * @cond * The following section will be excluded from the documentation. */ #include "MMBasic_Includes.h" #include "Hardware_Includes.h" #include "hardware/spi.h" #ifndef PICOMITEWEB #include "pico/multicore.h" extern mutex_t frameBufferMutex; #endif #ifdef PICOMITEWEB #include "pico/cyw43_arch.h" #endif #define LONG long #define max(x, y) (((x) > (y)) ? (x) : (y)) #define min(x, y) (((x) < (y)) ? (x) : (y)) #define RoundUptoInt(a) (((a) + (32 - 1)) & (~(32 - 1)))// round up to the nearest whole integer void DrawFilledCircle(int x, int y, int radius, int r, int fill, int ints_per_line, uint32_t *br, MMFLOAT aspect, MMFLOAT aspect2); void hline(int x0, int x1, int y, int f, int ints_per_line, uint32_t *br); void SaveTriangle(int bnbr, char *buff); void RestoreTriangle(int bnbr, char *buff); void ReadLine(int x1,int y1,int x2,int y2, char *buff); void cmd_RestoreTriangle(unsigned char *p); void polygon(unsigned char *p, int close); typedef struct _BMPDECODER { LONG lWidth; LONG lHeight; LONG lImageOffset; WORD wPaletteEntries; BYTE bBitsPerPixel; BYTE bHeaderType; BYTE blBmMarkerFlag : 1; BYTE blCompressionType : 3; BYTE bNumOfPlanes : 3; BYTE b16bit565flag : 1; BYTE aPalette[256][3]; /* Each palette entry has RGB */ } BMPDECODER; /***************************************************************************/ // define the fonts #include "font1.h" #include "Misc_12x20_LE.h" #include "Hom_16x24_LE.h" #include "Fnt_10x16.h" #include "Inconsola.h" #include "ArialNumFontPlus.h" #include "Font_8x6.h" #include "arial_bold.h" #ifdef PICOMITEVGA #ifndef HDMI #include "Include.h" #endif #endif #include "smallfont.h" unsigned char *FontTable[FONT_TABLE_SIZE] = { (unsigned char *)font1, (unsigned char *)Misc_12x20_LE, #ifdef PICOMITEVGA #ifdef HDMI (unsigned char *)Hom_16x24_LE, #else (unsigned char *)arial_bold, #endif #else (unsigned char *)Hom_16x24_LE, #endif (unsigned char *)Fnt_10x16, (unsigned char *)Inconsola, (unsigned char *)ArialNumFontPlus, (unsigned char *)F_6x8_LE, (unsigned char *)TinyFont, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; /***************************************************************************/ // the default function for DrawRectangle() and DrawBitmap() short gui_font; int gui_fcolour; int gui_bcolour; short low_y=LCDMaxV, high_y=0, low_x=LCDMaxH, high_x=0; int PrintPixelMode=0; short CurrentX=0, CurrentY=0; // the current default position for the next char to be written short DisplayHRes, DisplayVRes; // the physical characteristics of the display struct spritebuffer spritebuff[MAXBLITBUF+1] = { 0 }; struct blitbuffer blitbuff[MAXBLITBUF+1] = { 0 }; char CMM1=0; // the MMBasic programming characteristics of the display // note that HRes == 0 is an indication that a display is not configured short HRes = 0, VRes = 0; short lastx,lasty; const int CMM1map[16]={BLACK,BLUE,GREEN,CYAN,RED,MAGENTA,YELLOW,WHITE,MYRTLE,COBALT,MIDGREEN,CERULEAN,RUST,FUCHSIA,BROWN,LILAC}; int RGB121map[16]; uint32_t remap[256]; // pointers to the drawing primitives #ifndef PICOMITEWEB struct D3D* struct3d[MAX3D + 1] = { NULL }; s_camera camera[MAXCAM + 1]; #endif int layer_in_use[MAXLAYER + 1]; unsigned char LIFO[MAXBLITBUF]; unsigned char zeroLIFO[MAXBLITBUF]; uint8_t LIFOpointer = 0; uint8_t zeroLIFOpointer = 0; uint8_t sprites_in_use = 0; char* COLLISIONInterrupt = NULL; bool CollisionFound = false; int sprite_which_collided = -1; static bool hideall = 0; uint8_t sprite_transparent=0; #ifdef PICOMITEVGA short gui_font_width, gui_font_height; int last_bcolour, last_fcolour; volatile int CursorTimer=0; // used to time the flashing cursor extern volatile int QVgaScanLine; extern uint16_t map16[16]; bool mergedread=0; int ScreenSize=0; #else extern int SSD1963data; int map[16]={0}; #ifdef PICOMITEWEB #ifndef rp2350 short gui_font_width, gui_font_height; int last_bcolour, last_fcolour; volatile int CursorTimer=0; // used to time the flashing cursor int display_backlight; // the brightness of the backlight (1 to 100) #else #endif extern int InvokingCtrl; #else extern int InvokingCtrl; bool mergerunning=false; volatile bool mergedone=false; uint32_t mergetimer=0; #endif #endif void cmd_ReadTriangle(unsigned char *p); void (*DrawRectangle)(int x1, int y1, int x2, int y2, int c) = (void (*)(int , int , int , int , int ))DisplayNotSet; void (*DrawBitmap)(int x1, int y1, int width, int height, int scale, int fc, int bc, unsigned char *bitmap) = (void (*)(int , int , int , int , int , int , int , unsigned char *))DisplayNotSet; void (*ScrollLCD) (int lines) = (void (*)(int ))DisplayNotSet; void (*DrawBuffer)(int x1, int y1, int x2, int y2, unsigned char *c) = (void (*)(int , int , int , int , unsigned char * ))DisplayNotSet; void (*ReadBuffer)(int x1, int y1, int x2, int y2, unsigned char *c) = (void (*)(int , int , int , int , unsigned char * ))DisplayNotSet; void (*DrawBLITBuffer)(int x1, int y1, int x2, int y2, unsigned char *c) = (void (*)(int , int , int , int , unsigned char * ))DisplayNotSet; void (*ReadBLITBuffer)(int x1, int y1, int x2, int y2, unsigned char *c) = (void (*)(int , int , int , int , unsigned char * ))DisplayNotSet; void (*DrawBufferFast)(int x1, int y1, int x2, int y2, int blank, unsigned char *c) = (void (*)(int , int , int , int , int, unsigned char * ))DisplayNotSet; void (*ReadBufferFast)(int x1, int y1, int x2, int y2, unsigned char *c) = (void (*)(int , int , int , int , unsigned char * ))DisplayNotSet; void (*DrawPixel)(int x1, int y1, int c) = (void (*)(int , int , int ))DisplayNotSet; void DrawTriangle(int x0, int y0, int x1, int y1, int x2, int y2, int c, int fill); // these are the GUI commands that are common to the MX170 and MX470 versions // in the case of the MX170 this function is called directly by MMBasic when the GUI command is used // in the case of the MX470 it is called by MX470GUI in GUI.c const int colours[16]={0x00,0xFF,0x4000,0x40ff,0x8000,0x80ff,0xff00,0xffff,0xff0000,0xff00FF,0xff4000,0xff40ff,0xff8000,0xff80ff,0xffff00,0xffffff}; void MIPS16 initFonts(void){ FontTable[0] = (unsigned char *)font1; FontTable[1] = (unsigned char *)Misc_12x20_LE; #ifdef PICOMITEVGA #ifdef HDMI FontTable[2] = (unsigned char *)Hom_16x24_LE; #else FontTable[2] = (unsigned char *)arial_bold; #endif #else FontTable[2] = (unsigned char *)Hom_16x24_LE; #endif FontTable[3] = (unsigned char *)Fnt_10x16; FontTable[4] = (unsigned char *)Inconsola; FontTable[5] = (unsigned char *)ArialNumFontPlus; FontTable[6] = (unsigned char *)F_6x8_LE; FontTable[7] = (unsigned char *)TinyFont; FontTable[8] = NULL; FontTable[9] = NULL; FontTable[10] = NULL; FontTable[11] = NULL; FontTable[12] = NULL; FontTable[13] = NULL; FontTable[14] = NULL; FontTable[15] = NULL; } uint16_t __not_in_flash_func(RGB555)(uint32_t c){ return ((c & 0xf8)>>3) | ((c& 0xf800)>>6) | ((c & 0xf80000)>>9); } uint8_t __not_in_flash_func(RGB332)(uint32_t c){ return ((c & 0b111000000000000000000000)>>16) | ((c & 0b1110000000000000)>>11) | ((c & 0b11000000)>>6); } uint8_t __not_in_flash_func(RGB121)(uint32_t c){ return ((c & 0x800000)>> 20) | ((c & 0xC000)>>13) | ((c & 0x80)>>7); } uint16_t __not_in_flash_func(RGB121pack)(uint32_t c){ return (RGB121(c)<<12) | (RGB121(c)<<8) | (RGB121(c)<<4) | RGB121(c); } /* @endcond */ void MIPS16 cmd_guiMX170(void) { unsigned char *p; if(Option.DISPLAY_TYPE == 0) error("Display not configured"); // display a bitmap stored in an integer or string if((p = checkstring(cmdline, (unsigned char *)"BITMAP"))) { int x, y, fc, bc, h, w, scale, t, bytes; unsigned char *s; MMFLOAT f; long long int i64; getargs(&p, 15, (unsigned char *)","); if(!(argc & 1) || argc < 5) error("Argument count"); // set the defaults h = 8; w = 8; scale = 1; bytes = 8; fc = gui_fcolour; bc = gui_bcolour; x = getinteger(argv[0]); y = getinteger(argv[2]); // get the type of argument 3 (the bitmap) and its value (integer or string) t = T_NOTYPE; evaluate(argv[4], &f, &i64, &s, &t, true); if(t & T_NBR) error("Invalid argument"); else if(t & T_INT) s = (unsigned char *)&i64; else if(t & T_STR) bytes = *s++; if(argc > 5 && *argv[6]) w = getint(argv[6], 1, HRes); if(argc > 7 && *argv[8]) h = getint(argv[8], 1, VRes); if(argc > 9 && *argv[10]) scale = getint(argv[10], 1, 15); if(argc > 11 && *argv[12]) fc = getint(argv[12], 0, WHITE); if(argc == 15) bc = getint(argv[14], -1, WHITE); if(h * w > bytes * 8) error("Not enough data"); DrawBitmap(x, y, w, h, scale, fc, bc, (unsigned char *)s); if(Option.Refresh)Display_Refresh(); return; } #ifndef PICOMITEVGA #ifdef GUICONTROLS if((p = checkstring(cmdline, (unsigned char *)"BEEP"))) { if(Option.TOUCH_Click == 0) error("Click option not set"); ClickTimer = getint(p, 0, INT_MAX) + 1; return; } #endif if((p = checkstring(cmdline, (unsigned char *)"RESET"))) { if((checkstring(p, (unsigned char *)"LCDPANEL"))) { #ifdef PICOMITE if(mergerunning){ multicore_fifo_push_blocking(0xFF); busy_wait_ms(mergetimer+200); if(mergerunning){ _excep_code = RESET_COMMAND; SoftReset(); } } #endif InitDisplaySPI(true); InitDisplayI2C(true); if((Option.TOUCH_CS || Option.TOUCH_IRQ) && !Option.TOUCH_CAP) { GetTouchValue(CMD_PENIRQ_ON); // send the controller the command to turn on PenIRQ GetTouchAxis(CMD_MEASURE_X); } return; } } if((p = checkstring(cmdline, (unsigned char *)"CALIBRATE"))) { int tlx, tly, trx, try, blx, bly, brx, bry, midy; char *s; if(Option.TOUCH_CS == 0 && Option.TOUCH_IRQ ==0) error("Touch not configured"); if(*p && *p != '\'') { // if the calibration is provided on the command line getargs(&p, 9, (unsigned char *)","); if(argc != 9) error("Argument count"); Option.TOUCH_SWAPXY = getinteger(argv[0]); Option.TOUCH_XZERO = getinteger(argv[2]); Option.TOUCH_YZERO = getinteger(argv[4]); Option.TOUCH_XSCALE = getinteger(argv[6]) / 10000.0; Option.TOUCH_YSCALE = getinteger(argv[8]) / 10000.0; if(!CurrentLinePtr) SaveOptions(); return; } else { if(CurrentLinePtr) error("Invalid in a program"); Option.TOUCH_SWAPXY = 0; Option.TOUCH_XZERO = 0; Option.TOUCH_YZERO = 0; Option.TOUCH_XSCALE = 1.0f; Option.TOUCH_YSCALE = 1.0f; } calibrate=1; GetCalibration(TARGET_OFFSET, TARGET_OFFSET, &tlx, &tly); GetCalibration(HRes - TARGET_OFFSET, TARGET_OFFSET, &trx, &try); if(abs(trx - tlx) < CAL_ERROR_MARGIN && abs(tly - try) < CAL_ERROR_MARGIN) { calibrate=0; error("Touch hardware failure %,%,%,%",tlx,trx,tly,try); } GetCalibration(TARGET_OFFSET, VRes - TARGET_OFFSET, &blx, &bly); GetCalibration(HRes - TARGET_OFFSET, VRes - TARGET_OFFSET, &brx, &bry); calibrate=0; midy = max(max(tly, try), max(bly, bry)) / 2; Option.TOUCH_SWAPXY = ((tly < midy && try > midy) || (tly > midy && try < midy)); if(Option.TOUCH_SWAPXY) { swap(tlx, tly); swap(trx, try); swap(blx, bly); swap(brx, bry); } Option.TOUCH_XSCALE = (MMFLOAT)(HRes - TARGET_OFFSET * 2) / (MMFLOAT)(trx - tlx); Option.TOUCH_YSCALE = (MMFLOAT)(VRes - TARGET_OFFSET * 2) / (MMFLOAT)(bly - tly); Option.TOUCH_XZERO = ((MMFLOAT)tlx - ((MMFLOAT)TARGET_OFFSET / Option.TOUCH_XSCALE)); Option.TOUCH_YZERO = ((MMFLOAT)tly - ((MMFLOAT)TARGET_OFFSET / Option.TOUCH_YSCALE)); SaveOptions(); brx = (HRes - TARGET_OFFSET) - ((brx - Option.TOUCH_XZERO) * Option.TOUCH_XSCALE); bry = (VRes - TARGET_OFFSET) - ((bry - Option.TOUCH_YZERO)*Option.TOUCH_YSCALE); if(abs(brx) > CAL_ERROR_MARGIN || abs(bry) > CAL_ERROR_MARGIN) { s = "Warning: Inaccurate calibration\r\n"; } else s = "Done. No errors\r\n"; CurrentX = CurrentY = 0; MMPrintString(s); strcpy((char *)inpbuf, "Deviation X = "); IntToStr((char *)inpbuf + strlen((char *)inpbuf), brx, 10); strcat((char *)inpbuf, ", Y = "); IntToStr((char *)inpbuf + strlen((char *)inpbuf), bry, 10); strcat((char *)inpbuf, " (pixels)\r\n"); MMPrintString((char *)inpbuf); if(!Option.DISPLAY_CONSOLE) { GUIPrintString(0, 0, 0x11, JUSTIFY_LEFT, JUSTIFY_TOP, ORIENT_NORMAL, WHITE, BLACK, s); GUIPrintString(0, 36, 0x11, JUSTIFY_LEFT, JUSTIFY_TOP, ORIENT_NORMAL, WHITE, BLACK, (char *)inpbuf); } return; } #endif if((p = checkstring(cmdline, (unsigned char *)"TEST"))) { if((checkstring(p, (unsigned char *)"LCDPANEL"))) { int t; t = ((HRes > VRes) ? HRes : VRes) / 7; while(getConsole() < '\r') { routinechecks(); #ifdef PICOMITEWEB {if(startupcomplete)ProcessWeb(1);} #endif DrawCircle(rand() % HRes, rand() % VRes, (rand() % t) + t/5, 1, 1, rgb((rand() % 8)*256/8, (rand() % 8)*256/8, (rand() % 8)*256/8), 1); #ifdef PICOMITEVGA #ifdef HDMI while(v_scanline!=0){} #else while(QVgaScanLine!=0){} #endif #endif } ClearScreen(gui_bcolour); return; } #ifndef PICOMITEVGA if((checkstring(p, (unsigned char *)"TOUCH"))) { int x, y; ClearScreen(gui_bcolour); while(getConsole() < '\r') { x = GetTouch(GET_X_AXIS); y = GetTouch(GET_Y_AXIS); if(x != TOUCH_ERROR && y != TOUCH_ERROR) DrawBox(x - 1, y - 1, x + 1, y + 1, 0, WHITE, WHITE); } ClearScreen(gui_bcolour); return; } #endif } error("Unknown command"); } /* * @cond * The following section will be excluded from the documentation. */ void getargaddress (unsigned char *p, long long int **ip, MMFLOAT **fp, int *n){ unsigned char *ptr=NULL; *fp=NULL; *ip=NULL; char pp[STRINGSIZE]={0}; strcpy(pp,(char *)p); if(!isnamestart(pp[0])){ //found a literal *n=1; return; } ptr = findvar((unsigned char *)pp, V_FIND | V_EMPTY_OK | V_NOFIND_NULL); if(ptr && g_vartbl[g_VarIndex].type & (T_NBR | T_INT)) { if(g_vartbl[g_VarIndex].dims[0] <= 0){ //simple variable *n=1; return; } else { // array or array element if(*n == 0)*n=g_vartbl[g_VarIndex].dims[0] + 1 - g_OptionBase; else *n = (g_vartbl[g_VarIndex].dims[0] + 1 - g_OptionBase)< *n ? (g_vartbl[g_VarIndex].dims[0] + 1 - g_OptionBase) : *n; skipspace(p); do { p++; } while(isnamechar(*p)); if(*p == '!' || *p== '%') p++; if(*p == '(') { p++; skipspace(p); if(*p != ')') { //array element *n=1; return; } } } if(g_vartbl[g_VarIndex].dims[1] != 0) error("Invalid variable"); if(g_vartbl[g_VarIndex].type & T_NBR)*fp = (MMFLOAT*)ptr; else *ip = (long long int *)ptr; } else { *n=1; //may be a function call } } /**************************************************************************************************** General purpose drawing routines ****************************************************************************************************/ int rgb(int r, int g, int b) { return RGB(r, g, b); } void getcoord(char *p, int *x, int *y) { unsigned char *tp, *ttp; char b[STRINGSIZE]; char savechar; tp = getclosebracket((unsigned char *)p); savechar=*tp; *tp = 0; // remove the closing brackets strcpy(b, p); // copy the coordinates to the temp buffer *tp = savechar; // put back the closing bracket ttp = (unsigned char *)b+1; // kludge (todo: fix this) { getargs(&ttp, 3, (unsigned char *)","); // this is a macro and must be the first executable stmt in a block if(argc != 3) error("Invalid Syntax"); *x = getinteger(argv[0]); *y = getinteger(argv[2]); } } int getColour(char *c, int minus){ int colour; if(CMM1){ colour = getint((unsigned char *)c,(minus ? -1: 0),15); if(colour>=0)colour=CMM1map[colour]; } else colour=getint((unsigned char *)c,(minus ? -1: 0),0xFFFFFFF); return colour; } #ifndef PICOMITEVGA void DrawPixelNormal(int x, int y, int c) { DrawRectangle(x, y, x, y, c); } #endif void ClearScreen(int c) { #ifdef PICOMITEVGA if(DISPLAY_TYPE==SCREENMODE1 && WriteBuf==DisplayBuf){ DrawRectangle(0, 0, HRes - 1, VRes - 1, 0); #ifdef HDMI memset((void *)WriteBuf,0,ScreenSize); if(FullColour){ uint16_t bcolour = RGB555(c); for(int x=0;x 0) ? (a) : -(a)) int SizeLine(int x1, int y1, int x2, int y2){ int n=0; if(y1 == y2) { return abs(x1-x2)+1; } if(x1 == x2) { return abs(y1-y2)+1; } int dx, dy, sx, sy, err, e2; dx = abs(x2 - x1); sx = x1 < x2 ? 1 : -1; dy = -abs(y2 - y1); sy = y1 < y2 ? 1 : -1; err = dx + dy; while(1) { n++; e2 = 2 * err; if (e2 >= dy) { if (x1 == x2) break; err += dy; x1 += sx; } if (e2 <= dx) { if (y1 == y2) break; err += dx; y1 += sy; } } return n; } void ReadLine(int x1,int y1,int x2,int y2, char *buff){ if(y1 == y2 || x1 == x2) { ReadBuffer(x1, y1, x2, y2, (unsigned char *)buff); // horiz line return; } int dx, dy, sx, sy, err, e2; dx = abs(x2 - x1); sx = x1 < x2 ? 1 : -1; dy = -abs(y2 - y1); sy = y1 < y2 ? 1 : -1; err = dx + dy; while(1) { ReadBuffer(x1, y1, x1, y1, (unsigned char *)buff); buff+=3; e2 = 2 * err; if (e2 >= dy) { if (x1 == x2) break; err += dy; x1 += sx; } if (e2 <= dx) { if (y1 == y2) break; err += dx; y1 += sy; } } } void RestoreLine(int x1,int y1,int x2,int y2, char *buff){ if(y1 == y2 || x1 == x2) { DrawBuffer(x1, y1, x2, y2, (unsigned char *)buff); // horiz line return; } int dx, dy, sx, sy, err, e2; dx = abs(x2 - x1); sx = x1 < x2 ? 1 : -1; dy = -abs(y2 - y1); sy = y1 < y2 ? 1 : -1; err = dx + dy; while(1) { DrawBuffer(x1, y1, x1, y1, (unsigned char *)buff); buff+=3; e2 = 2 * err; if (e2 >= dy) { if (x1 == x2) break; err += dy; x1 += sx; } if (e2 <= dx) { if (y1 == y2) break; err += dx; y1 += sy; } } } void DrawLine(int x1, int y1, int x2, int y2, int w, int c) { if(y1 == y2 && w>0) { DrawRectangle(x1, y1, x2, y2 + w - 1, c); // horiz line if(Option.Refresh)Display_Refresh(); return; } if(x1 == x2 && w>0) { DrawRectangle(x1, y1, x2 + w - 1, y2, c); // vert line if(Option.Refresh)Display_Refresh(); return; } if(w==1 || w==-1){ int dx, dy, sx, sy, err, e2; dx = abs(x2 - x1); sx = x1 < x2 ? 1 : -1; dy = -abs(y2 - y1); sy = y1 < y2 ? 1 : -1; err = dx + dy; while(1) { DrawBuffered(x1, y1, c,0); e2 = 2 * err; if (e2 >= dy) { if (x1 == x2) break; err += dy; x1 += sx; } if (e2 <= dx) { if (y1 == y2) break; err += dx; y1 += sy; } } DrawBuffered(0, 0, 0, 1); } else { float start,end; if(w<0){ w=abs(w); start=-(w / 2.0f); end=w / 2.0f; } else { start=0.0f; end=w; } // Calculate the line direction and length float dx = x2 - x1; float dy = y2 - y1; float length = sqrtf(dx * dx + dy * dy); // Normalize direction vector float nx = dx / length; float ny = dy / length; // Calculate the perpendicular vector for width float px = -ny; float py = nx; // Half-width adjustment // Loop through every pixel inside the bounding rectangle of the line for (int i = 0; i <= length; i++) { float lineX = x1 + i * nx; float lineY = y1 + i * ny; for (float j = start; j <= end; j += 0.25f) { // Finer granularity float pixelX = lineX + j * px; float pixelY = lineY + j * py; DrawPixel(roundf(pixelX), roundf(pixelY), c); } } } if(Option.Refresh)Display_Refresh(); } /********************************************************************************************** Draw a box x1, y1 - the start coordinate x2, y2 - the end coordinate w - the width of the sides of the box (can be zero) c - the colour to use for sides of the box fill - the colour to fill the box (-1 for no fill) ***********************************************************************************************/ void DrawBox(int x1, int y1, int x2, int y2, int w, int c, int fill) { int t; // make sure the coordinates are in the right sequence if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } if(w > x2 - x1) w = x2 - x1; if(w > y2 - y1) w = y2 - y1; if(w > 0) { w--; DrawRectangle(x1, y1, x2, y1 + w, c); // Draw the top horiz line DrawRectangle(x1, y2 - w, x2, y2, c); // Draw the bottom horiz line DrawRectangle(x1, y1, x1 + w, y2, c); // Draw the left vert line DrawRectangle(x2 - w, y1, x2, y2, c); // Draw the right vert line w++; } if(fill >= 0) DrawRectangle(x1 + w, y1 + w, x2 - w, y2 - w, fill); } /********************************************************************************************** Draw a box with rounded corners x1, y1 - the start coordinate x2, y2 - the end coordinate radius - the radius (in pixels) of the arc forming the corners c - the colour to use for sides fill - the colour to fill the box (-1 for no fill) ***********************************************************************************************/ void MIPS16 DrawRBox(int x1, int y1, int x2, int y2, int radius, int c, int fill) { int f, ddF_x, ddF_y, xx, yy; f = 1 - radius; ddF_x = 1; ddF_y = -2 * radius; xx = 0; yy = radius; while(xx < yy) { if(f >= 0) { yy-=1; ddF_y += 2; f += ddF_y; } xx+=1; ddF_x += 2; f += ddF_x ; DrawPixel(x2 + xx - radius, y2 + yy - radius, c); // Bottom Right Corner DrawPixel(x2 + yy - radius, y2 + xx - radius, c); // ^^^ DrawPixel(x1 - xx + radius, y2 + yy - radius, c); // Bottom Left Corner DrawPixel(x1 - yy + radius, y2 + xx - radius, c); // ^^^ DrawPixel(x2 + xx - radius, y1 - yy + radius, c); // Top Right Corner DrawPixel(x2 + yy - radius, y1 - xx + radius, c); // ^^^ DrawPixel(x1 - xx + radius, y1 - yy + radius, c); // Top Left Corner DrawPixel(x1 - yy + radius, y1 - xx + radius, c); // ^^^ if(fill >= 0) { DrawLine(x2 + xx - radius - 1, y2 + yy - radius, x1 - xx + radius + 1, y2 + yy - radius, 1, fill); DrawLine(x2 + yy - radius - 1, y2 + xx - radius, x1 - yy + radius + 1, y2 + xx - radius, 1, fill); DrawLine(x2 + xx - radius - 1, y1 - yy + radius, x1 - xx + radius + 1, y1 - yy + radius, 1, fill); DrawLine(x2 + yy - radius - 1, y1 - xx + radius, x1 - yy + radius + 1, y1 - xx + radius, 1, fill); } } if(fill >= 0) DrawRectangle(x1 + 1, y1 + radius, x2 - 1, y2 - radius, fill); DrawRectangle(x1 + radius - 1, y1, x2 - radius + 1, y1, c); // top side DrawRectangle(x1 + radius - 1, y2, x2 - radius + 1, y2, c); // botom side DrawRectangle(x1, y1 + radius, x1, y2 - radius, c); // left side DrawRectangle(x2, y1 + radius, x2, y2 - radius, c); // right side if(Option.Refresh)Display_Refresh(); } /*********************************************************************************************** Draw a circle on the video output x, y - the center of the circle radius - the radius of the circle w - width of the line drawing the circle c - the colour to use for the circle fill - the colour to use for the fill or -1 if no fill aspect - the ration of the x and y axis (a MMFLOAT). 1.0 gives a prefect circle ***********************************************************************************************/ /*********************************************************************************************** Draw a circle on the video output x, y - the center of the circle radius - the radius of the circle w - width of the line drawing the circle c - the colour to use for the circle fill - the colour to use for the fill or -1 if no fill aspect - the ration of the x and y axis (a MMFLOAT). 1.0 gives a prefect circle ***********************************************************************************************/ void DrawCircle(int x, int y, int radius, int w, int c, int fill, MMFLOAT aspect) { int a, b, P; int A, B; int asp; MMFLOAT aspect2; if(w>1){ if(fill>=0){ // thick border with filled centre DrawCircle(x,y,radius,0,c,c,aspect); aspect2=((aspect*(MMFLOAT)radius)-(MMFLOAT)w)/((MMFLOAT)(radius-w)); DrawCircle(x,y,radius-w,0,fill,fill,aspect2); } else { //thick border with empty centre int r1=radius-w,r2=radius, xs=-1,xi=0, i,j,k,m, ll=radius; if(aspect>1.0)ll=(int)((MMFLOAT)radius*aspect); int ints_per_line=RoundUptoInt((ll*2)+1)/32; uint32_t *br=(uint32_t *)GetTempMemory(((ints_per_line+1)*((r2*2)+1))*4); DrawFilledCircle(x, y, r2, r2, 1, ints_per_line, br, aspect, aspect); aspect2=((aspect*(MMFLOAT)r2)-(MMFLOAT)w)/((MMFLOAT)r1); DrawFilledCircle(x, y, r1, r2, 0, ints_per_line, br, aspect, aspect2); x=(int)((MMFLOAT)x+(MMFLOAT)r2*(1.0-aspect)); for(j=0;j=0){ while(w >= 0 && radius > 0) { a = 0; b = radius; P = 1 - radius; asp = aspect * (MMFLOAT)(1 << 10); do { A = (a * asp) >> 10; B = (b * asp) >> 10; if(fill >= 0 && w >= 0) { DrawRectangle(x-A, y+b, x+A, y+b, fill); DrawRectangle(x-A, y-b, x+A, y-b, fill); DrawRectangle(x-B, y+a, x+B, y+a, fill); DrawRectangle(x-B, y-a, x+B, y-a, fill); } if(P < 0) P+= 3 + 2*a++; else P+= 5 + 2*(a++ - b--); } while(a <= b); w--; radius--; } } if(c!=fill){ w=w1; radius=r1; while(w >= 0 && radius > 0) { a = 0; b = radius; P = 1 - radius; asp = aspect * (MMFLOAT)(1 << 10); do { A = (a * asp) >> 10; B = (b * asp) >> 10; if(w) { DrawPixel(A+x, b+y, c); DrawPixel(B+x, a+y, c); DrawPixel(x-A, b+y, c); DrawPixel(x-B, a+y, c); DrawPixel(B+x, y-a, c); DrawPixel(A+x, y-b, c); DrawPixel(x-A, y-b, c); DrawPixel(x-B, y-a, c); } if(P < 0) P+= 3 + 2*a++; else P+= 5 + 2*(a++ - b--); } while(a <= b); w--; radius--; } } } if(Option.Refresh)Display_Refresh(); } void ClearTriangle(int x0, int y0, int x1, int y1, int x2, int y2, int ints_per_line, uint32_t *br) { if (x0 * (y1 - y2) + x1 * (y2 - y0) + x2 * (y0 - y1) == 0)return; long a, b, y, last; long dx01, dy01, dx02, dy02, dx12, dy12, sa, sb; if (y0 > y1) { swap(y0, y1); swap(x0, x1); } if (y1 > y2) { swap(y2, y1); swap(x2, x1); } if (y0 > y1) { swap(y0, y1); swap(x0, x1); } dx01 = x1 - x0; dy01 = y1 - y0; dx02 = x2 - x0; dy02 = y2 - y0; dx12 = x2 - x1; dy12 = y2 - y1; sa = 0; sb = 0; if(y1 == y2) { last = y1; //Include y1 scanline } else { last = y1 - 1; // Skip it } for (y = y0; y <= last; y++){ a = x0 + sa / dy01; b = x0 + sb / dy02; sa = sa + dx01; sb = sb + dx02; a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); if(a > b)swap(a, b); hline(a, b, y, 0, ints_per_line, br); } sa = dx12 * (y - y1); sb = dx02 * ( y- y0); while (y <= y2){ a = x1 + sa / dy12; b = x0 + sb / dy02; sa = sa + dx12; sb = sb + dx02; a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); if(a > b) swap(a, b); hline(a, b, y, 0, ints_per_line, br); y = y + 1; } } #define ABS(X) ((X)>0 ? (X) : (-(X))) void CalcLine(int x1, int y1, int x2, int y2, short *xmin, short *xmax) { if(y1 == y2) { if(y1<0)y1=0; if(y1>=VRes)y1=VRes-1; if(y2<0)y2=0; if(y2>=VRes)y2=VRes-1; if(x1xmax[y1])xmax[y1]=x1; if(x2>xmax[y1])xmax[y1]=x2; return; } if(x1 == x2) { if(y2=VRes)y1=VRes-1; if(y2<0)y2=0; if(y2>=VRes)y2=VRes-1; for(int y=y1;y<=y2;y++) { if(x1xmax[y])xmax[y]=x1; } return; } // uses a variant of Bresenham's line algorithm: // https://en.wikipedia.org/wiki/Talk:Bresenham%27s_line_algorithm if (y1 > y2) { swap(y1, y2); swap(x1, x2); } if(y1<0)y1=0; if(y1>=VRes)y1=VRes-1; if(y2<0)y2=0; if(y2>=VRes)y2=VRes-1; int absX = ABS(x1-x2); // absolute value of coordinate distances int absY = ABS(y1-y2); int offX = x2xmax[y])xmax[y]=x; if (absX > absY) { // line is more horizontal; increment along x-axis err = absX / 2; while (x != x1) { err = err - absY; if (err < 0) { y += offY; err += absX; } x += offX; if(xxmax[y])xmax[y]=x; } } else { // line is more vertical; increment along y-axis err = absY / 2; while (y != y1) { err = err - absX; if (err < 0) { x += offX; err += absY; } y += offY; if(xxmax[y])xmax[y]=x; } } } void DrawTriangle(int x0, int y0, int x1, int y1, int x2, int y2, int c, int f) { if(x0 * (y1 - y2) + x1 * (y2 - y0) + x2 * (y0 - y1)==0){ // points are co-linear i.e zero area if (y0 > y1) { swap(y0, y1); swap(x0, x1); } if (y1 > y2) { swap(y2, y1); swap(x2, x1); } if (y0 > y1) { swap(y0, y1); swap(x0, x1); } DrawLine(x0,y0,x2,y2,1,c); } else { if(f == -1){ // draw only the outline DrawLine(x0, y0, x1, y1, 1, c); DrawLine(x1, y1, x2, y2, 1, c); DrawLine(x2, y2, x0, y0, 1, c); } else { if (y0 > y1) { swap(y0, y1); swap(x0, x1); } if (y1 > y2) { swap(y2, y1); swap(x2, x1); } if (y0 > y1) { swap(y0, y1); swap(x0, x1); } short *xmin=(short *)GetMemory(VRes*sizeof(short)); short *xmax=(short *)GetMemory(VRes*sizeof(short)); int y; for(y=y0; y<=y2; y++){ if(y>=0 && y=0 && y y1) { swap(y0, y1); swap(x0, x1); } if (y1 > y2) { swap(y2, y1); swap(x2, x1); } if (y0 > y1) { swap(y0, y1); swap(x0, x1); } RestoreLine(x0,y0,x2,y2,buffp); } else { if (y0 > y1) { swap(y0, y1); swap(x0, x1); } if (y1 > y2) { swap(y2, y1); swap(x2, x1); } if (y0 > y1) { swap(y0, y1); swap(x0, x1); } short *xmin=(short *)GetMemory(VRes*sizeof(short)); short *xmax=(short *)GetMemory(VRes*sizeof(short)); int y; for(y=y0; y<=y2; y++){ if(y>=0 && y y1) { swap(y0, y1); swap(x0, x1); } if (y1 > y2) { swap(y2, y1); swap(x2, x1); } if (y0 > y1) { swap(y0, y1); swap(x0, x1); } ReadLine(x0,y0,x2,y2,buffp); } else { if (y0 > y1) { swap(y0, y1); swap(x0, x1); } if (y1 > y2) { swap(y2, y1); swap(x2, x1); } if (y0 > y1) { swap(y0, y1); swap(x0, x1); } short *xmin=(short *)GetMemory(VRes*sizeof(short)); short *xmax=(short *)GetMemory(VRes*sizeof(short)); int y; for(y=y0; y<=y2; y++){ if(y>=0 && y y1) { swap(y0, y1); swap(x0, x1); } if (y1 > y2) { swap(y2, y1); swap(x2, x1); } if (y0 > y1) { swap(y0, y1); swap(x0, x1); } return SizeLine(x0,y0,x2,y2); } else { if (y0 > y1) { swap(y0, y1); swap(x0, x1); } if (y1 > y2) { swap(y2, y1); swap(x2, x1); } if (y0 > y1) { swap(y0, y1); swap(x0, x1); } short *xmin=(short *)GetMemory(VRes*sizeof(short)); short *xmax=(short *)GetMemory(VRes*sizeof(short)); int y; for(y=y0; y<=y2; y++){ if(y>=0 && y ORIENT_VERT) FreeMemory(AllocatedMemory); } /****************************************************************************************** Print a string on the LCD display The string must be a C string (not an MMBasic string) Any characters not in the font will print as a space. *****************************************************************************************/ void GUIPrintString(int x, int y, int fnt, int jh, int jv, int jo, int fc, int bc, char *str) { CurrentX = x; CurrentY = y; if(jo == ORIENT_NORMAL) { if(jh == JUSTIFY_CENTER) CurrentX -= (strlen(str) * GetFontWidth(fnt)) / 2; if(jh == JUSTIFY_RIGHT) CurrentX -= (strlen(str) * GetFontWidth(fnt)); if(jv == JUSTIFY_MIDDLE) CurrentY -= GetFontHeight(fnt) / 2; if(jv == JUSTIFY_BOTTOM) CurrentY -= GetFontHeight(fnt); } else if(jo == ORIENT_VERT) { if(jh == JUSTIFY_CENTER) CurrentX -= GetFontWidth(fnt)/ 2; if(jh == JUSTIFY_RIGHT) CurrentX -= GetFontWidth(fnt); if(jv == JUSTIFY_MIDDLE) CurrentY -= (strlen(str) * GetFontHeight(fnt)) / 2; if(jv == JUSTIFY_BOTTOM) CurrentY -= (strlen(str) * GetFontHeight(fnt)); } else if(jo == ORIENT_INVERTED) { if(jh == JUSTIFY_CENTER) CurrentX += (strlen(str) * GetFontWidth(fnt)) / 2; if(jh == JUSTIFY_RIGHT) CurrentX += (strlen(str) * GetFontWidth(fnt)); if(jv == JUSTIFY_MIDDLE) CurrentY += GetFontHeight(fnt) / 2; if(jv == JUSTIFY_BOTTOM) CurrentY += GetFontHeight(fnt); } else if(jo == ORIENT_CCW90DEG) { if(jh == JUSTIFY_CENTER) CurrentX -= GetFontHeight(fnt) / 2; if(jh == JUSTIFY_RIGHT) CurrentX -= GetFontHeight(fnt); if(jv == JUSTIFY_MIDDLE) CurrentY += (strlen(str) * GetFontWidth(fnt)) / 2; if(jv == JUSTIFY_BOTTOM) CurrentY += (strlen(str) * GetFontWidth(fnt)); } else if(jo == ORIENT_CW90DEG) { if(jh == JUSTIFY_CENTER) CurrentX += GetFontHeight(fnt) / 2; if(jh == JUSTIFY_RIGHT) CurrentX += GetFontHeight(fnt); if(jv == JUSTIFY_MIDDLE) CurrentY -= (strlen(str) * GetFontWidth(fnt)) / 2; if(jv == JUSTIFY_BOTTOM) CurrentY -= (strlen(str) * GetFontWidth(fnt)); } while(*str) { #ifdef GUICONTROLS if(*str == 0xff && Ctrl[InvokingCtrl].type == 10) { // fc = rgb(0, 0, 255); // this is specially for GUI FORMATBOX str++; GUIPrintChar(fnt, bc, fc, *str++, jo); } else #endif GUIPrintChar(fnt, fc, bc, *str++, jo); } } /**************************************************************************************************** MMBasic commands and functions ****************************************************************************************************/ // get and decode the justify$ string used in TEXT and GUI CAPTION // the values are returned via pointers int GetJustification(char *p, int *jh, int *jv, int *jo) { switch(toupper(*p++)) { case 'L': *jh = JUSTIFY_LEFT; break; case 'C': *jh = JUSTIFY_CENTER; break; case 'R': *jh = JUSTIFY_RIGHT; break; case 0 : return true; default: p--; } skipspace(p); switch(toupper(*p++)) { case 'T': *jv = JUSTIFY_TOP; break; case 'M': *jv = JUSTIFY_MIDDLE; break; case 'B': *jv = JUSTIFY_BOTTOM; break; case 0 : return true; default: p--; } skipspace(p); switch(toupper(*p++)) { case 'N': *jo = ORIENT_NORMAL; break; // normal case 'V': *jo = ORIENT_VERT; break; // vertical text (top to bottom) case 'I': *jo = ORIENT_INVERTED; break; // inverted case 'U': *jo = ORIENT_CCW90DEG; break; // rotated CCW 90 degrees case 'D': *jo = ORIENT_CW90DEG; break; // rotated CW 90 degrees case 0 : return true; default: return false; } return *p == 0; } /* @endcond */ void cmd_text(void) { int x, y, font, scale, fc, bc; char *s; int jh = 0, jv = 0, jo = 0; getargs(&cmdline, 17, (unsigned char *)","); // this is a macro and must be the first executable stmt if(Option.DISPLAY_TYPE == 0) error("Display not configured"); if(!(argc & 1) || argc < 5) error("Argument count"); x = getinteger(argv[0]); y = getinteger(argv[2]); s = (char *)getCstring(argv[4]); if(argc > 5 && *argv[6]) if(!GetJustification((char *)argv[6], &jh, &jv, &jo)) if(!GetJustification((char *)getCstring(argv[6]), &jh, &jv, &jo)) error("Justification");; font = (gui_font >> 4) + 1; scale = (gui_font & 0b1111); fc = gui_fcolour; bc = gui_bcolour; // the defaults if(argc > 7 && *argv[8]) { if(*argv[8] == '#') argv[8]++; font = getint(argv[8], 1, FONT_TABLE_SIZE); } if(FontTable[font - 1] == NULL) error("Invalid font #%", font); if(argc > 9 && *argv[10]) scale = getint(argv[10], 1, 15); if(argc > 11 && *argv[12]) fc = getint(argv[12], 0, WHITE); if(argc ==15) bc = getint(argv[14], -1, WHITE); GUIPrintString(x, y, ((font - 1) << 4) | scale, jh, jv, jo, fc, bc, s); if(Option.Refresh)Display_Refresh(); } void cmd_pixel(void) { if(Option.DISPLAY_TYPE == 0) error("Display not configured"); if(CMM1){ int x, y, value; getcoord((char *)cmdline, &x, &y); cmdline = getclosebracket(cmdline) + 1; while(*cmdline && tokenfunction(*cmdline) != op_equal) cmdline++; if(!*cmdline) error("Invalid syntax"); ++cmdline; if(!*cmdline) error("Invalid syntax"); value = getColour((char *)cmdline,0); DrawPixel(x, y, value); lastx = x; lasty = y; } else { int x1, y1, c=0, n=0 ,i, nc=0; long long int *x1ptr, *y1ptr, *cptr; MMFLOAT *x1fptr, *y1fptr, *cfptr; getargs(&cmdline, 5,(unsigned char *)","); if(!(argc == 3 || argc == 5)) error("Argument count"); getargaddress(argv[0], &x1ptr, &x1fptr, &n); if(n != 1) getargaddress(argv[2], &y1ptr, &y1fptr, &n); if(n==1){ //just a single point c = gui_fcolour; // setup the defaults x1 = getinteger(argv[0]); y1 = getinteger(argv[2]); if(argc == 5) c = getint(argv[4], -1, WHITE); else c = gui_fcolour; if(c!=-1)DrawPixel(x1, y1, c); else { CurrentX=x1; CurrentY=y1; } } else { c = gui_fcolour; // setup the defaults if(argc == 5){ getargaddress(argv[4], &cptr, &cfptr, &nc); if(nc == 1) c = getint(argv[4], 0, WHITE); else if(nc>1) { if(nc < n) n=nc; //adjust the dimensionality for(i=0;i WHITE) error("% is invalid (valid is % to %)", (int)c, 0, WHITE); } } } for(i=0;i 1) c = (cfptr == NULL ? cptr[i] : (int)cfptr[i]); DrawPixel(x1, y1, c); } } } if(Option.Refresh)Display_Refresh(); } void cmd_circle(void) { if(Option.DISPLAY_TYPE == 0) error("Display not configured"); if(CMM1){ int x, y, radius, colour, fill; float aspect; getargs(&cmdline, 9, (unsigned char *)","); if(argc%2 == 0 || argc < 3) error("Invalid syntax"); if(*argv[0] != '(') error("Expected opening bracket"); if(toupper(*argv[argc - 1]) == 'F') { argc -= 2; fill = true; } else fill = false; getcoord((char *)argv[0] , &x, &y); radius = getinteger(argv[2]); if(radius == 0) return; //nothing to draw if(radius < 1) error("Invalid argument"); if(argc > 3 && *argv[4])colour = getColour((char *)argv[4],0); else colour = gui_fcolour; if(argc > 5 && *argv[6]) aspect = getnumber(argv[6]); else aspect = 1; DrawCircle(x, y, radius, (fill ? 0:1), colour, (fill ? colour : -1), aspect); lastx = x; lasty = y; } else { int x, y, r, w=0, c=0, f=0, n=0 ,i, nc=0, nw=0, nf=0, na=0; MMFLOAT a; long long int *xptr, *yptr, *rptr, *fptr, *wptr, *cptr, *aptr; MMFLOAT *xfptr, *yfptr, *rfptr, *ffptr, *wfptr, *cfptr, *afptr; getargs(&cmdline, 13,(unsigned char *)","); if(!(argc & 1) || argc < 5) error("Argument count"); getargaddress(argv[0], &xptr, &xfptr, &n); if(n != 1) { getargaddress(argv[2], &yptr, &yfptr, &n); getargaddress(argv[4], &rptr, &rfptr, &n); } if(n==1){ w = 1; c = gui_fcolour; f = -1; a = 1; // setup the defaults x = getinteger(argv[0]); y = getinteger(argv[2]); r = getinteger(argv[4]); if(argc > 5 && *argv[6]) w = getint(argv[6], 0, 100); if(argc > 7 && *argv[8]) a = getnumber(argv[8]); if(argc > 9 && *argv[10]) c = getint(argv[10], 0, WHITE); if(argc > 11) f = getint(argv[12], -1, WHITE); int save_refresh=Option.Refresh; Option.Refresh=0; DrawCircle(x, y, r, w, c, f, a); Option.Refresh=save_refresh; } else { w = 1; c = gui_fcolour; f = -1; a = 1; // setup the defaults if(argc > 5 && *argv[6]) { getargaddress(argv[6], &wptr, &wfptr, &nw); if(nw == 1) w = getint(argv[6], 0, 100); else if(nw>1) { if(nw > 1 && nw < n) n=nw; //adjust the dimensionality for(i=0;i 100) error("% is invalid (valid is % to %)", (int)w, 0, 100); } } } if(argc > 7 && *argv[8]){ getargaddress(argv[8], &aptr, &afptr, &na); if(na == 1) a = getnumber(argv[8]); if(na > 1 && na < n) n=na; //adjust the dimensionality } if(argc > 9 && *argv[10]){ getargaddress(argv[10], &cptr, &cfptr, &nc); if(nc == 1) c = getint(argv[10], 0, WHITE); else if(nc>1) { if(nc > 1 && nc < n) n=nc; //adjust the dimensionality for(i=0;i WHITE) error("% is invalid (valid is % to %)", (int)c, 0, WHITE); } } } if(argc > 11){ getargaddress(argv[12], &fptr, &ffptr, &nf); if(nf == 1) f = getint(argv[12], -1, WHITE); else if(nf>1) { if(nf > 1 && nf < n) n=nf; //adjust the dimensionality for(i=0;i WHITE) error("% is invalid (valid is % to %)", (int)f, 0, WHITE); } } } int save_refresh=Option.Refresh; Option.Refresh=0; for(i=0;i 1) w = (wfptr==NULL ? wptr[i] : (int)wfptr[i]); if(nc > 1) c = (cfptr==NULL ? cptr[i] : (int)cfptr[i]); if(nf > 1) f = (ffptr==NULL ? fptr[i] : (int)ffptr[i]); if(na > 1) a = (afptr==NULL ? (MMFLOAT)aptr[i] : afptr[i]); DrawCircle(x, y, r, w, c, f, a); } Option.Refresh=save_refresh; } } if(Option.Refresh)Display_Refresh(); } /* * @cond * The following section will be excluded from the documentation. */ static short xb0,xb1,yb0,yb1; void GetPixel(int x, int y, int *r, int *g, int *b){ union colourmap { char rgbbytes[4]; unsigned int rgb; } c; ReadBuffer(x,y,x,y,(unsigned char *)&c.rgb); *r=c.rgbbytes[2]; *g=c.rgbbytes[1]; *b=c.rgbbytes[0]; } void MIPS16 drawAAPixel( int x , int y , MMFLOAT alpha, uint32_t c){ int bgR, bgG, bgB; // Get the current background color of the pixel GetPixel(x, y, &bgR, &bgG, &bgB); union colourmap { unsigned char rgbbytes[4]; unsigned int rgb; } col; col.rgb=c; col.rgbbytes[0]= (unsigned char)((MMFLOAT)col.rgbbytes[0]*alpha); col.rgbbytes[0]+=(unsigned char)((MMFLOAT)bgB*(1.0-alpha)); col.rgbbytes[1]= (unsigned char)((MMFLOAT)col.rgbbytes[1]*alpha); col.rgbbytes[1]+=(unsigned char)((MMFLOAT)bgG*(1.0-alpha)); col.rgbbytes[2]= (unsigned char)((MMFLOAT)col.rgbbytes[2]*alpha); col.rgbbytes[2]+=(unsigned char)((MMFLOAT)bgR*(1.0-alpha)); if(((x>=xb0 && x<=xb1) && (y>=yb0 && y<=yb1)))DrawPixel(x,y,col.rgb); } void MIPS16 drawAALine(MMFLOAT x0 , MMFLOAT y0 , MMFLOAT x1 , MMFLOAT y1, uint32_t c, int w) { // Ensure positive integer values for width if(w < 1) w = 1; // If drawing a dot, the call drawDot function //if Math.abs(y1 - y0) < 1.0 && Math.abs(x1 - x0) < 1.0 // #drawDot (x0 + x1) / 2, (y0 + y1) / 2 // return xb0=x0;xb1=x1;yb0=y0;yb1=y1; if(xb1 1 int steep = abs(y1 - y0) >= abs(x1 - x0) ; // swap the co-ordinates if slope > 1 or we // draw backwards if (steep) { swap(x0 , y0); swap(x1 , y1); } if (x0 > x1) { swap(x0 ,x1); swap(y0 ,y1); } //compute the slope MMFLOAT dx = x1-x0; MMFLOAT dy = y1-y0; MMFLOAT gradient; if (dx <= 0.0) gradient = 1; else gradient=dy/dx; //rotate w w = w * sqrt(1 + (gradient * gradient)); // Handle first endpoint MMFLOAT xend = round(x0); MMFLOAT yend = y0 - (w - 1) * 0.5 + gradient * (xend - x0); MMFLOAT xgap = 1 - (x0 + 0.5 - xend); MMFLOAT xpxl1 = xend; //this will be used in the main loop MMFLOAT ypxl1 = floor(yend); MMFLOAT fpart = yend - floor(yend); MMFLOAT rfpart = 1.0 - fpart; if(steep){ drawAAPixel(ypxl1 , xpxl1, rfpart * xgap, c); for(int i=1;i<=w;i++) drawAAPixel(ypxl1 + i, xpxl1, 1, c); drawAAPixel(ypxl1 + w, xpxl1, fpart * xgap, c); } else { drawAAPixel(xpxl1, ypxl1 , rfpart * xgap, c); for(int i=1; i<=w; i++) drawAAPixel(xpxl1, ypxl1 + i, 1, c); drawAAPixel(xpxl1, ypxl1 + w, fpart * xgap, c); } MMFLOAT intery = yend + gradient; // first y-intersection for the main loop // Handle second endpoint xend = round(x1); yend = y1 - (w - 1) * 0.5 + gradient * (xend - x1); xgap = 1 - (x1 + 0.5 - xend); MMFLOAT xpxl2 = xend; // this will be used in the main loop MMFLOAT ypxl2 = floor(yend); fpart = yend - floor(yend); rfpart = 1 - fpart; if(steep){ drawAAPixel(ypxl2 , xpxl2, rfpart * xgap, c); for(int i=1;i<=w;i++) drawAAPixel(ypxl2 + i, xpxl2, 1, c); drawAAPixel(ypxl2 + w, xpxl2, fpart * xgap, c); } else { drawAAPixel(xpxl2, ypxl2 , rfpart * xgap, c); for(int i=1; i<=w; i++) drawAAPixel(xpxl2, ypxl2 + i, 1, c); drawAAPixel(xpxl2, ypxl2 + w, fpart * xgap, c); } // main loop if(steep){ for(int x=xpxl1 + 1; x<=xpxl2; x++){ fpart = intery - floor(intery); rfpart = 1 - fpart; MMFLOAT y = floor(intery); drawAAPixel(y , x, rfpart, c); for(int i=1;i 1 && *argv[2]){ colour = getColour((char *)argv[2],0); } if(argc == 5) { box = (strchr((char *)argv[4], 'b') != NULL || strchr((char *)argv[4], 'B') != NULL); fill = (strchr((char *)argv[4], 'f') != NULL || strchr((char *)argv[4], 'F') != NULL); } if(box) DrawBox(x1, y1, x2, y2, 1, colour, (fill ? colour : -1)); // draw a box else DrawLine(x1, y1, x2, y2, 1, colour); // or just a line lastx = x2; lasty = y2; // save in case the user wants the last value } else { int x1, y1, x2, y2, w=0, c=0, n=0 ,i, nc=0, nw=0; if((p=checkstring(cmdline,(unsigned char *)"PLOT"))){ long long int *y1ptr; MMFLOAT *y1fptr; int xs=0,xinc=1; int ys=0,yinc=1; getargs(&p, 13,(unsigned char *)","); getargaddress(argv[0], &y1ptr, &y1fptr, &n); if(n==1)error("Argument 1 is not an array"); nc=n; if(argc>=3 && *argv[2])nc=getint(argv[2],1,HRes-1); if(nc>n)nc=n; if(argc>=5 && *argv[4])xs=getint(argv[4],0,HRes-1); if(argc>=7 && *argv[6])xinc=getint(argv[6],1,HRes-1); if(argc>=9 && *argv[8])ys=getint(argv[8],g_OptionBase,n-2+g_OptionBase); if(argc>=11 && *argv[10])yinc=getint(argv[10],1,n-1); c = gui_fcolour; w = 1; // setup the defaults if(argc == 13) c = getint(argv[12], 0, WHITE); int y=ys-g_OptionBase; for(i=0;i<(nc-1);i++){ if(y>=nc)break; if(y+yinc>=nc)break; x1 = xs+i*xinc; y1 = (y1fptr==NULL ? y1ptr[y] : (int)y1fptr[y]); if(y1<0)y1=0; if(y1>=VRes)y1=VRes-1; x2 = xs+(i+1)*xinc; y2 = (y1fptr==NULL ? y1ptr[y+yinc] : (int)y1fptr[y+yinc]); if(x1>=HRes)break; //can only get worse so stop now if(x2>=HRes)x2=HRes-1; if(y2<0)y2=0; if(y2>=VRes)y2=VRes-1; DrawLine(x1, y1, x2, y2, w, c); y+=yinc; } } else if((p=checkstring(cmdline,(unsigned char *)"GRAPH"))){ unsigned char *pp=GetTempMemory(STRINGSIZE); strcpy((char *)pp,(char *)p); memmove(&pp[2],pp,strlen((char *)p)+1); pp[0]='0'; pp[1]=','; polygon(pp,0); return; } else if((p=checkstring(cmdline,(unsigned char *)"AA"))){ MMFLOAT x1, y1, x2, y2; getargs(&p, 11,(unsigned char *)","); c = gui_fcolour; ; w = 1; // setup the defaults x1 = getnumber(argv[0]); y1 = getnumber(argv[2]); x2 = getnumber(argv[4]); y2 = getnumber(argv[6]); if(argc > 7 && *argv[8]){ w = getint(argv[8], 1, 100); } if(argc == 11) c = getint(argv[10], 0, WHITE); if(x1==x2 || y1==y2)DrawLine(x1, y1, x2, y2, w, c); else drawAALine(x1, y1, x2, y2, c, w); return; } else { long long int *x1ptr, *y1ptr, *x2ptr, *y2ptr, *wptr, *cptr; MMFLOAT *x1fptr, *y1fptr, *x2fptr, *y2fptr, *wfptr, *cfptr; getargs(&cmdline, 11,(unsigned char *)","); if(!(argc & 1) || argc < 3) error("Argument count"); getargaddress(argv[0], &x1ptr, &x1fptr, &n); if(n != 1) { if(argc<7)error("Argument count"); getargaddress(argv[2], &y1ptr, &y1fptr, &n); getargaddress(argv[4], &x2ptr, &x2fptr, &n); getargaddress(argv[6], &y2ptr, &y2fptr, &n); } if(n==1){ c = gui_fcolour; w = 1; // setup the defaults x1 = getinteger(argv[0]); y1 = getinteger(argv[2]); if(argc>=5 && *argv[4])x2 = getinteger(argv[4]); else { x2=CurrentX;CurrentX=x1; } if(argc>=7 && *argv[6])y2 = getinteger(argv[6]); else { y2=CurrentY;CurrentY=y1; } if(x1==CurrentX && y1==CurrentY){ CurrentX=x2; CurrentY=y2; } if(argc > 7 && *argv[8]){ w = getint(argv[8], -100, 100); if(!w)return; } if(argc == 11) c = getint(argv[10], 0, WHITE); DrawLine(x1, y1, x2, y2, w, c); } else { c = gui_fcolour; w = 1; // setup the defaults if(argc > 7 && *argv[8]){ getargaddress(argv[8], &wptr, &wfptr, &nw); if(nw == 1) w = getint(argv[8], -100, 100); else if(nw>1) { if(nw > 1 && nw < n) n=nw; //adjust the dimensionality for(i=0;i 100) error("% is invalid (valid is % to %)", (int)w, 0, 100); } } } if(argc == 11){ getargaddress(argv[10], &cptr, &cfptr, &nc); if(nc == 1) c = getint(argv[10], 0, WHITE); else if(nc>1) { if(nc > 1 && nc < n) n=nc; //adjust the dimensionality for(i=0;i WHITE) error("% is invalid (valid is % to %)", (int)c, 0, WHITE); } } } for(i=0;i 1) w = (wfptr==NULL ? wptr[i] : (int)wfptr[i]); if(nc > 1) c = (cfptr==NULL ? cptr[i] : (int)cfptr[i]); if(w)DrawLine(x1, y1, x2, y2, w, c); } } } } if(Option.Refresh)Display_Refresh(); } void cmd_box(void) { int x1, y1, w=0, c=0, f=0, n=0 ,i, nc=0, nw=0, nf=0,hmod,wmod, nwidth=0, nheight=0, width=0, height=0; long long int *x1ptr, *y1ptr, *wiptr, *hptr, *wptr, *cptr, *fptr; MMFLOAT *x1fptr, *y1fptr, *wifptr, *hfptr, *wfptr, *cfptr, *ffptr; getargs(&cmdline, 13,(unsigned char *)","); if(Option.DISPLAY_TYPE == 0) error("Display not configured"); if(!(argc & 1) || argc < 7) error("Argument count"); getargaddress(argv[0], &x1ptr, &x1fptr, &n); if(n != 1) { getargaddress(argv[2], &y1ptr, &y1fptr, &n); } if(n == 1){ c = gui_fcolour; w = 1; f = -1; // setup the defaults x1 = getinteger(argv[0]); y1 = getinteger(argv[2]); width = getinteger(argv[4]) ; height = getinteger(argv[6]) ; wmod=(width > 0 ? -1 : 1); hmod=(height > 0 ? -1 : 1); if(argc > 7 && *argv[8]) w = getint(argv[8], 0, 100); if(argc > 9 && *argv[10]) c = getint(argv[10], 0, WHITE); if(argc == 13) f = getint(argv[12], -1, WHITE); if(width != 0 && height != 0) DrawBox(x1, y1, x1 + width + wmod, y1 + height + hmod, w, c, f); } else { getargaddress(argv[4], &wiptr, &wifptr, &nwidth); if(nwidth==1) width= getint(argv[4], 1, HRes); else if(nwidth>1) { if(nwidth > 1 && nwidth < n) n=nwidth; //adjust the dimensionality for(i=0;i HRes) error("Width % is invalid (valid is % to %)", (int)width, 1, HRes); } } getargaddress(argv[6], &hptr, &hfptr, &nheight); if(nheight==1) height= getint(argv[6], 1, VRes); else if(nheight>1) { if(nheight > 1 && nheight < n) n=nheight; //adjust the dimensionality for(i=0;i VRes) error("Height % is invalid (valid is % to %)", (int)height, 1, VRes); } } c = gui_fcolour; w = 1; // setup the defaults if(argc > 7 && *argv[8]){ getargaddress(argv[8], &wptr, &wfptr, &nw); if(nw == 1) w = getint(argv[8], 0, 100); else if(nw>1) { if(nw > 1 && nw < n) n=nw; //adjust the dimensionality for(i=0;i 100) error("% is invalid (valid is % to %)", (int)w, 0, 100); } } } if(argc > 9 && *argv[10]) { getargaddress(argv[10], &cptr, &cfptr, &nc); if(nc == 1) c = getint(argv[10], 0, WHITE); else if(nc>1) { if(nc > 1 && nc < n) n=nc; //adjust the dimensionality for(i=0;i WHITE) error("% is invalid (valid is % to %)", (int)c, 0, WHITE); } } } if(argc == 13){ getargaddress(argv[12], &fptr, &ffptr, &nf); if(nf == 1) f = getint(argv[12], 0, WHITE); else if(nf>1) { if(nf > 1 && nf < n) n=nf; //adjust the dimensionality for(i=0;i WHITE) error("% is invalid (valid is % to %)", (int)f, -1, WHITE); } } } for(i=0;i 1) width = (wifptr==NULL ? wiptr[i] : (int)wifptr[i]); if(nheight > 1) height = (hfptr==NULL ? hptr[i] : (int)hfptr[i]); wmod=(width > 0 ? -1 : 1); hmod=(height > 0 ? -1 : 1); if(nw > 1) w = (wfptr==NULL ? wptr[i] : (int)wfptr[i]); if(nc > 1) c = (cfptr==NULL ? cptr[i] : (int)cfptr[i]); if(nf > 1) f = (ffptr==NULL ? fptr[i] : (int)ffptr[i]); if(width != 0 && height != 0) DrawBox(x1, y1, x1 + width + wmod, y1 + height + hmod, w, c, f); } } if(Option.Refresh)Display_Refresh(); } /* * @cond * The following section will be excluded from the documentation. */ void MIPS16 bezier(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, int c){ float tmp,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7,tmp8,t=0.0,xt=x0,yt=y0; int i, xti,yti,xtlast=-1, ytlast=-1; for (i=0; i<500; i++) { tmp = 1.0 - t; tmp3 = t * t; tmp4 = tmp * tmp; tmp1 = tmp3 * t; tmp2 = tmp4 * tmp; tmp5 = 3.0 * t; tmp6 = 3.0 * tmp3; tmp7 = tmp5 * tmp4; tmp8 = tmp6 * tmp; xti=(int)xt; yti=(int)yt; xt = ((((tmp2 * x0) + (tmp7 * x1)) + (tmp8 * x2)) + (tmp1 * x3)); yt = ((((tmp2 * y0) + (tmp7 * y1)) + (tmp8 * y2)) +(tmp1 * y3)); if((xti!=xtlast) || (yti!=ytlast)) { DrawBuffered(xti, yti, c, 0); xtlast=xti; ytlast=yti; } t+=0.002; } DrawBuffered(0, 0, 0, 1); } void MIPS16 pointcalc(int angle, int x, int y, int r2, int *x0, int * y0){ float c1,s1; int quad; angle %=360; switch(angle){ case 0: *x0=x; *y0=y-r2; break; case 45: *x0=x+r2+1; *y0=y-r2; break; case 90: *x0=x+r2+1; *y0=y; break; case 135: *x0=x+r2+1; *y0=y+r2; break; case 180: *x0=x; *y0=y+r2; break; case 225: *x0=x-r2; *y0=y+r2; break; case 270: *x0=x-r2; *y0=y; break; case 315: *x0=x-r2; *y0=y-r2; break; default: c1=cos(Rad(angle)); s1=sin(Rad(angle)); quad = (angle / 45) % 8; switch(quad){ case 0: *y0=y-r2; *x0=x+s1*r2/c1; break; case 1: *x0=x+r2+1; *y0=y-c1*r2/s1; break; case 2: *x0=x+r2+1; *y0=y-c1*r2/s1; break; case 3: *y0=y+r2; *x0=x-s1*r2/c1; break; case 4: *y0=y+r2; *x0=x-s1*r2/c1; break; case 5: *x0=x-r2; *y0=y+c1*r2/s1; break; case 6: *x0=x-r2; *y0=y+c1*r2/s1; break; case 7: *y0=y-r2; *x0=x+s1*r2/c1; break; } } } /* @endcond */ void MIPS16 cmd_arc(void){ // Parameters are: // X coordinate of centre of arc // Y coordinate of centre of arc // inner radius of arc // outer radius of arc - omit it 1 pixel wide // start radial of arc in degrees // end radial of arc in degrees // Colour of arc int x, y, r1, r2, c ,i ,j, k, xs=-1, xi=0, m; int rad1, rad2, rad3, rstart, quadr; int x0, y0, x1, y1, x2, y2, xr, yr; getargs(&cmdline, 13,(unsigned char *)","); if(!(argc == 11 || argc == 13)) error("Argument count"); if(Option.DISPLAY_TYPE == 0) error("Display not configured"); x = getinteger(argv[0]); y = getinteger(argv[2]); r1 = getinteger(argv[4]); if(*argv[6])r2 = getinteger(argv[6]); else { r2=r1; r1--; } if(r2 < r1)error("Inner radius < outer"); rad1 = getnumber(argv[8]); rad2 = getnumber(argv[10]); while(rad1<0.0)rad1+=360.0; while(rad2<0.0)rad2+=360.0; if(rad1==rad2)error("Radials"); if(argc == 13) c = getint(argv[12], 0, WHITE); else c = gui_fcolour; while(rad2= (TFLOAT)y) || (main_fill_polyY[j] < (TFLOAT)y && main_fill_polyY[i] >= (TFLOAT)y)) { // intercept found; record it nodeX[nodes++] = (main_fill_polyX[i] + ((TFLOAT)y - main_fill_polyY[i]) / (main_fill_polyY[j] - main_fill_polyY[i]) * (main_fill_polyX[j] - main_fill_polyX[i])); } j = i; } // sort the nodes via simple insertion sort for (i = 1; i < nodes; i++) { temp = nodeX[i]; for (j = i; j > 0 && temp < nodeX[j-1]; j--) { nodeX[j] = nodeX[j-1]; } nodeX[j] = temp; } // fill the pixels between node pairs for (i = 0; i < nodes; i += 2) { xstart=(int)floorf(nodeX[i])+1; xend=(int)ceilf(nodeX[i+1])-1; DrawLine(xstart,y,xend,y,1, f); } } main_fill.filled = false; // redraw polygon (filling is imperfect and can occasionally occlude sides) for (i = 0; i < main_fill_poly_vertex_count; i++) { int x0 = (int)roundf(main_fill_polyX[i]); int y0 = (int)roundf(main_fill_polyY[i]); int x1 = (int)roundf(main_fill_polyX[(i+1) % main_fill_poly_vertex_count]); int y1 = (int)roundf(main_fill_polyY[(i+1) % main_fill_poly_vertex_count]); DrawLine(x0, y0, x1, y1, 1, c); } FreeMemory((void *)nodeX); } void polygon(unsigned char *p, int close){ int xcount=0; long long int *xptr=NULL, *yptr=NULL,xptr2=0, yptr2=0, *polycount=NULL, *cptr=NULL, *fptr=NULL; MMFLOAT *polycountf=NULL, *cfptr=NULL, *ffptr=NULL, *xfptr=NULL, *yfptr=NULL, xfptr2=0, yfptr2=0; int i, f=0, c, xtot=0, ymax=0, ymin=1000000; int n=0, nx=0, ny=0, nc=0, nf=0; getargs(&p, 9,(unsigned char *)","); if(Option.DISPLAY_TYPE == 0) error("Display not configured"); getargaddress(argv[0], &polycount, &polycountf, &n); if(n==1){ xcount = xtot = getinteger(argv[0]); if((xcount<3 || xcount>9999) && xcount!=0)error("Invalid number of vertices"); getargaddress(argv[2], &xptr, &xfptr, &nx); if(xcount==0){ xcount = xtot = nx; } if(nx 5 && *argv[6]) c = getint(argv[6], 0, WHITE); if(argc > 7 && *argv[8]){ main_fill_polyX=(TFLOAT *)GetTempMemory((xtot+1) * sizeof(TFLOAT)); main_fill_polyY=(TFLOAT *)GetTempMemory((xtot+1) * sizeof(TFLOAT)); f = getint(argv[8], 0, WHITE); fill_set_fill_color((f>>16) & 0xFF, (f>>8) & 0xFF , f & 0xFF); fill_set_pen_color((c>>16) & 0xFF, (c>>8) & 0xFF , c & 0xFF); fill_begin_fill(); } for(i=0;i 7){ main_fill_polyX[main_fill_poly_vertex_count] = (xfptr==NULL ? (TFLOAT )*xptr++ : (TFLOAT )*xfptr++) ; main_fill_polyY[main_fill_poly_vertex_count] = (yfptr==NULL ? (TFLOAT )*yptr++ : (TFLOAT )*yfptr++) ; if(main_fill_polyY[main_fill_poly_vertex_count]>ymax)ymax=main_fill_polyY[main_fill_poly_vertex_count]; if(main_fill_polyY[main_fill_poly_vertex_count] 7){ main_fill_polyX[main_fill_poly_vertex_count] = (xfptr==NULL ? (TFLOAT )*xptr++ : (TFLOAT )*xfptr++) ; main_fill_polyY[main_fill_poly_vertex_count] = (yfptr==NULL ? (TFLOAT )*yptr++ : (TFLOAT )*yfptr++) ; if(main_fill_polyY[main_fill_poly_vertex_count]>ymax)ymax=main_fill_polyY[main_fill_poly_vertex_count]; if(main_fill_polyY[main_fill_poly_vertex_count]5){ fill_end_fill(xcount,ymin,ymax); } else if(main_fill_poly_vertex_count==5){ DrawTriangle(main_fill_polyX[0],main_fill_polyY[0],main_fill_polyX[1],main_fill_polyY[1],main_fill_polyX[2],main_fill_polyY[2],f,f); DrawTriangle(main_fill_polyX[0],main_fill_polyY[0],main_fill_polyX[2],main_fill_polyY[2],main_fill_polyX[3],main_fill_polyY[3],f,f); if(f!=c){ DrawLine(main_fill_polyX[0],main_fill_polyY[0],main_fill_polyX[1],main_fill_polyY[1],1,c); DrawLine(main_fill_polyX[1],main_fill_polyY[1],main_fill_polyX[2],main_fill_polyY[2],1,c); DrawLine(main_fill_polyX[2],main_fill_polyY[2],main_fill_polyX[3],main_fill_polyY[3],1,c); DrawLine(main_fill_polyX[3],main_fill_polyY[3],main_fill_polyX[4],main_fill_polyY[4],1,c); } } else { DrawTriangle(main_fill_polyX[0],main_fill_polyY[0],main_fill_polyX[1],main_fill_polyY[1],main_fill_polyX[2],main_fill_polyY[2],c,f); } } else if(close){ int x1=(xfptr==NULL ? *xptr : (int)*xfptr); int x2=(xfptr==NULL ? xptr2 : (int)xfptr2); int y1=(yfptr==NULL ? *yptr : (int)*yfptr); int y2=(yfptr==NULL ? yptr2 : (int)yfptr2); DrawLine(x1,y1,x2,y2, 1, c); } } else { int *cc=GetTempMemory(n*sizeof(int)); //array for foreground colours int *ff=GetTempMemory(n*sizeof(int)); //array for background colours int xstart ,j, xmax=0; for(i=0;ixmax)xmax=(polycountf == NULL ? polycount[i] : (int)polycountf[i]); if(!(polycountf == NULL ? polycount[i] : (int)polycountf[i]))break; xtot+=(polycountf == NULL ? polycount[i] : (int)polycountf[i]); if((polycountf == NULL ? polycount[i] : (int)polycountf[i])<3 || (polycountf == NULL ? polycount[i] : (int)polycountf[i])>9999)error("Invalid number of vertices, polygon %",i); } n=i; getargaddress(argv[2], &xptr, &xfptr, &nx); if(nx 5 && *argv[6]){ //foreground colour specified getargaddress(argv[6], &cptr, &cfptr, &nc); if(nc == 1) for(i=0;i 0xFFFFFF) error("% is invalid (valid is % to %)", (int)cc[i], 0, 0xFFFFFF); } } } else for(i=0;i 7){ //background colour specified getargaddress(argv[8], &fptr, &ffptr, &nf); if(nf == 1) for(i=0;i 0xFFFFFF) error("% is invalid (valid is % to %)", (int)ff[i], 0, 0xFFFFFF); } } } xstart=0; for(i=0;i 7 && *argv[8]){ fill_set_pen_color((cc[i]>>16) & 0xFF, (cc[i]>>8) & 0xFF , cc[i] & 0xFF); fill_set_fill_color((ff[i]>>16) & 0xFF, (ff[i]>>8) & 0xFF , ff[i] & 0xFF); fill_begin_fill(); } for(j=xstart;j 7){ main_fill_polyX[main_fill_poly_vertex_count] = (xfptr==NULL ? (TFLOAT )*xptr++ : (TFLOAT )*xfptr++) ; main_fill_polyY[main_fill_poly_vertex_count] = (yfptr==NULL ? (TFLOAT )*yptr++ : (TFLOAT )*yfptr++) ; if(main_fill_polyY[main_fill_poly_vertex_count]>ymax)ymax=main_fill_polyY[main_fill_poly_vertex_count]; if(main_fill_polyY[main_fill_poly_vertex_count] 7){ main_fill_polyX[main_fill_poly_vertex_count] = (xfptr==NULL ? (TFLOAT )*xptr++ : (TFLOAT )*xfptr++) ; main_fill_polyY[main_fill_poly_vertex_count] = (yfptr==NULL ? (TFLOAT )*yptr++ : (TFLOAT )*yfptr++) ; if(main_fill_polyY[main_fill_poly_vertex_count]>ymax)ymax=main_fill_polyY[main_fill_poly_vertex_count]; if(main_fill_polyY[main_fill_poly_vertex_count]5){ fill_end_fill(xcount,ymin,ymax); } else if(main_fill_poly_vertex_count==5){ DrawTriangle(main_fill_polyX[0],main_fill_polyY[0],main_fill_polyX[1],main_fill_polyY[1],main_fill_polyX[2],main_fill_polyY[2],ff[i],ff[i]); DrawTriangle(main_fill_polyX[0],main_fill_polyY[0],main_fill_polyX[2],main_fill_polyY[2],main_fill_polyX[3],main_fill_polyY[3],ff[i],ff[i]); if(ff[i]!=cc[i]){ DrawLine(main_fill_polyX[0],main_fill_polyY[0],main_fill_polyX[1],main_fill_polyY[1],1,cc[i]); DrawLine(main_fill_polyX[1],main_fill_polyY[1],main_fill_polyX[2],main_fill_polyY[2],1,cc[i]); DrawLine(main_fill_polyX[2],main_fill_polyY[2],main_fill_polyX[3],main_fill_polyY[3],1,cc[i]); DrawLine(main_fill_polyX[3],main_fill_polyY[3],main_fill_polyX[4],main_fill_polyY[4],1,cc[i]); } } else { DrawTriangle(main_fill_polyX[0],main_fill_polyY[0],main_fill_polyX[1],main_fill_polyY[1],main_fill_polyX[2],main_fill_polyY[2],cc[i],ff[i]); } } else { int x1=(xfptr==NULL ? *xptr : (int)*xfptr); int x2=(xfptr==NULL ? xptr2 : (int)xfptr2); int y1=(yfptr==NULL ? *yptr : (int)*yfptr); int y2=(yfptr==NULL ? yptr2 : (int)yfptr2); DrawLine(x1,y1,x2,y2, 1, cc[i]); if(xfptr!=NULL)xfptr++; else xptr++; if(yfptr!=NULL)yfptr++; else yptr++; } xstart+=xcount; } } } /* @endcond */ void cmd_polygon(void){ polygon(cmdline,1); } void MIPS16 cmd_rbox(void) { int x1, y1, wi, h, w=0, c=0, f=0, r=0, n=0 ,i, nc=0, nw=0, nf=0,hmod,wmod; long long int *x1ptr, *y1ptr, *wiptr, *hptr, *wptr, *cptr, *fptr; MMFLOAT *x1fptr, *y1fptr, *wifptr, *hfptr, *wfptr, *cfptr, *ffptr; getargs(&cmdline, 13,(unsigned char*)","); if(Option.DISPLAY_TYPE == 0) error("Display not configured"); if(!(argc & 1) || argc < 7) error("Argument count"); getargaddress(argv[0], &x1ptr, &x1fptr, &n); if(n != 1) { getargaddress(argv[2], &y1ptr, &y1fptr, &n); getargaddress(argv[4], &wiptr, &wifptr, &n); getargaddress(argv[6], &hptr, &hfptr, &n); } if(n == 1){ c = gui_fcolour; w = 1; f = -1; r = 10; // setup the defaults x1 = getinteger(argv[0]); y1 = getinteger(argv[2]); w = getinteger(argv[4]); h = getinteger(argv[6]); wmod=(w > 0 ? -1 : 1); hmod=(h > 0 ? -1 : 1); if(argc > 7 && *argv[8]) r = getint(argv[8], 0, 100); if(argc > 9 && *argv[10]) c = getint(argv[10], 0, WHITE); if(argc == 13) f = getint(argv[12], -1, WHITE); if(w != 0 && h != 0) DrawRBox(x1, y1, x1 + w + wmod, y1 + h + hmod, r, c, f); } else { c = gui_fcolour; w = 1; // setup the defaults if(argc > 7 && *argv[8]){ getargaddress(argv[8], &wptr, &wfptr, &nw); if(nw == 1) w = getint(argv[8], 0, 100); else if(nw>1) { if(nw > 1 && nw < n) n=nw; //adjust the dimensionality for(i=0;i 100) error("% is invalid (valid is % to %)", (int)w, 0, 100); } } } if(argc > 9 && *argv[10]) { getargaddress(argv[10], &cptr, &cfptr, &nc); if(nc == 1) c = getint(argv[10], 0, WHITE); else if(nc>1) { if(nc > 1 && nc < n) n=nc; //adjust the dimensionality for(i=0;i WHITE) error("% is invalid (valid is % to %)", (int)c, 0, WHITE); } } } if(argc == 13){ getargaddress(argv[12], &fptr, &ffptr, &nf); if(nf == 1) f = getint(argv[12], 0, WHITE); else if(nf>1) { if(nf > 1 && nf < n) n=nf; //adjust the dimensionality for(i=0;i WHITE) error("% is invalid (valid is % to %)", (int)f, -1, WHITE); } } } for(i=0;i 0 ? -1 : 1); hmod=(h > 0 ? -1 : 1); if(nw > 1) w = (wfptr==NULL ? wptr[i] : (int)wfptr[i]); if(nc > 1) c = (cfptr==NULL ? cptr[i] : (int)cfptr[i]); if(nf > 1) f = (ffptr==NULL ? fptr[i] : (int)ffptr[i]); if(wi != 0 && h != 0) DrawRBox(x1, y1, x1 + wi + wmod, y1 + h + hmod, w, c, f); } } if(Option.Refresh)Display_Refresh(); } // this function positions the cursor within a PRINT command void MIPS16 fun_at(void) { char buf[27]; getargs(&ep, 5, (unsigned char *)","); if(commandfunction(cmdtoken) != cmd_print) error("Invalid function"); // if((argc == 3 || argc == 5)) error("Incorrect number of arguments"); // AutoLineWrap = false; CurrentX = getinteger(argv[0]); if(argc>=3 && *argv[2])CurrentY = getinteger(argv[2]); if(argc == 5) { PrintPixelMode = getinteger(argv[4]); if(PrintPixelMode < 0 || PrintPixelMode > 7) { PrintPixelMode = 0; error("Number out of bounds"); } } else PrintPixelMode = 0; // BJR: VT100 set cursor location: [y;xf // where x and y are ASCII string integers. // Assumes overall font size of 6x12 pixels (480/80 x 432/36), including gaps between characters and lines sprintf(buf, "\033[%d;%df", (int)CurrentY/(FontTable[gui_font >> 4][1] * (gui_font & 0b1111))+1, (int)CurrentX/(FontTable[gui_font >> 4][0] * (gui_font & 0b1111))+1); SSPrintString(buf); // send it to the USB if(PrintPixelMode==2 || PrintPixelMode==5)SSPrintString("\033[7m"); targ=T_STR; sret = (unsigned char *)"\0"; // normally pointing sret to a string in flash is illegal } // these three functions were written by Peter Mather (matherp on the Back Shed forum) // read the contents of a PIXEL out of screen memory void fun_pixel(void) { if((void *)ReadBuffer == (void *)DisplayNotSet) error("Invalid on this display"); int p; int x, y; getargs(&ep, 3, (unsigned char *)","); if(argc != 3) error("Argument count"); x = getinteger(argv[0]); y = getinteger(argv[2]); ReadBuffer(x, y, x, y, (unsigned char *)&p); iret = p & 0xFFFFFF; targ = T_INT; } void cmd_triangle(void) { // thanks to Peter Mather (matherp on the Back Shed forum) unsigned char *p; if((p=checkstring(cmdline, (unsigned char *)"SAVE"))){ if((void *)ReadBuffer == (void *)DisplayNotSet) error("Invalid on this display"); cmd_ReadTriangle(p); return; } if((p=checkstring(cmdline, (unsigned char *)"RESTORE"))){ if((void *)ReadBuffer == (void *)DisplayNotSet) error("Invalid on this display"); cmd_RestoreTriangle(p); return; } int x1, y1, x2, y2, x3, y3, c=0, f=0, n=0,i, nc=0, nf=0; long long int *x3ptr, *y3ptr, *x1ptr, *y1ptr, *x2ptr, *y2ptr, *fptr, *cptr; MMFLOAT *x3fptr, *y3fptr, *x1fptr, *y1fptr, *x2fptr, *y2fptr, *ffptr, *cfptr; getargs(&cmdline, 15,(unsigned char *)","); if(Option.DISPLAY_TYPE == 0) error("Display not configured"); if(!(argc & 1) || argc < 11) error("Argument count"); getargaddress(argv[0], &x1ptr, &x1fptr, &n); if(n != 1) { int cn=n; getargaddress(argv[2], &y1ptr, &y1fptr, &n); if(n= 13 && *argv[12]) c = getint(argv[12], BLACK, WHITE); if(argc == 15) f = getint(argv[14], -1, WHITE); DrawTriangle(x1, y1, x2, y2, x3, y3, c, f); } else { c = gui_fcolour; f = -1; if(argc >= 13 && *argv[12]) { getargaddress(argv[12], &cptr, &cfptr, &nc); if(nc == 1) c = getint(argv[10], 0, WHITE); else if(nc>1) { if(nc > 1 && nc < n) n=nc; //adjust the dimensionality for(i=0;i WHITE) error("% is invalid (valid is % to %)", (int)c, 0, WHITE); } } } if(argc == 15){ getargaddress(argv[14], &fptr, &ffptr, &nf); if(nf == 1) f = getint(argv[14], -1, WHITE); else if(nf>1) { if(nf > 1 && nf < n) n=nf; //adjust the dimensionality for(i=0;i WHITE) error("% is invalid (valid is % to %)", (int)f, -1, WHITE); } } } for(i=0;i 1) c = (cfptr==NULL ? cptr[i] : (int)cfptr[i]); if(nf > 1) f = (ffptr==NULL ? fptr[i] : (int)ffptr[i]); DrawTriangle(x1, y1, x2, y2, x3, y3, c, f); } } if(Option.Refresh)Display_Refresh(); } /* * @cond * The following section will be excluded from the documentation. */ char getnextuncompressednibble(char **s, int reset){ static int toggle=0; if(reset){ toggle=reset-1; return 0; } if(!toggle){ toggle ^=1; return **s & 0x0f; } else { toggle ^=1; char r=(**s & 0xf0)>>4; (*s)++; return r; } } static inline char getnextnibble(char **fc, int reset){ static uint8_t available; static char out; if(reset){ available=0; } if(available==0){ available=**fc & 0xF; //number of identical pixels out=(**fc)>>4; (*fc)++; } if(!reset)available--; return out; } void docompressed(char *fc,int x1, int y1, int w, int h, int8_t blank){ #ifndef PICOMITEVGA if(!WriteBuf){ //direct to screen if(blank==-1){ char tobuff[w/2], *to; int ww=w; int xx1=x1; if(x1<0){ ww+=x1; xx1=0; } if(x1+w>HRes){ ww=HRes-x1; } getnextnibble(&fc,1); //reset the decoder for(int y=y1;y=VRes){ getnextnibble(&fc,0); continue; } if(x>=0 && x0 && xx1HRes){ ww=HRes-xx; } if(xx>=0 && ww>0 && y>=0 && y=0){ char *t=tobuff-(xx/2)-(xx&1); ww+=xx; if(ww>0)copyframetoscreen((unsigned char *)t,0, ww-1, y, y, xx&1); } if(x>=x1+w)break; } } } } else #endif if(x1 %2 == 0 && w % 2 == 0 && blank==-1){ char c, *to; c=getnextnibble(&fc,1); //reset the decoder for(int y=y1;y>1)+(x1>>1); for(int x=x1;x=VRes)continue; if(x>=0 && x>1)+(x1>>1); //get the byte that will start the output if(x1 & 1)otoggle=1; // if x1 is odd then we will start on the high nibble else otoggle=0; for(int x=x1;x=VRes)continue; if(otoggle==0){ if(x>=0 && x=0 && xHRes){ ww=HRes-x1; } getnextuncompressednibble(&fc,1); //reset the decoder for(int y=y1;y=VRes){ getnextuncompressednibble(&fc,0); continue; } if(x>=0 && x0 && xx1HRes){ ww=HRes-xx; } if(xx>=0 && ww>0 && y>=0 && y=0){ char *t=tobuff-(xx/2)-(xx&1); ww+=xx; if(ww>0)copyframetoscreen((unsigned char *)t,0, ww-1, y, y, xx&1); } if(x>=x1+w)break; } } } } else #endif if(x1 %2 == 0 && w % 2 == 0 && blank==-1){ char c, *to; for(int y=y1;y>1)+(x1>>1); for(int x=x1;x=VRes)continue; if(x>=0 && x>1)+(x1>>1); //get the byte that will start the output if(x1 & 1)otoggle=1; // if x1 is odd then we will start on the high nibble else otoggle=0; for(int x=x1;x>4; from++; itoggle=0; } if(y<0 || y>=VRes)continue; if(otoggle==0){ if(x>=0 && x=0 && xHRes || h>VRes)error("Invalid dimensions, w=%, h=%",w,h); fc+=4; if(argc==7)blank=getint(argv[6],-1,15); docompressed(fc, x1, y1, w, h, blank); return 1; } else if ((p = checkstring(cmdline, (unsigned char*)"FRAMEBUFFER"))) { int8_t blank=-1; int otoggle=0,itoggle=0; //input will always start on a byte boundary volatile unsigned char *s=NULL, *d=NULL; getargs(&p, 17, (unsigned char*)","); if(argc<15)error("Syntax"); if(checkstring(argv[0],(unsigned char*)"L"))s=LayerBuf; else if(checkstring(argv[0],(unsigned char*)"F"))s=FrameBuf; #ifdef PICOMITEVGA else if(checkstring(argv[0],(unsigned char*)"N"))s=DisplayBuf; #ifdef rp2350 else if(checkstring(argv[0],(unsigned char*)"T"))s=SecondLayer; #endif #else else if(checkstring(argv[0],(unsigned char*)"N"))s=NULL; #endif else error("Syntax"); if(checkstring(argv[2],(unsigned char*)"L"))d=LayerBuf; else if(checkstring(argv[2],(unsigned char*)"F"))d=FrameBuf; #ifdef PICOMITEVGA else if(checkstring(argv[2],(unsigned char*)"N"))d=DisplayBuf; #ifdef rp2350 else if(checkstring(argv[2],(unsigned char*)"T"))d=SecondLayer; #endif #else else if(checkstring(argv[2],(unsigned char*)"N"))d=NULL; #endif else error("Syntax"); if(s==d)error("Same framebuffer"); if(s==NULL && (void *)ReadBuffer == (void *)DisplayNotSet) error("Invalid on this display"); x1 = (int)getinteger(argv[4]); y1 = (int)getinteger(argv[6]); x2 = (int)getinteger(argv[8]); y2 = (int)getinteger(argv[10]); w = (int)getinteger(argv[12]); h = (int)getinteger(argv[14]); if(argc==17)blank=getint(argv[16],-1,15); volatile unsigned char c,*to, *from; if(d!=NULL && s!=NULL){ if(x1==0 && x2==0 && w==HRes && blank==-1){ s+=y1*HRes/2; d+=y2*HRes/2; memmove((void *)d,(void *)s,h*HRes/2); } else { for(int y=y1,toy=y2;y>1)+(x1>>1); //get the byte that will start the output to=d+toy*(HRes>>1)+(x2>>1); //get the byte that will start the output if(x1 & 1)itoggle=1; // if x1 is odd then we will start on the high nibble else itoggle=0; if(x2 & 1)otoggle=1; // if x1 is odd then we will start on the high nibble else otoggle=0; for(int x=x1,tox=x2;x=0 && tox=0 && tox>4; else c=0; from++; itoggle=0; } if(y<0 || y>=VRes)continue; if(otoggle==0){ if(tox>=0 && tox=0 && toxHRes){ ww=HRes-xx; } if(x2>=0 && ww>0 && yo>=0 && yo=0){ char *t=tobuff-((x2)/2)-(x2&1); ww+=x2; if(ww>0){ copyframetoscreen((unsigned char *)t,0, ww-1, yo, yo, x2&1); } } if(x>=x1+w)break; } } } return 1; } else if(d!=NULL){ //reading from a physical LCD display union colourmap { char rgbbytes[4]; unsigned int rgb; } cb; unsigned char *rbuff=(unsigned char *)GetTempMemory(w*4); char *from=GetTempMemory((w+1)/2); for(int y=y1,toy=y2;y>1)+(x2>>1); //get the byte that will start the output itoggle=0; pp=from; if(x2 & 1)otoggle=1; // if x1 is odd then we will start on the high nibble else otoggle=0; for(int x=x1,tox=x2;x=0 && tox=0 && tox>4; else c=0; pp++; itoggle=0; } if(y<0 || y>=VRes)continue; if(otoggle==0){ if(tox>=0 && tox=0 && tox maxW) { if (!(spritebuff[bnbr].edges & 4)) { spritebuff[bnbr].edges |= 4; if (spritebuff[bnbr].collisions[*n] & 0xF0)spritebuff[bnbr].collisions[*n] |= 0xF4; else { spritebuff[bnbr].collisions[*n] = (char)0xF4; (*n)++; } } } else spritebuff[bnbr].edges &= ~4; if (spritebuff[bnbr].y + spritebuff[bnbr].h > maxH) { if (!(spritebuff[bnbr].edges & 8)) { spritebuff[bnbr].edges |= 8; if (spritebuff[bnbr].collisions[*n] & 0xF0)spritebuff[bnbr].collisions[*n] |= 0xF8; else { spritebuff[bnbr].collisions[*n] = (char)0xF8; (*n)++; } } } else spritebuff[bnbr].edges &= ~8; } void ProcessCollisions(int bnbr) { int k, j = 1, n = 1, bcol = 1; //We know that any collision is caused by movement of sprite bnbr // a value of zero indicates that we are processing movement of layer 0 and any // sprites on that layer CollisionFound = false; sprite_which_collided = -1; uint64_t mask, mymask = (uint64_t)1 << ((uint64_t)bnbr - (uint64_t)1); memset(spritebuff[0].collisions, 0, MAXCOLLISIONS); if (bnbr != 0) { // a specific sprite has moved memset(spritebuff[bnbr].collisions, 0, MAXCOLLISIONS); //clear our previous collisions if (spritebuff[bnbr].layer != 0) { if (layer_in_use[spritebuff[bnbr].layer] + layer_in_use[0] > 1) { //other sprites in this layer for (k = 1; k <= MAXBLITBUF; k++) { mask = (uint64_t)1 << ((uint64_t)k - (uint64_t)1); if (!(spritebuff[k].active)) { spritebuff[bnbr].lastcollisions &= ~mask; continue; } if (k == bnbr) continue; if (j == layer_in_use[spritebuff[bnbr].layer] + layer_in_use[0]) break; //nothing left to process if ((spritebuff[k].layer == spritebuff[bnbr].layer || spritebuff[k].layer == 0)) { j++; if (!(spritebuff[k].x + spritebuff[k].w < spritebuff[bnbr].x || spritebuff[k].x > spritebuff[bnbr].x + spritebuff[bnbr].w || spritebuff[k].y + spritebuff[k].h < spritebuff[bnbr].y || spritebuff[k].y > spritebuff[bnbr].y + spritebuff[bnbr].h)) { if (n < MAXCOLLISIONS && !(spritebuff[bnbr].lastcollisions & mask))spritebuff[bnbr].collisions[n++] = k; spritebuff[bnbr].lastcollisions |= mask; spritebuff[k].lastcollisions |= mymask; } else { spritebuff[bnbr].lastcollisions &= ~mask; spritebuff[k].lastcollisions &= ~mymask; } } } } } else { for (k = 1; k <= MAXBLITBUF; k++) { if (j == sprites_in_use) break; //nothing left to process if (k == bnbr) continue; mask = (uint64_t)1 << ((uint64_t)k - (uint64_t)1); if (!(spritebuff[k].active)) { spritebuff[bnbr].lastcollisions &= ~mask; continue; } else j++; if (!(spritebuff[k].x + spritebuff[k].w < spritebuff[bnbr].x || spritebuff[k].x > spritebuff[bnbr].x + spritebuff[bnbr].w || spritebuff[k].y + spritebuff[k].h < spritebuff[bnbr].y || spritebuff[k].y > spritebuff[bnbr].y + spritebuff[bnbr].h)) { if (n < MAXCOLLISIONS && !(spritebuff[bnbr].lastcollisions & mask))spritebuff[bnbr].collisions[n++] = k; spritebuff[bnbr].lastcollisions |= mask; spritebuff[k].lastcollisions |= mymask; } else { spritebuff[bnbr].lastcollisions &= ~mask; spritebuff[k].lastcollisions &= ~mymask; } } } // now look for collisions with the edge of the screen checklimits(bnbr, &n); if (n > 1) { CollisionFound = true; sprite_which_collided = bnbr; spritebuff[bnbr].collisions[0] = n - 1; } } else { //the background layer has moved j = 0; for (k = 1; k <= MAXBLITBUF; k++) { //loop through all sprites mask = (uint64_t)1 << ((uint64_t)k - (uint64_t)1); n = 1; int kk, jj = 1; if (j == sprites_in_use) break; //nothing left to process if (spritebuff[k].active) { //sprite found memset(spritebuff[k].collisions, 0, MAXCOLLISIONS); j++; if (layer_in_use[spritebuff[k].layer] + layer_in_use[0] > 1) { //other sprites in this layer for (kk = 1; kk <= MAXBLITBUF; kk++) { if (kk == k) continue; if (jj == layer_in_use[spritebuff[k].layer] + layer_in_use[0]) break; //nothing left to process if ((spritebuff[kk].layer == spritebuff[k].layer || spritebuff[kk].layer == 0)) { jj++; if (!(spritebuff[kk].x + spritebuff[kk].w < spritebuff[k].x || spritebuff[kk].x > spritebuff[k].x + spritebuff[k].w || spritebuff[kk].y + spritebuff[kk].h < spritebuff[k].y || spritebuff[kk].y > spritebuff[k].y + spritebuff[k].h)) { if (n < MAXCOLLISIONS && !(spritebuff[k].lastcollisions & mask))spritebuff[k].collisions[n++] = kk; spritebuff[k].lastcollisions |= mask; } else { spritebuff[k].lastcollisions &= ~mask; } } } } checklimits(k, &n); if (n > 1 && n < MAXCOLLISIONS && bcol < MAXCOLLISIONS) { spritebuff[0].collisions[bcol] = k; bcol++; spritebuff[k].collisions[0] = n - 1; } } } if (bcol > 1) { CollisionFound = true; sprite_which_collided = 0; spritebuff[0].collisions[0] = bcol - 1; } } } void blithide(int bnbr, int free) { int w, h, x1, y1; w = spritebuff[bnbr].w; h = spritebuff[bnbr].h; x1 = spritebuff[bnbr].x; y1 = spritebuff[bnbr].y; spritebuff[bnbr].active = 0; DrawBufferFast(x1, y1, x1 + w - 1, y1 + h - 1, -1, (unsigned char *)spritebuff[bnbr].blitstoreptr); } void expandpixel(volatile unsigned char *ii, volatile unsigned char *oo, int n, int mode){ volatile unsigned char *o=oo,*i=ii; int toggle=0; if(mode==0){ while(n--){ if(toggle){ *o++=(*i++ >>4); } else { *o++=*i & 0xF; } toggle=!toggle; } } else { while(n--){ *o++=(*i >> toggle++) & 0x1; if(toggle==8){ i++; toggle=0; } } } } void contractpixel(volatile unsigned char *ii, volatile unsigned char *oo, int n, int mode){ int toggle=0; volatile unsigned char *o=oo,*i=ii; if(mode==0){ while(n--){ if(toggle){ *o++ |= (*i++ <<4); } else { *o= *i++ & 0xF; } toggle=!toggle; } } else { while(n--){ if(toggle==0)*o=0; *o|=(*i++ << toggle++); if(toggle==8){ toggle=0; o++; } } } } void BlitShowBuffer(int bnbr, int x1, int y1, int mode) { char* current; int x, xx, y, yy, rotation, fullmode=mode; mode &=7; rotation = spritebuff[bnbr].rotation; current = spritebuff[bnbr].blitstoreptr; int w, h; if (spritebuff[bnbr].spritebuffptr != NULL) { w = spritebuff[bnbr].w; h = spritebuff[bnbr].h; if (!(mode == 0 || mode & 4) && spritebuff[bnbr].active) { DrawBufferFast(spritebuff[bnbr].x, spritebuff[bnbr].y, spritebuff[bnbr].x + w - 1, spritebuff[bnbr].y + h - 1, -1, (unsigned char *)current); } spritebuff[bnbr].x = x1; spritebuff[bnbr].y = y1; if (!(mode == 2))ReadBufferFast(x1, y1, x1 + w - 1, y1 + h - 1, (unsigned char *)current); // we now have the old screen image stored together with the coordinates if(rotation){ unsigned char *d=GetTempMemory(w*h); unsigned char *r=GetTempMemory((w*h+1)>>1); expandpixel((unsigned char *)spritebuff[bnbr].spritebuffptr,d,w*h,0); if(rotation & 1){ //swap left/write for (y = 0; y < h; y++) { for (x = 0,xx=w-1; x < (w>>1); x++,xx--) { swap(d[y*w+x],d[y*w+xx]); } } } if(rotation & 2){ for(x=0;x>1);y++,yy--){ swap(d[x+y*w],d[x+yy*w]); } } } contractpixel(d,r,w*h,0); DrawBufferFast(x1, y1, x1 + w - 1, y1 + h - 1, ((fullmode & 8)==0 ? 0 : -1), (unsigned char *)r); } else { DrawBufferFast(x1, y1, x1 + w - 1, y1 + h - 1,((fullmode & 8)==0 ? 0 : -1) , (unsigned char *)spritebuff[bnbr].spritebuffptr); } if (!(mode & 4))spritebuff[bnbr].active = 1; } } int sumlayer(void) { int i, j = 0; for (i = 0; i <= MAXLAYER; i++)j += layer_in_use[i]; return j; } void hidesafe(int bnbr) { int found = 0; int i; for (i = LIFOpointer - 1; i >= 0; i--) { if (LIFO[i] == bnbr) { blithide(LIFO[i], 0); found = i; break; } blithide(LIFO[i], 0); } if (!found) { for (i = zeroLIFOpointer - 1; i >= 0; i--) { if (zeroLIFO[i] == bnbr) { blithide(zeroLIFO[i], 0); found = -i; break; } blithide(zeroLIFO[i], 0); } } sprites_in_use--; layer_in_use[spritebuff[bnbr].layer]--; spritebuff[bnbr].x = 10000; spritebuff[bnbr].y = 10000; if (spritebuff[bnbr].layer == 0)zeroLIFOremove(bnbr); else LIFOremove(bnbr); spritebuff[bnbr].layer = -1; spritebuff[bnbr].next_x = 10000; spritebuff[bnbr].next_y = 10000; spritebuff[bnbr].lastcollisions = 0; spritebuff[bnbr].edges = 0; if (found < 0) { found = -found; for (i = found; i < zeroLIFOpointer; i++) { BlitShowBuffer(zeroLIFO[i], spritebuff[zeroLIFO[i]].x, spritebuff[zeroLIFO[i]].y, 0); } for (i = 0; i < LIFOpointer; i++) { BlitShowBuffer(LIFO[i], spritebuff[LIFO[i]].x, spritebuff[LIFO[i]].y, 0); } } else { for (i = found; i < LIFOpointer; i++) { BlitShowBuffer(LIFO[i], spritebuff[LIFO[i]].x, spritebuff[LIFO[i]].y, 0); } } } void showsafe(int bnbr, int x, int y) { int found = 0; int i; for (i = LIFOpointer - 1; i >= 0; i--) { if (LIFO[i] == bnbr) { blithide(LIFO[i], 0); found = i; break; } blithide(LIFO[i], 0); } if (!found) { for (i = zeroLIFOpointer - 1; i >= 0; i--) { if (zeroLIFO[i] == bnbr) { blithide(zeroLIFO[i], 0); found = -i; break; } blithide(zeroLIFO[i], 0); } } BlitShowBuffer(bnbr, x, y, 1); if (found < 0) { found = -found; for (i = found + 1; i < zeroLIFOpointer; i++) { BlitShowBuffer(zeroLIFO[i], spritebuff[zeroLIFO[i]].x, spritebuff[zeroLIFO[i]].y, 0); } for (i = 0; i < LIFOpointer; i++) { BlitShowBuffer(LIFO[i], spritebuff[LIFO[i]].x, spritebuff[LIFO[i]].y, 0); } } else { for (i = found + 1; i < LIFOpointer; i++) { BlitShowBuffer(LIFO[i], spritebuff[LIFO[i]].x, spritebuff[LIFO[i]].y, 0); } } } void MIPS16 loadsprite(unsigned char* p) { int fnbr, width, number, height = 0, newsprite = 1, startsprite = 1, bnbr, lc, i, toggle=0;; char *q, *fname; unsigned char buff[256], *z; uint32_t data; getargs(&p, 5, (unsigned char *)","); int mode=0; fnbr = FindFreeFileNbr(); if(!InitSDCard()) return; fname = (char*)getFstring(argv[0]); if (argc >= 3 && *argv[2])startsprite = (int)getint(argv[2], 1, 64); if(argc==5)mode=getint(argv[4],0,1); if(strchr(fname, '.') == NULL) strcat(fname, ".spr"); if (!BasicFileOpen(fname, fnbr, FA_READ)) error((char *)"File not found"); MMgetline(fnbr, (char*)buff); // get the input line while (buff[0] == 39)MMgetline(fnbr, (char*)buff); z=buff; { getargs(&z,5,(unsigned char *)", "); width=getinteger(argv[0]); number=getinteger(argv[2]); if(argc==5)height=getinteger(argv[4]); if (height == 0)height = width; bnbr = startsprite; if (number + startsprite > MAXBLITBUF) { FileClose(fnbr); error((char *)"Maximum of % sprites",MAXBLITBUF); } while (!MMfeof(fnbr) && bnbr <= number + startsprite) { // while waiting for the end of file if (newsprite) { newsprite = 0; if (spritebuff[bnbr].spritebuffptr == NULL)spritebuff[bnbr].spritebuffptr = (char *)GetMemory((width * height + 1)>>1); if (spritebuff[bnbr].blitstoreptr == NULL)spritebuff[bnbr].blitstoreptr = (char*)GetMemory((width * height + 1)>>1); spritebuff[bnbr].w = width; spritebuff[bnbr].h = height; spritebuff[bnbr].master = 0; spritebuff[bnbr].mymaster = -1; spritebuff[bnbr].x = 10000; spritebuff[bnbr].y = 10000; spritebuff[bnbr].layer = -1; spritebuff[bnbr].next_x = 10000; spritebuff[bnbr].next_y = 10000; spritebuff[bnbr].active = false; spritebuff[bnbr].lastcollisions = 0; spritebuff[bnbr].edges = 0; q = spritebuff[bnbr].spritebuffptr; lc = height; } while (lc--) { MMgetline(fnbr, (char*)buff); // get the input line while (buff[0] == 39)MMgetline(fnbr, (char*)buff); if ((int)strlen((char*)buff) < width)memset(&buff[strlen((char*)buff)], 32, width - strlen((char*)buff)); for (i = 0; i < width; i++) { if(mode){ if (buff[i] == ' ')data = 0; else if (buff[i] == '0')data = BLACK; else if (buff[i] == '1')data = BLUE; else if (buff[i] == '2')data = MYRTLE; else if (buff[i] == '3')data = COBALT; else if (buff[i] == '4')data = MIDGREEN; else if (buff[i] == '5')data = CERULEAN; else if (buff[i] == '6')data = GREEN; else if (buff[i] == '7')data = CYAN; else if (buff[i] == '8')data = RED; else if (buff[i] == '9')data = MAGENTA; else if (buff[i] == 'A' || buff[i] == 'a')data = RUST; else if (buff[i] == 'B' || buff[i] == 'b')data = FUCHSIA; else if (buff[i] == 'C' || buff[i] == 'c')data = BROWN; else if (buff[i] == 'D' || buff[i] == 'd')data = LILAC; else if (buff[i] == 'E' || buff[i] == 'e')data = YELLOW; else if (buff[i] == 'F' || buff[i] == 'f')data = WHITE; else data = 0; } else { if (buff[i] == ' ')data = 0; else if (buff[i] == '0')data = BLACK; else if (buff[i] == '1')data = BLUE; else if (buff[i] == '2')data = GREEN; else if (buff[i] == '3')data = CYAN; else if (buff[i] == '4')data = RED; else if (buff[i] == '5')data = MAGENTA; else if (buff[i] == '6')data = YELLOW; else if (buff[i] == '7')data = WHITE; else if (buff[i] == '8')data = MYRTLE; else if (buff[i] == '9')data = COBALT; else if (buff[i] == 'A' || buff[i] == 'a')data = MIDGREEN; else if (buff[i] == 'B' || buff[i] == 'b')data = CERULEAN; else if (buff[i] == 'C' || buff[i] == 'c')data = RUST; else if (buff[i] == 'D' || buff[i] == 'd')data = FUCHSIA; else if (buff[i] == 'E' || buff[i] == 'e')data = BROWN; else if (buff[i] == 'F' || buff[i] == 'f')data = LILAC; else data = 0; } if(toggle){ *q++ |= (RGB121(data)<<4); } else { *q=RGB121(data); } toggle=!toggle; } } bnbr++; newsprite = 1; } FileClose(fnbr); } } void MIPS16 loadarray(unsigned char* p) { int bnbr, w, h, size, i, toggle=0; int maxH = VRes; int maxW =HRes; MMFLOAT* a3float = NULL; int64_t* a3int = NULL; char* q; // uint16_t* qq; // uint32_t* qqq; getargs(&p, 7, (unsigned char *)","); if (*argv[0] == '#') argv[0]++; bnbr = (int)getint(argv[0], 1, MAXBLITBUF); if (spritebuff[bnbr].spritebuffptr == NULL) { w = (int)getint(argv[2], 1, maxW); h = (int)getint(argv[4], 1, maxH); size=parsenumberarray(argv[6],&a3float,&a3int,4,1,NULL,true)-1; if (size < w * h - 1)error((char *)"Array Dimensions"); spritebuff[bnbr].spritebuffptr = (char *)GetMemory((w * h + 1)>>1); spritebuff[bnbr].blitstoreptr = (char *)GetMemory((w * h + 1)>>1); spritebuff[bnbr].w = w; spritebuff[bnbr].h = h; spritebuff[bnbr].master = 0; spritebuff[bnbr].mymaster = -1; spritebuff[bnbr].x = 10000; spritebuff[bnbr].y = 10000; spritebuff[bnbr].layer = -1; spritebuff[bnbr].next_x = 10000; spritebuff[bnbr].next_y = 10000; spritebuff[bnbr].active = false; spritebuff[bnbr].lastcollisions = 0; spritebuff[bnbr].edges = 0; q = spritebuff[bnbr].spritebuffptr; int c; for (i = 0; i < w * h; i++) { if (a3float)c = (int)a3float[i]; else c = (int)a3int[i]; if(toggle){ *q++ |= (RGB121(c)<<4); } else { *q=RGB121(c); } toggle=!toggle; } } else error((char *)"Buffer already in use"); } void ScrollBufferH(int pixels) { if (!pixels)return; volatile uint8_t *s, *d, *l, *ss, *dd; int y; if(HRes==320 && !(pixels & 1)){ if (pixels > 0) { for (y = 0; y < VRes; y++) { s = (((y * HRes )>>1) + WriteBuf); d = s + (pixels>>1); memmove((void *)d,(void *)s,160-(pixels>>1)); } } else { pixels = -pixels; for (y = 0; y < VRes; y++) { s = (((y * HRes )>>1) + WriteBuf); d=s; s+=(pixels>>1); memmove((void *)d,(void *)s,160-(pixels>>1)); } } } else { ss=GetTempMemory(HRes); dd=GetTempMemory(HRes); if (pixels > 0) { for (y = 0; y < VRes; y++) { l = (((y * HRes )>>(HRes==320?1:3)) + WriteBuf); s=ss; d=dd + pixels; expandpixel(l,s,HRes,(HRes==320?0:1)); memcpy((void *)d,(void *)s,(HRes - pixels)); contractpixel(dd,l,HRes,(HRes==320?0:1)); } } else { pixels = -pixels; for (y = 0; y < VRes; y++) { l = (((y * HRes )>>(HRes==320?1:3)) + WriteBuf); s=ss; d=dd; expandpixel(l,s,HRes,(HRes==320?0:1)); s += pixels; memcpy((void *)d,(void *)s,(HRes - pixels)); contractpixel(d,l,HRes,(HRes==320?0:1)); } } } } void ScrollBufferV(int lines, int blank) { uint8_t* s, * d; int y, yy; if(HRes==320){ int n = (HRes>>1); if (lines > 0) { for (y = 0; y < VRes - lines; y++) { yy = y + lines; d = (uint8_t*)(((y * HRes )>>1) + WriteBuf); s = (uint8_t*)(((yy * HRes )>>1) + WriteBuf); memcpy(d, s, n); } if (blank) { DrawRectangle(0, VRes - lines, HRes - 1, VRes - 1, gui_bcolour); // erase the line to be scrolled off } } else if (lines < 0) { lines = -lines; for (y = VRes - 1; y >= lines; y--) { yy = y - lines; d = (uint8_t*)(((y * HRes)>>1) + WriteBuf); s = (uint8_t*)(((yy * HRes )>>1) + WriteBuf); memcpy(d, s, n); } if (blank)DrawRectangle(0, 0, HRes - 1, lines - 1, gui_bcolour); // erase the line to be scrolled off } } else { int n = (HRes>>3); if (lines > 0) { for (y = 0; y < VRes - lines; y++) { yy = y + lines; d = (uint8_t*)(((y * HRes )>>3) + WriteBuf); s = (uint8_t*)(((yy * HRes )>>3) + WriteBuf); memcpy(d, s, n); } if (blank) { DrawRectangle(0, VRes - lines, HRes - 1, VRes - 1, gui_bcolour); // erase the line to be scrolled off } } else if (lines < 0) { lines = -lines; for (y = VRes - 1; y >= lines; y--) { yy = y - lines; d = (uint8_t*)(((y * HRes)>>3) + WriteBuf); s = (uint8_t*)(((yy * HRes )>>3) + WriteBuf); memcpy(d, s, n); } if (blank)DrawRectangle(0, 0, HRes - 1, lines - 1, gui_bcolour); // erase the line to be scrolled off } } } /* @endcond */ void cmd_sprite(void) { int x1, y1, w, h, bnbr; unsigned char *p; int maxW = HRes; int maxH = VRes; int newb = 0; #ifndef PICOMITEVGA if(WriteBuf==NULL)error("Not available on physical display"); #endif if(Option.DISPLAY_TYPE == 0) error("Display not configured"); if(DISPLAY_TYPE==SCREENMODE4 || DISPLAY_TYPE==SCREENMODE5 )error("Not available for this display mode"); if ((p = checkstring(cmdline, (unsigned char *)"SHOW SAFE"))) { int layer, mode=1; getargs(&p, 11, (unsigned char*)","); if (!(argc == 7 || argc == 9 || argc == 11)) error((char *)"Syntax"); if (hideall)error((char *)"Sprites are hidden"); if (*argv[0] == '#') argv[0]++; bnbr = (int)getint(argv[0], 1, MAXBLITBUF); // get the number if(spritebuff[bnbr].h==9999)error("Invalid buffer"); if (spritebuff[bnbr].spritebuffptr != NULL) { x1 = (int)getint(argv[2], -spritebuff[bnbr].w + 1, maxW - 1); y1 = (int)getint(argv[4], -spritebuff[bnbr].h + 1, maxH - 1); layer = (int)getint(argv[6], 0, MAXLAYER); if (argc >= 9 && *argv[8])spritebuff[bnbr].rotation = (char)getint(argv[8], 0, 7); else spritebuff[bnbr].rotation = 0; if(spritebuff[bnbr].rotation>3){ mode |=8; spritebuff[bnbr].rotation&=3; } if (argc == 11 && *argv[10]) { newb = (int)getint(argv[10], 0, 1); } // q = spritebuff[bnbr].spritebuffptr; w = spritebuff[bnbr].w; h = spritebuff[bnbr].h; if (spritebuff[bnbr].active) { if (newb) { hidesafe(bnbr); spritebuff[bnbr].layer = layer; layer_in_use[spritebuff[bnbr].layer]++; if (spritebuff[bnbr].layer == 0) zeroLIFOadd(bnbr); else LIFOadd(bnbr); sprites_in_use++; BlitShowBuffer(bnbr, x1, y1, mode); } else { showsafe(bnbr, x1, y1); } } else { spritebuff[bnbr].layer = layer; layer_in_use[spritebuff[bnbr].layer]++; if (spritebuff[bnbr].layer == 0) zeroLIFOadd(bnbr); else LIFOadd(bnbr); sprites_in_use++; BlitShowBuffer(bnbr, x1, y1, mode); } ProcessCollisions(bnbr); if (sprites_in_use != LIFOpointer + zeroLIFOpointer || sprites_in_use != sumlayer())error((char *)"sprite internal error"); } else error((char *)"Buffer not in use"); } else if ((p = checkstring(cmdline, (unsigned char*)"SHOW"))) { int layer, mode=1; getargs(&p, 9, (unsigned char*)","); if (!(argc == 7 || argc == 9)) error((char *)"Syntax"); if (hideall)error((char *)"Sprites are hidden"); if (*argv[0] == '#') argv[0]++; bnbr = (int)getint(argv[0], 1, MAXBLITBUF); // get the number if(spritebuff[bnbr].h==9999)error("Invalid buffer"); if (spritebuff[bnbr].spritebuffptr != NULL) { x1 = (int)getint(argv[2], -spritebuff[bnbr].w + 1, maxW - 1); y1 = (int)getint(argv[4], -spritebuff[bnbr].h + 1, maxH - 1); layer = (int)getint(argv[6], 0, MAXLAYER); if (argc == 9)spritebuff[bnbr].rotation = (int)getint(argv[8], 0, 7); else spritebuff[bnbr].rotation = 0; if(spritebuff[bnbr].rotation>3){ mode |=8; spritebuff[bnbr].rotation&=3; } w = spritebuff[bnbr].w; h = spritebuff[bnbr].h; if (spritebuff[bnbr].active) { layer_in_use[spritebuff[bnbr].layer]--; if (spritebuff[bnbr].layer == 0)zeroLIFOremove(bnbr); else LIFOremove(bnbr); sprites_in_use--; } spritebuff[bnbr].layer = layer; layer_in_use[spritebuff[bnbr].layer]++; if (spritebuff[bnbr].layer == 0) zeroLIFOadd(bnbr); else LIFOadd(bnbr); sprites_in_use++; // int cursorhidden = 0; BlitShowBuffer(bnbr, x1, y1, mode); ProcessCollisions(bnbr); if (sprites_in_use != LIFOpointer + zeroLIFOpointer || sprites_in_use != sumlayer())error((char *)"sprite internal error"); } else error((char *)"Buffer not in use"); } else if ((p = checkstring(cmdline, (unsigned char*)"HIDE ALL"))) { if (hideall)error((char *)"Sprites are hidden"); int i; // int cursorhidden = 0; for (i = LIFOpointer - 1; i >= 0; i--) { blithide(LIFO[i], 0); } for (i = zeroLIFOpointer - 1; i >= 0; i--) { blithide(zeroLIFO[i], 0); } hideall = 1; } else if ((p = checkstring(cmdline, (unsigned char*)"RESTORE"))) { if (!hideall)error((char *)"Sprites are not hidden"); int i; // int cursorhidden = 0; for (i = 0; i < zeroLIFOpointer; i++) { BlitShowBuffer(zeroLIFO[i], spritebuff[zeroLIFO[i]].x, spritebuff[zeroLIFO[i]].y, 0); } for (i = 0; i < LIFOpointer; i++) { if (spritebuff[LIFO[i]].next_x != 10000) { spritebuff[LIFO[i]].x = spritebuff[LIFO[i]].next_x; spritebuff[LIFO[i]].next_x = 10000; } if (spritebuff[LIFO[i]].next_y != 10000) { spritebuff[LIFO[i]].y = spritebuff[LIFO[i]].next_y; spritebuff[LIFO[i]].next_y = 10000; } BlitShowBuffer(LIFO[i], spritebuff[LIFO[i]].x, spritebuff[LIFO[i]].y, 0); } hideall = 0; ProcessCollisions(0); } else if ((p = checkstring(cmdline, (unsigned char*)"HIDE SAFE"))) { getargs(&p, 1, (unsigned char*)","); if (sprites_in_use != LIFOpointer + zeroLIFOpointer || sprites_in_use != sumlayer())error((char *)"sprite internal error"); if (argc != 1) error((char *)"Syntax"); if (*argv[0] == '#') argv[0]++; bnbr = (int)getint(argv[0], 1, MAXBLITBUF); // get the number if (hideall)error((char *)"Sprites are hidden"); if (spritebuff[bnbr].spritebuffptr != NULL) { if (spritebuff[bnbr].active) { // int cursorhidden = 0; hidesafe(bnbr); if (sprites_in_use != LIFOpointer + zeroLIFOpointer || sprites_in_use != sumlayer())error((char *)"sprite internal error"); } else error((char *)"Not Showing"); } else error((char *)"Buffer not in use"); } else if ((p = checkstring(cmdline, (unsigned char*)"HIDE"))) { getargs(&p, 1, (unsigned char*)","); if (argc != 1) error((char *)"Syntax"); if (*argv[0] == '#') argv[0]++; bnbr = (int)getint(argv[0], 1, MAXBLITBUF); // get the number if (spritebuff[bnbr].spritebuffptr != NULL) { if (spritebuff[bnbr].active) { sprites_in_use--; // int cursorhidden = 0; blithide(bnbr, 0); layer_in_use[spritebuff[bnbr].layer]--; spritebuff[bnbr].x = 10000; spritebuff[bnbr].y = 10000; if (spritebuff[bnbr].layer == 0)zeroLIFOremove(bnbr); else LIFOremove(bnbr); spritebuff[bnbr].layer = -1; spritebuff[bnbr].next_x = 10000; spritebuff[bnbr].next_y = 10000; spritebuff[bnbr].lastcollisions = 0; spritebuff[bnbr].edges = 0; } else error((char *)"Not Showing"); } else error((char *)"Buffer not in use"); if (sprites_in_use != LIFOpointer + zeroLIFOpointer || sprites_in_use != sumlayer())error((char *)"sprite internal error"); // } else if ((p = checkstring(cmdline, (unsigned char*)"SWAP"))) { int rbnbr=0, mode=2; int64_t master; signed char mymaster; getargs(&p, 5, (unsigned char*)","); if (argc < 3) error((char *)"Syntax"); if (hideall)error((char *)"Sprites are hidden"); if (*argv[0] == '#') argv[0]++; bnbr = (int)getint(argv[0], 1, MAXBLITBUF); // get the number if (*argv[2] == '#') argv[0]++; rbnbr = (int)getint(argv[2], 1, MAXBLITBUF); // get the number if (spritebuff[bnbr].spritebuffptr == NULL || spritebuff[bnbr].active == false) error((char *)"Original buffer not displayed"); if (!spritebuff[bnbr].active)error((char *)"Original buffer not displayed"); // if (spritebuff[bnbr].master == -1)error((char *)"Can't swap a copy"); if (spritebuff[rbnbr].active) error((char *)"New buffer already displayed"); // if (spritebuff[rbnbr].master == -1)error((char *)"Can't swap a copy"); if (!(spritebuff[rbnbr].w == spritebuff[bnbr].w && spritebuff[rbnbr].h == spritebuff[bnbr].h)) error((char *)"Size mismatch"); // copy the relevant data master=spritebuff[rbnbr].master; mymaster=spritebuff[rbnbr].mymaster; spritebuff[rbnbr].master=spritebuff[bnbr].master; spritebuff[rbnbr].mymaster=spritebuff[bnbr].mymaster; spritebuff[rbnbr].blitstoreptr = spritebuff[bnbr].blitstoreptr; spritebuff[rbnbr].x = spritebuff[bnbr].x; spritebuff[rbnbr].y = spritebuff[bnbr].y; spritebuff[rbnbr].layer = spritebuff[bnbr].layer; spritebuff[rbnbr].lastcollisions = spritebuff[bnbr].lastcollisions; if (spritebuff[rbnbr].layer == 0)zeroLIFOswap(bnbr, rbnbr); else LIFOswap(bnbr, rbnbr); // "Hide" the old sprite spritebuff[bnbr].master=master; spritebuff[bnbr].mymaster=mymaster; spritebuff[bnbr].x = 10000; spritebuff[bnbr].y = 10000; spritebuff[bnbr].layer = -1; spritebuff[bnbr].next_x = 10000; spritebuff[bnbr].next_y = 10000; spritebuff[bnbr].active = 0; spritebuff[bnbr].lastcollisions = 0; if (argc == 5)spritebuff[rbnbr].rotation = (int)getint(argv[4], 0, 7); else spritebuff[bnbr].rotation = 0; if(spritebuff[rbnbr].rotation>3){ mode |=8; spritebuff[rbnbr].rotation&=3; } BlitShowBuffer(rbnbr, spritebuff[rbnbr].x, spritebuff[rbnbr].y, mode); if (sprites_in_use != LIFOpointer + zeroLIFOpointer || sprites_in_use != sumlayer())error((char *)"sprite internal error"); } else if ((p = checkstring(cmdline, (unsigned char*)"READ"))) { getargs(&p, 11, (unsigned char*)","); if (!(argc == 9)) error((char *)"Syntax"); if (*argv[0] == '#') argv[0]++; bnbr = (int)getint(argv[0], 1, MAXBLITBUF); // get the number x1 = (int)getinteger(argv[2]); y1 = (int)getinteger(argv[4]); w = (int)getinteger(argv[6]); h = (int)getinteger(argv[8]); if (w < 1 || h < 1) return; if (spritebuff[bnbr].spritebuffptr == NULL) { spritebuff[bnbr].spritebuffptr = (char *)GetMemory((w * h +1)>>1 ); spritebuff[bnbr].blitstoreptr = (char*)GetMemory((w * h +1)>>1 ); spritebuff[bnbr].w = w; spritebuff[bnbr].h = h; spritebuff[bnbr].master = 0; spritebuff[bnbr].mymaster = -1; spritebuff[bnbr].x = 10000; spritebuff[bnbr].y = 10000; spritebuff[bnbr].layer = -1; spritebuff[bnbr].next_x = 10000; spritebuff[bnbr].next_y = 10000; spritebuff[bnbr].active = false; spritebuff[bnbr].lastcollisions = 0; spritebuff[bnbr].edges = 0; } else { if (spritebuff[bnbr].mymaster != -1) error((char *)"Can't read into a copy", bnbr); if (spritebuff[bnbr].master > 0) error((char *)"Copies exist", bnbr); if (!(spritebuff[bnbr].w == w && spritebuff[bnbr].h == h))error((char *)"Existing buffer is incorrect size"); } ReadBufferFast(x1, y1, x1 + w - 1, y1 + h - 1,(unsigned char *)spritebuff[bnbr].spritebuffptr); } else if ((p = checkstring(cmdline, (unsigned char*)"COPY"))) { int cpy, nbr, c1, n1; getargs(&p, 5, (unsigned char*)","); if (argc != 5) error((char *)"Syntax"); if (*argv[0] == '#') argv[0]++; bnbr = (int)getint(argv[0], 1, MAXBLITBUF); // get the number if (spritebuff[bnbr].spritebuffptr != NULL) { if (*argv[2] == '#') argv[2]++; c1 = cpy = (int)getint(argv[2], 1, MAXBLITBUF); n1 = nbr = (int)getint(argv[4], 1, MAXBLITBUF - 1); while (n1) { if (spritebuff[c1].spritebuffptr != NULL)error((char *)"Buffer already in use %", c1); if (spritebuff[bnbr].master == -1)error((char *)"Can't copy a copy");; n1--; c1++; } while (nbr) { spritebuff[cpy].spritebuffptr = spritebuff[bnbr].spritebuffptr; spritebuff[cpy].w = spritebuff[bnbr].w; spritebuff[cpy].h = spritebuff[bnbr].h; spritebuff[cpy].blitstoreptr = (char *)GetMemory((spritebuff[cpy].w * spritebuff[cpy].h +1)>>1); spritebuff[cpy].x = 10000; spritebuff[cpy].y = 10000; spritebuff[cpy].next_x = 10000; spritebuff[cpy].next_y = 10000; spritebuff[cpy].layer = -1; spritebuff[cpy].mymaster = bnbr; spritebuff[cpy].master = -1; spritebuff[cpy].edges = 0; spritebuff[bnbr].master |= ((int64_t)1 << (int64_t)cpy); spritebuff[bnbr].lastcollisions = 0; spritebuff[cpy].active = false; nbr--; cpy++; } } else error((char *)"Buffer not in use"); } else if ((p = checkstring(cmdline, (unsigned char*)"LOADARRAY"))) { loadarray(p); } else if ((p = checkstring(cmdline, (unsigned char *)"LOAD"))) { loadsprite(p); return; } else if ((p = checkstring(cmdline, (unsigned char*)"INTERRUPT"))) { getargs(&p, 1, (unsigned char*)","); COLLISIONInterrupt = (char*)GetIntAddress(argv[0]); // get the interrupt location InterruptUsed = true; return; } else if ((p = checkstring(cmdline, (unsigned char*)"NOINTERRUPT"))) { COLLISIONInterrupt = NULL; // get the interrupt location return; } else if ((p = checkstring(cmdline, (unsigned char*)"CLOSE ALL"))) { closeallsprites(); } else if ((p = checkstring(cmdline, (unsigned char*)"CLOSE"))) { getargs(&p, 1, (unsigned char*)","); if (hideall)error((char *)"Sprites are hidden"); if (*argv[0] == '#') argv[0]++; bnbr = (int)getint(argv[0], 1, MAXBLITBUF); if (spritebuff[bnbr].master > 0) error((char *)"Copies still open"); if (spritebuff[bnbr].spritebuffptr != NULL) { if (spritebuff[bnbr].active) { blithide(bnbr, 1); if (spritebuff[bnbr].layer == 0)zeroLIFOremove(bnbr); else LIFOremove(bnbr); layer_in_use[spritebuff[bnbr].layer]--; sprites_in_use--; } if (spritebuff[bnbr].mymaster == -1)FreeMemorySafe((void**)&spritebuff[bnbr].spritebuffptr); else spritebuff[spritebuff[bnbr].mymaster].master &= ~(1 << bnbr); FreeMemorySafe((void**)&spritebuff[bnbr].blitstoreptr); spritebuff[bnbr].spritebuffptr = NULL; spritebuff[bnbr].blitstoreptr = NULL; spritebuff[bnbr].master = -1; spritebuff[bnbr].mymaster = -1; spritebuff[bnbr].x = 10000; spritebuff[bnbr].y = 10000; spritebuff[bnbr].w = 0; spritebuff[bnbr].h = 0; spritebuff[bnbr].next_x = 10000; spritebuff[bnbr].next_y = 10000; spritebuff[bnbr].layer = -1; spritebuff[bnbr].active = false; spritebuff[bnbr].edges = 0; } else error((char *)"Buffer not in use"); if (sprites_in_use != LIFOpointer + zeroLIFOpointer || sprites_in_use != sumlayer())error((char *)"sprite internal error"); } else if ((p = checkstring(cmdline, (unsigned char*)"NEXT"))) { getargs(&p, 5, (unsigned char*)","); if (!(argc == 5)) error((char *)"Syntax"); if (*argv[0] == '#') argv[0]++; bnbr = (int)getint(argv[0], 1, MAXBLITBUF); // get the number spritebuff[bnbr].next_x = (short)getint(argv[2], -spritebuff[bnbr].w + 1, maxW - 1); spritebuff[bnbr].next_y = (short)getint(argv[4], -spritebuff[bnbr].h + 1, maxH - 1); // } else if ((p = checkstring(cmdline, (unsigned char*)"WRITE"))) { int mode = 4; getargs(&p, 7, (unsigned char*)","); if (!(argc == 5 || argc == 7)) error((char *)"Syntax"); if (*argv[0] == '#') argv[0]++; bnbr = (int)getint(argv[0], 1, MAXBLITBUF); // get the number if(spritebuff[bnbr].h==9999)error("Invalid buffer"); if (spritebuff[bnbr].spritebuffptr != NULL) { x1 = (int)getint(argv[2], -spritebuff[bnbr].w + 1, maxW); y1 = (int)getint(argv[4], -spritebuff[bnbr].h + 1, maxH); if (argc == 7)spritebuff[bnbr].rotation = (char)getint(argv[6], 0, 7); else spritebuff[bnbr].rotation = 4; if ((spritebuff[bnbr].rotation & 4) == 0)mode |= 8; spritebuff[bnbr].rotation &= 3; w = spritebuff[bnbr].w; h = spritebuff[bnbr].h; // int cursorhidden = 0; BlitShowBuffer(bnbr, x1, y1, mode); } else error((char *)"Buffer not in use"); } #ifdef rp2350 else if((p = checkstring(cmdline, (unsigned char *)"LOADPNG"))) { int toggle=0, transparent=0, cutoff=30; int w,h; upng_t* upng; // get the command line arguments getargs(&p, 11, (unsigned char *)","); // this MUST be the first executable line in the function if(*argv[0] == '#') argv[0]++; // check if the first arg is prefixed with a # bnbr = getint(argv[0], 1, MAXBLITBUF); // get the buffer number if(spritebuff[bnbr].spritebuffptr)error("Buffer % in use",bnbr); if(argc == 0) error("Argument count"); if(!InitSDCard()) return; unsigned char *q = getFstring(argv[2]); // get the file name if(argc >= 5 && *argv[4])transparent=getint(argv[4],0,15); transparent=RGB121map[transparent]; if(argc==7)cutoff=getint(argv[6],1,254); if(strchr((char *)q, '.') == NULL) strcat((char *)q, ".png"); upng = upng_new_from_file((char *)q); routinechecks(); upng_header(upng); w=upng_get_width(upng); h= upng_get_height(upng); spritebuff[bnbr].spritebuffptr = GetMemory((w * h + 4 )>>1); spritebuff[bnbr].blitstoreptr = GetMemory((w * h + 4 )>>1); spritebuff[bnbr].w=w; spritebuff[bnbr].h=h; spritebuff[bnbr].master = 0; spritebuff[bnbr].mymaster = -1; spritebuff[bnbr].x = 10000; spritebuff[bnbr].y = 10000; spritebuff[bnbr].layer = -1; spritebuff[bnbr].next_x = 10000; spritebuff[bnbr].next_y = 10000; spritebuff[bnbr].active = false; spritebuff[bnbr].lastcollisions = 0; spritebuff[bnbr].edges = 0; unsigned char *t=(unsigned char *)spritebuff[bnbr].spritebuffptr; if(w>HRes|| h >VRes){ upng_free(upng); error("Image too large"); } if(!(upng_get_format(upng)==3)){ upng_free(upng); error("Invalid format, must be RGBA8888"); } routinechecks(); upng_decode(upng); unsigned char *rr; routinechecks(); rr=(unsigned char *)upng_get_buffer(upng); unsigned char *pp=rr; char d[3]; int i=w*h; while(i--){ d[0]=rr[2]; d[1]=rr[1]; d[2]=rr[0]; if(rr[3]>cutoff){ pp[0]=d[0]; pp[1]=d[1]; pp[2]=d[2]; } else { pp[0]=(transparent & 0xFF0000)>>16; pp[1]=(transparent & 0xFF00)>>8; pp[2]=(transparent & 0xFF); } if(DISPLAY_TYPE==SCREENMODE1) { if(toggle){ *t |= (char)(((uint16_t)pp[2]+(uint16_t)pp[1]+(uint16_t)pp[0])<0x180? 0 : 0xF0); } else { *t= (char)(((uint16_t)pp[2]+(uint16_t)pp[1]+(uint16_t)pp[0])<0x180? 0 : 0xF); } } else { if(toggle){ *t |= ((pp[2] & 0x80)) | ((pp[1] & 0xC0)>>1) | ((pp[0] & 0x80)>>3); } else { *t = ((pp[2] & 0x80)>> 4) | ((pp[1] & 0xC0)>>5) | ((pp[0] & 0x80)>>7); } } if(toggle) t++; toggle=!toggle; pp+=3; rr+=4; } upng_free(upng); return; } #endif else if((p = checkstring(cmdline, (unsigned char *)"LOADBMP"))) { int fnbr,toggle=0; int xOrigin, yOrigin, xlen, ylen; BMPDECODER BmpDec; // get the command line arguments getargs(&p, 11, (unsigned char *)","); // this MUST be the first executable line in the function if(*argv[0] == '#') argv[0]++; // check if the first arg is prefixed with a # bnbr = getint(argv[0], 1, MAXBLITBUF); // get the buffer number if(spritebuff[bnbr].spritebuffptr)error("Buffer % in use",bnbr); if(argc == 0) error("Argument count"); if(!InitSDCard()) return; unsigned char *pp = getFstring(argv[2]); // get the file name xOrigin = yOrigin = 0; if(argc >= 5 && *argv[4]) xOrigin = getinteger(argv[4]); // get the x origin (optional) argument if(argc >= 7 && *argv[6]) yOrigin = getinteger(argv[6]); // get the y origin (optional) argument if(xOrigin<0 || yOrigin<0)error("Coordinates"); xlen = ylen =-1; if(argc >= 9 && *argv[8]) xlen = getinteger(argv[8]); // get the x length (optional) argument if(argc == 11 ) ylen = getinteger(argv[10]); // get the y length (optional) argument // open the file if(strchr((char *)pp, '.') == NULL) strcat((char *)pp, ".bmp"); fnbr = FindFreeFileNbr(); if(!BasicFileOpen((char *)pp, fnbr, FA_READ)) return; BDEC_bReadHeader(&BmpDec, fnbr); FileClose(fnbr); if(xlen==-1)xlen=BmpDec.lWidth; if(ylen==-1)ylen=BmpDec.lHeight; if(xlen+xOrigin>BmpDec.lWidth || ylen+yOrigin>BmpDec.lHeight)error("Coordinates"); char *q=GetTempMemory(xlen * ylen * 3); spritebuff[bnbr].spritebuffptr = GetMemory((xlen * ylen +4 )>>1); spritebuff[bnbr].blitstoreptr = GetMemory((xlen * ylen +4 )>>1); memset(q,0xFF,xlen * ylen * 3); fnbr = FindFreeFileNbr(); if(!BasicFileOpen((char *)pp, fnbr, FA_READ)) return; BMP_bDecode_memory(xOrigin, yOrigin, xlen, ylen, fnbr, q); spritebuff[bnbr].w=xlen; spritebuff[bnbr].h=ylen; spritebuff[bnbr].master = 0; spritebuff[bnbr].mymaster = -1; spritebuff[bnbr].x = 10000; spritebuff[bnbr].y = 10000; spritebuff[bnbr].layer = -1; spritebuff[bnbr].next_x = 10000; spritebuff[bnbr].next_y = 10000; spritebuff[bnbr].active = false; spritebuff[bnbr].lastcollisions = 0; spritebuff[bnbr].edges = 0; char *t=spritebuff[bnbr].spritebuffptr; int i=xlen*ylen; while(i--){ if(DISPLAY_TYPE==SCREENMODE1) { if(toggle){ *t |= (char)(((uint16_t)q[2]+(uint16_t)q[1]+(uint16_t)q[0])<0x180? 0 : 0xF0); } else { *t= (char)(((uint16_t)q[2]+(uint16_t)q[1]+(uint16_t)q[0])<0x180? 0 : 0xF); } } else { if(toggle){ *t |= ((q[2] & 0x80)) | ((q[1] & 0xC0)>>1) | ((q[0] & 0x80)>>3); } else { *t = ((q[2] & 0x80)>> 4) | ((q[1] & 0xC0)>>5) | ((q[0] & 0x80)>>7); } } if(toggle) t++; toggle=!toggle; q+=3; } FileClose(fnbr); return; } else if ((p = checkstring(cmdline, (unsigned char*)"MOVE"))) { if (hideall)error((char *)"Sprites are hidden"); int i; // int cursorhidden = 0; for (i = LIFOpointer - 1; i >= 0; i--) blithide(LIFO[i], 0); for (i = zeroLIFOpointer - 1; i >= 0; i--)blithide(zeroLIFO[i], 0); // for (i = 0; i < zeroLIFOpointer; i++) { if (spritebuff[zeroLIFO[i]].next_x != 10000) { spritebuff[zeroLIFO[i]].x = spritebuff[zeroLIFO[i]].next_x; spritebuff[zeroLIFO[i]].next_x = 10000; } if (spritebuff[zeroLIFO[i]].next_y != 10000) { spritebuff[zeroLIFO[i]].y = spritebuff[zeroLIFO[i]].next_y; spritebuff[zeroLIFO[i]].next_y = 10000; } BlitShowBuffer(zeroLIFO[i], spritebuff[zeroLIFO[i]].x, spritebuff[zeroLIFO[i]].y, 0); } for (i = 0; i < LIFOpointer; i++) { if (spritebuff[LIFO[i]].next_x != 10000) { spritebuff[LIFO[i]].x = spritebuff[LIFO[i]].next_x; spritebuff[LIFO[i]].next_x = 10000; } if (spritebuff[LIFO[i]].next_y != 10000) { spritebuff[LIFO[i]].y = spritebuff[LIFO[i]].next_y; spritebuff[LIFO[i]].next_y = 10000; } BlitShowBuffer(LIFO[i], spritebuff[LIFO[i]].x, spritebuff[LIFO[i]].y, 0); } ProcessCollisions(0); } else if ((p = checkstring(cmdline, (unsigned char*)"SCROLL"))) { int i, n, m = 0, blank = -2, x, y; char* current = NULL; getargs(&p, 5, (unsigned char*)","); if (hideall)error((char *)"Sprites are hidden"); x = (int)getint(argv[0], -maxW / 2 - 1, maxW); y = (int)getint(argv[2], -maxH / 2 - 1, maxH); if (argc == 5)blank = (int)getColour((char *)argv[2], 1); if (!(x == 0 && y == 0)) { m = ((maxW * (y > 0 ? y : -y)+1) >>1); n = ((maxH * (x > 0 ? x : -x)+1) >>1); if (n > m)m = n; if (blank == -2)current = (char *)GetMemory(m); for (i = LIFOpointer - 1; i >= 0; i--) blithide(LIFO[i], 0); for (i = zeroLIFOpointer - 1; i >= 0; i--) { int xs = spritebuff[zeroLIFO[i]].x + (spritebuff[zeroLIFO[i]].w >> 1); int ys = spritebuff[zeroLIFO[i]].y + (spritebuff[zeroLIFO[i]].h >> 1); blithide(zeroLIFO[i], 0); xs += x; if (xs >= maxW)xs -= maxW; if (xs < 0)xs += maxW; spritebuff[zeroLIFO[i]].x = xs - (spritebuff[zeroLIFO[i]].w >> 1); ys -= y; if (ys >= maxH)ys -= maxH; if (ys < 0)ys += maxH; spritebuff[zeroLIFO[i]].y = ys - (spritebuff[zeroLIFO[i]].h >> 1); } if (x > 0) { if (blank == -2)ReadBufferFast(maxW - x, 0, maxW - 1, maxH - 1, (unsigned char *)current); ScrollBufferH(x); if (blank == -2)DrawBufferFast(0, 0, x - 1, maxH - 1, -1, (unsigned char *)current); else if (blank != -1)DrawRectangle(0, 0, x - 1, maxH - 1, blank); } else if (x < 0) { x = -x; if (blank == -2)ReadBufferFast(0, 0, x - 1, maxH - 1, (unsigned char *)current); ScrollBufferH(-x); if (blank == -2)DrawBufferFast(maxW - x, 0, maxW - 1, maxH - 1, -1, (unsigned char *)current); else if (blank != -1)DrawRectangle(maxW - x, 0, maxW - 1, maxH - 1, blank); } if (y > 0) { if (blank == -2)ReadBufferFast(0, 0, maxW - 1, y - 1, (unsigned char *)current); ScrollBufferV(y, 0); if (blank == -2)DrawBufferFast(0, maxH - y, maxW - 1, maxH - 1, -1, (unsigned char *)current); else if (blank != -1)DrawRectangle(0, maxH - y, maxW - 1, maxH - 1, blank); } else if (y < 0) { y = -y; if (blank == -2)ReadBufferFast(0, maxH - y, maxW - 1, maxH - 1, (unsigned char *)current); ScrollBufferV(-y, 0); if (blank == -2)DrawBufferFast(0, 0, maxW - 1, y - 1, -1, (unsigned char *)current); else if (blank != -1)DrawRectangle(0, 0, maxW - 1, y - 1, blank); } for (i = 0; i < zeroLIFOpointer; i++) { BlitShowBuffer(zeroLIFO[i], spritebuff[zeroLIFO[i]].x, spritebuff[zeroLIFO[i]].y, 0); } for (i = 0; i < LIFOpointer; i++) { if (spritebuff[LIFO[i]].next_x != 10000) { spritebuff[LIFO[i]].x = spritebuff[LIFO[i]].next_x; spritebuff[LIFO[i]].next_x = 10000; } if (spritebuff[LIFO[i]].next_y != 10000) { spritebuff[LIFO[i]].y = spritebuff[LIFO[i]].next_y; spritebuff[LIFO[i]].next_y = 10000; } BlitShowBuffer(LIFO[i], spritebuff[LIFO[i]].x, spritebuff[LIFO[i]].y, 0); } ProcessCollisions(0); if (current)FreeMemory((unsigned char *)current); } } else if ((p = checkstring(cmdline, (unsigned char*)"SET TRANSPARENT"))) { sprite_transparent=getint((unsigned char *)p,0,15); } else error("Syntax"); } void fun_sprite(void) { int bnbr = 0, w = -1, h = -1, t = 0, x = 10000, y = 10000, l = 0, n, c = 0; getargs(&ep, 5, (unsigned char *)","); if (checkstring(argv[0], (unsigned char*)"W")) t = 1; else if (checkstring(argv[0], (unsigned char*)"H")) t = 2; else if (checkstring(argv[0], (unsigned char*)"X")) t = 3; else if (checkstring(argv[0], (unsigned char*)"Y")) t = 4; else if (checkstring(argv[0], (unsigned char*)"L")) t = 5; else if (checkstring(argv[0], (unsigned char*)"C")) t = 6; else if (checkstring(argv[0], (unsigned char*)"V")) t = 7; else if (checkstring(argv[0], (unsigned char*)"T")) t = 8; else if (checkstring(argv[0], (unsigned char*)"E")) t = 9; else if (checkstring(argv[0], (unsigned char*)"D")) t = 10; else if (checkstring(argv[0], (unsigned char*)"A")) t = 11; else if (checkstring(argv[0], (unsigned char*)"N")) t = 12; else if (checkstring(argv[0], (unsigned char*)"S")) t = 13; else error((char *)"Syntax"); if (t < 12) { if (argc < 3)error((char *)"Syntax"); if (*argv[2] == '#') argv[2]++; bnbr = (int)getint(argv[2], 0, MAXBLITBUF); if (bnbr == 0) { if (argc == 5 && !(t == 7 || t == 10)) { n = (int)getint(argv[4], 1, spritebuff[0].collisions[0]); c = spritebuff[0].collisions[n]; } else c = spritebuff[0].collisions[0]; } if (spritebuff[bnbr].spritebuffptr != NULL) { w = spritebuff[bnbr].w; h = spritebuff[bnbr].h; } if (spritebuff[bnbr].active) { x = spritebuff[bnbr].x; y = spritebuff[bnbr].y; l = spritebuff[bnbr].layer; if (argc == 5 && !(t == 7 || t == 10)) { n = (int)getint(argv[4], 1, spritebuff[bnbr].collisions[0]); c = spritebuff[bnbr].collisions[n]; } else c = spritebuff[bnbr].collisions[0]; } } if (t == 1)iret = w; else if (t == 2)iret = h; else if (t == 3) { if (spritebuff[bnbr].active)iret = x; else iret = 10000; } else if (t == 4) { if (spritebuff[bnbr].active)iret = y; else iret = 10000; } else if (t == 5) { if (spritebuff[bnbr].active)iret = l; else iret = -1; } else if (t == 8) { if (spritebuff[bnbr].active)iret = spritebuff[bnbr].lastcollisions; else iret = 0; } else if (t == 9) { if (spritebuff[bnbr].active)iret = spritebuff[bnbr].edges; else iret = 0; } else if (t == 6) { if (spritebuff[bnbr].collisions[0])iret = c; else iret = -1; } else if (t == 11) iret = (int64_t)((uint32_t)spritebuff[bnbr].spritebuffptr); else if (t == 7) { int rbnbr = 0; int x1 = 0, y1 = 0, h1 = 0, w1 = 0; MMFLOAT vector; if (argc < 5)error((char *)"Syntax"); if (*argv[4] == '#') argv[4]++; rbnbr = (int)getint(argv[4], 1, MAXBLITBUF); if (spritebuff[rbnbr].spritebuffptr != NULL) { w1 = spritebuff[rbnbr].w; h1 = spritebuff[rbnbr].h; } if (spritebuff[rbnbr].active) { x1 = spritebuff[rbnbr].x; y1 = spritebuff[rbnbr].y; } if (!(spritebuff[bnbr].active && spritebuff[rbnbr].active))fret = -1.0; else { x += w / 2; y += h / 2; x1 += w1 / 2; y1 += h1 / 2; y1 -= y; x1 -= x; vector = atan2(y1, x1); vector += M_PI_2; if (vector < 0)vector += M_TWOPI; fret = vector; } targ = T_NBR; return; } else if (t == 10) { int rbnbr = 0; int x1 = 0, y1 = 0, h1 = 0, w1 = 0; if (argc < 5)error((char *)"Syntax"); if (*argv[4] == '#') argv[4]++; rbnbr = (int)getint(argv[4], 1, MAXBLITBUF); if (spritebuff[rbnbr].spritebuffptr != NULL) { w1 = spritebuff[rbnbr].w; h1 = spritebuff[rbnbr].h; } if (spritebuff[rbnbr].active) { x1 = spritebuff[rbnbr].x; y1 = spritebuff[rbnbr].y; } if (!(spritebuff[bnbr].active && spritebuff[rbnbr].active))fret = -1.0; else { x += w / 2; y += h / 2; x1 += w1 / 2; y1 += h1 / 2; fret = sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y)); } targ = T_NBR; return; } else if (t == 12) { if (argc == 3) { n = (int)getint(argv[2], 0, MAXLAYER); iret = layer_in_use[n]; } else iret = sprites_in_use; } else if (t == 13) iret = sprite_which_collided; else { } targ = T_INT; } /* * @cond * The following section will be excluded from the documentation. */ #ifndef PICOMITEVGA void restorepanel(void){ if(Option.DISPLAY_TYPE>I2C_PANEL && Option.DISPLAY_TYPE < BufferedPanel){ if(Option.DISPLAY_ORIENTATION==PORTRAIT){ DrawRectangle = DrawRectangleSPISCR; DrawBitmap = DrawBitmapSPISCR; DrawBuffer = DrawBufferSPISCR; DrawPixel = DrawPixelNormal; DrawBLITBuffer = DrawBufferSPISCR; ScrollLCD = ScrollLCDSPISCR; if(Option.DISPLAY_TYPE == ILI9341 || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE == ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE == ST7789B){ ReadBuffer = ReadBufferSPISCR; ReadBLITBuffer = ReadBufferSPISCR; } } else { DrawRectangle = DrawRectangleSPI; DrawBitmap = DrawBitmapSPI; DrawBuffer = DrawBufferSPI; DrawPixel = DrawPixelNormal; DrawBLITBuffer = DrawBufferSPI; if(Option.DISPLAY_TYPE == ILI9341 || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE == ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE == ST7789B){ ReadBLITBuffer = ReadBufferSPI; ReadBuffer = ReadBufferSPI; ScrollLCD = ScrollLCDSPI; } } } else if(Option.DISPLAY_TYPE>=SSDPANEL && Option.DISPLAY_TYPE < VIRTUAL){ if(screen320){ DrawRectangle = DrawRectangle320; DrawBitmap = DrawBitmap320; DrawBuffer = DrawBuffer320; ReadBuffer = ReadBuffer320; } else { DrawRectangle= DrawRectangleSSD1963; DrawBitmap = DrawBitmapSSD1963; DrawBuffer = DrawBufferSSD1963; ReadBuffer = ReadBufferSSD1963; if(SSD16TYPE || Option.DISPLAY_TYPE==IPS_4_16){ DrawBLITBuffer= DrawBLITBufferSSD1963; ReadBLITBuffer = ReadBLITBufferSSD1963; } else { DrawBLITBuffer= DrawBufferSSD1963; ReadBLITBuffer = ReadBufferSSD1963; } } DrawPixel = DrawPixelNormal; if(!(Option.DISPLAY_TYPE == ILI9341_8 || Option.DISPLAY_TYPE == ILI9341_16 || Option.DISPLAY_TYPE == IPS_4_16 ))ScrollLCD = ScrollSSD1963; else ScrollLCD=ScrollLCDSPI; } WriteBuf=NULL; } void setframebuffer(void){ if(!((Option.DISPLAY_TYPE>I2C_PANEL && Option.DISPLAY_TYPE < BufferedPanel) || (Option.DISPLAY_TYPE>=SSDPANEL && Option.DISPLAY_TYPEI2C_PANEL && Option.DISPLAY_TYPE=SSDPANEL && Option.DISPLAY_TYPE<=SSD_PANEL_8)){ cnt=3; } if(map[15]==0){ for(i=0;i<16;i++){ if(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9481IPS){ col[0]=(RGB121map[i]>>16); col[1]=(RGB121map[i]>>8) & 0xFF; col[2]=(RGB121map[i] & 0xFF); } else if(Option.DISPLAY_TYPE>=SSDPANEL && Option.DISPLAY_TYPE<=SSD_PANEL_8){ col[2]=(RGB121map[i]>>16); col[1]=(RGB121map[i]>>8) & 0xFF; col[0]=(RGB121map[i] & 0xFF); } else if(Option.DISPLAY_TYPE>SSD_PANEL_8){ map[i]=((RGB121map[i]>>8) & 0xf800) | ((RGB121map[i]>>5) & 0x07e0) | ((RGB121map[i]>>3) & 0x001f); continue; } else { col[0]= ((RGB121map[i] >> 16) & 0b11111000) | ((RGB121map[i] >> 13) & 0b00000111); col[1] = ((RGB121map[i] >> 5) & 0b11100000) | ((RGB121map[i] >> 3) & 0b00011111); } if(Option.DISPLAY_TYPE == GC9A01){ col[0]=~col[0]; col[1]=~col[1]; } map[i]=col[0]|(col[1]<<8)|(col[2]<<16); } } i=(xend-xstart+1)*(yend-ystart+1); if(Option.DISPLAY_TYPE>I2C_PANEL && Option.DISPLAY_TYPE>4]; spi_write_fast(spi0,(uint8_t *)&c,cnt); s++; i--; } while(i>0){ c=map[*s & 0xF]; spi_write_fast(spi0,(uint8_t *)&c,cnt); if(i>1){ c=map[(*s & 0xF0)>>4]; spi_write_fast(spi0,(uint8_t *)&c,cnt); } s++; i-=2; } } else { if(odd){ c=map[(*s & 0xF0)>>4]; spi_write_fast(spi1,(uint8_t *)&c,cnt); s++; i--; } while(i>0){ c=map[*s & 0xF]; spi_write_fast(spi1,(uint8_t *)&c,cnt); if(i>1){ c=map[(*s & 0xF0)>>4]; spi_write_fast(spi1,(uint8_t *)&c,cnt); } s++; i-=2; } } if(PinDef[Option.SYSTEM_CLK].mode & SPI0SCK)spi_finish(spi0); else spi_finish(spi1); ClearCS(Option.LCD_CS); //set CS high } else { if(screen320 && Option.DISPLAY_TYPE!=SSD1963_4_16){ unsigned char *q = buff320; HRes=720; VRes=480; uint16_t *pp=(uint16_t *)q; if(odd){ //only used for a single line if(odd){ c=map[(*s & 0xF0)>>4]; *pp++=c; gpio_put(SSD1963_WR_GPPIN,0); gpio_put_masked64(0xFFFF<1){ c=map[(*s & 0xF0)>>4]; *pp++=c; gpio_put(SSD1963_WR_GPPIN,0); gpio_put_masked64(0xFFFF<1){ c=map[(*s & 0xF0)>>4]; *pp++=c; gpio_put(SSD1963_WR_GPPIN,0); gpio_put_masked64(0xFFFF<SSD_PANEL_8){ if(odd){ c=map[(*s & 0xF0)>>4]; gpio_put_masked64(0xFFFF<0){ c=map[*s & 0xF]; gpio_put_masked64(0xFFFF<1){ c=map[(*s & 0xF0)>>4]; gpio_put_masked64(0xFFFF<>4]; gpio_put_masked64(0b11111111<> 16) & 0xff)<> 8) & 0xff)<0){ c=map[*s & 0xF]; gpio_put_masked64(0b11111111<> 16) & 0xff)<> 8) & 0xff)<1){ c=map[(*s & 0xF0)>>4]; gpio_put_masked64(0b11111111<> 16) & 0xff)<> 8) & 0xff)<VRes-1)break; memcpy(LineBuf,d+y*HRes/2,HRes/2); ss=s+y*HRes/2; for(int x=0;x=1 && *argv[0]){ colour=getint(argv[0],0,15); } #ifdef PICOMITE uint8_t background=0; if(argc>=3 && *argv[2]){ if(checkstring(argv[2],(unsigned char *)"B"))background=1; else if(checkstring(argv[2],(unsigned char *)"R"))background=2; else if(checkstring(argv[2],(unsigned char *)"A"))background=3; else error("Syntax"); } if(background==1){ if(!(((Option.DISPLAY_TYPE>I2C_PANEL && Option.DISPLAY_TYPE=SSDPANEL && Option.DISPLAY_TYPEI2C_PANEL && Option.DISPLAY_TYPE=SSDPANEL && Option.DISPLAY_TYPEI2C_PANEL && Option.DISPLAY_TYPE=SSDPANEL && Option.DISPLAY_TYPE= 5 && *argv[4]) xOrigin = getinteger(argv[4]); // get the x origin (optional) argument if(argc >= 7 && *argv[6]) yOrigin = getinteger(argv[6]); // get the y origin (optional) argument if(xOrigin<0 || yOrigin<0)error("Coordinates"); xlen = ylen =-1; if(argc >= 9 && *argv[8]) xlen = getinteger(argv[8]); // get the x length (optional) argument if(argc == 11 ) ylen = getinteger(argv[10]); // get the y length (optional) argument // open the file if(strchr((char *)p, '.') == NULL) strcat((char *)p, ".bmp"); fnbr = FindFreeFileNbr(); if(!BasicFileOpen((char *)p, fnbr, FA_READ)) return; BDEC_bReadHeader(&BmpDec, fnbr); FileClose(fnbr); if(xlen==-1)xlen=BmpDec.lWidth; if(ylen==-1)ylen=BmpDec.lHeight; if(xlen+xOrigin>BmpDec.lWidth || ylen+yOrigin>BmpDec.lHeight)error("Coordinates"); blitbuff[bnbr].blitbuffptr = GetMemory(xlen * ylen * 3 +4 ); memset(blitbuff[bnbr].blitbuffptr,0xFF,xlen * ylen * 3 +4 ); fnbr = FindFreeFileNbr(); if(!BasicFileOpen((char *)p, fnbr, FA_READ)) return; BMP_bDecode_memory(xOrigin, yOrigin, xlen, ylen, fnbr, blitbuff[bnbr].blitbuffptr); blitbuff[bnbr].w=xlen; blitbuff[bnbr].h=ylen; FileClose(fnbr); return; } #ifndef PICOMITEVGA if((p=checkstring(cmdline, (unsigned char *)"MERGE"))) { //merge the layer onto the physical display if(!LayerBuf)error("Layer not created"); if(!FrameBuf)error("Framebuffer not created"); uint8_t colour=0; getargs(&p,13,(unsigned char *)","); if(argc>=1 && *argv[0]){ colour=getint(argv[0],0,15); } x1 = getinteger(argv[2]); y1 = getinteger(argv[4]); w = getinteger(argv[6]); h = getinteger(argv[8]); #ifdef PICOMITE uint8_t background=0; if(argc>=11 && *argv[10]){ if(checkstring(argv[10],(unsigned char *)"B"))background=1; else if(checkstring(argv[10],(unsigned char *)"R"))background=2; else if(checkstring(argv[10],(unsigned char *)"A"))background=3; else error("Syntax"); } if(background==1){ if(!(((Option.DISPLAY_TYPE>I2C_PANEL && Option.DISPLAY_TYPE=SSDPANEL && Option.DISPLAY_TYPEI2C_PANEL && Option.DISPLAY_TYPE=SSDPANEL && Option.DISPLAY_TYPE HRes) w = HRes - x1; if(y1 + h > VRes) h = VRes - y1; if(w < 1 || h < 1 || x1 < 0 || x1 + w > HRes || y1 < 0 || y1 + h > VRes ) return; if(blitbuff[bnbr].blitbuffptr == NULL){ blitbuff[bnbr].blitbuffptr = GetMemory(w * h * 3); ReadBuffer(x1, y1, x1 + w - 1, y1 + h - 1, (unsigned char *)blitbuff[bnbr].blitbuffptr); blitbuff[bnbr].w=w; blitbuff[bnbr].h=h; } else error("Buffer in use"); } else if ((p = checkstring(cmdline, (unsigned char*)"WRITE"))) { int mode = 0; getargs(&p, 7, (unsigned char*)","); if (!(argc == 5 || argc == 7)) error((char *)"Syntax"); if (*argv[0] == '#') argv[0]++; bnbr = (int)getint(argv[0], 1, MAXBLITBUF)-1; // get the number if(blitbuff[bnbr].h==9999)error("Invalid buffer"); if (blitbuff[bnbr].blitbuffptr != NULL) { x1 = (int)getint(argv[2], -blitbuff[bnbr].w + 1, HRes); y1 = (int)getint(argv[4], -blitbuff[bnbr].h + 1, VRes); if (argc == 7)mode = (char)getint(argv[6], 0, 7); w = blitbuff[bnbr].w; h = blitbuff[bnbr].h; // int cursorhidden = 0; int rotation = mode & 3; if(x1>=HRes || x1+w<0 || y1>=VRes || y1+h<0)return; if(x1>=0 && mode==0 && x1+w<=HRes)buff=(unsigned char *)blitbuff[bnbr].blitbuffptr; else { buff=GetTempMemory(w*h*4); for(int j=w*h*4-1,i=w*h*3-1;j>=0;j-=4){ buff[j]=0; buff[j-1]=blitbuff[bnbr].blitbuffptr[i--]; buff[j-2]=blitbuff[bnbr].blitbuffptr[i--]; buff[j-3]=blitbuff[bnbr].blitbuffptr[i--]; } int *d=(int *)buff; if(rotation & 1){ //swap left/write for (int y = 0; y < h; y++) { for (int x = 0,xx=w-1; x < (w>>1); x++,xx--) { swap(d[y*w+x],d[y*w+xx]); } } } if(rotation & 2){ for(int x=0;x>1);y++,yy--){ swap(d[x+y*w],d[x+yy*w]); } } } if(x1<0){ //now deal with situation where you are blitting part off the left of the screen int *s=(int *)buff; d=(int *)buff; int start=-x1; for(int y=0;y=start)*d++=*s++; else s++; } } w-=start; x1=0; } if(x1+w>=HRes){ //now deal with situation where you are blitting part off the right of the screen int *s=(int *)buff; d=(int *)buff; int over=((x1+w)-HRes); int end=w-over; for(int y=0;y=end)s++; else *d++=*s++; } } w-=over; } for(int i=0,j=0;i HRes) w = HRes - x1; if(x2 + w > HRes) w = HRes - x2; if(y1 + h > VRes) h = VRes - y1; if(y2 + h > VRes) h = VRes - y2; if(w < 1 || h < 1 || x1 < 0 || x1 + w > HRes || x2 < 0 || x2 + w > HRes || y1 < 0 || y1 + h > VRes || y2 < 0 || y2 + h > VRes) return; #ifdef PICOMITEVGA if(DISPLAY_TYPE==SCREENMODE2 || DISPLAY_TYPE==SCREENMODE3){ if((w & 1)==0 && (x1 & 1)==0 && (x2 & 1)==0){ //Easiest case - byte move in the x direction with w even if(y1=0;y--){ volatile uint8_t *in=WriteBuf + ((y+y1)*HRes + x1)/2; volatile uint8_t *out=WriteBuf + ((y+y2)*HRes + x2)/2; memcpy((void *)out,(void *)in,w/2); } } else if(y1>y2){ for(int y=0;yy2){ for(int y=0;y>4 ; *out =t ; in++; } else { uint8_t t=(*in & 0xf)<<4; *out|= t; out++; } toggle ^=1; } } if(!outtoggle){ memcpy((void *)WriteBuf + ((y+y2)*HRes + x2)/2, inbuff, w/2); if(w & 1){ volatile uint8_t *lastnibble=WriteBuf + ((y+y2) * HRes + x2 + w)/2; *lastnibble &= 0xf0; *lastnibble |= (inbuff[w/2] & 0xf); } } else { int toggle=1; volatile uint8_t *in=inbuff; volatile uint8_t *out=WriteBuf + ((y+y2) * HRes + x2)/2; for(int x=0;x>4); *out &=0xf0; *out|= t; in++; } toggle ^=1; } } } } else { for(int y=h-1;y>=0;y--){ if(!intoggle)memcpy(inbuff,(void *)WriteBuf + ((y+y1)*HRes + x1)/2, n); else { int toggle=1; volatile uint8_t *in=WriteBuf + ((y+y1)*HRes + x1)/2; volatile uint8_t *out=inbuff; for(int x=0;x>4 ; *out =t ; in++; } else { uint8_t t=(*in & 0xf)<<4; *out|= t; out++; } toggle ^=1; } } if(!outtoggle){ memcpy((void *)WriteBuf + ((y+y2)*HRes + x2)/2, inbuff, w/2); if(w & 1){ volatile uint8_t *lastnibble=WriteBuf + ((y+y2) * HRes + x2 + w)/2; *lastnibble &= 0xf0; *lastnibble |= (inbuff[w/2] & 0xf); } } else { int toggle=1; volatile uint8_t *in=inbuff; volatile uint8_t *out=WriteBuf + ((y+y2) * HRes + x2)/2; for(int x=0;x>4); *out &=0xf0; *out|= t; in++; } toggle ^=1; } } } } return; } } else if(DISPLAY_TYPE && (DISPLAY_TYPE==SCREENMODE4 || DISPLAY_TYPE==SCREENMODE5)){ unsigned char *buff = NULL; int max_x; if(x1 >= x2) { max_x = 1; buff = GetMemory((max_x * h) * (DISPLAY_TYPE==SCREENMODE4 ? 2 : 1)); while(w > max_x){ ReadBufferFast(x1, y1, x1 + max_x - 1, y1 + h - 1, buff); DrawBufferFast(x2, y2, x2 + max_x - 1, y2 + h - 1, -1, buff); x1 += max_x; x2 += max_x; w -= max_x; } ReadBufferFast(x1, y1, x1 + w - 1, y1 + h - 1, buff); DrawBufferFast(x2, y2, x2 + w - 1, y2 + h - 1, -1, buff); FreeMemory(buff); } if(x1 < x2) { int start_x1, start_x2; max_x = 1; buff = GetMemory((max_x * h) * (DISPLAY_TYPE==SCREENMODE4 ? 2 : 1)); start_x1 = x1 + w - max_x; start_x2 = x2 + w - max_x; while(w > max_x){ ReadBufferFast(start_x1, y1, start_x1 + max_x - 1, y1 + h - 1, buff); DrawBufferFast(start_x2, y2, start_x2 + max_x - 1, y2 + h - 1, -1, buff); w -= max_x; start_x1 -= max_x; start_x2 -= max_x; } ReadBufferFast(x1, y1, x1 + w - 1, y1 + h - 1, buff); DrawBufferFast(x2, y2, x2 + w - 1, y2 + h - 1, -1, buff); FreeMemory(buff); } } else if(DISPLAY_TYPE && DISPLAY_TYPE==SCREENMODE1){ unsigned char *buff = NULL; int max_x, ww; ww=w; if(x1 >= x2) { max_x = 1; buff = GetMemory((max_x * h)>>1); while(w > max_x){ ReadBufferFast(x1, y1, x1 + max_x - 1, y1 + h - 1, buff); DrawBufferFast(x2, y2, x2 + max_x - 1, y2 + h - 1, -1, buff); x1 += max_x; x2 += max_x; w -= max_x; } ReadBufferFast(x1, y1, x1 + w - 1, y1 + h - 1, buff); DrawBufferFast(x2, y2, x2 + w - 1, y2 + h - 1, -1, buff); FreeMemory(buff); if((x1 % 8==0) && (x2 % 8 ==0) && (y1 % ytileheight==0) && (y2 % ytileheight ==0) && (ww % 8==0) && (h % ytileheight==0)){ int tx1=x1/8; int xc=ww/8; int ty1=y1/ytileheight; int yc=h/ytileheight; int tx2=x2/8; int ty2=y2/ytileheight; for (int x=0;x max_x){ ReadBufferFast(start_x1, y1, start_x1 + max_x - 1, y1 + h - 1, buff); DrawBufferFast(start_x2, y2, start_x2 + max_x - 1, y2 + h - 1, -1, buff); w -= max_x; start_x1 -= max_x; start_x2 -= max_x; } ReadBufferFast(x1, y1, x1 + w - 1, y1 + h - 1, buff); DrawBufferFast(x2, y2, x2 + w - 1, y2 + h - 1, -1, buff); FreeMemory(buff); if((x1 % 8==0) && (x2 % 8 ==0) && (y1 % ytileheight==0) && (y2 % ytileheight ==0) && (ww % 8==0) && (h % ytileheight==0)){ int tx1=x1/8; int xc=ww/8; int ty1=y1/ytileheight; int yc=h/ytileheight; int tx2=x2/8; int ty2=y2/ytileheight; for (int x=xc-1;x>=0;x--){ for(int y=0;y=0;y--){ uint8_t *in=WriteBuf + ((y+y1)*HRes + x1)/2; uint8_t *out=WriteBuf + ((y+y2)*HRes + x2)/2; memcpy(out,in,w/2); } } else if(y1>y2){ for(int y=0;yy2){ for(int y=0;y>4 ; *out =t ; in++; } else { uint8_t t=(*in & 0xf)<<4; *out|= t; out++; } toggle ^=1; } } if(!outtoggle){ memcpy(WriteBuf + ((y+y2)*HRes + x2)/2, inbuff, w/2); if(w & 1){ uint8_t *lastnibble=WriteBuf + ((y+y2) * HRes + x2 + w)/2; *lastnibble &= 0xf0; *lastnibble |= (inbuff[w/2] & 0xf); } } else { int toggle=1; uint8_t *in=inbuff; uint8_t *out=WriteBuf + ((y+y2) * HRes + x2)/2; for(int x=0;x>4); *out &=0xf0; *out|= t; in++; } toggle ^=1; } } } } else { for(int y=h-1;y>=0;y--){ if(!intoggle)memcpy(inbuff,WriteBuf + ((y+y1)*HRes + x1)/2, n); else { int toggle=1; uint8_t *in=WriteBuf + ((y+y1)*HRes + x1)/2; uint8_t *out=inbuff; for(int x=0;x>4 ; *out =t ; in++; } else { uint8_t t=(*in & 0xf)<<4; *out|= t; out++; } toggle ^=1; } } if(!outtoggle){ memcpy(WriteBuf + ((y+y2)*HRes + x2)/2, inbuff, w/2); if(w & 1){ uint8_t *lastnibble=WriteBuf + ((y+y2) * HRes + x2 + w)/2; *lastnibble &= 0xf0; *lastnibble |= (inbuff[w/2] & 0xf); } } else { int toggle=1; uint8_t *in=inbuff; uint8_t *out=WriteBuf + ((y+y2) * HRes + x2)/2; for(int x=0;x>4); *out &=0xf0; *out|= t; in++; } toggle ^=1; } } } } return; } } else { if(x1 >= x2) { max_x = 1; buff = GetMemory(max_x * h * (SSD16TYPE || Option.DISPLAY_TYPE==IPS_4_16 ? 2 : 3)); while(w > max_x){ ReadBLITBuffer(x1, y1, x1 + max_x - 1, y1 + h - 1, buff); DrawBLITBuffer(x2, y2, x2 + max_x - 1, y2 + h - 1, buff); x1 += max_x; x2 += max_x; w -= max_x; } ReadBLITBuffer(x1, y1, x1 + w - 1, y1 + h - 1, buff); DrawBLITBuffer(x2, y2, x2 + w - 1, y2 + h - 1, buff); FreeMemory(buff); return; } if(x1 < x2) { int start_x1, start_x2; max_x = LargestContiguousHeap()/(SSD16TYPE || Option.DISPLAY_TYPE==IPS_4_16 ? 2 : 3); if(max_x>x2-x1+1)max_x=x2-x1+1; buff = GetMemory(max_x * h * (SSD16TYPE || Option.DISPLAY_TYPE==IPS_4_16 ? 2 : 3)); start_x1 = x1 + w - max_x; start_x2 = x2 + w - max_x; while(w > max_x){ ReadBLITBuffer(start_x1, y1, start_x1 + max_x - 1, y1 + h - 1, buff); DrawBLITBuffer(start_x2, y2, start_x2 + max_x - 1, y2 + h - 1, buff); w -= max_x; start_x1 -= max_x; start_x2 -= max_x; } ReadBLITBuffer(x1, y1, x1 + w - 1, y1 + h - 1, buff); DrawBLITBuffer(x2, y2, x2 + w - 1, y2 + h - 1, buff); FreeMemory(buff); if(Option.Refresh)Display_Refresh(); return; } } } #endif } void MIPS16 cmd_font(void) { getargs(&cmdline, 3, (unsigned char *)","); if(argc < 1) error("Argument count"); if(*argv[0] == '#') ++argv[0]; if(argc == 3) SetFont(((getint(argv[0], 1, FONT_TABLE_SIZE) - 1) << 4) | getint(argv[2], 1, 15)); else SetFont(((getint(argv[0], 1, FONT_TABLE_SIZE) - 1) << 4) | 1); if(Option.DISPLAY_CONSOLE && !CurrentLinePtr) { // if we are at the command prompt on the LCD #ifdef PICOMITEVGA if(gui_font_height>=8 && (gui_font_width % 8)==0){ ytileheight=gui_font_height; Y_TILE=(VRes+ytileheight-1)/ytileheight; for(int i=0;i= VRes) { ScrollLCD(CurrentY + gui_font_height - VRes); // scroll up if the font change split the line over the bottom CurrentY -= (CurrentY + gui_font_height - VRes); } } } #ifdef PICOMITEVGA void cmd_colourmap(void){ long long int *cptr=NULL, *fptr=NULL; MMFLOAT *cfptr=NULL, *ffptr=NULL; int nf,n,i; int map[16]; getargs(&cmdline,5,(unsigned char *)","); memcpy((void *)map,(void *)RGB121map,16*sizeof(int)); if(!(argc==3 || argc==5))error("Argument count"); n=parsenumberarray(argv[0],&cfptr,&cptr,1,1,NULL,true); if(argc==5){ //user defined mapping MMFLOAT* a3float = NULL; int64_t* a3int = NULL; if(parsenumberarray(argv[4],&a3float,&a3int,3,1,NULL,true)!=16)error("Array size not 16 elements"); if(a3int!=NULL){ for(i=0;i<16;i++) { map[i]=a3int[i]; if(map[i]<0 || map[i]>0xFFFFFF)error("Invalid colour"); } } else { for(i=0;i<16;i++) { map[i]=a3float[i]; if(map[i]<0 || map[i]>0xFFFFFF)error("Invalid colour"); } } } nf=parsenumberarray(argv[2],&ffptr,&fptr,1,1,NULL,false); if(nf!=n)error("Array size mismatch %, %",n,nf); for(int i=0;i=16)error("Input range error on element %",i); if(fptr==NULL)ffptr[i]=map[in]; else fptr[i]=map[in]; } } #endif void cmd_colour(void) { getargs(&cmdline, 3, (unsigned char *)","); if(argc < 1) error("Argument count"); gui_fcolour = getColour((char *)argv[0], 0); if(argc == 3) gui_bcolour = getColour((char *)argv[2], 0); last_fcolour = gui_fcolour; last_bcolour = gui_bcolour; if(!CurrentLinePtr) { PromptFC = gui_fcolour; PromptBC = gui_bcolour; } } #ifdef PICOMITEVGA void fun_map(void){ int cl=getint(ep,0,255); switch(DISPLAY_TYPE){ case SCREENMODE1: case SCREENMODE4: error("Invalid for Mode"); break; case SCREENMODE2: case SCREENMODE3: if(cl>15)error("Mode has 16 colours - 0 to 15"); targ=T_INT; iret=((cl & 0b1000)<<20) | ((cl & 0b110)<<13) | ((cl & 0b1)<<7); break; case SCREENMODE5: targ=T_INT; iret=((cl & 0b11100000)<<16) | ((cl & 0b00011100)<<11) | ((cl & 0b11)<<6); break; } } #ifndef HDMI void cmd_map(void){ unsigned char *p; // if(Option.CPU_Speed==126000)error("CPUSPEED >= 252000 for colour mapping"); if(!(DISPLAY_TYPE==SCREENMODE2 || DISPLAY_TYPE==SCREENMODE3 ))error("Invalid for this screen mode"); if((p=checkstring(cmdline, (unsigned char *)"RESET"))) { while(QVgaScanLine!=0){} for(int i=0;i<16;i++)remap[i]=RGB121map[i]; for(int i=0;i<16;i++)map16[i]=RGB121(remap[i]); } else if((p=checkstring(cmdline, (unsigned char *)"MAXIMITE"))) { while(QVgaScanLine!=0){} for(int i=0;i<16;i++)remap[i]=CMM1map[i]; for(int i=0;i<16;i++)map16[i]=RGB121(remap[i]); } else if((p=checkstring(cmdline, (unsigned char *)"SET"))) { while(QVgaScanLine!=0){} for(int i=0;i<16;i++)map16[i]=RGB121(remap[i]); } else { static bool first=true; int cl = getinteger(cmdline); while(*cmdline && tokenfunction(*cmdline) != op_equal) cmdline++; if(!*cmdline) error("Invalid syntax"); ++cmdline; if(!*cmdline) error("Invalid syntax"); int col=getColour((char *)cmdline,0); if(first){ for(int i=0;i<16;i++)remap[i]=RGB121map[i]; first=false; } remap[cl]=col; } } void cmd_tile(void){ unsigned char *tp; uint32_t bcolour=0xFFFFFFFF,fcolour=0xFFFFFFFF; int xlen=1,ylen=1; if(DISPLAY_TYPE!=SCREENMODE1)error("Invalid for this screen mode"); if(checkstring(cmdline,(unsigned char *)"RESET")){ for(int x=0;x=7 && *argv[6]){ tilebcolour = getColour((char *)argv[6], 0); bcolour = RGB121pack(tilebcolour); } if(argc>=9 && *argv[8]){ xlen=getint(argv[8],1,X_TILE-x); } if(argc>=11 && *argv[10]){ ylen=getint(argv[10],1,Y_TILE-y); } for(int xp=x;xp>3) | ((c& 0xf800)>>6) | ((c & 0xf80000)>>9); if(x1 < 0) x1 = 0; if(x1 >= HRes) x1 = HRes - 1; if(x2 < 0) x2 = 0; if(x2 >= HRes) x2 = HRes - 1; if(y1 < 0) y1 = 0; if(y1 >= VRes) y1 = VRes - 1; if(y2 < 0) y2 = 0; if(y2 >= VRes) y2 = VRes - 1; if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } for(y=y1;y<=y2;y++){ uint16_t *p=(uint16_t *)((uint8_t *)(WriteBuf+((y*HRes+x1)*2))); for(x=x1;x<=x2;x++){ *p++=col; } } } void DrawBitmap555(int x1, int y1, int width, int height, int scale, int fc, int bc, unsigned char *bitmap){ int i, j, k, m, x, y; // unsigned char mask; if(x1>=HRes || y1>=VRes || x1+width*scale<0 || y1+height*scale<0)return; uint16_t fcolour = RGB555(fc); uint16_t bcolour = RGB555(bc); for(i = 0; i < height; i++) { // step thru the font scan line by line for(j = 0; j < scale; j++) { // repeat lines to scale the font for(k = 0; k < width; k++) { // step through each bit in a scan line for(m = 0; m < scale; m++) { // repeat pixels to scale in the x axis x=x1 + k * scale + m ; y=y1 + i * scale + j ; if(x >= 0 && x < HRes && y >= 0 && y < VRes) { // if the coordinates are valid uint16_t *p=(uint16_t *)(((uint32_t) WriteBuf)+(y*(HRes<<1))+(x<<1)); if((bitmap[((i * width) + k)/8] >> (((height * width) - ((i * width) + k) - 1) %8)) & 1) { *p=fcolour; } else { if(bc>=0){ *p=bcolour; } } } } } } } } void DrawBuffer555(int x1, int y1, int x2, int y2, unsigned char *p){ int x,y, t; union colourmap { char rgbbytes[4]; unsigned int rgb; } c; uint16_t fcolour; uint16_t *pp; // make sure the coordinates are kept within the display area if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } if(x1 < 0) x1 = 0; if(x1 >= HRes) x1 = HRes - 1; if(x2 < 0) x2 = 0; if(x2 >= HRes) x2 = HRes - 1; if(y1 < 0) y1 = 0; if(y1 >= VRes) y1 = VRes - 1; if(y2 < 0) y2 = 0; if(y2 >= VRes) y2 = VRes - 1; for(y=y1;y<=y2;y++){ for(x=x1;x<=x2;x++){ c.rgbbytes[0]=*p++; //this order swaps the bytes to match the .BMP file c.rgbbytes[1]=*p++; c.rgbbytes[2]=*p++; fcolour = RGB555(c.rgb); pp=(uint16_t *)(((uint32_t) WriteBuf)+(y*(HRes<<1))+(x<<1)); *pp=fcolour; } } } void DrawBuffer555Fast(int x1, int y1, int x2, int y2, int blank, unsigned char *p){ int x,y,t; uint16_t c; uint16_t *pp, *qq=(uint16_t *)p; // make sure the coordinates are kept within the display area if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } for(y=y1;y<=y2;y++){ for(x=x1;x<=x2;x++){ if(x>=0 && x=0 && y=HRes || y>=VRes)return; uint16_t colour = RGB555(c); uint16_t *p=(uint16_t *)(((uint32_t) WriteBuf)+(y*(HRes<<1))+(x<<1)); *p=colour; } void ReadBuffer555(int x1, int y1, int x2, int y2, unsigned char *c){ int x,y,t; uint16_t *pp; if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } int xx1=x1, yy1=y1, xx2=x2, yy2=y2; if(x1 < 0) xx1 = 0; if(x1 >= HRes) xx1 = HRes - 1; if(x2 < 0) xx2 = 0; if(x2 >= HRes) xx2 = HRes - 1; if(y1 < 0) yy1 = 0; if(y1 >= VRes) yy1 = VRes - 1; if(y2 < 0) yy2 = 0; if(y2 >= VRes) yy2 = VRes - 1; for(y=yy1;y<=yy2;y++){ for(x=xx1;x<=xx2;x++){ pp=(uint16_t *)(((uint32_t) WriteBuf)+(y*(HRes<<1))+(x<<1)); t=*pp; *c++=((t&0x1F)<<3); *c++=(((t>>5)&0x1F)<<3); *c++=(((t>>10)&0x1F)<<3); } } } void ReadBuffer555Fast(int x1, int y1, int x2, int y2, unsigned char *c){ int x,y,t; uint16_t *pp, *qq=(uint16_t *)c; if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } int xx1=x1, yy1=y1, xx2=x2, yy2=y2; if(x1 < 0) xx1 = 0; if(x1 >= HRes) xx1 = HRes - 1; if(x2 < 0) xx2 = 0; if(x2 >= HRes) xx2 = HRes - 1; if(y1 < 0) yy1 = 0; if(y1 >= VRes) yy1 = VRes - 1; if(y2 < 0) yy2 = 0; if(y2 >= VRes) yy2 = VRes - 1; for(y=yy1;y<=yy2;y++){ for(x=xx1;x<=xx2;x++){ pp=(uint16_t *)(((uint32_t) WriteBuf)+(y*(HRes<<1))+(x<<1)); *qq++=*pp; } } } void ScrollLCD555(int lines){ if(lines==0)return; if(lines >= 0) { for(int i=0;i=lines;i--) { int d=i*(HRes<<1),s=(i-lines)*(HRes<<1); for(int c=0;c<(HRes<<1);c++)WriteBuf[d+c]=WriteBuf[s+c]; } DrawRectangle(0, 0, HRes - 1, lines - 1, PromptBC); // erase the lines introduced at the top } } void DrawRectangle256(int x1, int y1, int x2, int y2, int c){ int y,t; uint8_t colour =RGB332(c); if(x1 < 0) x1 = 0; if(x1 >= HRes) x1 = HRes - 1; if(x2 < 0) x2 = 0; if(x2 >= HRes) x2 = HRes - 1; if(y1 < 0) y1 = 0; if(y1 >= VRes) y1 = VRes - 1; if(y2 < 0) y2 = 0; if(y2 >= VRes) y2 = VRes - 1; if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } for(y=y1;y<=y2;y++){ volatile uint8_t *p=WriteBuf+(y*HRes+x1); memset((void *)p,colour,x2-x1+1); } } void DrawBitmap256(int x1, int y1, int width, int height, int scale, int fc, int bc, unsigned char *bitmap){ int i, j, k, m, x, y; // unsigned char mask; if(x1>=HRes || y1>=VRes || x1+width*scale<0 || y1+height*scale<0)return; uint8_t fcolour = RGB332(fc); uint8_t bcolour = RGB332(bc); for(i = 0; i < height; i++) { // step thru the font scan line by line for(j = 0; j < scale; j++) { // repeat lines to scale the font for(k = 0; k < width; k++) { // step through each bit in a scan line for(m = 0; m < scale; m++) { // repeat pixels to scale in the x axis x=x1 + k * scale + m ; y=y1 + i * scale + j ; if(x >= 0 && x < HRes && y >= 0 && y < VRes) { // if the coordinates are valid uint8_t *p=(uint8_t *)((uint32_t)(WriteBuf+y*HRes+x)); if((bitmap[((i * width) + k)/8] >> (((height * width) - ((i * width) + k) - 1) %8)) & 1) { *p=fcolour; } else { if(bc>=0){ *p=bcolour; } } } } } } } } void DrawBuffer256(int x1, int y1, int x2, int y2, unsigned char *p){ int x,y, t; union colourmap { char rgbbytes[4]; unsigned int rgb; } c; uint8_t fcolour; uint8_t *pp; // make sure the coordinates are kept within the display area if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } if(x1 < 0) x1 = 0; if(x1 >= HRes) x1 = HRes - 1; if(x2 < 0) x2 = 0; if(x2 >= HRes) x2 = HRes - 1; if(y1 < 0) y1 = 0; if(y1 >= VRes) y1 = VRes - 1; if(y2 < 0) y2 = 0; if(y2 >= VRes) y2 = VRes - 1; for(y=y1;y<=y2;y++){ for(x=x1;x<=x2;x++){ c.rgbbytes[0]=*p++; //this order swaps the bytes to match the .BMP file c.rgbbytes[1]=*p++; c.rgbbytes[2]=*p++; fcolour = RGB332(c.rgb); pp=(uint8_t *)((uint32_t)(WriteBuf+y*HRes+x)); *pp=fcolour; } } } void DrawBuffer256Fast(int x1, int y1, int x2, int y2, int blank, unsigned char *p){ int x,y,t; uint8_t c; uint8_t *pp, *qq=(uint8_t *)p; // make sure the coordinates are kept within the display area if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } for(y=y1;y<=y2;y++){ for(x=x1;x<=x2;x++){ if(x>=0 && x=0 && y=HRes || y>=VRes)return; uint8_t colour = RGB332(c); uint8_t *p=(uint8_t *)((uint32_t)(WriteBuf+y*HRes+x)); *p=colour; } void ReadBuffer256(int x1, int y1, int x2, int y2, unsigned char *c){ int x,y,t; uint8_t *pp; if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } int xx1=x1, yy1=y1, xx2=x2, yy2=y2; if(x1 < 0) xx1 = 0; if(x1 >= HRes) xx1 = HRes - 1; if(x2 < 0) xx2 = 0; if(x2 >= HRes) xx2 = HRes - 1; if(y1 < 0) yy1 = 0; if(y1 >= VRes) yy1 = VRes - 1; if(y2 < 0) yy2 = 0; if(y2 >= VRes) yy2 = VRes - 1; for(y=yy1;y<=yy2;y++){ for(x=xx1;x<=xx2;x++){ pp=(uint8_t *)((uint32_t)(WriteBuf+y*HRes+x)); #ifdef PICOMITEVGA unsigned int q; uint8_t *qq=pp; if(WriteBuf==DisplayBuf && LayerBuf != DisplayBuf && LayerBuf !=NULL)qq=(uint8_t *)((uint32_t)(LayerBuf+y*HRes+x)); #endif t=*pp; #ifdef PICOMITEVGA q=*qq; if(!(*qq==transparent) && mergedread)t=q; #endif *c++=((t & 0x3)<<6); *c++=(((t>>2) & 0x7)<<5); *c++=(((t>>5) & 0x7)<<5); } } } void ReadBuffer256Fast(int x1, int y1, int x2, int y2, unsigned char *c){ int x,y,t; uint8_t *pp, *qq=(uint8_t *)c; if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } int xx1=x1, yy1=y1, xx2=x2, yy2=y2; if(x1 < 0) xx1 = 0; if(x1 >= HRes) xx1 = HRes - 1; if(x2 < 0) xx2 = 0; if(x2 >= HRes) xx2 = HRes - 1; if(y1 < 0) yy1 = 0; if(y1 >= VRes) yy1 = VRes - 1; if(y2 < 0) yy2 = 0; if(y2 >= VRes) yy2 = VRes - 1; for(y=yy1;y<=yy2;y++){ for(x=xx1;x<=xx2;x++){ pp=(uint8_t *)((uint32_t)(WriteBuf+y*HRes+x)); *qq++=*pp; } } } void ScrollLCD256(int lines){ if(lines==0)return; if(lines >= 0) { for(int i=0;i=lines;i--) { int d=i*HRes,s=(i-lines)*HRes; for(int c=0;c<(HRes<<1);c++)WriteBuf[d+c]=WriteBuf[s+c]; } DrawRectangle(0, 0, HRes - 1, lines - 1, PromptBC); // erase the lines introduced at the top } } /* @endcond */ void cmd_tile(void){ unsigned char *tp; uint32_t bcolour=0xFFFFFFFF,fcolour=0xFFFFFFFF; int xlen=1,ylen=1; if(DISPLAY_TYPE!=SCREENMODE1)error("Invalid for this screen mode"); if(checkstring(cmdline,(unsigned char *)"RESET")){ fcolour=(FullColour) ? RGB555(Option.DefaultFC): RGB332(Option.DefaultFC); bcolour=(FullColour) ? RGB555(Option.DefaultBC): RGB332(Option.DefaultBC); for(int x=0;x=7 && *argv[6]){ tilebcolour = getColour((char *)argv[6], 0); bcolour = (FullColour) ? RGB555(tilebcolour): RGB332(tilebcolour); } if(argc>=9 && *argv[8]){ xlen=getint(argv[8],1,X_TILE-x); } if(argc>=11 && *argv[10]){ ylen=getint(argv[10],1,Y_TILE-y); } for(int xp=x;xp15)error("Mode supports 16 colours (0-15)"); while(*cmdline && tokenfunction(*cmdline) != op_equal) cmdline++; if(!*cmdline) error("Invalid syntax"); ++cmdline; if(!*cmdline) error("Invalid syntax"); int col=getColour((char *)cmdline,0); if(first){ if(DISPLAY_TYPE==SCREENMODE5)for(int i=0;i<256;i++)remap[i]=RGB555(MAP256DEF[i]); else if(FullColour)for(int i=0;i<16;i++)remap[i]=RGB555(MAP16DEF[i]); else if(DISPLAY_TYPE==SCREENMODE3)for(int i=0;i<16;i++)remap[i]=RGB332(MAP16DEF[i]) | (RGB332(MAP16DEF[i])<<8); else if(DISPLAY_TYPE==SCREENMODE2)for(int i=0;i<16;i++)remap[i]=RGB332(MAP16DEF[i]) | (RGB332(MAP16DEF[i])<<8) | (RGB332(MAP16DEF[i])<<16) | (RGB332(MAP16DEF[i])<<24); first=false; } if(FullColour)remap[cl]=RGB555(col); else if(DISPLAY_TYPE==SCREENMODE3)remap[cl]=RGB332(col) | (RGB332(col)<<8); else if(DISPLAY_TYPE==SCREENMODE2)remap[cl]=RGB332(col) | (RGB332(col)<<8) | (RGB332(col)<<16) | (RGB332(col)<<24); } } #endif void setmode(int mode, bool clear){ closeframebuffer('A'); if(clear)memset((void *)FRAMEBUFFER,0,framebuffersize); if(mode==5){ DISPLAY_TYPE=SCREENMODE5; ScreenSize=MODE5SIZE; } else if(mode==4){ if(!(FullColour))error("Mode not available in this resolution"); DISPLAY_TYPE=SCREENMODE4; ScreenSize=MODE4SIZE; } else if(mode==3){ DISPLAY_TYPE=SCREENMODE3; ScreenSize=MODE3SIZE; } else if(mode==2){ DISPLAY_TYPE=SCREENMODE2; ScreenSize=MODE2SIZE; } else { //mode=1 #ifdef rp2350 #ifndef HDMI tilefcols=(uint16_t *)((uint8_t*)FRAMEBUFFER+(MODE1SIZE*3)); tilebcols=(uint16_t *)((uint8_t*)FRAMEBUFFER+(MODE1SIZE*3)+(MODE1SIZE>>1)); #endif #endif DISPLAY_TYPE=SCREENMODE1; ScreenSize=MODE1SIZE; } // uSec(10000); ResetDisplay(); if(clear){ memset((void *)WriteBuf, 0, ScreenSize); CurrentX = CurrentY =0; ClearScreen(Option.DefaultBC); } #ifdef HDMI if(FullColour || MediumRes){ #endif if(DISPLAY_TYPE==SCREENMODE2 || DISPLAY_TYPE==SCREENMODE4 || DISPLAY_TYPE==SCREENMODE5){ SetFont((6<<4) | 1) ; PromptFont=(6<<4) | 1; } else { SetFont(1) ; PromptFont = 1; } #ifdef HDMI } else { if(DISPLAY_TYPE==SCREENMODE1){ SetFont((2<<4) | 1) ; PromptFont=(2<<4) | 1; } else if(DISPLAY_TYPE==SCREENMODE2 || DISPLAY_TYPE==SCREENMODE5){ SetFont((6<<4) | 1) ; PromptFont=(6<<4) | 1; } else if(DISPLAY_TYPE==SCREENMODE3){ SetFont(1) ; PromptFont = 1; } } #endif if(DISPLAY_TYPE==SCREENMODE1){ ytileheight=gui_font_height; Y_TILE=VRes/ytileheight; if(VRes % ytileheight)Y_TILE++; #ifdef PICOMITEVGA if(DISPLAY_TYPE==SCREENMODE1/* && WriteBuf==DisplayBuf*/){ gui_fcolour=Option.DefaultFC; gui_bcolour=Option.DefaultBC; #ifdef HDMI settiles(); #else int bcolour = RGB121pack(gui_bcolour); int fcolour = RGB121pack(gui_fcolour); for(int x=0;x> 4][0] * (gui_font & 0b1111); targ = T_INT; } void fun_mmcharheight(void) { if(Option.DISPLAY_TYPE == 0) error("Display not configured"); iret = FontTable[gui_font >> 4][1] * (gui_font & 0b1111); targ = T_INT; } /* @endcond */ /**************************************************************************************************** **************************************************************************************************** Basic drawing primitives for a user defined LCD display driver (ie, OPTION LCDPANEL USER) all drawing is done using either DrawRectangleUser() or DrawBitmapUser() **************************************************************************************************** ****************************************************************************************************/ void cmd_refresh(void){ if(Option.DISPLAY_TYPE == 0) error("Display not configured"); low_y=0; high_y=DisplayVRes-1; low_x=0; high_x=DisplayHRes-1; Display_Refresh(); } /* * @cond * The following section will be excluded from the documentation. */ void DrawPixel16(int x, int y, int c){ if(x<0 || y<0 || x>=HRes || y>=VRes)return; if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); unsigned char colour = RGB121(c); uint8_t *p=(uint8_t *)(((uint32_t) WriteBuf)+(y*(HRes>>1))+(x>>1)); if(x & 1){ *p &=0x0F; *p |=(colour<<4); } else { *p &=0xF0; *p |= colour; } } void DrawRectangle16(int x1, int y1, int x2, int y2, int c){ int x,y,x1p,x2p,t; // unsigned char mask; unsigned char colour = RGB121(c);; unsigned char bcolour=(colour<<4) | colour; if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); if(x1 < 0) x1 = 0; if(x1 >= HRes) x1 = HRes - 1; if(x2 < 0) x2 = 0; if(x2 >= HRes) x2 = HRes - 1; if(y1 < 0) y1 = 0; if(y1 >= VRes) y1 = VRes - 1; if(y2 < 0) y2 = 0; if(y2 >= VRes) y2 = VRes - 1; if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } for(y=y1;y<=y2;y++){ x1p=x1; x2p=x2; uint8_t *p=(uint8_t *)(((uint32_t) WriteBuf)+(y*(HRes>>1))+(x1>>1)); if((x1 % 2) == 1){ *p &=0x0F; *p |=(colour<<4); p++; x1p++; } if((x2 % 2) == 0){ uint8_t *q=(uint8_t *)(((uint32_t) WriteBuf)+(y*(HRes>>1))+(x2>>1)); *q &=0xF0; *q |= colour; x2p--; } for(x=x1p;x=HRes || y1>=VRes || x1+width*scale<0 || y1+height*scale<0)return; unsigned char fcolour = RGB121(fc); unsigned char bcolour = RGB121(bc); if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); for(i = 0; i < height; i++) { // step thru the font scan line by line for(j = 0; j < scale; j++) { // repeat lines to scale the font for(k = 0; k < width; k++) { // step through each bit in a scan line for(m = 0; m < scale; m++) { // repeat pixels to scale in the x axis x=x1 + k * scale + m ; y=y1 + i * scale + j ; if(x >= 0 && x < HRes && y >= 0 && y < VRes) { // if the coordinates are valid uint8_t *p=(uint8_t *)(((uint32_t) WriteBuf)+(y*(HRes>>1))+(x>>1)); if((bitmap[((i * width) + k)/8] >> (((height * width) - ((i * width) + k) - 1) %8)) & 1) { if(x & 1){ *p &=0x0F; *p |=(fcolour<<4); } else { *p &=0xF0; *p |= fcolour; } } else { if(bc>=0){ if(x & 1){ *p &=0x0F; *p |=(bcolour<<4); } else { *p &=0xF0; *p |= bcolour; } } } } } } } } } void ScrollLCD16(int lines){ if(lines==0)return; if(lines >= 0) { for(int i=0;i>1),s=(i+lines)*(HRes>>1); for(int c=0;c<(HRes>>1);c++)WriteBuf[d+c]=WriteBuf[s+c]; } DrawRectangle(0, VRes-lines, HRes - 1, VRes - 1, PromptBC); // erase the lines to be scrolled off } else { lines=-lines; for(int i=VRes-1;i>=lines;i--) { int d=i*(HRes>>1),s=(i-lines)*(HRes>>1); for(int c=0;c<(HRes>>1);c++)WriteBuf[d+c]=WriteBuf[s+c]; } DrawRectangle(0, 0, HRes - 1, lines - 1, PromptBC); // erase the lines introduced at the top } } void DrawBuffer16(int x1, int y1, int x2, int y2, unsigned char *p){ int x,y, t; union colourmap { char rgbbytes[4]; unsigned int rgb; } c; unsigned char fcolour; uint8_t *pp; if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); // make sure the coordinates are kept within the display area if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } if(x1 < 0) x1 = 0; if(x1 >= HRes) x1 = HRes - 1; if(x2 < 0) x2 = 0; if(x2 >= HRes) x2 = HRes - 1; if(y1 < 0) y1 = 0; if(y1 >= VRes) y1 = VRes - 1; if(y2 < 0) y2 = 0; if(y2 >= VRes) y2 = VRes - 1; for(y=y1;y<=y2;y++){ for(x=x1;x<=x2;x++){ c.rgbbytes[0]=*p++; //this order swaps the bytes to match the .BMP file c.rgbbytes[1]=*p++; c.rgbbytes[2]=*p++; fcolour = RGB121(c.rgb); pp=(uint8_t *)(((uint32_t) WriteBuf)+(y*(HRes>>1))+(x>>1)); if(x & 1){ *pp &=0x0F; *pp |=(fcolour<<4); } else { *pp &=0xF0; *pp |= fcolour; } } } } void DrawBuffer16Fast(int x1, int y1, int x2, int y2, int blank, unsigned char *p){ int x,y, t,toggle=0; unsigned char c,w; uint8_t *pp; // make sure the coordinates are kept within the display area if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); for(y=y1;y<=y2;y++){ for(x=x1;x<=x2;x++){ if(x>=0 && x=0 && y>1))+(x>>1)); if(x & 1){ w=*pp & 0xF0; *pp &=0x0F; if(toggle){ c=((*p++)&0xF0); } else { c=(*p<<4); } } else { w=*pp & 0xF; *pp &=0xF0; if(toggle){ c = ((*p++)>>4); } else { c = (*p & 0xF); } } if((!(c==sprite_transparent || c==sprite_transparent<<4)) || blank==-1)*pp |=c; else *pp |=w; toggle=!toggle; } else { if(toggle)p++; toggle=!toggle; } } } } void ReadBuffer16(int x1, int y1, int x2, int y2, unsigned char *c){ int x,y,t; uint8_t *pp; if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } int xx1=x1, yy1=y1, xx2=x2, yy2=y2; if(x1 < 0) xx1 = 0; if(x1 >= HRes) xx1 = HRes - 1; if(x2 < 0) xx2 = 0; if(x2 >= HRes) xx2 = HRes - 1; if(y1 < 0) yy1 = 0; if(y1 >= VRes) yy1 = VRes - 1; if(y2 < 0) yy2 = 0; if(y2 >= VRes) yy2 = VRes - 1; for(y=yy1;y<=yy2;y++){ for(x=xx1;x<=xx2;x++){ pp=(uint8_t *)(((uint32_t) WriteBuf)+(y*(HRes>>1))+(x>>1)); #ifdef PICOMITEVGA unsigned int q; uint8_t *qq=pp; if(WriteBuf==DisplayBuf && LayerBuf != DisplayBuf && LayerBuf !=NULL)qq=(uint8_t *)(((uint32_t) LayerBuf)+(y*(HRes>>1))+(x>>1)); #endif if(x & 1){ t=colours[(*pp)>>4]; #ifdef PICOMITEVGA q=colours[(*qq)>>4]; if(!(((*qq)>>4)==transparent) && mergedread)t=q; #endif } else { t=colours[(*pp)&0x0F]; #ifdef PICOMITEVGA q=colours[(*qq)&0x0F]; if(!(((*qq)&0x0F)==transparent) && mergedread)t=q; #endif } *c++=(t&0xFF); *c++=(t>>8)&0xFF; *c++=t>>16; } } } void ReadBuffer16Fast(int x1, int y1, int x2, int y2, unsigned char *c){ int x,y,t,toggle=0; uint8_t *pp; if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); for(y=y1;y<=y2;y++){ for(x=x1;x<=x2;x++){ if(x>=0 && x=0 && y>1))+(x>>1)); if(!(x & 1)){ if(toggle)*c++ |= (((*pp)&0x0F))<<4; else *c=((*pp)&0x0F); } else { if(toggle)*c++ |=((*pp)&0xF0); else *c=((*pp)>>4); } toggle=!toggle; } else { if(toggle) *c++ &= 0xF; else *c = 0 ; toggle=!toggle; } } } } #ifdef PICOMITEVGA void Display_Refresh(void){ } #endif void DrawPixel2(int x, int y, int c){ if(x<0 || y<0 || x>=HRes || y>=VRes)return; if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); uint8_t *p=(uint8_t *)(((uint32_t) WriteBuf)+(y*(HRes>>3))+(x>>3)); uint8_t bit = 1<<(x % 8); if(c)*p |=bit; else *p &= ~bit; } void DrawRectangle2(int x1, int y1, int x2, int y2, int c){ int x,y,x1p, x2p, t; unsigned char mask; volatile unsigned char *p; if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); if(x1 < 0) x1 = 0; if(x1 >= HRes) x1 = HRes - 1; if(x2 < 0) x2 = 0; if(x2 >= HRes) x2 = HRes - 1; if(y1 < 0) y1 = 0; if(y1 >= VRes) y1 = VRes - 1; if(y2 < 0) y2 = 0; if(y2 >= VRes) y2 = VRes - 1; if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } if(x1==x2){ for(y=y1;y<=y2;y++){ p=&WriteBuf[(y*(HRes>>3))+(x1>>3)]; mask=1<<(x1 % 8); //get the bit position for this bit if(c){ *p|=mask; } else { *p&=(~mask); } } } else { for(y=y1;y<=y2;y++){ x1p=x1; x2p=x2; if((x1 % 8) !=0){ p=&WriteBuf[(y*(HRes>>3))+(x1>>3)]; for(x=x1;x<=x2 && (x % 8)!=0;x++){ mask=1<<(x % 8); //get the bit position for this bit if(c){ *p|=mask; } else { *p&=(~mask); } x1p++; } } if(x1p-1!=x2 && (x2 % 8)!=7){ p=&WriteBuf[(y*(HRes>>3))+(x2p>>3)]; for(x=(x2 & 0xFFF8);x<=x2 ;x++){ mask=1<<(x % 8); //get the bit position for this bit if(c){ *p|=mask; } else { *p&=(~mask); } x2p--; } } p=&WriteBuf[(y*(HRes>>3))+(x1p>>3)]; for(x=x1p;x=HRes || y1>=VRes || x1+width*scale<0 || y1+height*scale<0)return; int tilematch=0; if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); #ifdef PICOMITEVGA int xa= 8; int ya=ytileheight; if(x1 % xa == 0 && y1 % ya==0 && width*scale % xa==0 && height*scale % ya==0)tilematch=1; #endif if(fc==0 && bc>0 && (tilematch==0 || editactive)){ for(i = 0; i < height; i++) { // step thru the font scan line by line for(j = 0; j < scale; j++) { // repeat lines to scale the font for(k = 0; k < width; k++) { // step through each bit in a scan line for(m = 0; m < scale; m++) { // repeat pixels to scale in the x axis x=x1 + k * scale + m ; y=y1 + i * scale + j ; mask=1<<(x % 8); //get the bit position for this bit if(x >= 0 && x < HRes && y >= 0 && y < VRes) { // if the coordinates are valid loc=(y*(HRes>>3))+(x>>3); if((bitmap[((i * width) + k)/8] >> (((height * width) - ((i * width) + k) - 1) %8)) & 1) { WriteBuf[loc]&= ~mask; } else WriteBuf[loc]|= mask; } } } } } } else { #ifdef PICOMITEVGA if(tilematch){ // the bitmap is aligned with the tiles int bcolour, fcolour ; #ifdef HDMI fcolour = (FullColour)? RGB555(fc) : RGB332(fc); bcolour = (FullColour)? RGB555(bc) : RGB332(bc); #else fcolour = RGB121pack(fc); bcolour = RGB121pack(bc); #endif int xt=x1 / xa; int yt=y1 / ya; int w=width*scale/xa; int h=height*scale/ya; // int pos; #ifdef HDMI if(FullColour){ #endif for(int yy=yt;yy= 0 && x < HRes && y >= 0 && y < VRes) { // if the coordinates are valid loc=(y*(HRes>>3))+(x>>3); if((bitmap[((i * width) + k)/8] >> (((height * width) - ((i * width) + k) - 1) %8)) & 1) { if(fc){ WriteBuf[loc]|=mask; } else { WriteBuf[loc]&= ~mask; } } else { if(bc>0){ WriteBuf[loc]|=mask; } else if(bc==0) { WriteBuf[loc]&= ~mask; } } } } } } } } else { for(i = 0; i < height; i++) { // step thru the font scan line by line for(j = 0; j < scale; j++) { // repeat lines to scale the font for(k = 0; k < width; k++) { // step through each bit in a scan line for(m = 0; m < scale; m++) { // repeat pixels to scale in the x axis x=x1 + k * scale + m ; y=y1 + i * scale + j ; mask=1<<(x % 8); //get the bit position for this bit if(x >= 0 && x < HRes && y >= 0 && y < VRes) { // if the coordinates are valid loc=(y*(HRes>>3))+(x>>3); if((bitmap[((i * width) + k)/8] >> (((height * width) - ((i * width) + k) - 1) %8)) & 1) { if(fc){ WriteBuf[loc]|=mask; } else { WriteBuf[loc]&= ~mask; } } else WriteBuf[loc]&= ~mask; } } } } } } } } void ScrollLCD2(int lines){ if(lines==0)return; if(lines >= 0) { #ifdef PICOMITEVGA #ifndef HDMI while(QVgaScanLine!=0){} #else while(v_scanline!=0){} #endif int ya=ytileheight; if((lines % ya ==0)){ int offset=lines/ya; for(int y=0;y>3),s=(i+lines)*(HRes>>3); for(int c=0;c<(HRes>>3);c++)WriteBuf[d+c]=WriteBuf[s+c]; } DrawRectangle(0, VRes-lines, HRes - 1, VRes - 1, 0); // erase the lines to be scrolled off } else { lines=-lines; #ifdef PICOMITEVGA #ifndef HDMI while(QVgaScanLine!=0){} #else while(v_scanline!=0){} #endif int ya=ytileheight; if((lines % ya ==0)){ int offset=lines/ya; for(int y=Y_TILE-1;y>=offset;y--){ int d=y*X_TILE; int s=(y-offset)*X_TILE; for(int x=0;x=lines;i--) { int d=i*(HRes>>3),s=(i-lines)*(HRes>>3); for(int c=0;c<(HRes>>3);c++)WriteBuf[d+c]=WriteBuf[s+c]; } DrawRectangle(0, 0, HRes - 1, lines - 1, 0); // erase the lines introduced at the top } } void DrawBuffer2(int x1, int y1, int x2, int y2, unsigned char *p){ int x,y, t, loc; unsigned char mask; union colourmap { char rgbbytes[4]; unsigned int rgb; } c; if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); // make sure the coordinates are kept within the display area if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } if(x1 < 0) x1 = 0; if(x1 >= HRes) x1 = HRes - 1; if(x2 < 0) x2 = 0; if(x2 >= HRes) x2 = HRes - 1; if(y1 < 0) y1 = 0; if(y1 >= VRes) y1 = VRes - 1; if(y2 < 0) y2 = 0; if(y2 >= VRes) y2 = VRes - 1; for(y=y1;y<=y2;y++){ for(x=x1;x<=x2;x++){ c.rgbbytes[0]=*p++; if(c.rgbbytes[0]<0x40)c.rgbbytes[0]=0; c.rgbbytes[1]=*p++; if(c.rgbbytes[1]<0x40)c.rgbbytes[1]=0; c.rgbbytes[2]=*p++; if(c.rgbbytes[2]<0x40)c.rgbbytes[2]=0; c.rgbbytes[3]=0; loc=(y*(HRes>>3))+(x>>3); mask=1<<(x % 8); //get the bit position for this bit if(c.rgb){ WriteBuf[loc]|=mask; } else { WriteBuf[loc]&=(~mask); } } } } void DrawBuffer2Fast(int x1, int y1, int x2, int y2, int blank, unsigned char *p){ int x,y, t, loc, toggle=0; unsigned char mask; // make sure the coordinates are kept within the display area if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); for(y=y1;y<=y2;y++){ for(x=x1;x<=x2;x++){ if(x>=0 && x=0 && y>3))+(x>>3); mask=1<<(x % 8); //get the bit position for this bit if(toggle){ if(*p++ & 0xF0){ WriteBuf[loc]|=mask; } else if(blank==-1){ WriteBuf[loc]&=(~mask); } } else { if(*p & 0xF){ WriteBuf[loc]|=mask; } else if(blank==-1){ WriteBuf[loc]&=(~mask); } } toggle=!toggle; } else { if(toggle)p++; toggle=!toggle; } } } } void ReadBuffer2(int x1, int y1, int x2, int y2, unsigned char *c){ int x,y,t,loc; // uint8_t *pp; unsigned char mask; if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } int xx1=x1, yy1=y1, xx2=x2, yy2=y2; if(x1 < 0) xx1 = 0; if(x1 >= HRes) xx1 = HRes - 1; if(x2 < 0) xx2 = 0; if(x2 >= HRes) xx2 = HRes - 1; if(y1 < 0) yy1 = 0; if(y1 >= VRes) yy1 = VRes - 1; if(y2 < 0) yy2 = 0; if(y2 >= VRes) yy2 = VRes - 1; for(y=yy1;y<=yy2;y++){ for(x=xx1;x<=xx2;x++){ #ifdef PICOMITEVGA int tile= x/8 + (y/ytileheight)*X_TILE; int back=RGB121map[tilebcols[tile] & 0xF]; int front=RGB121map[tilefcols[tile] & 0xF]; #else int front=0xFFFFFF; int back=0; #endif loc=(y*(HRes>>3))+(x>>3); mask=1<<(x % 8); //get the bit position for this bit if(WriteBuf[loc]&mask){ *c++=(front&0xFF); *c++=(front>>8)&0xFF; *c++=front>>16; } else { *c++=(back&0xFF); *c++=(back>>8)&0xFF; *c++=back>>16; } } } } void ReadBuffer2Fast(int x1, int y1, int x2, int y2, unsigned char *c){ int x,y,t,loc,toggle=0;; // uint8_t *pp; unsigned char mask; if(Option.DISPLAY_TYPE>=VIRTUAL && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8); if(x2 <= x1) { t = x1; x1 = x2; x2 = t; } if(y2 <= y1) { t = y1; y1 = y2; y2 = t; } for(y=y1;y<=y2;y++){ for(x=x1;x<=x2;x++){ if(x>=0 && x=0 && y>3))+(x>>3); mask=1<<(x % 8); //get the bit position for this bit if(toggle){ if(WriteBuf[loc]&mask){ *c++|=0xF0; } else { *c++&=0x0F; } } else { if(WriteBuf[loc]&mask){ *c=0xF; } else { *c=0x0; } } toggle=!toggle; } else { if(toggle) *c++ &= 0xF; else *c = 0 ; toggle=!toggle; } } } } void MIPS16 ConfigDisplayVirtual(unsigned char *p) { getargs(&p, 13, (unsigned char *)","); if(checkstring(argv[0], (unsigned char *)"VIRTUAL_M")) { DISPLAY_TYPE = VIRTUAL_M; } else if(checkstring(argv[0], (unsigned char *)"VIRTUAL_C")) { DISPLAY_TYPE = VIRTUAL_C; } else return; Option.DISPLAY_TYPE=DISPLAY_TYPE; Option.DISPLAY_ORIENTATION = LANDSCAPE; } void MIPS16 InitDisplayVirtual(void){ if(Option.DISPLAY_TYPE==0 || Option.DISPLAY_TYPE < VIRTUAL) return; DisplayHRes = HRes = display_details[Option.DISPLAY_TYPE].horizontal; DisplayVRes = VRes = display_details[Option.DISPLAY_TYPE].vertical; if(Option.DISPLAY_TYPE==VIRTUAL_M){ DrawRectangle=DrawRectangle2; DrawBitmap= DrawBitmap2; ScrollLCD=ScrollLCD2; DrawBuffer=DrawBuffer2; ReadBuffer=ReadBuffer2; DrawBufferFast=DrawBuffer2Fast; ReadBufferFast=ReadBuffer2Fast; DrawPixel=DrawPixel2; } else { DrawRectangle=DrawRectangle16; DrawBitmap= DrawBitmap16; ScrollLCD=ScrollLCD16; DrawBuffer=DrawBuffer16; ReadBuffer=ReadBuffer16; DrawBufferFast=DrawBuffer16Fast; ReadBufferFast=ReadBuffer16Fast; DrawPixel=DrawPixel16; } if(WriteBuf==NULL)WriteBuf=GetMemory(VMaxH*VMaxV/8); } /* @endcond */ #ifdef PICOMITEVGA #ifdef HDMI void fun_getscanline(void){ if(Option.CPU_Speed==Freq720P){ iret = v_scanline - 30; if(iret<0)iret+=750; targ=T_INT; } else if(Option.CPU_Speed==Freq480P){ iret = v_scanline - 20; if(iret<0)iret+=500; targ=T_INT; } else if(Option.CPU_Speed==FreqXGA){ iret = v_scanline - 38; if(iret<0)iret+=806; targ=T_INT; } else if(Option.CPU_Speed==FreqSVGA){ iret = v_scanline - 25; if(iret<0)iret+=625; targ=T_INT; } else if(Option.CPU_Speed==Freq252P || Option.CPU_Speed==Freq378P){ iret = v_scanline - 45; if(iret<0)iret+=525; targ=T_INT; } else if(Option.CPU_Speed==Freq848){ iret = v_scanline - 37; if(iret<0)iret+=517; targ=T_INT; } } #else void fun_getscanline(void){ iret=QVgaScanLine; targ=T_INT; } #endif #else /* * @cond * The following section will be excluded from the documentation. */ // Draw a filled rectangle // this is the basic drawing primitive used by most drawing routines // x1, y1, x2, y2 - the coordinates // c - the colour void MIPS16 DrawRectangleUser(int x1, int y1, int x2, int y2, int c){ char callstr[256]; unsigned char *nextstmtSaved = nextstmt; if(FindSubFun((unsigned char *)"MM.USER_RECTANGLE", 0) >= 0) { strcpy(callstr, "MM.USER_RECTANGLE"); strcat(callstr, " "); IntToStr(callstr + strlen(callstr), x1, 10); strcat(callstr, ","); IntToStr(callstr + strlen(callstr), y1, 10); strcat(callstr, ","); IntToStr(callstr + strlen(callstr), x2, 10); strcat(callstr, ","); IntToStr(callstr + strlen(callstr), y2, 10); strcat(callstr, ","); IntToStr(callstr + strlen(callstr), c, 10); callstr[strlen(callstr)+1] = 0; // two NULL chars required to terminate the call g_LocalIndex++; ExecuteProgram((unsigned char *)callstr); nextstmt = nextstmtSaved; g_LocalIndex--; g_TempMemoryIsChanged = true; // signal that temporary memory should be checked } else error("MM.USER_RECTANGLE not defined"); } //Print the bitmap of a char on the video output // x, y - the top left of the char // width, height - size of the char's bitmap // scale - how much to scale the bitmap // fc, bc - foreground and background colour // bitmap - pointer to the bitmap void MIPS16 DrawBitmapUser(int x1, int y1, int width, int height, int scale, int fc, int bc, unsigned char *bitmap){ char callstr[256]; unsigned char *nextstmtSaved = nextstmt; if(FindSubFun((unsigned char *)"MM.USER_BITMAP", 0) >= 0) { strcpy(callstr, "MM.USER_BITMAP"); strcat(callstr, " "); IntToStr(callstr + strlen(callstr), x1, 10); strcat(callstr, ","); IntToStr(callstr + strlen(callstr), y1, 10); strcat(callstr, ","); IntToStr(callstr + strlen(callstr), width, 10); strcat(callstr, ","); IntToStr(callstr + strlen(callstr), height, 10); strcat(callstr, ","); IntToStr(callstr + strlen(callstr), scale, 10); strcat(callstr, ","); IntToStr(callstr + strlen(callstr), fc, 10); strcat(callstr, ","); IntToStr(callstr + strlen(callstr), bc, 10); strcat(callstr, ",&H"); IntToStr(callstr + strlen(callstr), (unsigned int)bitmap, 16); callstr[strlen(callstr)+1] = 0; // two NULL chars required to terminate the call g_LocalIndex++; ExecuteProgram((unsigned char *)callstr); g_LocalIndex--; g_TempMemoryIsChanged = true; // signal that temporary memory should be checked nextstmt = nextstmtSaved; } else error("MM.USER_BITMAP not defined"); } #endif /**************************************************************************************************** General purpose routines ****************************************************************************************************/ int GetFontWidth(int fnt) { return FontTable[fnt >> 4][0] * (fnt & 0b1111); } int GetFontHeight(int fnt) { return FontTable[fnt >> 4][1] * (fnt & 0b1111); } void SetFont(int fnt) { if(FontTable[fnt >> 4] == NULL) error("Invalid font number #%", (fnt >> 4)+1); gui_font_width = FontTable[fnt >> 4][0] * (fnt & 0b1111); gui_font_height = FontTable[fnt >> 4][1] * (fnt & 0b1111); if(Option.DISPLAY_CONSOLE) { Option.Height = VRes/gui_font_height; Option.Width = HRes/gui_font_width; } gui_font = fnt; } void MIPS16 ResetDisplay(void) { SetFont(Option.DefaultFont); gui_fcolour = Option.DefaultFC; gui_bcolour = Option.DefaultBC; PromptFont = Option.DefaultFont; PromptFC = Option.DefaultFC; PromptBC = Option.DefaultBC; #ifdef PICOMITEVGA #ifdef rp2350 if(Option.CPU_Speed==Freq848)HRes=((DISPLAY_TYPE == SCREENMODE1 || DISPLAY_TYPE == SCREENMODE3) ? 848: 424); else if(Option.CPU_Speed==Freq400)HRes=((DISPLAY_TYPE == SCREENMODE1 || DISPLAY_TYPE == SCREENMODE3) ? 720: 360); else if(Option.CPU_Speed==FreqSVGA)HRes=((DISPLAY_TYPE == SCREENMODE1 || DISPLAY_TYPE == SCREENMODE3) ? 800: 400); else HRes=((DISPLAY_TYPE == SCREENMODE1 || DISPLAY_TYPE == SCREENMODE3) ? 640: 320); #else if(Option.CPU_Speed==Freq400)HRes=((DISPLAY_TYPE == SCREENMODE1 || DISPLAY_TYPE == SCREENMODE3) ? 720: 360); else HRes=((DISPLAY_TYPE == SCREENMODE1 || DISPLAY_TYPE == SCREENMODE3) ? 640: 320); #endif if(Option.CPU_Speed==Freq400)VRes=((DISPLAY_TYPE == SCREENMODE1 || DISPLAY_TYPE == SCREENMODE3) ? 400: 200); #ifdef rp2350 else if(Option.CPU_Speed==FreqSVGA)VRes=((DISPLAY_TYPE == SCREENMODE1 || DISPLAY_TYPE == SCREENMODE3) ? 600: 300); #endif else VRes=((DISPLAY_TYPE == SCREENMODE1 || DISPLAY_TYPE == SCREENMODE3) ? 480: 240); #ifdef HDMI if(Option.CPU_Speed==Freq720P){ HRes=(DISPLAY_TYPE == SCREENMODE1 ? 1280 : ((DISPLAY_TYPE==SCREENMODE2 || DISPLAY_TYPE==SCREENMODE5) ? 320 : 640)); VRes=(DISPLAY_TYPE == SCREENMODE1 ? 720 : ((DISPLAY_TYPE==SCREENMODE2 || DISPLAY_TYPE==SCREENMODE5) ? 180 : 360)); } else if(Option.CPU_Speed==FreqXGA){ HRes=(DISPLAY_TYPE == SCREENMODE1 ? 1024 : ((DISPLAY_TYPE==SCREENMODE2 || DISPLAY_TYPE==SCREENMODE5) ? 256 : 512)); VRes=(DISPLAY_TYPE == SCREENMODE1 ? 768 : ((DISPLAY_TYPE==SCREENMODE2 || DISPLAY_TYPE==SCREENMODE5) ? 192 : 384)); } else if(Option.CPU_Speed==FreqSVGA){ HRes=((DISPLAY_TYPE == SCREENMODE1 || DISPLAY_TYPE == SCREENMODE3) ? 800: 400); VRes=((DISPLAY_TYPE == SCREENMODE1 || DISPLAY_TYPE == SCREENMODE3) ? 600: 300); } #endif switch(DISPLAY_TYPE){ case SCREENMODE1: ScreenSize= MODE1SIZE; break; case SCREENMODE2: ScreenSize=MODE2SIZE; break; case SCREENMODE3: ScreenSize=MODE3SIZE; break; case SCREENMODE4: ScreenSize=MODE4SIZE; break; case SCREENMODE5: ScreenSize=MODE5SIZE; break; } if(DISPLAY_TYPE == SCREENMODE2 || DISPLAY_TYPE == SCREENMODE3){ DrawRectangle=DrawRectangle16; DrawBitmap= DrawBitmap16; ScrollLCD=ScrollLCD16; DrawBuffer=DrawBuffer16; ReadBuffer=ReadBuffer16; DrawBufferFast=DrawBuffer16Fast; ReadBufferFast=ReadBuffer16Fast; DrawPixel=DrawPixel16; #ifdef HDMI } else if(DISPLAY_TYPE == SCREENMODE4){ DrawRectangle=DrawRectangle555; DrawBitmap= DrawBitmap555; ScrollLCD=ScrollLCD555; DrawBuffer=DrawBuffer555; ReadBuffer=ReadBuffer555; DrawBufferFast=DrawBuffer555Fast; ReadBufferFast=ReadBuffer555Fast; DrawPixel=DrawPixel555; } else if(DISPLAY_TYPE == SCREENMODE5){ DrawRectangle=DrawRectangle256; DrawBitmap= DrawBitmap256; ScrollLCD=ScrollLCD256; DrawBuffer=DrawBuffer256; ReadBuffer=ReadBuffer256; DrawBufferFast=DrawBuffer256Fast; ReadBufferFast=ReadBuffer256Fast; DrawPixel=DrawPixel256; #endif } else { DrawRectangle=DrawRectangle2; DrawBitmap= DrawBitmap2; ScrollLCD=ScrollLCD2; DrawBuffer=DrawBuffer2; ReadBuffer=ReadBuffer2; DrawBufferFast=DrawBuffer2Fast; ReadBufferFast=ReadBuffer2Fast; DrawPixel=DrawPixel2; PromptFC = gui_fcolour= Option.DefaultFC; PromptBC = gui_bcolour= Option.DefaultBC; } #ifdef HDMI settiles(); #else #ifdef rp2350 if(DISPLAY_TYPE==SCREENMODE1){ tilefcols=(uint16_t *)((uint32_t)FRAMEBUFFER+(MODE1SIZE*3)); tilebcols=(uint16_t *)((uint32_t)FRAMEBUFFER+(MODE1SIZE*3)+(MODE1SIZE>>1)); } #endif for(int x=0;x1){ //first deal with full words for(i=w0+1;i> 10; B = (b * asp) >> 10; hline(x-A-radius, x+A-radius, y+b-radius, fill, ints_per_line, br); hline(x-A-radius, x+A-radius, y-b-radius, fill, ints_per_line, br); hline(x-B-radius, x+B-radius, y+a-radius, fill, ints_per_line, br); hline(x-B-radius, x+B-radius, y-a-radius, fill, ints_per_line, br); if(P < 0) P+= 3 + 2*a++; else P+= 5 + 2*(a++ - b--); } while(a <= b); } /****************************************************************************************** Print a char on the LCD display (SSD1963 and in landscape only). It handles control chars such as newline and will wrap at the end of the line and scroll the display if necessary. The char is printed at the current location defined by CurrentX and CurrentY *****************************************************************************************/ void DisplayPutC(char c) { if(!Option.DISPLAY_CONSOLE) return; // if it is printable and it is going to take us off the right hand end of the screen do a CRLF if(c >= FontTable[gui_font >> 4][2] && c < FontTable[gui_font >> 4][2] + FontTable[gui_font >> 4][3]) { if(CurrentX + gui_font_width > HRes) { DisplayPutC('\r'); DisplayPutC('\n'); } } // handle the standard control chars switch(c) { case '\b': CurrentX -= gui_font_width; // if (CurrentX < 0) CurrentX = 0; if(CurrentX < 0){ //Go to end of previous line CurrentY -= gui_font_height ; //Go up one line if (CurrentY < 0) CurrentY = 0; CurrentX = (Option.Width-1) * gui_font_width; //go to last character } return; case '\r': CurrentX = 0; return; case '\n': if(CurrentY + 2* gui_font_height > VRes) { if(Option.NoScroll && Option.DISPLAY_CONSOLE){ClearScreen(gui_bcolour);CurrentX=0;CurrentY=0;} else { ScrollLCD( gui_font_height); } } else { CurrentY += gui_font_height; } return; case '\t': do { DisplayPutC(' '); } while((CurrentX/gui_font_width) % Option.Tab); return; } GUIPrintChar(gui_font, gui_fcolour, gui_bcolour, c, ORIENT_NORMAL); // print it routinechecks(); } void ShowCursor(int show) { static int visible = false; int newstate; if(!Option.DISPLAY_CONSOLE) return; newstate = ((CursorTimer <= CURSOR_ON) && show); // what should be the state of the cursor? if(visible == newstate) return; // we can skip the rest if the cursor is already in the correct state visible = newstate; // draw the cursor BELOW the font DrawLine(CurrentX, CurrentY + gui_font_height-(gui_font_height<=12? 1:2), CurrentX + gui_font_width-1, CurrentY + gui_font_height-(gui_font_height<=12? 1:2), (gui_font_height<=12 ? 1 : 2), visible ? gui_fcolour : (DISPLAY_TYPE==SCREENMODE1 ? 0 :gui_bcolour)); } #ifndef PICOMITEWEB #define ABS(X) ((X)>0 ? (X) : (-(X))) void DrawPolygon(int n, short *xcoord, short *ycoord, int face){ int i, facecount=struct3d[n]->facecount[face]; int c=struct3d[n]->line[face]; int f=struct3d[n]->fill[face]; // first deal with outline only if(struct3d[n]->fill[face]==0xFFFFFFFF){ for(i=0;i>16) & 0xFF, (c>>8) & 0xFF , c & 0xFF); fill_set_fill_color((f>>16) & 0xFF, (f>>8) & 0xFF , f & 0xFF); fill_begin_fill(); main_fill_poly_vertex_count=0; for(i=0;iymax)ymax=main_fill_polyY[main_fill_poly_vertex_count]; if(main_fill_polyY[main_fill_poly_vertex_count]q_vertices);//array of original vertices FreeMemorySafe((void *)&struct3d[i]->r_vertices); //array of rotated vertices FreeMemorySafe((void *)&struct3d[i]->q_centroids);//array of original vertices FreeMemorySafe((void *)&struct3d[i]->r_centroids); //array of rotated vertices FreeMemorySafe((void *)&struct3d[i]->facecount); //number of vertices for each face FreeMemorySafe((void *)&struct3d[i]->facestart); //index into the face_x_vert table of the start of a given face FreeMemorySafe((void *)&struct3d[i]->fill); //fill colours FreeMemorySafe((void *)&struct3d[i]->line); //line colours FreeMemorySafe((void *)&struct3d[i]->colours); FreeMemorySafe((void *)&struct3d[i]->face_x_vert); //list of vertices for each face FreeMemorySafe((void *)&struct3d[i]->dots); FreeMemorySafe((void *)&struct3d[i]->depth); FreeMemorySafe((void *)&struct3d[i]->depthindex); FreeMemorySafe((void *)&struct3d[i]->normals); FreeMemorySafe((void *)&struct3d[i]->flags); FreeMemorySafe((void *)&struct3d[i]); } void MIPS16 closeall3d(void){ int i; for(i = 0; i < MAX3D; i++) { if(struct3d[i]!=NULL){ Free3DMemory(i); } } for(i=1; i<4;i++){ camera[i].viewplane=-32767; } } void T_Mult(FLOAT3D *q1, FLOAT3D *q2, FLOAT3D *n){ FLOAT3D a1=q1[0],a2=q2[0],b1=q1[1],b2=q2[1],c1=q1[2],c2=q2[2],d1=q1[3],d2=q2[3]; n[0]=a1*a2-b1*b2-c1*c2-d1*d2; n[1]=a1*b2+b1*a2+c1*d2-d1*c2; n[2]=a1*c2-b1*d2+c1*a2+d1*b2; n[3]=a1*d2+b1*c2-c1*b2+d1*a2; n[4]=q1[4]*q2[4]; } void T_Invert(FLOAT3D *q, FLOAT3D *n){ n[0]=q[0]; n[1]=-q[1]; n[2]=-q[2]; n[3]=-q[3]; n[4]=q[4]; } void depthsort(FLOAT3D *farray, int n, int *index){ int i, j = n, s = 1; int t; FLOAT3D f; while (s) { s = 0; for (i = 1; i < j; i++) { if (farray[i] > farray[i - 1]) { f = farray[i]; farray[i] = farray[i - 1]; farray[i - 1] = f; s = 1; if(index!=NULL){ t=index[i-1]; index[i-1]=index[i]; index[i]=t; } } } j--; } } void q_rotate(s_quaternion *in, s_quaternion rotate, s_quaternion *out){ // PFlt(in->x);PFltComma(in->y);PFltComma(in->z);PFltComma(in->m);PRet(); s_quaternion temp, qtemp; T_Mult((FLOAT3D *)&rotate, (FLOAT3D *)in, (FLOAT3D *)&temp); T_Invert((FLOAT3D *)&rotate, (FLOAT3D *)&qtemp); T_Mult((FLOAT3D *)&temp, (FLOAT3D *)&qtemp, (FLOAT3D *)out); // PFlt(out->x);PFltComma(out->y);PFltComma(out->z);PFltComma(out->m);PRet(); } void normalise(s_vector *v){ FLOAT3D n = sqrt3d((v->x) * (v->x) + (v->y) * (v->y) + (v->z) * (v->z) ); v->x /= n; v->y /= n; v->z /= n; } void display3d(int n, FLOAT3D x, FLOAT3D y, FLOAT3D z, int clear, int nonormals){ s_vector ray, lighting={0}; s_vector p1, p2, p3, U, V; FLOAT3D x1, y1, z1, tmp; FLOAT3D at, bt, ct, t, /*A=0, B=0, */C=1, D=-camera[struct3d[n]->camera].viewplane; int maxH=VRes; int maxW=HRes; int vp, v, f, sortindex, csave=0, fsave=0; if(struct3d[n]->vmax>4){ //needed for polygon fill main_fill_polyX=(TFLOAT *)GetMemory(struct3d[n]->tot_face_x_vert * sizeof(TFLOAT)); main_fill_polyY=(TFLOAT *)GetMemory(struct3d[n]->tot_face_x_vert * sizeof(TFLOAT)); } if(struct3d[n]->xmin!=32767 && clear)DrawRectangle(struct3d[n]->xmin,struct3d[n]->ymin,struct3d[n]->xmax,struct3d[n]->ymax,0); struct3d[n]->xmin=32767; struct3d[n]->ymin=32767; struct3d[n]->xmax=-32767; struct3d[n]->ymax=-32767; short xcoord[MAX_POLYGON_VERTICES],ycoord[MAX_POLYGON_VERTICES]; struct3d[n]->distance=0.0; for(f=0;fnf;f++){ // calculate the surface normals for each face vp=struct3d[n]->facestart[f]; p1.x=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+1]].x * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+1]].m + x; p1.y=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+1]].y *struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+1]].m + y; p1.z=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+1]].z * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+1]].m + z; p2.x=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+2]].x * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+2]].m + x; p2.y=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+2]].y * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+2]].m + y; p2.z=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+2]].z * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+2]].m + z; p3.x=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp]].x * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp]].m + x; p3.y=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp]].y * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp]].m + y; p3.z=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp]].z * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp]].m + z; U.x=p2.x-p1.x; U.y=p2.y-p1.y; U.z=p2.z-p1.z; V.x=p3.x-p1.x; V.y=p3.y-p1.y; V.z=p3.z-p1.z; struct3d[n]->normals[f].x=U.y * V.z - U.z * V.y; struct3d[n]->normals[f].y=U.z * V.x - U.x * V.z; struct3d[n]->normals[f].z=U.x * V.y - U.y * V.x; normalise(&struct3d[n]->normals[f]); ray.x=p1.x - camera[struct3d[n]->camera].x; ray.y=p1.y - camera[struct3d[n]->camera].y; ray.z=p1.z - camera[struct3d[n]->camera].z; normalise(&ray); lighting.x=p1.x - struct3d[n]->light.x; lighting.y=p1.y - struct3d[n]->light.y; lighting.z=p1.z - struct3d[n]->light.z; normalise(&lighting); struct3d[n]->dots[f] = ray.x * struct3d[n]->normals[f].x + ray.y * struct3d[n]->normals[f].y + ray.z * struct3d[n]->normals[f].z; tmp=struct3d[n]->r_centroids[f].m; struct3d[n]->depth[f]=sqrt3d( (struct3d[n]->r_centroids[f].z * tmp + z - camera[struct3d[n]->camera].z) * (struct3d[n]->r_centroids[f].z * tmp + z - camera[struct3d[n]->camera].z) + (struct3d[n]->r_centroids[f].y * tmp + y - camera[struct3d[n]->camera].y) * (struct3d[n]->r_centroids[f].y * tmp + y - camera[struct3d[n]->camera].y) + (struct3d[n]->r_centroids[f].x * tmp + x - camera[struct3d[n]->camera].x) * (struct3d[n]->r_centroids[f].x * tmp + x - camera[struct3d[n]->camera].x) ); struct3d[n]->depthindex[f]=f; struct3d[n]->distance+=struct3d[n]->depth[f]; } struct3d[n]->distance/=f; // sort the distances from the faces to the camera depthsort(struct3d[n]->depth, struct3d[n]->nf, struct3d[n]->depthindex); // display the forward facing faces in the order of the furthest away first for(f=0;fnf;f++){ sortindex=struct3d[n]->depthindex[f]; vp=struct3d[n]->facestart[sortindex]; if(struct3d[n]->flags[sortindex] & 4)struct3d[n]->dots[sortindex]=-struct3d[n]->dots[sortindex]; if(nonormals || struct3d[n]->dots[sortindex]<0){ for(v=0;vfacecount[sortindex];v++){ x1=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+v]].x * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+v]].m + x; y1=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+v]].y * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+v]].m + y; z1=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+v]].z * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+v]].m + z; // We now have the coordinates in real space so project them at=x1-camera[struct3d[n]->camera].x; bt=y1-camera[struct3d[n]->camera].y; ct=z1-camera[struct3d[n]->camera].z; t=-(/*A * x1 + B * y1*/ + C * z1 + D)/(/*A * at + B * bt + */C *ct); xcoord[v]=x1+round3d(at*t)+(maxW>>1)-camera[struct3d[n]->camera].x-camera[struct3d[n]->camera].panx; ycoord[v]=maxH-round3d(y1+bt*t)-1; ycoord[v]-=(maxH>>1)-camera[struct3d[n]->camera].y-camera[struct3d[n]->camera].pany; if(clear){ if(xcoord[v]>struct3d[n]->xmax)struct3d[n]->xmax=xcoord[v]; if(xcoord[v]xmin)struct3d[n]->xmin=xcoord[v]; if(ycoord[v]>struct3d[n]->ymax)struct3d[n]->ymax=ycoord[v]; if(ycoord[v]ymin)struct3d[n]->ymin=ycoord[v]; } } if((struct3d[n]->flags[sortindex] & 1) == 0) { if(struct3d[n]->flags[sortindex] & 10) { fsave=struct3d[n]->fill[sortindex]; csave=struct3d[n]->line[sortindex]; if(struct3d[n]->flags[sortindex] & 2)struct3d[n]->fill[sortindex]=0xFF0000; if(struct3d[n]->flags[sortindex] & 8){ FLOAT3D lightratio=fabs3d(lighting.x * struct3d[n]->normals[sortindex].x + lighting.y * struct3d[n]->normals[sortindex].y + lighting.z * struct3d[n]->normals[sortindex].z); lightratio=(lightratio*struct3d[n]->ambient)+struct3d[n]->ambient; int red=(struct3d[n]->fill[sortindex] & 0xFF0000)>>16; int green=(struct3d[n]->fill[sortindex] & 0xFF00)>>8; int blue=(struct3d[n]->fill[sortindex] & 0xFF); red=(round3d)((FLOAT3D)red*lightratio); green=(round3d)((FLOAT3D)green*lightratio); blue=(round3d)((FLOAT3D)blue*lightratio); struct3d[n]->fill[sortindex]=(red<<16) | (green<<8) | blue; red=(struct3d[n]->line[sortindex] & 0xFF0000)>>16; green=(struct3d[n]->line[sortindex] & 0xFF00)>>8; blue=(struct3d[n]->line[sortindex] & 0xFF); red=(round3d)((FLOAT3D)red*lightratio); green=(round3d)((FLOAT3D)green*lightratio); blue=(round3d)((FLOAT3D)blue*lightratio); struct3d[n]->line[sortindex]=(red<<16) | (green<<8) | blue; } } DrawPolygon(n, xcoord, ycoord, sortindex); if(struct3d[n]->flags[sortindex] & 10){ struct3d[n]->fill[sortindex]=fsave; struct3d[n]->line[sortindex]=csave; } } } } // Save information about how it was displayed for DRAW3D function and RESTORE command struct3d[n]->current.x=x; struct3d[n]->current.y=y; struct3d[n]->current.z=z; struct3d[n]->nonormals=nonormals; if(struct3d[n]->vmax>4){ //needed for polygon fill FreeMemory((unsigned char *)main_fill_polyX); FreeMemory((unsigned char *)main_fill_polyY); } } void MIPS16 diagnose3d(int n, FLOAT3D x, FLOAT3D y, FLOAT3D z, int sort){ s_vector ray, normals; s_vector p1, p2, p3, U, V; FLOAT3D tmp; int vp, f, sortindex; for(f=0;fnf;f++){ // calculate the surface normals for each face vp=struct3d[n]->facestart[f]; p1.x=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+1]].x * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+1]].m + x; p1.y=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+1]].y *struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+1]].m + y; p1.z=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+1]].z * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+1]].m + z; p2.x=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+2]].x * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+2]].m + x; p2.y=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+2]].y * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+2]].m + y; p2.z=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+2]].z * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp+2]].m + z; p3.x=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp]].x * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp]].m + x; p3.y=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp]].y * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp]].m + y; p3.z=struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp]].z * struct3d[n]->r_vertices[struct3d[n]->face_x_vert[vp]].m + z; U.x=p2.x-p1.x; U.y=p2.y-p1.y; U.z=p2.z-p1.z; V.x=p3.x-p1.x; V.y=p3.y-p1.y; V.z=p3.z-p1.z; normals.x=U.y * V.z - U.z * V.y; normals.y=U.z * V.x - U.x * V.z; normals.z=U.x * V.y - U.y * V.x; normalise(&normals); ray.x=p1.x - camera[struct3d[n]->camera].x; ray.y=p1.y - camera[struct3d[n]->camera].y; ray.z=p1.z/* -camera[struct3d[n]->camera].z*/; normalise(&ray); struct3d[n]->dots[f] = ray.x * normals.x + ray.y * normals.y + ray.z * normals.z; tmp=struct3d[n]->r_centroids[f].m; struct3d[n]->depth[f]=sqrt3d( (struct3d[n]->r_centroids[f].z * tmp + z - camera[struct3d[n]->camera].z) * (struct3d[n]->r_centroids[f].z * tmp + z - camera[struct3d[n]->camera].z) + (struct3d[n]->r_centroids[f].y * tmp + y - camera[struct3d[n]->camera].y) * (struct3d[n]->r_centroids[f].y * tmp + y - camera[struct3d[n]->camera].y) + (struct3d[n]->r_centroids[f].x * tmp + x - camera[struct3d[n]->camera].x) * (struct3d[n]->r_centroids[f].x * tmp + x - camera[struct3d[n]->camera].x) ); struct3d[n]->depthindex[f]=f; } // sort the dot products depthsort(struct3d[n]->depth, struct3d[n]->nf, struct3d[n]->depthindex); // display the forward facing faces in the order of the furthest away first for(f=0;fnf;f++){ if(sort)sortindex=struct3d[n]->depthindex[f]; else sortindex=f; vp=struct3d[n]->facestart[sortindex]; MMPrintString("Face ");PInt(sortindex); MMPrintString(" at distance ");PFlt(struct3d[n]->depth[f]); MMPrintString(" dot product is ");PFlt(struct3d[n]->dots[sortindex]); MMPrintString(" so the face is ");MMPrintString(struct3d[n]->dots[sortindex]>0 ? "Hidden" : "Showing");PRet(); } } /* @endcond */ void MIPS16 cmd_3D(void){ unsigned char *p; if((p=checkstring(cmdline, (unsigned char *)"CREATE"))) { // parameters are // 3D object number (1 to MAX3D // # of vertices = nv // # of faces = nf // vertex structure (nv) // face array (face number, vertex number) // colours array // edge colour index array [nf] // fill colour index array [nf] // centroid structure [nf] // normals structure [nf] MMFLOAT *vertex; TFLOAT tmp; long long int *faces, *facecount, *facecountindex, *colours, *linecolour=NULL, *fillcolour=NULL; getargs(&p,19,(unsigned char *)","); if(argc<17)error("Argument count"); int c, colourcount=0, vp, v, f, fc=0, n=getint(argv[0],1,MAX3D); if(struct3d[n]!=NULL)error("Object already exists"); int nv=getinteger(argv[2]); if(nv<3)error("3D object must have a minimum of 3 vertices"); int nf=getinteger(argv[4]); if(nf<1)error("3D object must have a minimum of 1 face"); int cam=getint(argv[6],1,MAXCAM); if(parsefloatrarray(argv[8],&vertex,5,2,NULL,false)=17 && *argv[16]){ if(parseintegerarray(argv[16],&linecolour,9,1,NULL,false)nf=nf; struct3d[n]->nv=nv; struct3d[n]->current.x=-32767; struct3d[n]->current.y=-32767; struct3d[n]->current.z=-32767; struct3d[n]->xmin=32767; struct3d[n]->ymin=32767; struct3d[n]->xmax=-32767; struct3d[n]->ymax=-32767; struct3d[n]->camera=cam; struct3d[n]->q_vertices=NULL;//array of original vertices struct3d[n]->r_vertices=NULL; //array of rotated vertices struct3d[n]->q_centroids=NULL;//array of original vertices struct3d[n]->r_centroids=NULL; //array of rotated vertices struct3d[n]->facecount=NULL; //number of vertices for each face struct3d[n]->facestart=NULL; //index into the face_x_vert table of the start of a given face struct3d[n]->fill=NULL; //fill colours struct3d[n]->line=NULL; //line colours struct3d[n]->colours=NULL; struct3d[n]->face_x_vert=NULL; //list of vertices for each face struct3d[n]->light.x=0; struct3d[n]->light.y=0; struct3d[n]->light.z=0; struct3d[n]->ambient=0; // load up things that have one entry per vertex struct3d[n]->q_vertices=GetMemory(struct3d[n]->nv * sizeof(struct t_quaternion)); struct3d[n]->r_vertices=GetMemory(struct3d[n]->nv * sizeof(struct t_quaternion)); for(v=0;vnv;v++){ FLOAT3D m=0.0; struct3d[n]->q_vertices[v].x=(FLOAT3D)(*vertex++); m+=struct3d[n]->q_vertices[v].x*struct3d[n]->q_vertices[v].x; struct3d[n]->q_vertices[v].y=*vertex++; m+=struct3d[n]->q_vertices[v].y*struct3d[n]->q_vertices[v].y; struct3d[n]->q_vertices[v].z=*vertex++; m+=struct3d[n]->q_vertices[v].z*struct3d[n]->q_vertices[v].z; if(m){ m=sqrt(m); struct3d[n]->q_vertices[v].x=struct3d[n]->q_vertices[v].x/m; struct3d[n]->q_vertices[v].y=struct3d[n]->q_vertices[v].y/m; struct3d[n]->q_vertices[v].z=struct3d[n]->q_vertices[v].z/m; struct3d[n]->q_vertices[v].w=0.0; struct3d[n]->q_vertices[v].m=m; } else { struct3d[n]->q_vertices[v].x=0; struct3d[n]->q_vertices[v].y=0; struct3d[n]->q_vertices[v].z=0; struct3d[n]->q_vertices[v].w=0.0; struct3d[n]->q_vertices[v].m=1.0; } memcpy(&struct3d[n]->r_vertices[v],&struct3d[n]->q_vertices[v], sizeof(s_quaternion)); } struct3d[n]->tot_face_x_vert=0; //load up things that have one entry per face struct3d[n]->vmax=0; struct3d[n]->facecount=GetMemory(struct3d[n]->nf * sizeof(uint16_t)); struct3d[n]->facestart=GetMemory(struct3d[n]->nf * sizeof(uint16_t)); struct3d[n]->fill=GetMemory(struct3d[n]->nf * sizeof(uint32_t)); struct3d[n]->line=GetMemory(struct3d[n]->nf * sizeof(uint32_t)); struct3d[n]->r_centroids=GetMemory(struct3d[n]->nf * sizeof(struct t_quaternion)); struct3d[n]->q_centroids=GetMemory(struct3d[n]->nf * sizeof(struct t_quaternion)); struct3d[n]->dots=GetMemory(struct3d[n]->nf * sizeof(MMFLOAT)); struct3d[n]->depth=GetMemory(struct3d[n]->nf * sizeof(MMFLOAT)); struct3d[n]->flags=GetMemory(struct3d[n]->nf * sizeof(uint8_t)); struct3d[n]->depthindex=GetMemory(struct3d[n]->nf * sizeof(int)); struct3d[n]->normals=GetMemory(struct3d[n]->nf * sizeof(struct SVD)); for(f=0;fnf;f++){ struct3d[n]->facecount[f]=*facecount++; if(struct3d[n]->facecount[f]<3){ Free3DMemory(n); error("Vertex count less than 3 for face %",f+g_OptionBase); } if(struct3d[n]->facecount[f]>struct3d[n]->vmax)struct3d[n]->vmax=struct3d[n]->facecount[f]; struct3d[n]->facestart[f]=struct3d[n]->tot_face_x_vert; struct3d[n]->tot_face_x_vert+=struct3d[n]->facecount[f]; } // load up the array that holds all the face vertex information struct3d[n]->face_x_vert=GetMemory(struct3d[n]->tot_face_x_vert * sizeof(uint16_t)); // allocate memory for the list of vertices per face struct3d[n]->colours=GetMemory(colourcount * sizeof(uint32_t)); for(c=0; ccolours[c]=(uint32_t)*colours++; } for(f=0;ftot_face_x_vert;f++){ struct3d[n]->face_x_vert[f]=*faces++; } for(f=0;fnf;f++){ if(linecolour!=NULL){ int index=(*linecolour++) - g_OptionBase; if(index>=colourcount || index<0){ Free3DMemory(n); error("Edge colour Index %",index); } struct3d[n]->line[f]=struct3d[n]->colours[index]; } else struct3d[n]->line[f]=gui_fcolour; if(fillcolour!=NULL){ int index=(*fillcolour++) - g_OptionBase; if(index>=colourcount || index<0){ Free3DMemory(n); error("Fill colour Index %",index); } struct3d[n]->fill[f]=struct3d[n]->colours[index]; } else struct3d[n]->fill[f]=0xFFFFFFFF; FLOAT3D x=0, y=0, z=0, scale; vp=struct3d[n]->facestart[f]; // calculate the centroids of each face for(v=0;vfacecount[f];v++){ tmp=struct3d[n]->q_vertices[struct3d[n]->face_x_vert[vp+v]].m; x+=struct3d[n]->q_vertices[struct3d[n]->face_x_vert[vp+v]].x*tmp; y+=struct3d[n]->q_vertices[struct3d[n]->face_x_vert[vp+v]].y*tmp; z+=struct3d[n]->q_vertices[struct3d[n]->face_x_vert[vp+v]].z*tmp; } x/=(FLOAT3D)struct3d[n]->facecount[f]; y/=(FLOAT3D)struct3d[n]->facecount[f]; z/=(FLOAT3D)struct3d[n]->facecount[f]; struct3d[n]->q_centroids[f].x=x; struct3d[n]->q_centroids[f].y=y; struct3d[n]->q_centroids[f].z=z; scale=sqrt(struct3d[n]->q_centroids[f].x*struct3d[n]->q_centroids[f].x + struct3d[n]->q_centroids[f].y*struct3d[n]->q_centroids[f].y + struct3d[n]->q_centroids[f].z*struct3d[n]->q_centroids[f].z); struct3d[n]->q_centroids[f].x/=scale; struct3d[n]->q_centroids[f].y/=scale; struct3d[n]->q_centroids[f].z/=scale; struct3d[n]->q_centroids[f].m=scale; struct3d[n]->q_centroids[f].w=0; memcpy(&struct3d[n]->r_centroids[f],&struct3d[n]->q_centroids[f], sizeof(s_quaternion)); } return; } else if((p=checkstring(cmdline, (unsigned char *)"DIAGNOSE"))) { getargs(&p,9,(unsigned char *)","); if(argc<7)error("Argument count"); int n=getint(argv[0],1,MAX3D); int x=getint(argv[2],-32766,32766); int y=getint(argv[4],-32766,32766); int z=getinteger(argv[6]); int sort=1; if(argc==9)sort=getint(argv[8],0,1); if(struct3d[n]==NULL)error("Object % does not exist",n); if(camera[struct3d[n]->camera].viewplane==-32767)error("Camera position not defined"); diagnose3d(n, x, y, z, sort); return; } else if((p=checkstring(cmdline, (unsigned char *)"LIGHT"))) { getargs(&p,9,(unsigned char *)","); if(argc!=9)error("Argument count"); int n=getint(argv[0],1,MAX3D); struct3d[n]->light.x=getint(argv[2],-32766,32766); struct3d[n]->light.y=getint(argv[4],-32766,32766); struct3d[n]->light.z=getint(argv[6],-32766,32766); struct3d[n]->ambient=(FLOAT3D)(getint(argv[8],0,100))/100.0; return; } else if((p=checkstring(cmdline, (unsigned char *)"SHOW"))) { getargs(&p,9,(unsigned char *)","); if(argc<7)error("Argument count"); int n=getint(argv[0],1,MAX3D); int x=getint(argv[2],-32766,32766); int y=getint(argv[4],-32766,32766); int z=getinteger(argv[6]); int nonormals=0; if(argc==9)nonormals=getint(argv[8],0,1); if(struct3d[n]==NULL)error("Object % does not exist",n); if(camera[struct3d[n]->camera].viewplane==-32767)error("Camera position not defined"); display3d(n, x, y, z, 1, nonormals); return; } else if((p=checkstring(cmdline, (unsigned char *)"SET FLAGS"))) { int i, face, nbr; getargs(&p, ((MAX_ARG_COUNT-1) * 2) - 1, (unsigned char *)","); if((argc & 0b11) != 0b11) error("Invalid syntax"); int n=getint(argv[0],1,MAX3D); int flag=getint(argv[2],0,255); // step over the equals sign and get the value for the assignment for(i = 4; i < argc; i += 4) { face = getinteger(argv[i]); nbr = getinteger(argv[i + 2]); if(nbr <= 0 || nbr>struct3d[n]->nf-face) error("Invalid argument"); while(--nbr>=0) { struct3d[n]->flags[face+nbr]=flag; } } } else if((p=checkstring(cmdline, (unsigned char *)"ROTATE"))) { int i, n, v, f; s_quaternion q1; MMFLOAT *q=NULL; getargs(&p, (MAX_ARG_COUNT * 2) - 1, (unsigned char *)","); // getargs macro must be the first executable stmt in a block if((argc & 0x01 || argc<3) == 0) error("Argument count"); if(parsefloatrarray(argv[0],&q,1,1,NULL,true)!=5)error("Argument 1 must be a 5 element floating point array"); q1.w=(FLOAT3D)(*q++); q1.x=(FLOAT3D)(*q++); q1.y=(FLOAT3D)(*q++); q1.z=(FLOAT3D)(*q++); q1.m=(FLOAT3D)(*q); for(i = 2; i < argc; i += 2) { n=getint(argv[i],1,MAX3D); if(struct3d[n]==NULL)error("Object % does not exist",n); for(v=0;vnv;v++){ q_rotate(&struct3d[n]->q_vertices[v],q1,&struct3d[n]->r_vertices[v]); } for(f=0;fnf;f++){ q_rotate(&struct3d[n]->q_centroids[f],q1,&struct3d[n]->r_centroids[f]); } } return; } else if((p=checkstring(cmdline, (unsigned char *)"HIDE ALL"))) { for(int i=1;i<=MAX3D;i++){ if(struct3d[i]!=NULL && struct3d[i]->xmin!=32767){ DrawRectangle(struct3d[i]->xmin,struct3d[i]->ymin,struct3d[i]->xmax,struct3d[i]->ymax,0); struct3d[i]->xmin=32767; struct3d[i]->ymin=32767; struct3d[i]->xmax=-32767; struct3d[i]->ymax=-32767; } } return; } else if((p=checkstring(cmdline, (unsigned char *)"RESET"))) { int i, n; int v, f; getargs(&p, (MAX_ARG_COUNT * 2) - 1, (unsigned char *)","); // getargs macro must be the first executable stmt in a block if((argc & 0x01 || argc<3) == 0) error("Argument count"); for(i = 0; i < argc; i += 2) { n=getint(argv[i],1,MAX3D); for(v=0;vnv;v++){ memcpy(&struct3d[n]->q_vertices[v],&struct3d[n]->r_vertices[v], sizeof(s_quaternion)); } for(f=0;fnf;f++){ memcpy(&struct3d[n]->q_centroids[f],&struct3d[n]->r_centroids[f], sizeof(s_quaternion)); } } return; } else if((p=checkstring(cmdline, (unsigned char *)"HIDE"))) { int i, n; getargs(&p, (MAX_ARG_COUNT * 2) - 1, (unsigned char *)","); // getargs macro must be the first executable stmt in a block if((argc & 0x01 || argc<3) == 0) error("Argument count"); for(i = 0; i < argc; i += 2) { n=getint(argv[i],1,MAX3D); if(struct3d[n]==NULL)error("Object % does not exist",n); if(struct3d[n]->xmin==32767)return; DrawRectangle(struct3d[n]->xmin,struct3d[n]->ymin,struct3d[n]->xmax,struct3d[n]->ymax,0); struct3d[n]->xmin=32767; struct3d[n]->ymin=32767; struct3d[n]->xmax=-32767; struct3d[n]->ymax=-32767; } return; } else if((p=checkstring(cmdline, (unsigned char *)"RESTORE"))) { int i, n; getargs(&p, (MAX_ARG_COUNT * 2) - 1, (unsigned char *)","); // getargs macro must be the first executable stmt in a block if((argc & 0x01 || argc<3) == 0) error("Argument count"); for(i = 0; i < argc; i += 2) { n=getint(argv[i],1,MAX3D); if(struct3d[n]==NULL)error("Object % does not exist",n); if(struct3d[n]->xmin!=32767)error("Object % is not hidden",n); display3d(n, struct3d[n]->current.x, struct3d[n]->current.y, struct3d[n]->current.z, 1, struct3d[n]->nonormals); } return; } else if((p=checkstring(cmdline, (unsigned char *)"WRITE"))) { getargs(&p,9,(unsigned char *)","); if(argc<7)error("Argument count"); int n=getint(argv[0],1,MAX3D); int x=getint(argv[2],-32766,32766); int y=getint(argv[4],-32766,32766); int z=getinteger(argv[6]); int nonormals=0; if(argc==9)nonormals=getint(argv[8],0,1); if(struct3d[n]==NULL)error("Object % does not exist",n); if(camera[struct3d[n]->camera].viewplane==-32767)error("Camera position not defined"); display3d(n, x, y, z, 0, nonormals); return; } else if((p=checkstring(cmdline, (unsigned char *)"CLOSE ALL"))) { closeall3d(); return; } else if((p=checkstring(cmdline, (unsigned char *)"CLOSE"))) { int i, n; getargs(&p, (MAX_ARG_COUNT * 2) - 1, (unsigned char *)","); // getargs macro must be the first executable stmt in a block if((argc & 0x01 || argc<3) == 0) error("Argument count"); for(i = 0; i < argc; i += 2) { n=getint(argv[i],1,MAX3D); if(struct3d[n]==NULL)error("Object % does not exist",n); if(struct3d[n]->xmin!=32767)DrawRectangle(struct3d[n]->xmin,struct3d[n]->ymin,struct3d[n]->xmax,struct3d[n]->ymax,0); Free3DMemory(n); } return; } else if((p=checkstring(cmdline, (unsigned char *)"CAMERA"))) { getargs(&p,11,(unsigned char *)","); if(argc<3)error("Argument count"); int n=getint(argv[0],1,MAXCAM); camera[n].viewplane=getnumber(argv[2]); camera[n].x=(FLOAT3D)0; camera[n].y=(FLOAT3D)0; camera[n].panx=(FLOAT3D)0; camera[n].pany=(FLOAT3D)0; camera[n].z=0.0; if(argc>=5 && *argv[4]) camera[n].x=getnumber(argv[4]); if(camera[n].x > 32766 || camera[n].x < -32766 )error("Valid is -32766 to 32766"); if(argc>=7 && *argv[6]) camera[n].y=getnumber(argv[6]); if(camera[n].y > 32766 || camera[n].x < -32766 )error("Valid is -32766 to 32766"); if(argc>=9 && *argv[8]) camera[n].panx=getint(argv[8],-32766-camera[n].x,32766-camera[n].x); if(argc==11 )camera[n].pany=getint(argv[10],-32766-camera[n].y,32766-camera[n].y); return; } else { error("Syntax"); } } void MIPS16 fun_3D(void){ unsigned char *p; if((p=checkstring(ep, (unsigned char *)"XMIN"))) { getargs(&p,1,(unsigned char *)","); int n=getint(argv[0],1,MAX3D); if(struct3d[n]==NULL)error("Object does not exist"); fret=struct3d[n]->xmin; } else if((p=checkstring(ep, (unsigned char *)"XMAX"))) { getargs(&p,1,(unsigned char *)","); int n=getint(argv[0],1,MAX3D); if(struct3d[n]==NULL)error("Object does not exist"); fret=struct3d[n]->xmax; } else if((p=checkstring(ep, (unsigned char *)"YMIN"))) { getargs(&p,1,(unsigned char *)","); int n=getint(argv[0],1,MAX3D); if(struct3d[n]==NULL)error("Object does not exist"); fret=struct3d[n]->ymin; } else if((p=checkstring(ep, (unsigned char *)"YMAX"))) { getargs(&p,1,(unsigned char *)","); int n=getint(argv[0],1,MAX3D); if(struct3d[n]==NULL)error("Object does not exist"); fret=struct3d[n]->ymax; } else if((p=checkstring(ep, (unsigned char *)"X"))) { getargs(&p,1,(unsigned char *)","); int n=getint(argv[0],1,MAX3D); if(struct3d[n]==NULL)error("Object does not exist"); fret=struct3d[n]->current.x; } else if((p=checkstring(ep, (unsigned char *)"Y"))) { getargs(&p,1,(unsigned char *)","); int n=getint(argv[0],1,MAX3D); if(struct3d[n]==NULL)error("Object does not exist"); fret=struct3d[n]->current.y; } else if((p=checkstring(ep, (unsigned char *)"DISTANCE"))) { getargs(&p,1,(unsigned char *)","); int n=getint(argv[0],1,MAX3D); if(struct3d[n]==NULL)error("Object does not exist"); fret=struct3d[n]->distance; } else if((p=checkstring(ep, (unsigned char *)"Z"))) { getargs(&p,1,(unsigned char *)","); int n=getint(argv[0],1,MAX3D); if(struct3d[n]==NULL)error("Object does not exist"); fret=struct3d[n]->current.z; } else error("Syntax"); targ=T_NBR; } /* * @cond * The following section will be excluded from the documentation. */ #endif #ifdef PICOMITEVGA void closeframebuffer(char layer){ if(layer=='A')WriteBuf=DisplayBuf; if(FrameBuf!=DisplayBuf && (layer=='A' || layer=='F')){ if(WriteBuf==FrameBuf)WriteBuf=DisplayBuf; switch(DISPLAY_TYPE){ case SCREENMODE1: case SCREENMODE2: #ifdef rp2350 FrameBuf=DisplayBuf; #else FreeMemory((void *)FrameBuf); #endif break; #ifdef rp2350 case SCREENMODE3: FreeMemory((void *)FrameBuf); break; #ifdef HDMI case SCREENMODE4: case SCREENMODE5: FreeMemory((void *)FrameBuf); break; #endif #endif } } if(LayerBuf!=DisplayBuf && (layer=='A' || layer=='L')){ if(WriteBuf==LayerBuf)WriteBuf=DisplayBuf; volatile unsigned char *temp= LayerBuf; switch(DISPLAY_TYPE){ case SCREENMODE2: transparent=0; case SCREENMODE1: #ifdef rp2350 LayerBuf=DisplayBuf; #else LayerBuf=DisplayBuf; FreeMemory((void *)temp); #endif break; #ifdef rp2350 case SCREENMODE3: LayerBuf=DisplayBuf; FreeMemory((void *)temp); break; #ifdef HDMI case SCREENMODE4: LayerBuf=DisplayBuf; FreeMemory((void *)temp); break; case SCREENMODE5: LayerBuf=DisplayBuf; transparent=0; break; #endif #endif } } if(SecondFrame!=DisplayBuf && (layer=='A' || layer=='2')){ FreeMemory((void *)SecondFrame); } if(SecondLayer!=DisplayBuf && (layer=='A' || layer=='T')){ if(WriteBuf==LayerBuf)WriteBuf=DisplayBuf; volatile unsigned char *temp= SecondLayer; switch(DISPLAY_TYPE){ case SCREENMODE2: transparents=0; SecondLayer=DisplayBuf; break; case SCREENMODE1: SecondLayer=DisplayBuf; FreeMemory((void *)temp); break; #ifdef rp2350 case SCREENMODE3: SecondLayer=DisplayBuf; FreeMemory((void *)temp); break; #ifdef HDMI case SCREENMODE4: SecondLayer=DisplayBuf; FreeMemory((void *)temp); break; case SCREENMODE5: SecondLayer=DisplayBuf; transparents=0; break; #endif #endif } } WriteBuf=(unsigned char *)FRAMEBUFFER; DisplayBuf=(unsigned char *)FRAMEBUFFER; LayerBuf=(unsigned char *)FRAMEBUFFER; FrameBuf=(unsigned char *)FRAMEBUFFER; SecondLayer=(unsigned char *)FRAMEBUFFER; SecondFrame=(unsigned char *)FRAMEBUFFER; transparent=0; } /* @endcond */ void cmd_framebuffer(void){ /* RP2040 version support just modes 1 and 2 RP2350 vversions support modes 1 to 5 All modes can have a framebuffer and a layer buffer but only modes 2 and 5 automatically display the layer buffer over the top of the main display In all other cases it is just another framebuffer that can be used to build up images to be copied to the main display For VGA/HDMI Layer buffers and framebuffers have exactly the same resolution as the main display (unlike TFT displays) For RP2350 Modes 1 and 2 both buffers are in the allocated Video Memory (640x240 bytes == 320x240x2) For RP2350 Mode 5 the layer buffer is in the allocated video memory All other buffers are allocated out of variable space using GetMemory NB: for RP2350 with PSRAM buffers may be allocated in the slower external memory Buffer sizes are: Normal: #define MODE1SIZE_S VMaxH*VMaxV/8 #define MODE2SIZE_S 320*240/2 #define MODE3SIZE_S VMaxH*VMaxV/2 #define MODE4SIZE_S 320*240*2 #define MODE5SIZE_S 320*240 Widescreen: #define MODE1SIZE_W 1280 *720 /8 #define MODE2SIZE_W (1280/4) * (720/4)/2 #define MODE3SIZE_W (1280/2) * (720/2)/2 #define MODE5SIZE_W (1280/4) * (720/4) XGA: #define MODE1SIZE_W `1024 *768 /8 #define MODE2SIZE_W (1024/4) * (768/4)/2 #define MODE3SIZE_W (1024/2) * (768/2)/2 #define MODE5SIZE_W (1024/4) * (768/4) */ unsigned char *p; #ifdef rp2350 if((p=checkstring(cmdline, (unsigned char *)"CREATE 2"))) { int colour=0; if(SecondFrame==DisplayBuf){ getargs(&p,1,(unsigned char *)","); switch(DISPLAY_TYPE){ case SCREENMODE2: case SCREENMODE1: SecondFrame=GetMemory(ScreenSize); break; #ifdef rp2350 case SCREENMODE3: SecondFrame=GetMemory(ScreenSize); break; #ifdef HDMI case SCREENMODE4: SecondFrame=GetMemory(ScreenSize); break; case SCREENMODE5: SecondFrame=GetMemory(ScreenSize); break; #endif #endif } } else error("Framebuffer 2 already exists"); memset((void *)SecondFrame,colour,ScreenSize); } else #endif if((p=checkstring(cmdline, (unsigned char *)"CREATE"))) { if(FrameBuf==DisplayBuf){ switch(DISPLAY_TYPE){ case SCREENMODE1: case SCREENMODE2: #ifdef rp2350 if(ScreenSize=(uint8_t *)PSRAMbase && SecondLayer< (uint8_t *)(PSRAMbase + 1024*1024*16)){ FreeMemory((void *)SecondLayer); error("Second Layer must be in tightly coupled RAM, declare before other variables"); } colour=transparents | (transparents<<4); break; #ifdef HDMI case SCREENMODE4: SecondLayer=GetMemory(ScreenSize); break; case SCREENMODE5: SecondLayer=GetMemory(ScreenSize); if(SecondLayer>=(uint8_t *)PSRAMbase && SecondLayer< (uint8_t *)(PSRAMbase + 1024*1024*16)){ FreeMemory((void *)SecondLayer); error("Second Layer must be in tightly coupled RAM, declare before other variables"); } if(argc==1)transparents=getint(argv[0],0,255); colour=transparents; break; #endif } } else error("Framebuffer already exists"); memset((void *)SecondLayer,colour,ScreenSize); #endif } else if((p=checkstring(cmdline, (unsigned char *)"LAYER"))) { int colour=0; if(LayerBuf==DisplayBuf){ getargs(&p,1,(unsigned char *)","); switch(DISPLAY_TYPE){ case SCREENMODE2: if(argc==1)transparent=getint(argv[0],0,15); colour=transparent | (transparent<<4); case SCREENMODE1: #ifdef rp2350 if(ScreenSize(uint8_t *)PSRAMbase && LayerBuf< (uint8_t *)(PSRAMbase + 1024*1024*16)){ FreeMemory((void *)LayerBuf); error("Layer Buffer must be in tightly coupled RAM, declare before other variables"); } #endif } else error("Framebuffer already exists"); if(DISPLAY_TYPE!=SCREENMODE4)memset((void *)LayerBuf,colour,ScreenSize); else { uint16_t *p=(uint16_t *)LayerBuf; for(int i=0;i>2); // #else memcpy((void *)d,(void *)s,ScreenSize); // #endif else error("Buffer not created"); } else error("Syntax"); } #endif