diff --git a/sdk/draw-2d.c b/sdk/draw-2d.c index 41648f9..7310f8b 100644 --- a/sdk/draw-2d.c +++ b/sdk/draw-2d.c @@ -23,7 +23,7 @@ RenderQueueItem * drawPixel(RenderQueueItem *prev, uint16_t x, uint16_t y, uint8 prev->next = item; } - item->flags = 1; //Clear bit field, set the update bit + item->flags = RQI_UPDATE; return item; } @@ -51,7 +51,7 @@ RenderQueueItem * drawLine(RenderQueueItem *prev, uint16_t x1, uint16_t y1, uint prev->next = item; } - item->flags = 1; //Clear bit field, set the update bit + item->flags = RQI_UPDATE; return item; } @@ -78,7 +78,7 @@ RenderQueueItem * drawRectangle(RenderQueueItem *prev, uint16_t x1, uint16_t y1, prev->next = item; } - item->flags = 1; //Clear bit field, set the update bit + item->flags = RQI_UPDATE; return item; } @@ -120,7 +120,7 @@ RenderQueueItem * drawCircle(RenderQueueItem *prev, uint16_t x, uint16_t y, uint prev->next = item; } - item->flags = 1; //Clear bit field, set the update bit + item->flags = RQI_UPDATE; return item; } @@ -151,7 +151,7 @@ RenderQueueItem * drawFilledRectangle(RenderQueueItem *prev, uint16_t x1, uint16 prev->next = item; } - item->flags = 1; //Clear bit field, set the update bit + item->flags = RQI_UPDATE; return item; } @@ -181,7 +181,7 @@ RenderQueueItem * drawFilledCircle(RenderQueueItem *prev, uint16_t x, uint16_t y prev->next = item; } - item->flags = 1; //Clear bit field, set the update bit + item->flags = RQI_UPDATE; return item; } @@ -211,7 +211,7 @@ RenderQueueItem * fillScreen(RenderQueueItem *prev, uint8_t obj[FRAME_HEIGHT][FR prev->next = item; } - item->flags = 1; //Clear bit field, set the update bit + item->flags = RQI_UPDATE; return item; } @@ -227,7 +227,7 @@ void clearScreen() { item = item->next; } - background.flags = 1; + background.flags = RQI_UPDATE; } @@ -236,19 +236,26 @@ void clearScreen() { ============================== */ uint8_t *font = (uint8_t *)cp437; //The current font in use by the system -#define CHAR_WIDTH 5 -#define CHAR_HEIGHT 8 -//add word wrap -RenderQueueItem * drawText(RenderQueueItem *prev, uint16_t x, uint16_t y, char *str, uint8_t color, uint8_t scale) { +RenderQueueItem * drawText(RenderQueueItem *prev, uint16_t x1, uint16_t y, uint16_t x2, char *str, + uint8_t color, uint16_t bgColor, bool wrap, uint8_t strSizeOverride) { RenderQueueItem *item = (RenderQueueItem *) malloc(sizeof(RenderQueueItem)); if(item == NULL) return NULL; item->type = 'c'; - item->x1 = x; + item->x1 = x1; item->y1 = y; + item->x2 = x2; + item->y2 = bgColor; item->color = color; - item->obj = str; + + if(strSizeOverride) { + item->obj = (uint8_t *) malloc((strSizeOverride + 1)*sizeof(char)); + } + else { + item->obj = (uint8_t *) malloc((strlen(str) + 1)*sizeof(char)); + } + strcpy(item->obj, str); if(prev == NULL) { item->next = NULL; //Set *next to NULL, means it is the last item in linked list @@ -261,7 +268,8 @@ RenderQueueItem * drawText(RenderQueueItem *prev, uint16_t x, uint16_t y, char * prev->next = item; } - item->flags = 1; //Clear bit field, set the update bit + item->flags = RQI_UPDATE; + if(wrap) item->flags |= RQI_WORDWRAP; return item; } @@ -280,10 +288,10 @@ RenderQueueItem * drawSprite(RenderQueueItem *prev, uint8_t *sprite, uint16_t x, if(item == NULL) return NULL; item->type = 's'; - item->x1 = x; //Makes sure the point closer to (0,0) is assigned to (x,y) and not (w,h) + item->x1 = x; item->y1 = y; - item->x2 = x + dimX; - item->y2 = y + dimY; + item->x2 = dimX; + item->y2 = dimY; item->color = nullColor; item->obj = sprite; @@ -298,7 +306,7 @@ RenderQueueItem * drawSprite(RenderQueueItem *prev, uint8_t *sprite, uint16_t x, prev->next = item; } - item->flags = 1; //Clear bit field, set the update bit + item->flags = RQI_UPDATE; return item; } @@ -317,20 +325,20 @@ void setBackground(uint8_t obj[FRAME_HEIGHT][FRAME_WIDTH], uint8_t color) { else { //set the background to a picture/sprite/something not a solid color background.obj = (uint8_t *)obj; } - background.flags |= 1u; + background.flags |= RQI_UPDATE; } //Set item to be hidden (true = hidden, false = showing) void setHidden(RenderQueueItem *item, uint8_t hidden) { if(hidden) item->flags |= (1u << 1); else item->flags &= ~(1u << 1); - item->flags |= 1u; //Set the update bit + item->flags |= RQI_UPDATE; } //Set the color for item. void setColor(RenderQueueItem *item, uint8_t color) { item->color = color; - item->flags |= 1u; //Set the update bit + item->flags |= RQI_UPDATE; } //Set the coordinates for item. Set parameter to -1 to leave it unchanged. @@ -339,11 +347,11 @@ void setCoordinates(RenderQueueItem *item, int16_t x1, int16_t y1, int16_t x2, i if(y1 >= 0) item->y1 = y1; if(x2 >= 0) item->x2 = x2; if(y2 >= 0) item->y2 = y2; - item->flags |= 1u; //Set the update bit + item->flags |= RQI_UPDATE; } //Permanently remove item from the render queue. void removeItem(RenderQueueItem *item) { item->type = 'n'; - item->flags |= 1u; //Set the update bit + item->flags |= RQI_UPDATE; } \ No newline at end of file diff --git a/sdk/font.h b/sdk/font.h index 1c3141b..eeb3616 100644 --- a/sdk/font.h +++ b/sdk/font.h @@ -16,7 +16,7 @@ */ -const uint8_t cp437[256][8] = { +const uint8_t cp437[256][CHAR_HEIGHT] = { { 0b00000, 0b00000, 0b00000, diff --git a/sdk/init.c b/sdk/init.c index 906dfec..23bd7b3 100644 --- a/sdk/init.c +++ b/sdk/init.c @@ -43,12 +43,12 @@ static void initSecondCore(); static void updateFramePtr(); -int initDisplay(uint8_t autoRenderEn) { +int initDisplay(bool autoRenderEn) { //Clock configuration -- 120MHz system clock frequency clocks_init(); set_sys_clock_pll(1440000000, 6, 2); //VCO frequency (MHz), PD1, PD2 -- see vcocalc.py - autoRender = autoRenderEn; + autoRender = (uint8_t)autoRenderEn; initController(); diff --git a/sdk/pico-vga.h b/sdk/pico-vga.h index e08fb38..eacb511 100644 --- a/sdk/pico-vga.h +++ b/sdk/pico-vga.h @@ -8,6 +8,7 @@ #include #include #include +#include /* Structs @@ -106,14 +107,19 @@ extern volatile Controller C4; #define COLOR_PURPLE 0b10000010 //RenderQueueItem.flags macros -#define RQI_UPDATE (1 << 0) -#define RQI_HIDDEN (1 << 1) +#define RQI_UPDATE (1 << 0) +#define RQI_HIDDEN (1 << 1) +#define RQI_WORDWRAP (1 << 2) + +#define RQI_UPDATE_GET(b) (b >> RQI_UPDATE) & 1u +#define RQI_HIDDEN_GET(b) (b >> RQI_HIDDEN) & 1u +#define RQI_WORDWRAP_GET(b) (b >> RQI_WORDWRAP) & 1u /* Functions ========================= */ -int initDisplay(uint8_t autoRenderEn); +int initDisplay(bool autoRenderEn); void updateDisplay(); extern volatile RenderQueueItem background; @@ -140,7 +146,7 @@ void clearScreen(); RenderQueueItem * drawSprite(RenderQueueItem* prev, uint8_t *sprite, uint16_t x, uint16_t y, uint16_t dimX, uint16_t dimY, uint8_t nullColor, uint8_t scale); //Draws the chars from the default character library. Dimensions are 5x8 pixels each. -RenderQueueItem * drawText(RenderQueueItem* prev, uint16_t x, uint16_t y, char *str, uint8_t color, uint8_t scale); +RenderQueueItem * drawText(RenderQueueItem *prev, uint16_t x1, uint16_t y, uint16_t x2, char *str, uint8_t color, uint16_t bgColor, bool wrap, uint8_t strSizeOverride); void setTextFont(uint8_t *newFont); //Modifiers: @@ -154,5 +160,6 @@ void removeItem(RenderQueueItem *item); uint8_t HTMLTo8Bit(uint32_t color); uint8_t rgbTo8Bit(uint8_t r, uint8_t g, uint8_t b); uint8_t hsvToRGB(uint8_t hue, uint8_t saturation, uint8_t value); +uint8_t invertColor(uint8_t color); #endif \ No newline at end of file diff --git a/sdk/render.c b/sdk/render.c index f9778a1..66c75ce 100644 --- a/sdk/render.c +++ b/sdk/render.c @@ -1,5 +1,4 @@ #include "sdk.h" -#include "font.h" #include "pico/multicore.h" #include "pico/malloc.h" @@ -20,7 +19,7 @@ static volatile uint8_t update = 0; void updateDisplay() { update = 1; - if(autoRender) background.flags |= 1u; //force-update in autoRender mode + if(autoRender) background.flags |= RQI_UPDATE; //force-update in autoRender mode } //Checks for out-of-bounds coordinates and writes to the frame @@ -29,6 +28,10 @@ static inline void writePixel(uint16_t y, uint16_t x, uint8_t color) { else frame[y][x] = color; } +static inline uint8_t getFontBit(uint8_t c, uint8_t x, uint8_t y) { + return *(font + CHAR_HEIGHT*c + y) >> (CHAR_WIDTH - x + 1) & 1u; +} + void render() { multicore_fifo_push_blocking(13); //tell core 0 that everything is ok/it's running @@ -39,12 +42,12 @@ void render() { if(autoRender) { item = (RenderQueueItem *) &background; //look for the first item that needs an update, render that item and everything after it - while(!(item->flags & 1u)) { + while(!(item->flags & RQI_UPDATE)) { previousItem = item; item = item->next; if(item == NULL) item = (RenderQueueItem *) &background; } - if(((item->flags >> 1) & 1u) || item->type == 'n') item = (RenderQueueItem *) &background; //if the update is to hide an item, rerender the whole thing + if(RQI_HIDDEN_GET(item->flags) || item->type == 'n') item = (RenderQueueItem *) &background; //if the update is to hide an item, rerender the whole thing } else { //manual rendering while(!update); //wait until it's told to update the display @@ -52,7 +55,7 @@ void render() { } while(item != NULL) { - if(!((item->flags >> 1) & 1u)) { + if(!RQI_HIDDEN_GET(item->flags)) { switch(item->type) { case 'p': //Pixel writePixel(item->y1, item->x1, item->color); @@ -103,28 +106,30 @@ void render() { } break; case 'c': //Character/String - /*for(uint16_t i = 0; item->obj[i] != '\0'; i++) { - x = item->x1 + (i*CHAR_WIDTH); - for(uint8_t j; j < CHAR_WIDTH; j++) { - //font[][] is a bit array, so check if a particular bit is true, if so, set the pixel array - if(((*font)[item->obj[i]][currentLine - item->y1]) & ((1 << (CHAR_WIDTH - 1)) >> j)) { - frame[l][x + j] = item->color; + //x1, y1 = top left corner, x2 = right side (for word wrap), y2 = background color + uint16_t x = item->x1; + uint16_t y = item->y1; + for(uint16_t c = 0; item->obj[c] != '\0'; c++) { + for(uint8_t i = 0; i < CHAR_HEIGHT; i++) { + for(uint8_t j = 0; j < CHAR_WIDTH; j++) { + writePixel(y + i, x + j, getFontBit(item->obj[c], i, j) ? item->color : item->y2); } } - }*/ + x += CHAR_WIDTH + 1; + if(RQI_WORDWRAP_GET(item->flags) && x + CHAR_WIDTH >= item->x2) { + x = item->x1; + y += CHAR_HEIGHT; + } + } break; case 's': //Sprites - /*for(uint16_t i = item->x1; i < item->x2; i++) { - //Skip changing the pixel if it's set to the COLOR_NULL value - if(*(item->obj + ((currentLine - item->y1)*(item->x2 - item->x1)) + i) == COLOR_NULL) continue; - if(item->color == 0) { - //*(original mem location + (currentRowInArray * nColumns) + currentColumnInArray) - frame[l][i] = *(item->obj + ((currentLine - item->y1)*(item->x2 - item->x1)) + i); - } - else { - frame[l][i] = item->color; + for(uint16_t i = 0; i < item->y2; i++) { + for(uint16_t j = 0; j < item->x2; j++) { + if(*(item->obj + i*item->x2 + j) != item->color) { + writePixel(item->y1 + i, item->x1 + j, *(item->obj + i*item->x2 + j)); + } } - }*/ + } break; case 'f': //Fill the screen for(uint16_t y = 0; y < FRAME_HEIGHT; y++) { @@ -154,7 +159,7 @@ void render() { } } - item->flags &= ~(1u); //Clear the update bit + item->flags &= ~RQI_UPDATE; //Clear the update bit previousItem = item; item = item->next; } diff --git a/sdk/sdk.h b/sdk/sdk.h index 3285dfc..a3f01bf 100644 --- a/sdk/sdk.h +++ b/sdk/sdk.h @@ -16,6 +16,8 @@ extern uint8_t autoRender; extern volatile RenderQueueItem background; //First element of the linked list, can be reset to any background extern volatile RenderQueueItem *lastItem; //Last item in linked list, used to set *last in RenderQueueItem +#define CHAR_WIDTH 5 +#define CHAR_HEIGHT 8 extern uint8_t *font; //The current font in use by the system inline void busyWait(uint64_t n) { diff --git a/sdk/utils.c b/sdk/utils.c index 446c6b4..d8ea203 100644 --- a/sdk/utils.c +++ b/sdk/utils.c @@ -48,4 +48,8 @@ uint8_t hsvToRGB(uint8_t hue, uint8_t saturation, uint8_t value) { else return 0; return rgbTo8Bit(r, g, b); +} + +uint8_t invertColor(uint8_t color) { + return 255 - color; } \ No newline at end of file