mirror of
https://github.com/clockworkpi/PicoCalc.git
synced 2025-12-12 10:18:54 +01:00
9192 lines
367 KiB
C
9192 lines
367 KiB
C
/***********************************************************************************************************************
|
|
PicoMite MMBasic
|
|
|
|
Draw.c
|
|
|
|
<COPYRIGHT HOLDERS> Geoff Graham, Peter Mather
|
|
Copyright (c) 2021, <COPYRIGHT HOLDERS> 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 <copyright holder>.
|
|
5. Neither the name of the <copyright holder> 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 <COPYRIGHT HOLDERS> 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 <COPYRIGHT HOLDERS> 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))
|
|
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=2000, high_y=-1, low_x=2000, high_x=-1;
|
|
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<X_TILE;x++){
|
|
for(int y=0;y<Y_TILE;y++){
|
|
tilefcols[y*X_TILE+x]=RGB555(gui_fcolour);
|
|
tilebcols[y*X_TILE+x]=bcolour;
|
|
}
|
|
}
|
|
} else {
|
|
uint8_t bcolour = RGB332(c);
|
|
for(int x=0;x<X_TILE;x++){
|
|
for(int y=0;y<Y_TILE;y++){
|
|
tilefcols_w[y*X_TILE+x]=RGB332(gui_fcolour);
|
|
tilebcols_w[y*X_TILE+x]=bcolour;
|
|
}
|
|
}
|
|
}
|
|
CurrentX=CurrentY=0;
|
|
#else
|
|
memset((void *)WriteBuf,0,ScreenSize);
|
|
for(int x=0;x<X_TILE;x++){
|
|
for(int y=0;y<Y_TILE;y++){
|
|
tilefcols[y*X_TILE+x]=RGB121pack(gui_fcolour);
|
|
tilebcols[y*X_TILE+x]=RGB121pack(c);
|
|
}
|
|
}
|
|
#endif
|
|
} else DrawRectangle(0, 0, HRes - 1, VRes - 1, c);
|
|
#else
|
|
DrawRectangle(0, 0, HRes - 1, VRes - 1, c);
|
|
#endif
|
|
}
|
|
void DrawBuffered(int xti, int yti, int c, int complete){
|
|
static unsigned char pos=0;
|
|
static unsigned char movex, movey, movec;
|
|
static short xtilast[8];
|
|
static short ytilast[8];
|
|
static int clast[8];
|
|
xtilast[pos]=xti;
|
|
ytilast[pos]=yti;
|
|
clast[pos]=c;
|
|
if(complete==1){
|
|
if(pos==1){
|
|
DrawPixel(xtilast[0],ytilast[0],clast[0]);
|
|
} else {
|
|
DrawLine(xtilast[0],ytilast[0],xtilast[pos-1],ytilast[pos-1],1,clast[0]);
|
|
}
|
|
pos=0;
|
|
} else {
|
|
if(pos==0){
|
|
movex = movey = movec = 1;
|
|
pos+=1;
|
|
} else {
|
|
if(xti==xtilast[0] && abs(yti-ytilast[pos-1])==1)movex=0;else movex=1;
|
|
if(yti==ytilast[0] && abs(xti-xtilast[pos-1])==1)movey=0;else movey=1;
|
|
if(c==clast[0])movec=0;else movec=1;
|
|
if(movec==0 && (movex==0 || movey==0) && pos<6) pos+=1;
|
|
else {
|
|
if(pos==1){
|
|
DrawPixel(xtilast[0],ytilast[0],clast[0]);
|
|
} else {
|
|
DrawLine(xtilast[0],ytilast[0],xtilast[pos-1],ytilast[pos-1],1,clast[0]);
|
|
}
|
|
movex = movey = movec = 1;
|
|
xtilast[0]=xti;
|
|
ytilast[0]=yti;
|
|
clast[0]=c;
|
|
pos=1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************************************
|
|
Draw a line on a the video output
|
|
x1, y1 - the start coordinate
|
|
x2, y2 - the end coordinate
|
|
w - the width of the line (ignored for diagional lines)
|
|
c - the colour to use
|
|
***************************************************************************************************/
|
|
#define abs( a) (((a)> 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<r2*2+1;j++){
|
|
for(i=0;i<ints_per_line;i++){
|
|
k=br[i+j*ints_per_line];
|
|
for(m=0;m<32;m++){
|
|
if(xs==-1 && (k & 0x80000000)){
|
|
xs=m;
|
|
xi=i;
|
|
}
|
|
if(xs!=-1 && !(k & 0x80000000)){
|
|
DrawRectangle(x-r2+xs+xi*32, y-r2+j, x-r2+m+i*32, y-r2+j, c);
|
|
xs=-1;
|
|
}
|
|
k<<=1;
|
|
}
|
|
}
|
|
if(xs!=-1){
|
|
DrawRectangle(x-r2+xs+xi*32, y-r2+j, x-r2+m+i*32, y-r2+j, c);
|
|
xs=-1;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else { //single thickness outline
|
|
int w1=w,r1=radius;
|
|
if(fill>=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(x1<xmin[y1])xmin[y1]=x1;
|
|
if(x2<xmin[y1])xmin[y1]=x2;
|
|
if(x1>xmax[y1])xmax[y1]=x1;
|
|
if(x2>xmax[y1])xmax[y1]=x2;
|
|
return;
|
|
}
|
|
if(x1 == x2) {
|
|
if(y2<y1)swap(y2,y1);
|
|
if(y1<0)y1=0;
|
|
if(y1>=VRes)y1=VRes-1;
|
|
if(y2<0)y2=0;
|
|
if(y2>=VRes)y2=VRes-1;
|
|
for(int y=y1;y<=y2;y++) {
|
|
if(x1<xmin[y])xmin[y]=x1;
|
|
if(x1>xmax[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 = x2<x1 ? 1 : -1; // line-drawing direction offsets
|
|
int offY = y2<y1 ? 1 : -1;
|
|
int x = x2; // incremental location
|
|
int y = y2;
|
|
int err;
|
|
if(x<xmin[y])xmin[y]=x;
|
|
if(x>xmax[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(x<xmin[y])xmin[y]=x;
|
|
if(x>xmax[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(x<xmin[y])xmin[y]=x;
|
|
if(x>xmax[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<VRes){
|
|
xmin[y]=32767;
|
|
xmax[y]=-1;
|
|
}
|
|
}
|
|
CalcLine(x0, y0, x1, y1, xmin, xmax);
|
|
CalcLine(x1, y1, x2, y2, xmin, xmax);
|
|
CalcLine(x2, y2, x0, y0, xmin, xmax);
|
|
for(y=y0;y<=y2;y++){
|
|
if(y>=0 && y<VRes)DrawRectangle(xmin[y], y, xmax[y], y, f);
|
|
}
|
|
// if(c!=f){
|
|
DrawLine(x0, y0, x1, y1, 1, c);
|
|
DrawLine(x1, y1, x2, y2, 1, c);
|
|
DrawLine(x2, y2, x0, y0, 1, c);
|
|
// }
|
|
FreeMemory((unsigned char *)xmin);
|
|
FreeMemory((unsigned char *)xmax);
|
|
}
|
|
}
|
|
|
|
}
|
|
void RestoreTriangle(int bnbr, char *buff){
|
|
short *p=(short *)buff;
|
|
int x0=p[0];
|
|
int y0=p[1];
|
|
int x1=p[2];
|
|
int y1=p[3];
|
|
int x2=p[4];
|
|
int y2=p[5];
|
|
char *buffp=(char *)&p[6];
|
|
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);
|
|
}
|
|
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<VRes){
|
|
xmin[y]=32767;
|
|
xmax[y]=-1;
|
|
}
|
|
}
|
|
CalcLine(x0, y0, x1, y1, xmin, xmax);
|
|
CalcLine(x1, y1, x2, y2, xmin, xmax);
|
|
CalcLine(x2, y2, x0, y0, xmin, xmax);
|
|
for(y=y0;y<=y2;y++){
|
|
DrawBuffer(xmin[y], y, xmax[y], y, (unsigned char *)buffp);
|
|
buffp+=(xmax[y]-xmin[y]+1)*3;
|
|
}
|
|
FreeMemory((unsigned char *)xmin);
|
|
FreeMemory((unsigned char *)xmax);
|
|
}
|
|
}
|
|
void SaveTriangle(int bnbr, char *buff){
|
|
short *p=(short *)buff;
|
|
int x0=p[0];
|
|
int y0=p[1];
|
|
int x1=p[2];
|
|
int y1=p[3];
|
|
int x2=p[4];
|
|
int y2=p[5];
|
|
char *buffp=(char *)&p[6];
|
|
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);
|
|
}
|
|
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<VRes){
|
|
xmin[y]=32767;
|
|
xmax[y]=-1;
|
|
}
|
|
}
|
|
CalcLine(x0, y0, x1, y1, xmin, xmax);
|
|
CalcLine(x1, y1, x2, y2, xmin, xmax);
|
|
CalcLine(x2, y2, x0, y0, xmin, xmax);
|
|
for(y=y0;y<=y2;y++){
|
|
ReadBuffer(xmin[y], y, xmax[y], y, (unsigned char *)buffp);
|
|
buffp+=(xmax[y]-xmin[y]+1)*3;
|
|
}
|
|
FreeMemory((unsigned char *)xmin);
|
|
FreeMemory((unsigned char *)xmax);
|
|
}
|
|
}
|
|
int SizeTriangle(int x0, int y0, int x1, int y1, int x2, int y2) {
|
|
int n=0;
|
|
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);
|
|
}
|
|
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<VRes){
|
|
xmin[y]=32767;
|
|
xmax[y]=-1;
|
|
}
|
|
}
|
|
CalcLine(x0, y0, x1, y1, xmin, xmax);
|
|
CalcLine(x1, y1, x2, y2, xmin, xmax);
|
|
CalcLine(x2, y2, x0, y0, xmin, xmax);
|
|
for(y=y0;y<=y2;y++){
|
|
n+=(xmax[y]-xmin[y]+1);
|
|
}
|
|
FreeMemory((unsigned char *)xmin);
|
|
FreeMemory((unsigned char *)xmax);
|
|
}
|
|
return n;
|
|
}
|
|
/* @endcond */
|
|
|
|
void cmd_RestoreTriangle(unsigned char *p){
|
|
getargs(&p, 1, (unsigned char*)",");
|
|
if(*argv[0]=='#')argv[0]++;
|
|
int bnbr = getint(argv[0], 1, MAXBLITBUF) - 1; // get the buffer number
|
|
if (blitbuff[bnbr].blitbuffptr == NULL) error((char *)"Buffer not in use");
|
|
if(blitbuff[bnbr].h!=9999)error("Invalid buffer for restore");
|
|
RestoreTriangle(bnbr,blitbuff[bnbr].blitbuffptr);
|
|
FreeMemory((unsigned char *)blitbuff[bnbr].blitbuffptr);
|
|
blitbuff[bnbr].blitbuffptr = NULL;
|
|
}
|
|
|
|
void cmd_ReadTriangle(unsigned char *p){
|
|
int bnbr,x1,x2,x3,y1,y2,y3,size;
|
|
getargs(&p, 13, (unsigned char*)",");
|
|
if(argc!=13)error((char *)"Syntax");
|
|
if(*argv[0]=='#')argv[0]++;
|
|
bnbr = getint(argv[0], 1, MAXBLITBUF) - 1; // get the buffer number
|
|
if (blitbuff[bnbr].blitbuffptr != NULL) error((char *)"Buffer in use");
|
|
x1 = getinteger(argv[2]);
|
|
y1 = getinteger(argv[4]);
|
|
x2 = getinteger(argv[6]);
|
|
y2 = getinteger(argv[8]);
|
|
x3 = getinteger(argv[10]);
|
|
y3 = getinteger(argv[12]);
|
|
size=SizeTriangle(x1,y1,x2,y2,x3,y3);
|
|
blitbuff[bnbr].blitbuffptr = GetMemory(size*3+256);
|
|
blitbuff[bnbr].h=9999;
|
|
short *buff = (short *)blitbuff[bnbr].blitbuffptr;
|
|
*buff++=x1;
|
|
*buff++=y1;
|
|
*buff++=x2;
|
|
*buff++=y2;
|
|
*buff++=x3;
|
|
*buff++=y3;
|
|
SaveTriangle(bnbr,blitbuff[bnbr].blitbuffptr);
|
|
}
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
|
|
/******************************************************************************************
|
|
Print a char on the LCD display
|
|
Any characters not in the font will print as a space.
|
|
The char is printed at the current location defined by CurrentX and CurrentY
|
|
*****************************************************************************************/
|
|
void GUIPrintChar(int fnt, int fc, int bc, char c, int orientation) {
|
|
unsigned char *p, *fp, *np = NULL, *AllocatedMemory = NULL;
|
|
int BitNumber, BitPos, x, y, newx, newy, modx, mody, scale = fnt & 0b1111;
|
|
int height, width;
|
|
if(PrintPixelMode==1)bc=-1;
|
|
if(PrintPixelMode==2){
|
|
int s=bc;
|
|
bc=fc;
|
|
fc=s;
|
|
}
|
|
if(PrintPixelMode==5){
|
|
fc=bc;
|
|
bc=-1;
|
|
}
|
|
// to get the +, - and = chars for font 6 we fudge them by scaling up font 1
|
|
if((fnt & 0xf0) == 0x50 && (c == '-' || c == '+' || c == '=')) {
|
|
fp = (unsigned char *)FontTable[0];
|
|
scale = scale * 4;
|
|
} else
|
|
fp = (unsigned char *)FontTable[fnt >> 4];
|
|
|
|
height = fp[1];
|
|
width = fp[0];
|
|
modx = mody = 0;
|
|
if(orientation > ORIENT_VERT){
|
|
AllocatedMemory = np = GetMemory(width * height);
|
|
if (orientation == ORIENT_INVERTED) {
|
|
modx -= width * scale -1;
|
|
mody -= height * scale -1;
|
|
}
|
|
else if (orientation == ORIENT_CCW90DEG) {
|
|
mody -= width * scale;
|
|
}
|
|
else if (orientation == ORIENT_CW90DEG){
|
|
modx -= height * scale -1;
|
|
}
|
|
}
|
|
|
|
if(c >= fp[2] && c < fp[2] + fp[3]) {
|
|
p = fp + 4 + (int)(((c - fp[2]) * height * width) / 8);
|
|
|
|
if(orientation > ORIENT_VERT) { // non-standard orientation
|
|
if (orientation == ORIENT_INVERTED) {
|
|
for(y = 0; y < height; y++) {
|
|
newy = height - y - 1;
|
|
for(x=0; x < width; x++) {
|
|
newx = width - x - 1;
|
|
if((p[((y * width) + x)/8] >> (((height * width) - ((y * width) + x) - 1) %8)) & 1) {
|
|
BitNumber=((newy * width) + newx);
|
|
BitPos = 128 >> (BitNumber % 8);
|
|
np[BitNumber / 8] |= BitPos;
|
|
}
|
|
}
|
|
}
|
|
} else if (orientation == ORIENT_CCW90DEG) {
|
|
for(y = 0; y < height; y++) {
|
|
newx = y;
|
|
for(x = 0; x < width; x++) {
|
|
newy = width - x - 1;
|
|
if((p[((y * width) + x)/8] >> (((height * width) - ((y * width) + x) - 1) %8)) & 1) {
|
|
BitNumber=((newy * height) + newx);
|
|
BitPos = 128 >> (BitNumber % 8);
|
|
np[BitNumber / 8] |= BitPos;
|
|
}
|
|
}
|
|
}
|
|
} else if (orientation == ORIENT_CW90DEG) {
|
|
for(y = 0; y < height; y++) {
|
|
newx = height - y - 1;
|
|
for(x=0; x < width; x++) {
|
|
newy = x;
|
|
if((p[((y * width) + x)/8] >> (((height * width) - ((y * width) + x) - 1) %8)) & 1) {
|
|
BitNumber=((newy * height) + newx);
|
|
BitPos = 128 >> (BitNumber % 8);
|
|
np[BitNumber / 8] |= BitPos;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else np = p;
|
|
|
|
if(orientation < ORIENT_CCW90DEG) DrawBitmap(CurrentX + modx, CurrentY + mody, width, height, scale, fc, bc, np);
|
|
else DrawBitmap(CurrentX + modx, CurrentY + mody, height, width, scale, fc, bc, np);
|
|
} else {
|
|
if(orientation < ORIENT_CCW90DEG) DrawRectangle(CurrentX + modx, CurrentY + mody, CurrentX + modx + (width * scale), CurrentY + mody + (height * scale), bc);
|
|
else DrawRectangle(CurrentX + modx, CurrentY + mody, CurrentX + modx + (height * scale), CurrentY + mody + (width * scale), bc);
|
|
}
|
|
|
|
// to get the . and degree symbols for font 6 we draw a small circle
|
|
if((fnt & 0xf0) == 0x50) {
|
|
if(orientation > ORIENT_VERT) {
|
|
if(orientation == ORIENT_INVERTED) {
|
|
if(c == '.') DrawCircle(CurrentX + modx + (width * scale)/2, CurrentY + mody + 7 * scale, 4 * scale, 0, fc, fc, 1.0);
|
|
if(c == 0x60) DrawCircle(CurrentX + modx + (width * scale)/2, CurrentY + mody + (height * scale)- 9 * scale, 6 * scale, 2 * scale, fc, -1, 1.0);
|
|
} else if(orientation == ORIENT_CCW90DEG) {
|
|
if(c == '.') DrawCircle(CurrentX + modx + (height * scale) - 7 * scale, CurrentY + mody + (width * scale)/2, 4 * scale, 0, fc, fc, 1.0);
|
|
if(c == 0x60) DrawCircle(CurrentX + modx + 9 * scale, CurrentY + mody + (width * scale)/2, 6 * scale, 2 * scale, fc, -1, 1.0);
|
|
} else if(orientation == ORIENT_CW90DEG) {
|
|
if(c == '.') DrawCircle(CurrentX + modx + 7 * scale, CurrentY + mody + (width * scale)/2, 4 * scale, 0, fc, fc, 1.0);
|
|
if(c == 0x60) DrawCircle(CurrentX + modx + (height * scale)- 9 * scale, CurrentY + mody + (width * scale)/2, 6 * scale, 2 * scale, fc, -1, 1.0);
|
|
}
|
|
|
|
} else {
|
|
if(c == '.') DrawCircle(CurrentX + modx + (width * scale)/2, CurrentY + mody + (height * scale) - 7 * scale, 4 * scale, 0, fc, fc, 1.0);
|
|
if(c == 0x60) DrawCircle(CurrentX + modx + (width * scale)/2, CurrentY + mody + 9 * scale, 6 * scale, 2 * scale, fc, -1, 1.0);
|
|
}
|
|
}
|
|
|
|
if(orientation == ORIENT_NORMAL) CurrentX += width * scale;
|
|
else if (orientation == ORIENT_VERT) CurrentY += height * scale;
|
|
else if (orientation == ORIENT_INVERTED) CurrentX -= width * scale;
|
|
else if (orientation == ORIENT_CCW90DEG) CurrentY -= width * scale;
|
|
else if (orientation == ORIENT_CW90DEG ) CurrentY += width * scale;
|
|
if(orientation > 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<nc;i++){
|
|
c = (cfptr == NULL ? cptr[i] : (int)cfptr[i]);
|
|
if(c < 0 || c > WHITE) error("% is invalid (valid is % to %)", (int)c, 0, WHITE);
|
|
}
|
|
}
|
|
}
|
|
for(i=0;i<n;i++){
|
|
x1 = (x1fptr == NULL ? x1ptr[i] : (int)x1fptr[i]);
|
|
y1 = (y1fptr == NULL ? y1ptr[i] : (int)y1fptr[i]);
|
|
if(nc > 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<nw;i++){
|
|
w = (wfptr == NULL ? wptr[i] : (int)wfptr[i]);
|
|
if(w < 0 || w > 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<nc;i++){
|
|
c = (cfptr == NULL ? cptr[i] : (int)cfptr[i]);
|
|
if(c < 0 || c > 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<nf;i++){
|
|
f = (ffptr == NULL ? fptr[i] : (int)ffptr[i]);
|
|
if(f < 0 || f > WHITE) error("% is invalid (valid is % to %)", (int)f, 0, WHITE);
|
|
}
|
|
}
|
|
}
|
|
int save_refresh=Option.Refresh;
|
|
Option.Refresh=0;
|
|
for(i=0;i<n;i++){
|
|
x = (xfptr==NULL ? xptr[i] : (int)xfptr[i]);
|
|
y = (yfptr==NULL ? yptr[i] : (int)yfptr[i]);
|
|
r = (rfptr==NULL ? rptr[i] : (int)rfptr[i])-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(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<xb0)swap(xb1,xb0);
|
|
if(yb1<yb0)swap(yb1,yb0);
|
|
|
|
// steep means that m > 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<w;i++) drawAAPixel(y + i, x, 1, c);
|
|
drawAAPixel(y + w, x, fpart, c);
|
|
intery = intery + gradient;
|
|
}
|
|
} else {
|
|
for(int x=xpxl1 + 1; x<=xpxl2; x++){
|
|
fpart = intery - floor(intery);
|
|
rfpart = 1 - fpart;
|
|
MMFLOAT y = floor(intery);
|
|
drawAAPixel(x, y , rfpart, c);
|
|
for(int i=1;i<w;i++) drawAAPixel(x, y + i, 1, c);
|
|
drawAAPixel(x, y + w, fpart, c);
|
|
intery = intery + gradient;
|
|
}
|
|
}
|
|
}
|
|
/* @endcond */
|
|
|
|
void cmd_line(void) {
|
|
if(Option.DISPLAY_TYPE == 0) error("Display not configured");
|
|
unsigned char *p;
|
|
if(CMM1){
|
|
int x1, y1, x2, y2, colour, box, fill;
|
|
getargs(&cmdline, 5, (unsigned char *)",");
|
|
|
|
// check if it is actually a LINE INPUT command
|
|
if(argc < 1) error("Invalid syntax");
|
|
x1 = lastx; y1 = lasty; colour = gui_fcolour; box = false; fill = false; // set the defaults for optional components
|
|
p = argv[0];
|
|
if(tokenfunction(*p) != op_subtract) {
|
|
// the start point is specified - get the coordinates and step over to where the minus token should be
|
|
if(*p != '(') error("Expected opening bracket");
|
|
getcoord((char *)p , &x1, &y1);
|
|
p = getclosebracket(p) + 1;
|
|
skipspace(p);
|
|
}
|
|
if(tokenfunction(*p) != op_subtract) error("Invalid syntax");
|
|
p++;
|
|
skipspace(p);
|
|
if(*p != '(') error("Expected opening bracket");
|
|
getcoord((char *)p , &x2, &y2);
|
|
if(argc > 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<nw;i++){
|
|
w = (wfptr == NULL ? wptr[i] : (int)wfptr[i]);
|
|
if(w < -100 || w > 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<nc;i++){
|
|
c = (cfptr == NULL ? cptr[i] : (int)cfptr[i]);
|
|
if(c < 0 || c > WHITE) error("% is invalid (valid is % to %)", (int)c, 0, WHITE);
|
|
}
|
|
}
|
|
}
|
|
for(i=0;i<n;i++){
|
|
x1 = (x1fptr==NULL ? x1ptr[i] : (int)x1fptr[i]);
|
|
y1 = (y1fptr==NULL ? y1ptr[i] : (int)y1fptr[i]);
|
|
x2 = (x2fptr==NULL ? x2ptr[i] : (int)x2fptr[i]);
|
|
y2 = (y2fptr==NULL ? y2ptr[i] : (int)y2fptr[i]);
|
|
if(nw > 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<nwidth;i++){
|
|
width = (wifptr == NULL ? wiptr[i] : (int)wifptr[i]);
|
|
if(width <1 || width > 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<nheight;i++){
|
|
height = (hfptr == NULL ? hptr[i] : (int)hfptr[i]);
|
|
if(height <1 || height > 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<nw;i++){
|
|
w = (wfptr == NULL ? wptr[i] : (int)wfptr[i]);
|
|
if(w < 0 || w > 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<nc;i++){
|
|
c = (cfptr == NULL ? cptr[i] : (int)cfptr[i]);
|
|
if(c < 0 || c > 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<nf;i++){
|
|
f = (ffptr == NULL ? fptr[i] : (int)ffptr[i]);
|
|
if(f < -1 || f > WHITE) error("% is invalid (valid is % to %)", (int)f, -1, WHITE);
|
|
}
|
|
}
|
|
}
|
|
for(i=0;i<n;i++){
|
|
x1 = (x1fptr==NULL ? x1ptr[i] : (int)x1fptr[i]);
|
|
y1 = (y1fptr==NULL ? y1ptr[i] : (int)y1fptr[i]);
|
|
if(nwidth > 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<rad1)rad2+=360;
|
|
rad3=rad1+360;
|
|
rstart=rad2;
|
|
int quad1 = (rad1 / 45) % 8;
|
|
x2=x;y2=y;
|
|
int ints_per_line=RoundUptoInt((r2*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, 1.0, 1.0);
|
|
DrawFilledCircle(x, y, r1, r2, 0, ints_per_line, br, 1.0, 1.0);
|
|
while(rstart<rad3){
|
|
pointcalc(rstart, x, y, r2, &x0, &y0);
|
|
quadr = (rstart / 45) % 8;
|
|
if(quadr==quad1 && rad3-rstart<45){
|
|
pointcalc(rad3, x, y, r2, &x1, &y1);
|
|
ClearTriangle(x0-x+r2, y0-y+r2, x1-x+r2, y1-y+r2, x2-x+r2, y2-y+r2, ints_per_line, br);
|
|
rstart=rad3;
|
|
} else {
|
|
rstart +=45;
|
|
rstart -= (rstart % 45);
|
|
pointcalc(rstart, x, y, r2, &xr, &yr);
|
|
ClearTriangle(x0-x+r2, y0-y+r2, xr-x+r2, yr-y+r2, x2-x+r2, y2-y+r2, ints_per_line, br);
|
|
}
|
|
}
|
|
int save_refresh=Option.Refresh;
|
|
Option.Refresh=0;
|
|
for(j=0;j<r2*2+1;j++){
|
|
for(i=0;i<ints_per_line;i++){
|
|
k=br[i+j*ints_per_line];
|
|
for(m=0;m<32;m++){
|
|
if(xs==-1 && (k & 0x80000000)){
|
|
xs=m;
|
|
xi=i;
|
|
}
|
|
if(xs!=-1 && !(k & 0x80000000)){
|
|
DrawRectangle(x-r2+xs+xi*32, y-r2+j, x-r2+m+i*32, y-r2+j, c);
|
|
xs=-1;
|
|
}
|
|
k<<=1;
|
|
}
|
|
}
|
|
if(xs!=-1){
|
|
DrawRectangle(x-r2+xs+xi*32, y-r2+j, x-r2+m+i*32, y-r2+j, c);
|
|
xs=-1;
|
|
}
|
|
}
|
|
Option.Refresh=save_refresh;
|
|
if(Option.Refresh)Display_Refresh();
|
|
}
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
|
|
typedef struct {
|
|
unsigned char red;
|
|
unsigned char green;
|
|
unsigned char blue;
|
|
} rgb_t;
|
|
#define TFLOAT float
|
|
typedef struct {
|
|
TFLOAT xpos; // current position and heading
|
|
TFLOAT ypos; // (uses floating-point numbers for
|
|
TFLOAT heading; // increased accuracy)
|
|
|
|
rgb_t pen_color; // current pen color
|
|
rgb_t fill_color; // current fill color
|
|
bool pendown; // currently drawing?
|
|
bool filled; // currently filling?
|
|
} fill_t;
|
|
fill_t main_fill;
|
|
fill_t backup_fill;
|
|
int main_fill_poly_vertex_count = 0; // polygon vertex count
|
|
TFLOAT *main_fill_polyX=NULL; // polygon vertex x-coords
|
|
TFLOAT *main_fill_polyY=NULL; // polygon vertex y-coords
|
|
|
|
void fill_set_pen_color(int red, int green, int blue)
|
|
{
|
|
main_fill.pen_color.red = red;
|
|
main_fill.pen_color.green = green;
|
|
main_fill.pen_color.blue = blue;
|
|
}
|
|
|
|
void fill_set_fill_color(int red, int green, int blue)
|
|
{
|
|
main_fill.fill_color.red = red;
|
|
main_fill.fill_color.green = green;
|
|
main_fill.fill_color.blue = blue;
|
|
}
|
|
static void fill_begin_fill()
|
|
{
|
|
main_fill.filled = true;
|
|
main_fill_poly_vertex_count = 0;
|
|
}
|
|
|
|
static void fill_end_fill(int count, int ystart, int yend)
|
|
{
|
|
// based on public-domain fill algorithm in C by Darel Rex Finley, 2007
|
|
// from http://alienryderflex.com/polygon_fill/
|
|
|
|
TFLOAT *nodeX=GetMemory(count * sizeof(TFLOAT)); // x-coords of polygon intercepts
|
|
int nodes; // size of nodeX
|
|
int y, i, j; // current pixel and loop indices
|
|
TFLOAT temp; // temporary variable for sorting
|
|
int f=(main_fill.fill_color.red<<16) | (main_fill.fill_color.green<<8) | main_fill.fill_color.blue;
|
|
int c= (main_fill.pen_color.red<<16) | (main_fill.pen_color.green<<8) | main_fill.pen_color.blue;
|
|
int xstart, xend;
|
|
// loop through the rows of the image
|
|
|
|
for (y = ystart; y < yend; y++) {
|
|
|
|
// build a list of polygon intercepts on the current line
|
|
nodes = 0;
|
|
j = main_fill_poly_vertex_count-1;
|
|
for (i = 0; i < main_fill_poly_vertex_count; i++) {
|
|
if ((main_fill_polyY[i] < (TFLOAT)y &&
|
|
main_fill_polyY[j] >= (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<xtot)error("X Dimensions %", nx);
|
|
getargaddress(argv[4], &yptr, &yfptr, &ny);
|
|
if(ny<xtot)error("Y Dimensions %", ny);
|
|
if(xptr)xptr2=*xptr;
|
|
else xfptr2=*xfptr;
|
|
if(yptr)yptr2=*yptr;
|
|
else yfptr2=*yfptr;
|
|
c = gui_fcolour; // setup the defaults
|
|
if(argc > 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<xcount-1;i++){
|
|
if(argc > 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]<ymin)ymin=main_fill_polyY[main_fill_poly_vertex_count];
|
|
main_fill_poly_vertex_count++;
|
|
} else {
|
|
int x1=(xfptr==NULL ? *xptr++ : (int)*xfptr++);
|
|
int x2=(xfptr==NULL ? *xptr : (int)*xfptr);
|
|
int y1=(yfptr==NULL ? *yptr++ : (int)*yfptr++);
|
|
int y2=(yfptr==NULL ? *yptr : (int)*yfptr);
|
|
DrawLine(x1,y1,x2,y2, 1, c);
|
|
}
|
|
}
|
|
if(argc > 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]<ymin)ymin=main_fill_polyY[main_fill_poly_vertex_count];
|
|
if(main_fill_polyY[main_fill_poly_vertex_count]!=main_fill_polyY[0] || main_fill_polyX[main_fill_poly_vertex_count] != main_fill_polyX[0]){
|
|
main_fill_poly_vertex_count++;
|
|
main_fill_polyX[main_fill_poly_vertex_count]=main_fill_polyX[0];
|
|
main_fill_polyY[main_fill_poly_vertex_count]=main_fill_polyY[0];
|
|
}
|
|
main_fill_poly_vertex_count++;
|
|
if(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;i<n;i++){
|
|
if((polycountf == NULL ? polycount[i] : (int)polycountf[i])>xmax)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<xtot)error("X Dimensions %", nx);
|
|
getargaddress(argv[4], &yptr, &yfptr, &ny);
|
|
if(ny<xtot)error("Y Dimensions %", ny);
|
|
main_fill_polyX=(TFLOAT *)GetTempMemory(xmax * sizeof(TFLOAT));
|
|
main_fill_polyY=(TFLOAT *)GetTempMemory(xmax * sizeof(TFLOAT));
|
|
if(argc > 5 && *argv[6]){ //foreground colour specified
|
|
getargaddress(argv[6], &cptr, &cfptr, &nc);
|
|
if(nc == 1) for(i=0;i<n;i++)cc[i] = getint(argv[6], 0, WHITE);
|
|
else {
|
|
if(nc < n) error("Foreground colour Dimensions");
|
|
for(i=0;i<n;i++){
|
|
cc[i] = (cfptr == NULL ? cptr[i] : (int)cfptr[i]);
|
|
if(cc[i] < 0 || cc[i] > 0xFFFFFF) error("% is invalid (valid is % to %)", (int)cc[i], 0, 0xFFFFFF);
|
|
}
|
|
}
|
|
} else for(i=0;i<n;i++)cc[i] = gui_fcolour;
|
|
if(argc > 7){ //background colour specified
|
|
getargaddress(argv[8], &fptr, &ffptr, &nf);
|
|
if(nf == 1) for(i=0;i<n;i++) ff[i] = getint(argv[8], 0, WHITE);
|
|
else {
|
|
if(nf < n) error("Background colour Dimensions");
|
|
for(i=0;i<n;i++){
|
|
ff[i] = (ffptr == NULL ? fptr[i] : (int)ffptr[i]);
|
|
if(ff[i] < 0 || ff[i] > 0xFFFFFF) error("% is invalid (valid is % to %)", (int)ff[i], 0, 0xFFFFFF);
|
|
}
|
|
}
|
|
}
|
|
xstart=0;
|
|
for(i=0;i<n;i++){
|
|
if(xptr)xptr2=*xptr;
|
|
else xfptr2=*xfptr;
|
|
if(yptr)yptr2=*yptr;
|
|
else yfptr2=*yfptr;
|
|
ymax=0;
|
|
ymin=1000000;
|
|
main_fill_poly_vertex_count=0;
|
|
xcount = (int)(polycountf == NULL ? polycount[i] : (int)polycountf[i]);
|
|
if(argc > 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<xstart+xcount-1;j++){
|
|
if(argc > 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]<ymin)ymin=main_fill_polyY[main_fill_poly_vertex_count];
|
|
main_fill_poly_vertex_count++;
|
|
} else {
|
|
int x1=(xfptr==NULL ? *xptr++ : (int)*xfptr++);
|
|
int x2=(xfptr==NULL ? *xptr : (int)*xfptr);
|
|
int y1=(yfptr==NULL ? *yptr++ : (int)*yfptr++);
|
|
int y2=(yfptr==NULL ? *yptr : (int)*yfptr);
|
|
DrawLine(x1,y1,x2,y2, 1, cc[i]);
|
|
}
|
|
}
|
|
if(argc > 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]<ymin)ymin=main_fill_polyY[main_fill_poly_vertex_count];
|
|
if(main_fill_polyY[main_fill_poly_vertex_count]!=main_fill_polyY[0] || main_fill_polyX[main_fill_poly_vertex_count] != main_fill_polyX[0]){
|
|
main_fill_poly_vertex_count++;
|
|
main_fill_polyX[main_fill_poly_vertex_count]=main_fill_polyX[0];
|
|
main_fill_polyY[main_fill_poly_vertex_count]=main_fill_polyY[0];
|
|
}
|
|
main_fill_poly_vertex_count++;
|
|
if(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<nw;i++){
|
|
w = (wfptr == NULL ? wptr[i] : (int)wfptr[i]);
|
|
if(w < 0 || w > 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<nc;i++){
|
|
c = (cfptr == NULL ? cptr[i] : (int)cfptr[i]);
|
|
if(c < 0 || c > 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<nf;i++){
|
|
f = (ffptr == NULL ? fptr[i] : (int)ffptr[i]);
|
|
if(f < -1 || f > WHITE) error("% is invalid (valid is % to %)", (int)f, -1, WHITE);
|
|
}
|
|
}
|
|
}
|
|
for(i=0;i<n;i++){
|
|
x1 = (x1fptr==NULL ? x1ptr[i] : (int)x1fptr[i]);
|
|
y1 = (y1fptr==NULL ? y1ptr[i] : (int)y1fptr[i]);
|
|
wi = (wifptr==NULL ? wiptr[i] : (int)wifptr[i]);
|
|
h = (hfptr==NULL ? hptr[i] : (int)hfptr[i]);
|
|
wmod=(wi > 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: <esc>[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<cn)cn=n;
|
|
getargaddress(argv[4], &x2ptr, &x2fptr, &n);
|
|
if(n<cn)cn=n;
|
|
getargaddress(argv[6], &y2ptr, &y2fptr, &n);
|
|
if(n<cn)cn=n;
|
|
getargaddress(argv[8], &x3ptr, &x3fptr, &n);
|
|
if(n<cn)cn=n;
|
|
getargaddress(argv[10], &y3ptr, &y3fptr, &n);
|
|
if(n<cn)cn=n;
|
|
n=cn;
|
|
}
|
|
if(n == 1){
|
|
c = gui_fcolour; f = -1;
|
|
x1 = getinteger(argv[0]);
|
|
y1 = getinteger(argv[2]);
|
|
x2 = getinteger(argv[4]);
|
|
y2 = getinteger(argv[6]);
|
|
x3 = getinteger(argv[8]);
|
|
y3 = getinteger(argv[10]);
|
|
if(argc >= 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<nc;i++){
|
|
c = (cfptr == NULL ? cptr[i] : (int)cfptr[i]);
|
|
if(c < 0 || c > 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<nf;i++){
|
|
f = (ffptr == NULL ? fptr[i] : (int)ffptr[i]);
|
|
if(f < -1 || f > WHITE) error("% is invalid (valid is % to %)", (int)f, -1, WHITE);
|
|
}
|
|
}
|
|
}
|
|
for(i=0;i<n;i++){
|
|
x1 = (x1fptr==NULL ? x1ptr[i] : (int)x1fptr[i]);
|
|
y1 = (y1fptr==NULL ? y1ptr[i] : (int)y1fptr[i]);
|
|
x2 = (x2fptr==NULL ? x2ptr[i] : (int)x2fptr[i]);
|
|
y2 = (y2fptr==NULL ? y2ptr[i] : (int)y2fptr[i]);
|
|
x3 = (x3fptr==NULL ? x3ptr[i] : (int)x3fptr[i]);
|
|
y3 = (y3fptr==NULL ? y3ptr[i] : (int)y3fptr[i]);
|
|
if(x1==x2 && x1==x3 && y1==y2 && y1==y3 && x1==-1 && y1==-1)return;
|
|
if(nc > 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<y1+h;y++){
|
|
to=tobuff;
|
|
int otoggle=0;
|
|
for(int x=x1;x<x1+w;x++){
|
|
if(y<0 || y>=VRes){
|
|
getnextnibble(&fc,0);
|
|
continue;
|
|
}
|
|
if(x>=0 && x<HRes){
|
|
if(otoggle==0){
|
|
*to=getnextnibble(&fc,0);
|
|
otoggle ^=1;
|
|
} else {
|
|
*to|=(getnextnibble(&fc,0)<<4);
|
|
otoggle^=1;
|
|
to++;
|
|
}
|
|
} else getnextnibble(&fc,0);
|
|
}
|
|
if(ww>0 && xx1<HRes)copyframetoscreen((unsigned char *)tobuff,xx1, xx1+ww-1, y, y, 0);
|
|
}
|
|
} else {
|
|
char tobuff[w/2], *to;
|
|
getnextnibble(&fc,1); //reset the decoder
|
|
for(int y=y1;y<y1+h;y++){
|
|
int x=x1;
|
|
while(1){
|
|
to=tobuff;
|
|
int otoggle=0;
|
|
char c;
|
|
int ww=0;
|
|
int xx=-1;
|
|
while((c=getnextnibble(&fc,0))==blank){
|
|
x++;
|
|
if(x==x1+w)break;
|
|
}
|
|
if(x==x1+w)break; //nothing found so exit
|
|
*to=c;
|
|
otoggle ^=1;
|
|
xx=x;
|
|
x++;
|
|
ww=1;
|
|
if(xx!=x1+w-1){
|
|
while((c=getnextnibble(&fc,0))!=blank){
|
|
x++;
|
|
ww++;
|
|
if(otoggle==0){
|
|
*to=c;
|
|
otoggle ^=1;
|
|
} else {
|
|
*to|=(c<<4);
|
|
otoggle^=1;
|
|
to++;
|
|
}
|
|
if(x==x1+w)break;
|
|
}
|
|
}
|
|
x++;
|
|
if(xx+ww>HRes){
|
|
ww=HRes-xx;
|
|
}
|
|
if(xx>=0 && ww>0 && y>=0 && y<VRes)copyframetoscreen((unsigned char *)tobuff,xx, xx+ww-1, y, y, 0);
|
|
if(xx<0 && xx+ww>=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<y1+h;y++){
|
|
to=(char *)WriteBuf+y*(HRes>>1)+(x1>>1);
|
|
for(int x=x1;x<x1+w;x+=2){
|
|
c=getnextnibble(&fc,0);
|
|
c|=(getnextnibble(&fc,0)<<4);
|
|
if(y<0 || y>=VRes)continue;
|
|
if(x>=0 && x<HRes)*to=c;
|
|
to++;
|
|
}
|
|
}
|
|
} else {
|
|
int otoggle=0,itoggle=0; //input will always start on a byte boundary
|
|
char c,*to;
|
|
c=getnextnibble(&fc,1); //reset the decoder
|
|
for(int y=y1;y<y1+h;y++){ //loop though all of the output lines
|
|
to=(char *)WriteBuf+y*(HRes>>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<x1+w;x++){
|
|
if(itoggle==0){
|
|
c=getnextnibble(&fc,0);
|
|
itoggle=1;
|
|
} else {
|
|
c=getnextnibble(&fc,0);
|
|
itoggle=0;
|
|
}
|
|
if(y<0 || y>=VRes)continue;
|
|
if(otoggle==0){
|
|
if(x>=0 && x<HRes){
|
|
if(c!=blank){
|
|
*to &= 0xF0;
|
|
*to |=c;
|
|
}
|
|
}
|
|
} else {
|
|
if(x>=0 && x<HRes){
|
|
if(c!=blank){
|
|
*to &=0x0f;
|
|
*to |= (c<<4);
|
|
}
|
|
}
|
|
to++;
|
|
}
|
|
otoggle^=1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* @endcond */
|
|
|
|
void cmd_blitmemory(void){
|
|
int x1, y1, w, h;
|
|
int8_t blank=-1;
|
|
getargs(&cmdline, 7, (unsigned char*)",");
|
|
if(argc<5)error("Syntax");
|
|
char *from=(char *)GetPeekAddr(argv[0]);
|
|
x1 = (int)getinteger(argv[2]);
|
|
y1 = (int)getinteger(argv[4]);
|
|
uint16_t *size=(uint16_t *)from;
|
|
w=(size[0] & 0x7FFF);
|
|
h=(size[1] & 0x7FFF);
|
|
from+=4;
|
|
if(argc==7)blank=getint(argv[6],-1,15);
|
|
if(size[0] & 0x8000 || size[1] & 0x8000) {
|
|
docompressed(from, x1, y1, w, h, blank);
|
|
} else {
|
|
#ifndef PICOMITEVGA
|
|
if(!WriteBuf){
|
|
if(blank==-1){
|
|
char *fc=from;
|
|
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;
|
|
}
|
|
getnextuncompressednibble(&fc,1); //reset the decoder
|
|
for(int y=y1;y<y1+h;y++){
|
|
to=tobuff;
|
|
int otoggle=0;
|
|
for(int x=x1;x<x1+w;x++){
|
|
if(y<0 || y>=VRes){
|
|
getnextuncompressednibble(&fc,0);
|
|
continue;
|
|
}
|
|
if(x>=0 && x<HRes){
|
|
if(otoggle==0){
|
|
*to=getnextuncompressednibble(&fc,0);
|
|
otoggle ^=1;
|
|
} else {
|
|
*to|=(getnextuncompressednibble(&fc,0)<<4);
|
|
otoggle^=1;
|
|
to++;
|
|
}
|
|
} else getnextuncompressednibble(&fc,0);
|
|
}
|
|
if(ww>0 && xx1<HRes)copyframetoscreen((unsigned char *)tobuff,xx1, xx1+ww-1, y, y, 0);
|
|
}
|
|
} else {
|
|
char *fc=from;
|
|
char tobuff[w/2], *to;
|
|
getnextuncompressednibble(&fc,1); //reset the decoder
|
|
for(int y=y1;y<y1+h;y++){
|
|
int x=x1;
|
|
while(1){
|
|
to=tobuff;
|
|
int otoggle=0;
|
|
char c;
|
|
int ww=0;
|
|
int xx=-1;
|
|
while((c=getnextuncompressednibble(&fc,0))==blank){
|
|
x++;
|
|
if(x==x1+w)break;
|
|
}
|
|
if(x==x1+w)break; //nothing found so exit
|
|
*to=c;
|
|
otoggle ^=1;
|
|
xx=x;
|
|
x++;
|
|
ww=1;
|
|
if(xx!=x1+w-1){
|
|
while((c=getnextuncompressednibble(&fc,0))!=blank){
|
|
x++;
|
|
ww++;
|
|
if(otoggle==0){
|
|
*to=c;
|
|
otoggle ^=1;
|
|
} else {
|
|
*to|=(c<<4);
|
|
otoggle^=1;
|
|
to++;
|
|
}
|
|
if(x==x1+w)break;
|
|
}
|
|
}
|
|
x++;
|
|
if(xx+ww>HRes){
|
|
ww=HRes-xx;
|
|
}
|
|
if(xx>=0 && ww>0 && y>=0 && y<VRes)copyframetoscreen((unsigned char *)tobuff,xx, xx+ww-1, y, y, 0);
|
|
if(xx<0 && xx+ww>=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<y1+h;y++){
|
|
to=(char *)WriteBuf+y*(HRes>>1)+(x1>>1);
|
|
for(int x=x1;x<x1+w;x+=2){
|
|
c=*from++;
|
|
if(y<0 || y>=VRes)continue;
|
|
if(x>=0 && x<HRes)*to=c;
|
|
to++;
|
|
}
|
|
}
|
|
} else {
|
|
int otoggle=0,itoggle=0; //input will always start on a byte boundary
|
|
char c,*to;
|
|
for(int y=y1;y<y1+h;y++){ //loop though all of the output lines
|
|
to=(char *)WriteBuf+y*(HRes>>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<x1+w;x++){
|
|
if(itoggle==0){
|
|
c=*from & 0x0f;
|
|
itoggle=1;
|
|
} else {
|
|
c= *from >>4;
|
|
from++;
|
|
itoggle=0;
|
|
}
|
|
if(y<0 || y>=VRes)continue;
|
|
if(otoggle==0){
|
|
if(x>=0 && x<HRes){
|
|
if(c!=blank){
|
|
*to &= 0xF0;
|
|
*to |=c;
|
|
}
|
|
}
|
|
} else {
|
|
if(x>=0 && x<HRes){
|
|
if(c!=blank){
|
|
*to &=0x0f;
|
|
*to |= (c<<4);
|
|
}
|
|
}
|
|
to++;
|
|
}
|
|
otoggle^=1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
|
|
int blitother(void){
|
|
int x1, y1, x2, y2, w, h;
|
|
unsigned char *p;
|
|
if ((p = checkstring(cmdline, (unsigned char*)"COMPRESSED"))) {
|
|
int8_t blank=-1;
|
|
getargs(&p, 7, (unsigned char*)",");
|
|
if(argc<5)error("Syntax");
|
|
char *fc=(char *)GetPeekAddr(argv[0]);
|
|
x1 = (int)getinteger(argv[2]);
|
|
y1 = (int)getinteger(argv[4]);
|
|
uint16_t *size=(uint16_t *)fc;
|
|
w=size[0];
|
|
h=size[1];
|
|
if(w>HRes || 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<y1+h;y++,toy++){ //loop though all of the output lines
|
|
from=s+y*(HRes>>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<x1+w;x++,tox++){
|
|
if(itoggle==0){
|
|
if(tox>=0 && tox<HRes)c=*from & 0x0f;
|
|
else c=0;
|
|
itoggle=1;
|
|
} else {
|
|
if(tox>=0 && tox<HRes)c= *from >>4;
|
|
else c=0;
|
|
from++;
|
|
itoggle=0;
|
|
}
|
|
if(y<0 || y>=VRes)continue;
|
|
if(otoggle==0){
|
|
if(tox>=0 && tox<HRes){
|
|
if(c!=blank){
|
|
*to &= 0xF0;
|
|
*to |=c;
|
|
}
|
|
}
|
|
} else {
|
|
if(tox>=0 && tox<HRes){
|
|
if(c!=blank){
|
|
*to &=0x0f;
|
|
*to |= (c<<4);
|
|
}
|
|
}
|
|
to++;
|
|
}
|
|
otoggle^=1;
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
#ifndef PICOMITEVGA
|
|
else if(s!=NULL){ //writing to a physical LCD display
|
|
if(x1==0 && x2==0 && w==HRes && blank==-1){
|
|
s+=y1*HRes/2;
|
|
copyframetoscreen((void *)s,0,HRes-1,y2,y2+h-1,0);
|
|
} else {
|
|
if(screen320 && Option.DISPLAY_TYPE!=SSD1963_4_16)x2*=2;
|
|
char tobuff[w/2], *to;
|
|
for(int y=y1,yo=y2;y<y1+h;y++,yo++){
|
|
char *fc=(char *)s+y*HRes/2+x1/2;
|
|
getnextuncompressednibble(&fc,1+(x1&1)); //reset the decoder
|
|
int x=x1;
|
|
while(1){
|
|
to=tobuff;
|
|
int otoggle=0;
|
|
char c;
|
|
int ww=0;
|
|
int xx=-1;
|
|
while((c=getnextuncompressednibble(&fc,0))==blank){
|
|
x++;
|
|
if(x==x1+w)break;
|
|
}
|
|
if(x==x1+w)break; //nothing found so exit
|
|
*to=c;
|
|
otoggle ^=1;
|
|
xx=x;
|
|
x++;
|
|
ww=1;
|
|
if(xx!=x1+w-1){
|
|
while((c=getnextuncompressednibble(&fc,0))!=blank){
|
|
x++;
|
|
ww++;
|
|
if(otoggle==0){
|
|
*to=c;
|
|
otoggle ^=1;
|
|
} else {
|
|
*to|=(c<<4);
|
|
otoggle^=1;
|
|
to++;
|
|
}
|
|
if(x==x1+w)break;
|
|
}
|
|
}
|
|
x++;
|
|
if(xx+ww>HRes){
|
|
ww=HRes-xx;
|
|
}
|
|
if(x2>=0 && ww>0 && yo>=0 && yo<VRes){
|
|
copyframetoscreen((unsigned char *)tobuff,x2, x2+ww-1, yo, yo, 0);
|
|
}
|
|
if(x2<0 && x2+ww>=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<y1+h;y++,toy++){ //loop though all of the output lines
|
|
ReadBuffer(x1,y,x1+w-1,y,rbuff);
|
|
uint8_t *p=rbuff;
|
|
char *pp=from;
|
|
for(int x=x1;x<x1+w;x++){
|
|
cb.rgbbytes[0]=*p++; //this order swaps the bytes to match the .BMP file
|
|
cb.rgbbytes[1]=*p++;
|
|
cb.rgbbytes[2]=*p++;
|
|
int fcolour = RGB121(cb.rgb);
|
|
if(x & 1){
|
|
*pp &=0x0F;
|
|
*pp |=(fcolour<<4);
|
|
pp++;
|
|
} else {
|
|
*pp &=0xF0;
|
|
*pp |= fcolour;
|
|
}
|
|
}
|
|
to=d+toy*(HRes>>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<x1+w;x++,tox++){
|
|
if(itoggle==0){
|
|
if(tox>=0 && tox<HRes)c=*pp & 0x0f;
|
|
else c=0;
|
|
itoggle=1;
|
|
} else {
|
|
if(tox>=0 && tox<HRes)c= *pp >>4;
|
|
else c=0;
|
|
pp++;
|
|
itoggle=0;
|
|
}
|
|
if(y<0 || y>=VRes)continue;
|
|
if(otoggle==0){
|
|
if(tox>=0 && tox<HRes){
|
|
if(c!=blank){
|
|
*to &= 0xF0;
|
|
*to |=c;
|
|
}
|
|
}
|
|
} else {
|
|
if(tox>=0 && tox<HRes){
|
|
if(c!=blank){
|
|
*to &=0x0f;
|
|
*to |= (c<<4);
|
|
}
|
|
}
|
|
to++;
|
|
}
|
|
otoggle^=1;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|
|
/* @endcond */
|
|
void cmd_cls(void) {
|
|
if(Option.DISPLAY_TYPE == 0) error("Display not configured");
|
|
#ifdef GUICONTROLS
|
|
HideAllControls();
|
|
#endif
|
|
skipspace(cmdline);
|
|
if(!(*cmdline == 0 || *cmdline == '\'')){ //Colour specified
|
|
#ifdef PICOMITEVGA
|
|
if(DISPLAY_TYPE==SCREENMODE2 || DISPLAY_TYPE==SCREENMODE3 ){
|
|
int fc=getint(cmdline, 0, WHITE);
|
|
unsigned char fcolour = RGB121(fc);
|
|
fcolour|=(fcolour<<4);
|
|
memset((void *)WriteBuf,fcolour,ScreenSize);
|
|
} else {
|
|
ClearScreen(getint(cmdline, 0, WHITE));
|
|
}
|
|
#else
|
|
ClearScreen(getint(cmdline, 0, WHITE));
|
|
#endif
|
|
} else { //Default colour
|
|
#ifdef PICOMITEVGA
|
|
if((WriteBuf==LayerBuf && (DISPLAY_TYPE==SCREENMODE2 || DISPLAY_TYPE==SCREENMODE3 ) && LayerBuf!=DisplayBuf)
|
|
|| (WriteBuf==SecondLayer && (DISPLAY_TYPE==SCREENMODE2 || DISPLAY_TYPE==SCREENMODE3 ) && SecondLayer!=DisplayBuf)){
|
|
uint8_t colour=(WriteBuf==LayerBuf ? transparent|(transparent<<4) : transparents|(transparents<<4)) ;
|
|
memset((void *)WriteBuf,colour,HRes*VRes/2);
|
|
#ifdef HDMI
|
|
} else if(WriteBuf==LayerBuf && (DISPLAY_TYPE==SCREENMODE5 ) && LayerBuf!=DisplayBuf){
|
|
memset((void *)WriteBuf,transparent,HRes*VRes);
|
|
} else if((void *)WriteBuf==LayerBuf && (DISPLAY_TYPE==SCREENMODE4 ) && LayerBuf!=DisplayBuf){
|
|
uint16_t *p=(uint16_t *)WriteBuf;
|
|
for(int i=0;i<HRes*VRes;i++)*p++=RGBtransparent;
|
|
#endif
|
|
} else
|
|
#endif
|
|
ClearScreen(gui_bcolour);
|
|
}
|
|
CurrentX = CurrentY = 0;
|
|
if(Option.Refresh)Display_Refresh();
|
|
}
|
|
|
|
|
|
|
|
void fun_rgb(void) {
|
|
getargs(&ep, 5, (unsigned char *)",");
|
|
if(argc == 5)
|
|
iret = rgb(getint(argv[0], 0, 255), getint(argv[2], 0, 255), getint(argv[4], 0, 255));
|
|
else if(argc == 1) {
|
|
if(checkstring(argv[0], (unsigned char *)"WHITE")) iret = WHITE;
|
|
else if(checkstring(argv[0], (unsigned char *)"YELLOW")) iret = YELLOW;
|
|
else if(checkstring(argv[0], (unsigned char *)"LILAC")) iret = LILAC;
|
|
else if(checkstring(argv[0], (unsigned char *)"BROWN")) iret = BROWN;
|
|
else if(checkstring(argv[0], (unsigned char *)"FUCHSIA")) iret = FUCHSIA;
|
|
else if(checkstring(argv[0], (unsigned char *)"RUST")) iret = RUST;
|
|
else if(checkstring(argv[0], (unsigned char *)"MAGENTA")) iret = MAGENTA;
|
|
else if(checkstring(argv[0], (unsigned char *)"RED")) iret = RED;
|
|
else if(checkstring(argv[0], (unsigned char *)"CYAN")) iret = CYAN;
|
|
else if(checkstring(argv[0], (unsigned char *)"GREEN")) iret = GREEN;
|
|
else if(checkstring(argv[0], (unsigned char *)"CERULEAN"))iret = CERULEAN;
|
|
else if(checkstring(argv[0], (unsigned char *)"MIDGREEN"))iret = MIDGREEN;
|
|
else if(checkstring(argv[0], (unsigned char *)"COBALT")) iret = COBALT;
|
|
else if(checkstring(argv[0], (unsigned char *)"MYRTLE")) iret = MYRTLE;
|
|
else if(checkstring(argv[0], (unsigned char *)"BLUE")) iret = BLUE;
|
|
else if(checkstring(argv[0], (unsigned char *)"BLACK")) iret = BLACK;
|
|
else if(checkstring(argv[0], (unsigned char *)"GRAY")) iret = GRAY;
|
|
else if(checkstring(argv[0], (unsigned char *)"GREY")) iret = GRAY;
|
|
else if(checkstring(argv[0], (unsigned char *)"LIGHTGRAY")) iret = LITEGRAY;
|
|
else if(checkstring(argv[0], (unsigned char *)"LIGHTGREY")) iret = LITEGRAY;
|
|
else if(checkstring(argv[0], (unsigned char *)"ORANGE")) iret = ORANGE;
|
|
else if(checkstring(argv[0], (unsigned char *)"PINK")) iret = PINK;
|
|
else if(checkstring(argv[0], (unsigned char *)"GOLD")) iret = GOLD;
|
|
else if(checkstring(argv[0], (unsigned char *)"SALMON")) iret = SALMON;
|
|
else if(checkstring(argv[0], (unsigned char *)"BEIGE")) iret = BEIGE;
|
|
else error("Invalid colour: $", argv[0]);
|
|
} else
|
|
error("Syntax");
|
|
targ = T_INT;
|
|
}
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
|
|
void fun_mmhres(void) {
|
|
iret = HRes;
|
|
targ = T_INT;
|
|
}
|
|
|
|
|
|
|
|
void fun_mmvres(void) {
|
|
iret = VRes;
|
|
targ = T_INT;
|
|
}
|
|
extern BYTE BDEC_bReadHeader(BMPDECODER *pBmpDec, int fnbr);
|
|
extern BYTE BMP_bDecode_memory(int x, int y, int xlen, int ylen, int fnbr, char *p);
|
|
void LIFOadd(int n) {
|
|
int i, j = 0;
|
|
for (i = 0; i < LIFOpointer; i++) {
|
|
if (LIFO[i] != n) {
|
|
LIFO[j] = LIFO[i];
|
|
j++;
|
|
}
|
|
}
|
|
LIFO[j] = n;
|
|
LIFOpointer = j + 1;
|
|
}
|
|
void LIFOremove(int n) {
|
|
int i, j = 0;
|
|
for (i = 0; i < LIFOpointer; i++) {
|
|
if (LIFO[i] != n) {
|
|
LIFO[j] = LIFO[i];
|
|
j++;
|
|
}
|
|
}
|
|
LIFOpointer = j;
|
|
}
|
|
void LIFOswap(int n, int m) {
|
|
int i;
|
|
for (i = 0; i < LIFOpointer; i++) {
|
|
if (LIFO[i] == n)LIFO[i] = m;
|
|
}
|
|
}
|
|
void zeroLIFOadd(int n) {
|
|
int i, j = 0;
|
|
for (i = 0; i < zeroLIFOpointer; i++) {
|
|
if (zeroLIFO[i] != n) {
|
|
zeroLIFO[j] = zeroLIFO[i];
|
|
j++;
|
|
}
|
|
}
|
|
zeroLIFO[j] = n;
|
|
zeroLIFOpointer = j + 1;
|
|
}
|
|
void zeroLIFOremove(int n) {
|
|
int i, j = 0;
|
|
for (i = 0; i < zeroLIFOpointer; i++) {
|
|
if (zeroLIFO[i] != n) {
|
|
zeroLIFO[j] = zeroLIFO[i];
|
|
j++;
|
|
}
|
|
}
|
|
zeroLIFOpointer = j;
|
|
}
|
|
void zeroLIFOswap(int n, int m) {
|
|
int i;
|
|
for (i = 0; i < zeroLIFOpointer; i++) {
|
|
if (zeroLIFO[i] == n)zeroLIFO[i] = m;
|
|
}
|
|
}
|
|
void MIPS16 closeallsprites(void) {
|
|
int i;
|
|
for (i = 0; i <= MAXBLITBUF; i++) {
|
|
if (i <= MAXLAYER)layer_in_use[i] = 0;
|
|
if (i) {
|
|
if (spritebuff[i].mymaster == -1) {
|
|
if (spritebuff[i].spritebuffptr != NULL) {
|
|
FreeMemory((unsigned char *)spritebuff[i].spritebuffptr);
|
|
spritebuff[i].spritebuffptr = NULL;
|
|
}
|
|
}
|
|
if (spritebuff[i].blitstoreptr != NULL) {
|
|
FreeMemory((unsigned char*)spritebuff[i].blitstoreptr);
|
|
spritebuff[i].blitstoreptr = NULL;
|
|
}
|
|
}
|
|
spritebuff[i].spritebuffptr = NULL;
|
|
spritebuff[i].blitstoreptr = NULL;
|
|
spritebuff[i].master = -1;
|
|
spritebuff[i].mymaster = -1;
|
|
spritebuff[i].x = 10000;
|
|
spritebuff[i].y = 10000;
|
|
spritebuff[i].w = 0;
|
|
spritebuff[i].h = 0;
|
|
spritebuff[i].next_x = 10000;
|
|
spritebuff[i].next_y = 10000;
|
|
spritebuff[i].layer = -1;
|
|
spritebuff[i].active = false;
|
|
spritebuff[i].edges = 0;
|
|
}
|
|
LIFOpointer = 0;
|
|
zeroLIFOpointer = 0;
|
|
sprites_in_use = 0;
|
|
hideall = 0;
|
|
}
|
|
void checklimits(int bnbr, int* n) {
|
|
int maxW = HRes;
|
|
int maxH = VRes;
|
|
spritebuff[bnbr].collisions[*n] = 0;
|
|
if (spritebuff[bnbr].x < 0) {
|
|
if (!(spritebuff[bnbr].edges & 1)) {
|
|
spritebuff[bnbr].edges |= 1;
|
|
spritebuff[bnbr].collisions[*n] = (char)0xF1;
|
|
(*n)++;
|
|
}
|
|
}
|
|
else spritebuff[bnbr].edges &= ~1;
|
|
|
|
if (spritebuff[bnbr].y < 0) {
|
|
if (!(spritebuff[bnbr].edges & 2)) {
|
|
spritebuff[bnbr].edges |= 2;
|
|
if (spritebuff[bnbr].collisions[*n] & 0xF0)spritebuff[bnbr].collisions[*n] |= 0xF2;
|
|
else {
|
|
spritebuff[bnbr].collisions[*n] = (char)0xF2;
|
|
(*n)++;
|
|
}
|
|
}
|
|
}
|
|
else spritebuff[bnbr].edges &= ~2;
|
|
|
|
if (spritebuff[bnbr].x + spritebuff[bnbr].w > 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<w;x++){
|
|
for(y=0,yy=h-1;y<(h>>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 == ST7796SP || 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 == ST7796SP || 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_TYPE<VIRTUAL) || Option.DISPLAY_TYPE>=NEXTGEN))return;
|
|
DrawRectangle=DrawRectangle16;
|
|
DrawBitmap= DrawBitmap16;
|
|
ScrollLCD=ScrollLCD16;
|
|
DrawBuffer=DrawBuffer16;
|
|
ReadBLITBuffer=ReadBuffer16;
|
|
DrawBLITBuffer=DrawBuffer16;
|
|
ReadBuffer=ReadBuffer16;
|
|
DrawBufferFast=DrawBuffer16Fast;
|
|
ReadBufferFast=ReadBuffer16Fast;
|
|
DrawPixel=DrawPixel16;
|
|
}
|
|
void closeframebuffer(char layer){
|
|
#ifdef PICOMITE
|
|
if(mergerunning){
|
|
multicore_fifo_push_blocking(0xFF);
|
|
busy_wait_ms(mergetimer+200);
|
|
if(mergerunning){
|
|
_excep_code = RESET_COMMAND;
|
|
SoftReset();
|
|
}
|
|
}
|
|
#endif
|
|
if(FrameBuf)FreeMemory(FrameBuf);
|
|
if(LayerBuf)FreeMemory(LayerBuf);
|
|
FrameBuf=NULL;
|
|
WriteBuf=NULL;
|
|
restorepanel();
|
|
}
|
|
void copyframetoscreen(uint8_t *s,int xstart, int xend, int ystart, int yend, int odd){
|
|
unsigned char col[3]={0};
|
|
int c;
|
|
if(Option.DISPLAY_TYPE>I2C_PANEL && Option.DISPLAY_TYPE<BufferedPanel)DefineRegionSPI(xstart,ystart,xend,yend, 1);
|
|
else if(Option.DISPLAY_TYPE == ILI9341_8){
|
|
SetAreaILI9341(xstart,ystart,xend,yend, 1);
|
|
} else if(Option.DISPLAY_TYPE == ILI9341_16 || Option.DISPLAY_TYPE == ILI9486_16) {
|
|
if(Option.DISPLAY_TYPE == ILI9486_16){
|
|
Write16bitCommand(ILI9341_PIXELFORMAT);
|
|
WriteData16bit(0x55);
|
|
}
|
|
SetAreaILI9341(xstart,ystart,xend,yend, 1);
|
|
} else if(Option.DISPLAY_TYPE==IPS_4_16) {
|
|
if(LCDAttrib==1)WriteCmdDataIPS_4_16(0x3A00,1,0x55);
|
|
if(screen320){
|
|
SetAreaIPS_4_16(xstart+80,ystart*2,xend*2-xstart+81,yend*2+1,1); // setup the area to be filled
|
|
} else {
|
|
SetAreaIPS_4_16(xstart,ystart,xend,yend, 1); // setup the area to be filled
|
|
}
|
|
} else {
|
|
if(screen320){
|
|
if(Option.DISPLAY_TYPE!=SSD1963_4_16)SetAreaSSD1963(xstart+80,ystart*2,xend*2-xstart+81,yend*2+1); // setup the area to be filled
|
|
else SetAreaSSD1963(xstart+80,ystart+16,xend+80,yend+16);
|
|
} else {
|
|
SetAreaSSD1963(xstart,ystart,xend,yend); // setup the area to be filled
|
|
}
|
|
WriteComand(CMD_WR_MEMSTART);
|
|
}
|
|
int i;
|
|
int cnt=2;
|
|
if(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9481IPS || (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<BufferedPanel ){
|
|
if(PinDef[Option.SYSTEM_CLK].mode & SPI0SCK){
|
|
if(odd){
|
|
c=map[(*s & 0xF0)>>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<<SSD1963data,c<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
s++;
|
|
i--;
|
|
int x=1;
|
|
while(x<=xend-xstart){
|
|
c=map[*s & 0xF];
|
|
*pp++=c;
|
|
gpio_put(SSD1963_WR_GPPIN,0);
|
|
gpio_put_masked64(0xFFFF<<SSD1963data,c<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
if(i>1){
|
|
c=map[(*s & 0xF0)>>4];
|
|
*pp++=c;
|
|
gpio_put(SSD1963_WR_GPPIN,0);
|
|
gpio_put_masked64(0xFFFF<<SSD1963data,c<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
}
|
|
s++;
|
|
i-=2;
|
|
x+=2;
|
|
}
|
|
pp=(uint16_t *)q;
|
|
for(int x=xstart;x<=xend;x++){
|
|
gpio_put(SSD1963_WR_GPPIN,0);
|
|
gpio_put_masked64(0xFFFF<<SSD1963data,(*pp++)<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
}
|
|
}
|
|
} else {
|
|
for(int y=ystart;y<=yend;y++){
|
|
pp=(uint16_t *)q;
|
|
int x=0;
|
|
while(x<=xend-xstart){
|
|
c=map[*s & 0xF];
|
|
*pp++=c;
|
|
gpio_put(SSD1963_WR_GPPIN,0);
|
|
gpio_put_masked64(0xFFFF<<SSD1963data,c<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
if(i>1){
|
|
c=map[(*s & 0xF0)>>4];
|
|
*pp++=c;
|
|
gpio_put(SSD1963_WR_GPPIN,0);
|
|
gpio_put_masked64(0xFFFF<<SSD1963data,c<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
}
|
|
s++;
|
|
i-=2;
|
|
x+=2;
|
|
}
|
|
pp=(uint16_t *)q;
|
|
for(int x=xstart;x<=xend;x++){
|
|
gpio_put(SSD1963_WR_GPPIN,0);
|
|
gpio_put_masked64(0xFFFF<<SSD1963data,(*pp++)<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
}
|
|
}
|
|
}
|
|
HRes=320;
|
|
VRes=240;
|
|
} else {
|
|
if(Option.DISPLAY_TYPE>SSD_PANEL_8){
|
|
if(odd){
|
|
c=map[(*s & 0xF0)>>4];
|
|
gpio_put_masked64(0xFFFF<<SSD1963data,c<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
s++;
|
|
i--;
|
|
}
|
|
while(i>0){
|
|
c=map[*s & 0xF];
|
|
gpio_put_masked64(0xFFFF<<SSD1963data,c<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
if(i>1){
|
|
c=map[(*s & 0xF0)>>4];
|
|
gpio_put_masked64(0xFFFF<<SSD1963data,c<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
}
|
|
s++;
|
|
i-=2;
|
|
}
|
|
} else {
|
|
if(odd){
|
|
c=map[(*s & 0xF0)>>4];
|
|
gpio_put_masked64(0b11111111<<SSD1963data,((c >> 16) & 0xff)<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
gpio_put_masked64(0b11111111<<SSD1963data,((c >> 8) & 0xff)<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
nop;gpio_put_masked64(0b11111111<<SSD1963data,(c & 0xff)<<SSD1963data);
|
|
gpio_put(SSD1963_WR_GPPIN,0);nop;nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
s++;
|
|
i--;
|
|
}
|
|
while(i>0){
|
|
c=map[*s & 0xF];
|
|
gpio_put_masked64(0b11111111<<SSD1963data,((c >> 16) & 0xff)<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
gpio_put_masked64(0b11111111<<SSD1963data,((c >> 8) & 0xff)<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
nop;gpio_put_masked64(0b11111111<<SSD1963data,(c & 0xff)<<SSD1963data);
|
|
gpio_put(SSD1963_WR_GPPIN,0);nop;nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
if(i>1){
|
|
c=map[(*s & 0xF0)>>4];
|
|
gpio_put_masked64(0b11111111<<SSD1963data,((c >> 16) & 0xff)<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
gpio_put_masked64(0b11111111<<SSD1963data,((c >> 8) & 0xff)<<SSD1963data);
|
|
nop;gpio_put(SSD1963_WR_GPPIN,0);nop;nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
nop;gpio_put_masked64(0b11111111<<SSD1963data,(c & 0xff)<<SSD1963data);
|
|
gpio_put(SSD1963_WR_GPPIN,0);nop;nop;gpio_put(SSD1963_WR_GPPIN,1);
|
|
}
|
|
s++;
|
|
i-=2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void blitmerge (int x0, int y0, int w, int h, uint8_t colour){
|
|
if(LayerBuf==NULL || FrameBuf==NULL)return;
|
|
uint8_t *ss,*s=LayerBuf;
|
|
uint8_t *d=FrameBuf;
|
|
uint8_t LineBuf[HRes/2];
|
|
uint8_t highcolour=colour<<4;
|
|
#ifdef PICOMITE
|
|
mutex_enter_blocking(&frameBufferMutex); // lock the frame buffer
|
|
#endif
|
|
if(Option.DISPLAY_TYPE==ILI9341 || Option.DISPLAY_TYPE == ST7796SP || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE==ST7789B || Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P ){
|
|
while(GetLineILI9341()!=0){}
|
|
}
|
|
for(int y=y0;y<y0+h;y++){
|
|
if(y>VRes-1)break;
|
|
memcpy(LineBuf,d+y*HRes/2,HRes/2);
|
|
ss=s+y*HRes/2;
|
|
for(int x=0;x<HRes/2;x++){
|
|
uint8_t top=*ss & 0xF0;
|
|
uint8_t bottom=*ss++ &0x0f;
|
|
if(top==highcolour && bottom==colour)continue;
|
|
if(top!=highcolour && bottom!=colour)LineBuf[x]=(top|bottom);
|
|
else if(top!=highcolour){
|
|
LineBuf[x]&=0x0F;
|
|
LineBuf[x]|=top;
|
|
} else {
|
|
LineBuf[x]&=0xF0;
|
|
LineBuf[x]|=bottom;
|
|
}
|
|
}
|
|
copyframetoscreen(&LineBuf[x0/2],x0,x0+w-1,y,y,0);
|
|
}
|
|
#ifdef PICOMITE
|
|
mutex_exit(&frameBufferMutex);
|
|
mergedone=true;
|
|
__dmb();
|
|
#endif
|
|
}
|
|
void merge(uint8_t colour){
|
|
if(LayerBuf==NULL || FrameBuf==NULL)return;
|
|
uint8_t *ss,*s=LayerBuf;
|
|
uint8_t *d=FrameBuf;
|
|
uint8_t LineBuf[HRes/2];
|
|
uint8_t highcolour=colour<<4;
|
|
#ifdef PICOMITE
|
|
mutex_enter_blocking(&frameBufferMutex); // lock the frame buffer
|
|
#endif
|
|
if(Option.DISPLAY_TYPE==ILI9341 || Option.DISPLAY_TYPE == ST7796SP || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE==ST7789B || Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P ){
|
|
while(GetLineILI9341()!=0){}
|
|
}
|
|
for(int y=0;y<VRes;y++){
|
|
memcpy(LineBuf,d+y*HRes/2,HRes/2);
|
|
ss=s+y*HRes/2;
|
|
for(int x=0;x<HRes/2;x++){
|
|
uint8_t top=*ss & 0xF0;
|
|
uint8_t bottom=*ss++ &0x0f;
|
|
if(top==highcolour && bottom==colour)continue;
|
|
if(top!=highcolour && bottom!=colour)LineBuf[x]=(top|bottom);
|
|
else if(top!=highcolour){
|
|
LineBuf[x]&=0x0F;
|
|
LineBuf[x]|=top;
|
|
} else {
|
|
LineBuf[x]&=0xF0;
|
|
LineBuf[x]|=bottom;
|
|
}
|
|
}
|
|
copyframetoscreen(LineBuf,0,HRes-1,y,y,0);
|
|
}
|
|
#ifdef PICOMITE
|
|
mutex_exit(&frameBufferMutex);
|
|
mergedone=true;
|
|
__dmb();
|
|
#endif
|
|
}
|
|
/* @endcond */
|
|
void cmd_framebuffer(void){
|
|
unsigned char *p=NULL;
|
|
if((p=checkstring(cmdline, (unsigned char *)"CREATE"))) {
|
|
if(FrameBuf==NULL){
|
|
FrameBuf=GetMemory(HRes*VRes/2);
|
|
}
|
|
else error("Framebuffer already exists");
|
|
} else if((p=checkstring(cmdline, (unsigned char *)"WRITE"))) {
|
|
if(checkstring(p, (unsigned char *)"N")){
|
|
#ifdef PICOMITE
|
|
if(mergerunning)error("Display in use for merged operation");
|
|
#endif
|
|
restorepanel();
|
|
return;
|
|
}
|
|
else if(checkstring(p, (unsigned char *)"L")){
|
|
if(!LayerBuf)error("Layer buffer not created");
|
|
WriteBuf=LayerBuf;
|
|
setframebuffer();
|
|
return;
|
|
}
|
|
else if(checkstring(p, (unsigned char *)"F")){
|
|
if(!FrameBuf)error("Frame buffer not created");
|
|
WriteBuf=FrameBuf;
|
|
setframebuffer();
|
|
return;
|
|
}
|
|
{
|
|
getargs(&p,1,(unsigned char *)",");
|
|
if(argc!=1)error("Syntax");
|
|
char *q=(char *)getCstring(argv[0]);
|
|
if(strcasecmp(q,"N")==0){
|
|
#ifdef PICOMITE
|
|
if(mergerunning)error("Display in use for merged operation");
|
|
#endif
|
|
restorepanel();
|
|
} else if(strcasecmp(q,"L")==0){
|
|
if(!LayerBuf)error("Layer buffer not created");
|
|
WriteBuf=LayerBuf;
|
|
setframebuffer();
|
|
} else if(strcasecmp(q,"F")==0){
|
|
if(!FrameBuf)error("Frame buffer not created");
|
|
WriteBuf=FrameBuf;
|
|
setframebuffer();
|
|
} else error("Syntax");
|
|
}
|
|
#ifndef PICOMITEVGA
|
|
#ifdef PICOMITE
|
|
} else if((p=checkstring(cmdline, (unsigned char *)"SYNC"))) { //merge the layer onto the physical display
|
|
mergedone=false;
|
|
while(mergedone==false){CheckAbort();}
|
|
#endif
|
|
} else 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,5,(unsigned char *)",");
|
|
if(argc>=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<BufferedPanel ) || (Option.DISPLAY_TYPE>=SSDPANEL && Option.DISPLAY_TYPE<VIRTUAL))))error("Not available on this display");
|
|
if(diskchecktimer<200 && SPIatRisk)diskchecktimer = 200;
|
|
multicore_fifo_push_blocking(2);
|
|
multicore_fifo_push_blocking((uint32_t)colour);
|
|
} else if(background==2){
|
|
mergetimer=0;
|
|
if(argc==5)mergetimer=getint(argv[4],0,60*10*1000);
|
|
if(!(((Option.DISPLAY_TYPE>I2C_PANEL && Option.DISPLAY_TYPE<BufferedPanel ) || (Option.DISPLAY_TYPE>=SSDPANEL && Option.DISPLAY_TYPE<VIRTUAL))))error("Not available on this display");
|
|
if(WriteBuf==NULL)WriteBuf=FrameBuf;
|
|
setframebuffer();
|
|
multicore_fifo_push_blocking(3);
|
|
multicore_fifo_push_blocking((uint32_t)colour);
|
|
multicore_fifo_push_blocking((uint32_t)mergetimer*1000);
|
|
} else if(background==3){
|
|
if(mergerunning){
|
|
multicore_fifo_push_blocking(0xFF);
|
|
busy_wait_ms(mergetimer+200);
|
|
if(mergerunning){
|
|
_excep_code = RESET_COMMAND;
|
|
SoftReset();
|
|
}
|
|
}
|
|
} else
|
|
#endif
|
|
merge(colour);
|
|
#endif
|
|
} else if((p=checkstring(cmdline, (unsigned char *)"LAYER"))) {
|
|
if(LayerBuf==NULL){
|
|
LayerBuf=GetMemory(HRes*VRes/2);
|
|
} else error("Layer already exists");
|
|
} else if((p=checkstring(cmdline, (unsigned char *)"WAIT"))) {
|
|
if(Option.DISPLAY_TYPE==ILI9341 || Option.DISPLAY_TYPE == ST7796SP || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE==ST7789B || Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P ){
|
|
while(GetLineILI9341()!=0){}
|
|
}
|
|
} else if((p=checkstring(cmdline, (unsigned char *)"CLOSE"))) {
|
|
if(checkstring(p, (unsigned char *)"F")){
|
|
#ifdef PICOMITE
|
|
if(mergerunning){
|
|
multicore_fifo_push_blocking(0xFF);
|
|
busy_wait_ms(mergetimer+200);
|
|
if(mergerunning){
|
|
_excep_code = RESET_COMMAND;
|
|
SoftReset();
|
|
}
|
|
}
|
|
#endif
|
|
if(WriteBuf!=LayerBuf)restorepanel();
|
|
if(FrameBuf)FreeMemory(FrameBuf);
|
|
FrameBuf=NULL;
|
|
} else if(checkstring(p, (unsigned char *)"L")){
|
|
#ifdef PICOMITE
|
|
if(mergerunning){
|
|
multicore_fifo_push_blocking(0xFF);
|
|
busy_wait_ms(mergetimer+200);
|
|
if(mergerunning){
|
|
_excep_code = RESET_COMMAND;
|
|
SoftReset();
|
|
}
|
|
}
|
|
#endif
|
|
if(WriteBuf!=FrameBuf)restorepanel();
|
|
if(LayerBuf)FreeMemory(LayerBuf);
|
|
LayerBuf=NULL;
|
|
} else closeframebuffer('A');
|
|
} else if((p=checkstring(cmdline, (unsigned char *)"COPY"))) {
|
|
#ifdef PICOMITE
|
|
int complex=0, background=0;
|
|
unsigned char *buff = WriteBuf;
|
|
getargs(&p,5,(unsigned char *)",");
|
|
if(!(argc==3 || argc==5))error("Syntax");
|
|
if(argc==5){
|
|
if(checkstring(argv[4],(unsigned char *)"B"))background=1;
|
|
else error("Syntax");
|
|
}
|
|
#else
|
|
int complex=0;
|
|
unsigned char *buff = WriteBuf;
|
|
getargs(&p,3,(unsigned char *)",");
|
|
if(!(argc==3))error("Syntax");
|
|
#endif
|
|
uint8_t *s=NULL,*d=NULL;
|
|
if(checkstring(argv[0],(unsigned char *)"N")){
|
|
complex=1;
|
|
if((void *)ReadBuffer == (void *)DisplayNotSet) error("Invalid on this display");
|
|
}
|
|
else if(checkstring(argv[0],(unsigned char *)"L"))s=LayerBuf;
|
|
else if(checkstring(argv[0],(unsigned char *)"F"))s=FrameBuf;
|
|
else error("Syntax");
|
|
if(checkstring(argv[2],(unsigned char *)"N")){
|
|
complex=2;
|
|
}
|
|
else if(checkstring(argv[2],(unsigned char *)"L"))d=LayerBuf;
|
|
else if(checkstring(argv[2],(unsigned char *)"F"))d=FrameBuf;
|
|
else error("Syntax");
|
|
|
|
if(d!=s){
|
|
if(!complex) memcpy(d,s,HRes*VRes/2);
|
|
else {
|
|
if(complex==1){//copying from the real display
|
|
char *LCDBuffer=GetTempMemory(HRes*3);
|
|
int DisplayMode=0;
|
|
if(DrawBufferSPI==DrawBuffer || DrawBufferSSD1963==DrawBuffer) DisplayMode=1;
|
|
WriteBuf=d;
|
|
for(int y=0;y<VRes;y++){
|
|
restorepanel();
|
|
ReadBuffer(0,y,HRes-1,y,(unsigned char *)LCDBuffer);
|
|
WriteBuf=d;
|
|
setframebuffer();
|
|
DrawBuffer(0,y,HRes-1,y,(unsigned char *)LCDBuffer);
|
|
}
|
|
if(DisplayMode) restorepanel();
|
|
} else { //copying to the real display
|
|
#ifdef PICOMITE
|
|
if(background){
|
|
if(!(((Option.DISPLAY_TYPE>I2C_PANEL && Option.DISPLAY_TYPE<BufferedPanel ) || (Option.DISPLAY_TYPE>=SSDPANEL && Option.DISPLAY_TYPE<VIRTUAL))))error("Not available on this display");
|
|
if(diskchecktimer<100 && SPIatRisk) diskchecktimer=100;
|
|
multicore_fifo_push_blocking(1);
|
|
multicore_fifo_push_blocking((uint32_t)s);
|
|
} else {
|
|
#endif
|
|
copyframetoscreen(s,0,HRes-1,0,VRes-1,0);
|
|
#ifdef PICOMITE
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
WriteBuf=buff;
|
|
} else error("Syntax");
|
|
}
|
|
#endif
|
|
|
|
void cmd_blit(void) {
|
|
int x1, y1, x2, y2, w, h, bnbr;
|
|
unsigned char *buff = NULL;
|
|
unsigned char *p;
|
|
if(Option.DISPLAY_TYPE == 0) error("Display not configured");
|
|
if(blitother())return;
|
|
p = checkstring(cmdline, (unsigned char *)"LOADBMP");
|
|
if(p==NULL)p = checkstring(cmdline, (unsigned char *)"LOAD");
|
|
if(p) {
|
|
int fnbr;
|
|
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) - 1; // get the buffer number
|
|
if(blitbuff[bnbr].blitbuffptr)error("Buffer % in use",bnbr);
|
|
if(argc == 0) error("Argument count");
|
|
if(!InitSDCard()) return;
|
|
p = getCstring(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 *)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<BufferedPanel ) || (Option.DISPLAY_TYPE>=SSDPANEL && Option.DISPLAY_TYPE<VIRTUAL))))error("Not available on this display");
|
|
if(diskchecktimer<200 && SPIatRisk)diskchecktimer = 200;
|
|
multicore_fifo_push_blocking(4);
|
|
multicore_fifo_push_blocking(x1);
|
|
multicore_fifo_push_blocking(y1);
|
|
multicore_fifo_push_blocking(w);
|
|
multicore_fifo_push_blocking(h);
|
|
multicore_fifo_push_blocking((uint32_t)colour);
|
|
} else if(background==2){
|
|
mergetimer=0;
|
|
if(argc==13)mergetimer=getint(argv[12],0,60*10*1000);
|
|
if(!(((Option.DISPLAY_TYPE>I2C_PANEL && Option.DISPLAY_TYPE<BufferedPanel ) || (Option.DISPLAY_TYPE>=SSDPANEL && Option.DISPLAY_TYPE<VIRTUAL))))error("Not available on this display");
|
|
if(WriteBuf==NULL)WriteBuf=FrameBuf;
|
|
setframebuffer();
|
|
multicore_fifo_push_blocking(5);
|
|
multicore_fifo_push_blocking(x1);
|
|
multicore_fifo_push_blocking(y1);
|
|
multicore_fifo_push_blocking(w);
|
|
multicore_fifo_push_blocking(h);
|
|
multicore_fifo_push_blocking((uint32_t)colour);
|
|
multicore_fifo_push_blocking((uint32_t)mergetimer*1000);
|
|
} else if(background==3){
|
|
if(mergerunning){
|
|
multicore_fifo_push_blocking(0xFF);
|
|
busy_wait_ms(mergetimer+200);
|
|
if(mergerunning){
|
|
_excep_code = RESET_COMMAND;
|
|
SoftReset();
|
|
}
|
|
}
|
|
} else
|
|
#endif
|
|
blitmerge(x1,y1,w,h,colour);
|
|
return;
|
|
}
|
|
#endif
|
|
if((p = checkstring(cmdline, (unsigned char *)"READ"))) {
|
|
getargs(&p, 9, (unsigned char *)",");
|
|
if((void *)ReadBuffer == (void *)DisplayNotSet) error("Invalid on this display");
|
|
if(argc !=9) error("Syntax");
|
|
if(*argv[0] == '#') argv[0]++; // check if the first arg is prefixed with a #
|
|
bnbr = getint(argv[0], 1, MAXBLITBUF) - 1; // get the buffer number
|
|
x1 = getinteger(argv[2]);
|
|
y1 = getinteger(argv[4]);
|
|
w = getinteger(argv[6]);
|
|
h = getinteger(argv[8]);
|
|
if(w < 1 || h < 1) return;
|
|
if(x1 < 0) { x2 -= x1; w += x1; x1 = 0; }
|
|
if(y1 < 0) { y2 -= y1; h += y1; y1 = 0; }
|
|
if(x1 + w > 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<w;x++){
|
|
for(int y=0,yy=h-1;y<(h>>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<h;y++){
|
|
for(int x=0;x<w;x++){
|
|
if(x>=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<h;y++){
|
|
for(int x=0;x<w;x++){
|
|
if(x>=end)s++;
|
|
else *d++=*s++;
|
|
}
|
|
}
|
|
w-=over;
|
|
}
|
|
for(int i=0,j=0;i<w*h*3;i+=3){
|
|
buff[i]=buff[j++];
|
|
buff[i+1]=buff[j++];
|
|
buff[i+2]=buff[j++];
|
|
j++;
|
|
}
|
|
}
|
|
if(!(mode & 4)){
|
|
if(y1<0){
|
|
buff-=(y1*3*w);
|
|
h+=y1;
|
|
y1=0;
|
|
}
|
|
DrawBuffer(x1, y1, x1 + w - 1, y1 + h - 1, buff);
|
|
} else {
|
|
if((void *)ReadBuffer == (void *)DisplayNotSet) error("Invalid on this display");
|
|
unsigned char *current=GetTempMemory(w*h*3);
|
|
if(y1<0){
|
|
buff-=(y1*3*w);
|
|
h+=y1;
|
|
y1=0;
|
|
}
|
|
ReadBuffer(x1, y1, x1 + w - 1, y1 + h - 1, current);
|
|
for(int i=0;i<w*h*3;i+=3){
|
|
if(buff[i] || buff[i+1] || buff[i+2]){
|
|
current[i]=buff[i];
|
|
current[i+1]=buff[i+1];
|
|
current[i+2]=buff[i+2];
|
|
}
|
|
}
|
|
DrawBuffer(x1, y1, x1 + w - 1, y1 + h - 1, current);
|
|
}
|
|
}
|
|
else error((char *)"Buffer not in use");
|
|
} else if((p = checkstring(cmdline, (unsigned char *)"CLOSE"))) {
|
|
getargs(&p, 1, (unsigned char *)",");
|
|
if(*argv[0] == '#') argv[0]++; // check if the first arg is prefixed with a #
|
|
bnbr = getint(argv[0], 1, MAXBLITBUF) - 1; // get the buffer number
|
|
if(blitbuff[bnbr].blitbuffptr != NULL){
|
|
FreeMemory((unsigned char *)blitbuff[bnbr].blitbuffptr);
|
|
blitbuff[bnbr].blitbuffptr = NULL;
|
|
} else error("Buffer not in use");
|
|
// get the number
|
|
} else {
|
|
getargs(&cmdline, 11, (unsigned char *)",");
|
|
if((void *)ReadBuffer == (void *)DisplayNotSet) error("Invalid on this display");
|
|
if(argc != 11) error("Syntax");
|
|
x1 = getinteger(argv[0]);
|
|
y1 = getinteger(argv[2]);
|
|
x2 = getinteger(argv[4]);
|
|
y2 = getinteger(argv[6]);
|
|
w = getinteger(argv[8]);
|
|
h = getinteger(argv[10]);
|
|
if(w < 1 || h < 1) return;
|
|
if(x1 < 0) { x2 -= x1; w += x1; x1 = 0; }
|
|
if(x2 < 0) { x1 -= x2; w += x2; x2 = 0; }
|
|
if(y1 < 0) { y2 -= y1; h += y1; y1 = 0; }
|
|
if(y2 < 0) { y1 -= y2; h += y2; y2 = 0; }
|
|
if(x1 + w > 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<y2){
|
|
for(int y=h-1; y>=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;y<h;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 {
|
|
for(int y=0;y<h;y++){
|
|
volatile uint8_t *in=WriteBuf + ((y+y1)*HRes + x1)/2;
|
|
volatile uint8_t *out=WriteBuf + ((y+y2)*HRes + x2)/2;
|
|
memmove((void *)out,(void *)in,w/2);
|
|
}
|
|
}
|
|
return;
|
|
} else { //nibble move not as easy
|
|
uint8_t *inbuff=GetTempMemory(HRes/2);
|
|
int intoggle=x1 & 1;
|
|
int outtoggle=x2 & 1;
|
|
int n=w/2;
|
|
if(w & 1)n++;
|
|
if(y1>y2){
|
|
for(int y=0;y<h;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<w;x++){
|
|
if(toggle){
|
|
uint8_t t=*in >>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<w;x++){
|
|
if(toggle){
|
|
uint8_t t=(*in & 0xf)<<4;
|
|
*out &=0x0f; //clear the top byte of the output
|
|
*out |=t;
|
|
out++;
|
|
} else {
|
|
uint8_t t=(*in >>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<w;x++){
|
|
if(toggle){
|
|
uint8_t t=*in >>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<w;x++){
|
|
if(toggle){
|
|
uint8_t t=(*in & 0xf)<<4;
|
|
*out &=0x0f; //clear the top byte of the output
|
|
*out |=t;
|
|
out++;
|
|
} else {
|
|
uint8_t t=(*in >>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<xc;x++){
|
|
for(int y=0;y<yc;y++){
|
|
int s=(y+ty1)*X_TILE+x+tx1;
|
|
int d=(y+ty2)*X_TILE+x+tx2;
|
|
tilefcols[d]=tilefcols[s];
|
|
tilebcols[d]=tilebcols[s];
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
if(x1 < x2) {
|
|
int start_x1, start_x2;
|
|
max_x = 1;
|
|
buff = GetMemory(max_x * h);
|
|
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);
|
|
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<yc;y++){
|
|
int s=(y+ty1)*X_TILE+x+tx1;
|
|
int d=(y+ty2)*X_TILE+x+tx2;
|
|
tilefcols[d]=tilefcols[s];
|
|
tilebcols[d]=tilebcols[s];
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
int max_x;
|
|
if((WriteBuf==LayerBuf || WriteBuf==FrameBuf) && WriteBuf){
|
|
if((w & 1)==0 && (x1 & 1)==0 && (x2 & 1)==0){ //Easiest case - byte move in the x direction with w even
|
|
if(y1<y2){
|
|
for(int y=h-1; 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;y<h;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 {
|
|
for(int y=0;y<h;y++){
|
|
uint8_t *in=WriteBuf + ((y+y1)*HRes + x1)/2;
|
|
uint8_t *out=WriteBuf + ((y+y2)*HRes + x2)/2;
|
|
memmove(out,in,w/2);
|
|
}
|
|
}
|
|
return;
|
|
} else { //nibble move not as easy
|
|
uint8_t *inbuff=GetTempMemory(HRes/2);
|
|
int intoggle=x1 & 1;
|
|
int outtoggle=x2 & 1;
|
|
int n=w/2;
|
|
if(w & 1)n++;
|
|
if(y1>y2){
|
|
for(int y=0;y<h;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<w;x++){
|
|
if(toggle){
|
|
uint8_t t=*in >>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<w;x++){
|
|
if(toggle){
|
|
uint8_t t=(*in & 0xf)<<4;
|
|
*out &=0x0f; //clear the top byte of the output
|
|
*out |=t;
|
|
out++;
|
|
} else {
|
|
uint8_t t=(*in >>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<w;x++){
|
|
if(toggle){
|
|
uint8_t t=*in >>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<w;x++){
|
|
if(toggle){
|
|
uint8_t t=(*in & 0xf)<<4;
|
|
*out &=0x0f; //clear the top byte of the output
|
|
*out |=t;
|
|
out++;
|
|
} else {
|
|
uint8_t t=(*in >>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<X_TILE*Y_TILE;i++){
|
|
#if defined(rp2350) && defined(HDMI)
|
|
if(FullColour){
|
|
tilefcols[i]=tilefcols[0];
|
|
tilebcols[i]=tilebcols[0];
|
|
} else {
|
|
tilefcols_w[i]=tilefcols_w[0];
|
|
tilebcols_w[i]=tilebcols_w[0];
|
|
}
|
|
#else
|
|
tilefcols[i]=tilefcols[0];
|
|
tilebcols[i]=tilebcols[0];
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
PromptFont = gui_font;
|
|
if(CurrentY + gui_font_height >= 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<n;i++){
|
|
int in=(cptr == NULL ? (int)cfptr[i] : cptr[i]);
|
|
if(in>=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<X_TILE;x++){
|
|
for(int y=0;y<Y_TILE;y++){
|
|
tilefcols[y*X_TILE+x]=RGB121pack(gui_fcolour);
|
|
tilebcols[y*X_TILE+x]=RGB121pack(gui_bcolour);
|
|
}
|
|
}
|
|
} else if((tp=checkstring(cmdline,(unsigned char *)"HEIGHT"))){
|
|
if(!(WriteBuf==DisplayBuf))error("Not available when write is set to a buffer");
|
|
ytileheight=getint(tp,12,VRes);
|
|
Y_TILE=VRes/ytileheight;
|
|
if(VRes % ytileheight)Y_TILE++;
|
|
ClearScreen(Option.DefaultBC);
|
|
} else {
|
|
getargs(&cmdline, 11, (unsigned char *)",");
|
|
if(!(DISPLAY_TYPE==SCREENMODE1))return;
|
|
if(argc<5)error("Syntax");
|
|
int x=getint(argv[0],0,X_TILE);
|
|
int y=getint(argv[2],0,Y_TILE);
|
|
int tilebcolour, tilefcolour ;
|
|
if(*argv[4]){
|
|
tilefcolour = getColour((char *)argv[4], 0);
|
|
fcolour = RGB121pack(tilefcolour);
|
|
}
|
|
if(argc>=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<x+xlen;xp++){
|
|
for(int yp=y;yp<y+ylen;yp++){
|
|
if(fcolour!=0xFFFFFFFF) tilefcols[yp*X_TILE+xp]=(uint16_t)fcolour;
|
|
if(bcolour!=0xFFFFFFFF) tilebcols[yp*X_TILE+xp]=(uint16_t)bcolour;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
void DrawRectangle555(int x1, int y1, int x2, int y2, int c){
|
|
int x,y,t;
|
|
uint16_t col=((c & 0xf8)>>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<HRes && y>=0 && y<VRes){
|
|
pp=(uint16_t *)(WriteBuf+(y*(HRes<<1))+(x<<1));
|
|
c=*qq++;
|
|
if(c!=sprite_transparent || blank==-1)*pp = c;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void DrawPixel555(int x, int y, int c){
|
|
if(x<0 || y<0 || x>=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<VRes-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, 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 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<HRes && y>=0 && y<VRes){
|
|
pp=(uint8_t *)((uint32_t)(WriteBuf+y*HRes+x));
|
|
c=*qq++;
|
|
if(c!=sprite_transparent || blank==-1)*pp = c;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void DrawPixel256(int x, int y, int c){
|
|
if(x<0 || y<0 || x>=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<VRes-lines;i++) {
|
|
int d=i*HRes,s=(i+lines)*HRes;
|
|
for(int c=0;c<(HRes);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,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<X_TILE;x++){
|
|
for(int y=0;y<Y_TILE;y++){
|
|
#ifdef HDMI
|
|
if(FullColour){
|
|
#endif
|
|
if(fcolour!=0xFFFFFFFF) tilefcols[y*X_TILE+x]=fcolour;
|
|
if(bcolour!=0xFFFFFFFF) tilebcols[y*X_TILE+x]=bcolour;
|
|
#ifdef HDMI
|
|
} else {
|
|
if(fcolour!=0xFFFFFFFF) tilefcols_w[y*X_TILE+x]=fcolour;
|
|
if(bcolour!=0xFFFFFFFF) tilebcols_w[y*X_TILE+x]=bcolour;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
} else if((tp=checkstring(cmdline,(unsigned char *)"HEIGHT"))){
|
|
ytileheight=getint(tp,8,VRes);
|
|
Y_TILE=VRes/ytileheight;
|
|
if(VRes % ytileheight)Y_TILE++;
|
|
ClearScreen(Option.DefaultBC);
|
|
} else {
|
|
getargs(&cmdline, 11, (unsigned char *)",");
|
|
if(!(DISPLAY_TYPE==SCREENMODE1))return;
|
|
if(argc<5)error("Syntax");
|
|
int x=getint(argv[0],0,X_TILE-1);
|
|
int y=getint(argv[2],0,Y_TILE-1);
|
|
int tilebcolour, tilefcolour ;
|
|
if(*argv[4]){
|
|
tilefcolour = getColour((char *)argv[4], 0);
|
|
fcolour = (FullColour) ? RGB555(tilefcolour): RGB332(tilefcolour);
|
|
}
|
|
if(argc>=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;xp<x+xlen;xp++){
|
|
for(int yp=y;yp<y+ylen;yp++){
|
|
#ifdef HDMI
|
|
if(FullColour){
|
|
#endif
|
|
if(fcolour!=0xFFFFFFFF) tilefcols[yp*X_TILE+xp]=(uint16_t)fcolour;
|
|
if(bcolour!=0xFFFFFFFF) tilebcols[yp*X_TILE+xp]=(uint16_t)bcolour;
|
|
#ifdef HDMI
|
|
} else {
|
|
if(fcolour!=0xFFFFFFFF) tilefcols_w[yp*X_TILE+xp]=(uint8_t)fcolour;
|
|
if(bcolour!=0xFFFFFFFF) tilebcols_w[yp*X_TILE+xp]=(uint8_t)bcolour;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void cmd_map(void){
|
|
unsigned char *p;
|
|
static bool first=true;
|
|
if(!(DISPLAY_TYPE==SCREENMODE2 || DISPLAY_TYPE==SCREENMODE3 || DISPLAY_TYPE==SCREENMODE5 ))error("Invalid for this screen mode");
|
|
if((p=checkstring(cmdline, (unsigned char *)"RESET"))) {
|
|
while(v_scanline!=0){}
|
|
if(DISPLAY_TYPE==SCREENMODE5)for(int i=0;i<256;i++)map256[i]=remap[i]=RGB555(MAP256DEF[i]);
|
|
else if(FullColour)for(int i=0;i<16;i++){
|
|
map16[i]=remap[i]=RGB555(MAP16DEF[i]);
|
|
map16pairs[i]=map16[i] | (map16[i]<<16);
|
|
}
|
|
else if(DISPLAY_TYPE==SCREENMODE3)for(int i=0;i<16;i++) map16d[i]=remap[i]=RGB332(MAP16DEF[i]) | (RGB332(MAP16DEF[i])<<8);
|
|
else if(DISPLAY_TYPE==SCREENMODE2)for(int i=0;i<16;i++) map16q[i]=remap[i]=RGB332(MAP16DEF[i]) | (RGB332(MAP16DEF[i])<<8) | (RGB332(MAP16DEF[i])<<16) | (RGB332(MAP16DEF[i])<<24);
|
|
first=false;
|
|
} else if((checkstring(cmdline, (unsigned char *)"GRAYSCALE") || checkstring(cmdline, (unsigned char *)"GREYSCALE")) && (FullColour)) {
|
|
while(v_scanline!=0){}
|
|
if(DISPLAY_TYPE==SCREENMODE5) {
|
|
for(int i=1;i<=32;i++){
|
|
int j=i*8-(8-i/4+1);
|
|
if(j<0)j=0;
|
|
map256[i-1]=remap[i-1]=RGB555(j*65536 + j*256 + j);
|
|
map256[i+32-1]=remap[i+32-1]=RGB555(j);
|
|
map256[i+64-1]=remap[i+64-1]=RGB555(j*256 );
|
|
map256[i+96-1]=remap[i+96-1]=RGB555(j*256 + j);
|
|
map256[i+128-1]=remap[i+128-1]=RGB555(j*65536);
|
|
map256[i+160-1]=remap[i+160-1]=RGB555(j*65536 + j);
|
|
map256[i+192-1]=remap[i+192-1]=RGB555(j*65536 + j*256);
|
|
map256[i+224-1]=remap[i+224-1]=RGB555(j*65536 + j*256 + j);
|
|
}
|
|
} else {
|
|
for(int i=1;i<=16;i++){
|
|
int j=i*16-(16-i+1);
|
|
map16[i-1]=remap[i-1]= RGB555(j*65536+j*256+j);
|
|
map16pairs[i-1]=map16[i-1] | (map16[i-1]<<16);
|
|
}
|
|
}
|
|
first=false;
|
|
} else if((p=checkstring(cmdline, (unsigned char *)"MAXIMITE"))) {
|
|
while(v_scanline!=0){}
|
|
if(DISPLAY_TYPE==SCREENMODE5)for(int i=0;i<16;i++)map256[i]=remap[i]=RGB555(CMM1map[i]);
|
|
else for(int i=0;i<16;i++){
|
|
map16[i]=remap[i]=RGB555(CMM1map[i]);
|
|
map16pairs[i]=map16[i] | (map16[i]<<16);
|
|
#ifdef HDMI
|
|
if(DISPLAY_TYPE==SCREENMODE3 && (FullColour))map16d[i]=remap[i]=RGB332(CMM1map[i]) | (RGB332(CMM1map[i])<<8);
|
|
if(DISPLAY_TYPE==SCREENMODE2 && (FullColour))map16q[i]=remap[i]=RGB332(CMM1map[i]) | (RGB332(CMM1map[i])<<8)| (RGB332(CMM1map[i])<<16)| (RGB332(CMM1map[i])<<24);
|
|
#endif
|
|
}
|
|
first=false;
|
|
} else if((p=checkstring(cmdline, (unsigned char *)"SET"))) {
|
|
while(v_scanline!=0){}
|
|
if(DISPLAY_TYPE==SCREENMODE5) for(int i=0;i<256;i++)map256[i]=remap[i];
|
|
else for(int i=0;i<16;i++){
|
|
if(FullColour){map16[i]=remap[i];map16pairs[i]=map16[i] | (map16[i]<<16);}
|
|
else if(DISPLAY_TYPE==SCREENMODE3)map16d[i]=remap[i];
|
|
else if(DISPLAY_TYPE==SCREENMODE2)map16q[i]=remap[i];
|
|
}
|
|
} else {
|
|
int cl = getint(cmdline,0,255);
|
|
if(DISPLAY_TYPE!=SCREENMODE5 && cl >15)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<X_TILE;x++){
|
|
for(int y=0;y<Y_TILE;y++){
|
|
tilefcols[y*X_TILE+x]=fcolour;
|
|
tilebcols[y*X_TILE+x]=bcolour;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef USBKEYBOARD
|
|
clearrepeat();
|
|
#endif
|
|
}
|
|
|
|
|
|
void cmd_mode(void){
|
|
int mode =getint(cmdline,1,MAXMODES);
|
|
setmode(mode, true);
|
|
}
|
|
#endif
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
/* @endcond */
|
|
void fun_mmcharwidth(void) {
|
|
if(Option.DISPLAY_TYPE == 0) error("Display not configured");
|
|
iret = FontTable[gui_font >> 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 && Option.DISPLAY_TYPE<NEXTGEN) && 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 && Option.DISPLAY_TYPE<NEXTGEN) && 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<x2p;x+=2){
|
|
*p++=bcolour;
|
|
}
|
|
}
|
|
}
|
|
void DrawBitmap16(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;
|
|
unsigned char fcolour = RGB121(fc);
|
|
unsigned char bcolour = RGB121(bc);
|
|
if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE<NEXTGEN) && 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<VRes-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, 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 && Option.DISPLAY_TYPE<NEXTGEN) && 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 && Option.DISPLAY_TYPE<NEXTGEN) && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8);
|
|
for(y=y1;y<=y2;y++){
|
|
for(x=x1;x<=x2;x++){
|
|
if(x>=0 && x<HRes && y>=0 && y<VRes){
|
|
pp=(uint8_t *)(WriteBuf+(y*(HRes>>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 && Option.DISPLAY_TYPE<NEXTGEN) && 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 && Option.DISPLAY_TYPE<NEXTGEN) && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8);
|
|
for(y=y1;y<=y2;y++){
|
|
for(x=x1;x<=x2;x++){
|
|
if(x>=0 && x<HRes && y>=0 && y<VRes){
|
|
pp=(uint8_t *)(((uint32_t) WriteBuf)+(y*(HRes>>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 && Option.DISPLAY_TYPE<NEXTGEN) && 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 && Option.DISPLAY_TYPE<NEXTGEN) && 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<x2p;x+=8){
|
|
if(c){
|
|
*p++=0xFF;
|
|
} else {
|
|
*p++=0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrawBitmap2(int x1, int y1, int width, int height, int scale, int fc, int bc, unsigned char *bitmap){
|
|
int i, j, k, m, x, y, loc;
|
|
unsigned char mask;
|
|
if(x1>=HRes || y1>=VRes || x1+width*scale<0 || y1+height*scale<0)return;
|
|
int tilematch=0;
|
|
if((Option.DISPLAY_TYPE>=VIRTUAL && Option.DISPLAY_TYPE<NEXTGEN) && 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<yt+h;yy++){
|
|
for(int xx=xt; xx<xt+w;xx++){
|
|
tilefcols[yy*X_TILE+xx]=(uint16_t)fcolour;
|
|
tilebcols[yy*X_TILE+xx]=(uint16_t)bcolour;
|
|
}
|
|
}
|
|
#ifdef HDMI
|
|
} else {
|
|
for(int yy=yt;yy<yt+h;yy++){
|
|
for(int xx=xt; xx<xt+w;xx++){
|
|
tilefcols_w[yy*X_TILE+xx]=(uint8_t)fcolour;
|
|
tilebcols_w[yy*X_TILE+xx]=(uint8_t)bcolour;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
if(fc==0 && bc!=0 && fc!=bc && bc!=-1) fc=1;
|
|
if(bc<=0 || fc==0){
|
|
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 {
|
|
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<Y_TILE-offset;y++){
|
|
int d=y*X_TILE;
|
|
int s=(y+offset)*X_TILE;
|
|
for(int x=0;x<X_TILE;x++){
|
|
#ifdef HDMI
|
|
if(FullColour){
|
|
#endif
|
|
tilefcols[d+x]=tilefcols[s+x];
|
|
tilebcols[d+x]=tilebcols[s+x];
|
|
#ifdef HDMI
|
|
} else {
|
|
tilefcols_w[d+x]=tilefcols_w[s+x];
|
|
tilebcols_w[d+x]=tilebcols_w[s+x];
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
for(int i=0;i<VRes-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, 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<X_TILE;x++){
|
|
#ifdef HDMI
|
|
if(FullColour){
|
|
#endif
|
|
tilefcols[d+x]=tilefcols[s+x];
|
|
tilebcols[d+x]=tilebcols[s+x];
|
|
#ifdef HDMI
|
|
} else {
|
|
tilefcols_w[d+x]=tilefcols_w[s+x];
|
|
tilebcols_w[d+x]=tilebcols_w[s+x];
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
for(int i=VRes-1;i>=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 && Option.DISPLAY_TYPE<NEXTGEN) && 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 && Option.DISPLAY_TYPE<NEXTGEN) && WriteBuf==NULL) WriteBuf=GetMemory(VMaxH*VMaxV/8);
|
|
for(y=y1;y<=y2;y++){
|
|
for(x=x1;x<=x2;x++){
|
|
if(x>=0 && x<HRes && y>=0 && y<VRes){
|
|
loc=(y*(HRes>>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 && Option.DISPLAY_TYPE<NEXTGEN) && 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 && Option.DISPLAY_TYPE<NEXTGEN) && 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<HRes && y>=0 && y<VRes){
|
|
loc=(y*(HRes>>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 || Option.DISPLAY_TYPE >= NEXTGEN) 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;x<X_TILE;x++){
|
|
for(int y=0;y<Y_TILE;y++){
|
|
tilefcols[y*X_TILE+x]=RGB121pack(Option.DefaultFC);
|
|
tilebcols[y*X_TILE+x]=RGB121pack(Option.DefaultBC);
|
|
}
|
|
}
|
|
#endif
|
|
#else
|
|
#ifdef GUICONTROLS
|
|
ResetGUI();
|
|
#endif
|
|
#endif
|
|
}
|
|
void hline(int x0, int x1, int y, int f, int ints_per_line, uint32_t *br) { //draw a horizontal line
|
|
uint32_t w1, xx1, w0, xx0, x, xn, i;
|
|
const uint32_t a[]={0xFFFFFFFF,0x7FFFFFFF,0x3FFFFFFF,0x1FFFFFFF,0xFFFFFFF,0x7FFFFFF,0x3FFFFFF,0x1FFFFFF,
|
|
0xFFFFFF,0x7FFFFF,0x3FFFFF,0x1FFFFF,0xFFFFF,0x7FFFF,0x3FFFF,0x1FFFF,
|
|
0xFFFF,0x7FFF,0x3FFF,0x1FFF,0xFFF,0x7FF,0x3FF,0x1FF,
|
|
0xFF,0x7F,0x3F,0x1F,0x0F,0x07,0x03,0x01};
|
|
const uint32_t b[]={0x80000000,0xC0000000,0xe0000000,0xf0000000,0xf8000000,0xfc000000,0xfe000000,0xff000000,
|
|
0xff800000,0xffC00000,0xffe00000,0xfff00000,0xfff80000,0xfffc0000,0xfffe0000,0xffff0000,
|
|
0xffff8000,0xffffC000,0xffffe000,0xfffff000,0xfffff800,0xfffffc00,0xfffffe00,0xffffff00,
|
|
0xffffff80,0xffffffC0,0xffffffe0,0xfffffff0,0xfffffff8,0xfffffffc,0xfffffffe,0xffffffff};
|
|
w0 = y * (ints_per_line);
|
|
xx0 = 0;
|
|
w1 = y * (ints_per_line) + x1/32;
|
|
xx1 = (x1 & 0x1F);
|
|
w0 = y * (ints_per_line) + x0/32;
|
|
xx0 = (x0 & 0x1F);
|
|
w1 = y * (ints_per_line) + x1/32;
|
|
xx1 = (x1 & 0x1F);
|
|
if(w1==w0){ //special case both inside same word
|
|
x=(a[xx0] & b[xx1]);
|
|
xn=~x;
|
|
if(f)br[w0] |= x; else br[w0] &= xn; // turn on the pixel
|
|
} else {
|
|
if(w1-w0>1){ //first deal with full words
|
|
for(i=w0+1;i<w1;i++){
|
|
// draw the pixel
|
|
br[i]=0;
|
|
if(f)br[i] = 0xFFFFFFFF; // turn on the pixels
|
|
}
|
|
}
|
|
x=~a[xx0];
|
|
br[w0] &= x;
|
|
x=~x;
|
|
if(f)br[w0] |= x; // turn on the pixel
|
|
x=~b[xx1];
|
|
br[w1] &= x;
|
|
x=~x;
|
|
if(f)br[w1] |= x; // turn on the pixel
|
|
}
|
|
}
|
|
|
|
void DrawFilledCircle(int x, int y, int radius, int r, int fill, int ints_per_line, uint32_t *br, MMFLOAT aspect, MMFLOAT aspect2) {
|
|
int a, b, P;
|
|
int A, B, asp;
|
|
x=(int)((MMFLOAT)r*aspect)+radius;
|
|
y=r+radius;
|
|
a = 0;
|
|
b = radius;
|
|
P = 1 - radius;
|
|
asp = aspect2 * (MMFLOAT)(1 << 10);
|
|
do {
|
|
A = (a * asp) >> 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<facecount;i++){
|
|
if(i<facecount-1){
|
|
DrawLine(xcoord[i],ycoord[i],xcoord[i+1],ycoord[i+1],1,c);
|
|
} else {
|
|
DrawLine(xcoord[i],ycoord[i],xcoord[0],ycoord[0],1,c);
|
|
}
|
|
}
|
|
} else {
|
|
if(facecount==3){
|
|
DrawTriangle(xcoord[0],ycoord[0],xcoord[1],ycoord[1],xcoord[2],ycoord[2],c,f);
|
|
} else if(facecount==4){
|
|
DrawTriangle(xcoord[0],ycoord[0],xcoord[1],ycoord[1],xcoord[2],ycoord[2],f,f);
|
|
DrawTriangle(xcoord[0],ycoord[0],xcoord[2],ycoord[2],xcoord[3],ycoord[3],f,f);
|
|
if(f!=c){
|
|
DrawLine(xcoord[0],ycoord[0],xcoord[1],ycoord[1],1,c);
|
|
DrawLine(xcoord[1],ycoord[1],xcoord[2],ycoord[2],1,c);
|
|
DrawLine(xcoord[2],ycoord[2],xcoord[3],ycoord[3],1,c);
|
|
DrawLine(xcoord[0],ycoord[0],xcoord[3],ycoord[3],1,c);
|
|
}
|
|
} else {
|
|
int ymax=-1000000, ymin=1000000;
|
|
fill_set_pen_color((c>>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;i<facecount;i++){
|
|
main_fill_polyX[main_fill_poly_vertex_count] = (TFLOAT)xcoord[i];
|
|
main_fill_polyY[main_fill_poly_vertex_count] = (TFLOAT)ycoord[i];
|
|
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]<ymin)ymin=main_fill_polyY[main_fill_poly_vertex_count];
|
|
main_fill_polyX[main_fill_poly_vertex_count] = (TFLOAT)xcoord[i];
|
|
main_fill_poly_vertex_count++;
|
|
}
|
|
if(main_fill_polyY[main_fill_poly_vertex_count]!=main_fill_polyY[0] || main_fill_polyX[main_fill_poly_vertex_count] != main_fill_polyX[0]){
|
|
main_fill_polyX[main_fill_poly_vertex_count]=main_fill_polyX[0];
|
|
main_fill_polyY[main_fill_poly_vertex_count]=main_fill_polyY[0];
|
|
main_fill_poly_vertex_count++;
|
|
}
|
|
fill_end_fill(main_fill_poly_vertex_count-1,ymin,ymax);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void MIPS16 Free3DMemory(int i){
|
|
FreeMemorySafe((void *)&struct3d[i]->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;f<struct3d[n]->nf;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;f<struct3d[n]->nf;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;v<struct3d[n]->facecount[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]<struct3d[n]->xmin)struct3d[n]->xmin=xcoord[v];
|
|
if(ycoord[v]>struct3d[n]->ymax)struct3d[n]->ymax=ycoord[v];
|
|
if(ycoord[v]<struct3d[n]->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;f<struct3d[n]->nf;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;f<struct3d[n]->nf;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)<nv)error("Vertex array too small");
|
|
if(parseintegerarray(argv[10],&facecount,6,1,NULL,false)<nf)error("Vertex count array too small");
|
|
facecountindex=facecount;
|
|
for(f=0;f<nf;f++)fc += (*facecountindex++);
|
|
if(parseintegerarray(argv[12],&faces,7,1,NULL,false)<fc)error("Face/vertex array too small");
|
|
colourcount=parseintegerarray(argv[14],&colours,8,1,NULL,false);
|
|
if(argc>=17 && *argv[16]){
|
|
if(parseintegerarray(argv[16],&linecolour,9,1,NULL,false)<nf)error("Line colour array too small");
|
|
}
|
|
|
|
if(argc==19){
|
|
if(parseintegerarray(argv[18],&fillcolour,10,1,NULL,false)<nf)error("Fill colour array too small");
|
|
}
|
|
// The data look valid so now create the object in memory
|
|
struct3d[n]=GetMemory(sizeof(struct D3D));
|
|
struct3d[n]->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;v<struct3d[n]->nv;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;f<struct3d[n]->nf;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; c<colourcount;c++){
|
|
struct3d[n]->colours[c]=(uint32_t)*colours++;
|
|
}
|
|
for(f=0;f<struct3d[n]->tot_face_x_vert;f++){
|
|
struct3d[n]->face_x_vert[f]=*faces++;
|
|
}
|
|
for(f=0;f<struct3d[n]->nf;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;v<struct3d[n]->facecount[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;v<struct3d[n]->nv;v++){
|
|
q_rotate(&struct3d[n]->q_vertices[v],q1,&struct3d[n]->r_vertices[v]);
|
|
}
|
|
for(f=0;f<struct3d[n]->nf;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;v<struct3d[n]->nv;v++){
|
|
memcpy(&struct3d[n]->q_vertices[v],&struct3d[n]->r_vertices[v], sizeof(s_quaternion));
|
|
}
|
|
for(f=0;f<struct3d[n]->nf;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<framebuffersize/3)FrameBuf=DisplayBuf+2*ScreenSize;
|
|
else FrameBuf=GetMemory(ScreenSize);
|
|
#else
|
|
FrameBuf=GetMemory(ScreenSize);
|
|
#endif
|
|
break;
|
|
#ifdef rp2350
|
|
case SCREENMODE3:
|
|
FrameBuf=GetMemory(ScreenSize);
|
|
break;
|
|
#ifdef HDMI
|
|
case SCREENMODE4:
|
|
case SCREENMODE5:
|
|
FrameBuf=GetMemory(ScreenSize);
|
|
break;
|
|
#endif
|
|
#endif
|
|
}
|
|
} else error("Framebuffer already exists");
|
|
memset((void *)FrameBuf,0,ScreenSize);
|
|
|
|
#ifdef rp2350
|
|
} else if((p=checkstring(cmdline, (unsigned char *)"LAYER TOP"))) {
|
|
int colour=0;
|
|
if(SecondLayer==DisplayBuf){
|
|
getargs(&p,1,(unsigned char *)",");
|
|
switch(DISPLAY_TYPE){
|
|
case SCREENMODE2:
|
|
if(argc==1)transparents=getint(argv[0],0,15);
|
|
colour=transparents | (transparents<<4);
|
|
if(ScreenSize<framebuffersize/4)SecondLayer=DisplayBuf+3*ScreenSize;
|
|
else SecondLayer=GetMemory(ScreenSize);
|
|
break;
|
|
case SCREENMODE1:
|
|
SecondLayer=GetMemory(ScreenSize);
|
|
break;
|
|
case SCREENMODE3:
|
|
if(argc==1)transparents=getint(argv[0],0,15);
|
|
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");
|
|
}
|
|
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<framebuffersize/2)LayerBuf=DisplayBuf+ScreenSize;
|
|
else LayerBuf=GetMemory(ScreenSize);
|
|
#else
|
|
LayerBuf=GetMemory(ScreenSize);
|
|
#endif
|
|
break;
|
|
#ifdef rp2350
|
|
case SCREENMODE3:
|
|
if(argc==1)transparent=getint(argv[0],0,15);
|
|
LayerBuf=GetMemory(ScreenSize);
|
|
colour=transparent | (transparent<<4);
|
|
break;
|
|
#ifdef HDMI
|
|
case SCREENMODE4:
|
|
LayerBuf=GetMemory(ScreenSize);
|
|
if(argc==1)RGBtransparent=RGB555(getColour((char *)argv[0],0));
|
|
else RGBtransparent=0;
|
|
break;
|
|
case SCREENMODE5:
|
|
if(ScreenSize<framebuffersize/2)LayerBuf=DisplayBuf+ScreenSize;
|
|
else LayerBuf=GetMemory(ScreenSize);
|
|
if(argc==1)transparent=getint(argv[0],0,255);
|
|
colour=transparent;
|
|
break;
|
|
#endif
|
|
#endif
|
|
}
|
|
#ifdef rp2350
|
|
if(LayerBuf>(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<HRes*VRes;i++)*p++=RGBtransparent;
|
|
}
|
|
} else if((p=checkstring(cmdline, (unsigned char *)"CLOSE"))) {
|
|
if(checkstring(p, (unsigned char *)"F")){
|
|
closeframebuffer('F');
|
|
} else if(checkstring(p, (unsigned char *)"L")){
|
|
closeframebuffer('T');
|
|
#ifdef rp2350
|
|
} else if(checkstring(p, (unsigned char *)"T")){
|
|
closeframebuffer('L');
|
|
} else if(checkstring(p, (unsigned char *)"2")){
|
|
closeframebuffer('2');
|
|
#endif
|
|
} else closeframebuffer('A');
|
|
} else if((p=checkstring(cmdline, (unsigned char *)"WRITE"))) {
|
|
if(checkstring(p, (unsigned char *)"N"))WriteBuf=DisplayBuf;
|
|
else if(checkstring(p, (unsigned char *)"L")){
|
|
if(LayerBuf==DisplayBuf)error("Layer not created");
|
|
WriteBuf=LayerBuf;
|
|
}
|
|
#ifdef rp2350
|
|
else if(checkstring(p, (unsigned char *)"T")){
|
|
if(SecondLayer==DisplayBuf)error("Layer 2 not created");
|
|
WriteBuf=SecondLayer;
|
|
}
|
|
else if(checkstring(p, (unsigned char *)"2")){
|
|
if(SecondFrame==DisplayBuf)error("Frame 2 not created");
|
|
WriteBuf=SecondFrame;
|
|
}
|
|
#endif
|
|
else if(checkstring(p, (unsigned char *)"F")){
|
|
if(FrameBuf==DisplayBuf)error("Frame buffer not created");
|
|
WriteBuf=FrameBuf;
|
|
}
|
|
else {
|
|
getargs(&p,1,(unsigned char *)",");
|
|
char *q=(char *)getCstring(argv[0]);
|
|
if(strcasecmp(q,"N")==0)WriteBuf=DisplayBuf;
|
|
else if(strcasecmp(q,"L")==0){
|
|
if(LayerBuf==DisplayBuf)error("Layer not created");
|
|
WriteBuf=LayerBuf;
|
|
} else if(strcasecmp(q,"F")==0){
|
|
if(FrameBuf==DisplayBuf)error("Frame buffer not created");
|
|
WriteBuf=FrameBuf;
|
|
} else if(strcasecmp(q,"2")==0){
|
|
if(SecondFrame==DisplayBuf)error("Frame buffer 2 not created");
|
|
WriteBuf=SecondFrame;
|
|
} else if(strcasecmp(q,"T")==0){
|
|
if(SecondLayer==DisplayBuf)error("Layer Top not created");
|
|
WriteBuf=SecondLayer;
|
|
}
|
|
else error("Syntax");
|
|
}
|
|
} else if((p=checkstring(cmdline, (unsigned char *)"WAIT"))) {
|
|
#ifdef HDMI
|
|
while(v_scanline!=0){}
|
|
#else
|
|
while(QVgaScanLine!=0){}
|
|
#endif
|
|
|
|
} else if((p=checkstring(cmdline, (unsigned char *)"COPY"))) {
|
|
getargs(&p,5,(unsigned char *)",");
|
|
if(!(argc==3 || argc==5))error("Syntax");
|
|
volatile uint8_t *s=NULL,*d=NULL;
|
|
if(checkstring(argv[0],(unsigned char *)"N"))s=DisplayBuf;
|
|
else if(checkstring(argv[0],(unsigned char *)"L"))s=LayerBuf;
|
|
else if(checkstring(argv[0],(unsigned char *)"F"))s=FrameBuf;
|
|
else if(checkstring(argv[0],(unsigned char *)"2"))s=SecondFrame;
|
|
else if(checkstring(argv[0],(unsigned char *)"T"))s=SecondLayer;
|
|
else error("Syntax");
|
|
if(checkstring(argv[2],(unsigned char *)"N"))d=DisplayBuf;
|
|
else if(checkstring(argv[2],(unsigned char *)"L"))d=LayerBuf;
|
|
else if(checkstring(argv[2],(unsigned char *)"F"))d=FrameBuf;
|
|
else if(checkstring(argv[2],(unsigned char *)"2"))d=SecondFrame;
|
|
else if(checkstring(argv[2],(unsigned char *)"T"))d=SecondLayer;
|
|
else error("Syntax");
|
|
if(argc==5){
|
|
if(checkstring(argv[4],(unsigned char *)"B")){
|
|
#ifdef HDMI
|
|
while(v_scanline!=0){}
|
|
#else
|
|
while(QVgaScanLine!=0){}
|
|
#endif
|
|
} else error("Syntax");
|
|
}
|
|
if(d!=s)
|
|
// #ifdef rp2350
|
|
// _Z10copy_wordsPKmPmm((uint32_t *)s, (uint32_t *)d, ScreenSize>>2);
|
|
// #else
|
|
memcpy((void *)d,(void *)s,ScreenSize);
|
|
// #endif
|
|
else error("Buffer not created");
|
|
} else error("Syntax");
|
|
}
|
|
#endif |