Landtiger LPC1768 C BigLib 1
A self made, custom C library for the LandTiger board.
 
Loading...
Searching...
No Matches
glcd_processor.c File Reference
#include "glcd_processor.h"
#include "glcd.h"
#include <math.h>

Go to the source code of this file.

Macros

#define IS_MODE(mode, flag)   (((mode) & (flag)) != 0)
 
#define SWAP(type, src, dst)
 
#define SET_POINT(mode, color, x, y)
 

Enumerations

enum  PrintCharError {
  PRINT_CHR_OK = 0 , PRINT_CHR_NOTHINGNESS , PRINT_CHR_ERR_NULL_PARAMS , PRINT_CHR_ERR_SHOULD_NEWLINE ,
  PRINT_CHR_ERR_OUT_OF_VERTICAL_BOUNDS
}
 

Functions

_PRIVATE bool process_line (const LCD_Line *const line, LCD_BBox *out_bbox, u8 mode)
 
_PRIVATE bool process_rect (const LCD_Rect *const rect, LCD_Coordinate pos, LCD_BBox *out_bbox, u8 mode)
 
_PRIVATE bool process_circle (const LCD_Circle *const circle, LCD_BBox *out_bbox, u8 mode)
 
_PRIVATE bool process_img_rle (const LCD_Image *const img, LCD_Coordinate pos, LCD_BBox *out_bbox, u8 mode)
 
_PRIVATE PrintCharError print_char (u8 chr, const LCD_Font *const font, LCD_Coordinate where, u8 mode, LCD_Color txt_col, LCD_Color bg_col, u16 *out_char_w, u16 *out_char_h)
 
_PRIVATE bool process_text (const LCD_Text *const text, LCD_Coordinate pos, LCD_BBox *out_bbox, u8 mode)
 Prints the string onto the screen, or calculates its dimensions without the overhead of printing.
 
_PRIVATE bool process_button (const LCD_Button *const button, LCD_Coordinate pos, LCD_BBox *out_bbox, u8 mode)
 
_PRIVATE bool delete_button (const LCD_Button *const button, LCD_Coordinate pos)
 
_PRIVATE LCD_BBox get_union_bbox (LCD_Component *comps, u16 comps_sz)
 
bool __LCD_PROC_DoProcessObject (const LCD_Obj *const obj, LCD_BBox *out_bbox, u8 mode)
 

Variables

_DECL_EXTERNALLY u16 LCDMaxX
 
_DECL_EXTERNALLY u16 LCDMaxY
 
_DECL_EXTERNALLY LCD_Color LCDCurrentBGColor
 
_DECL_EXTERNALLY LCD_Font LCDFontList []
 
_DECL_EXTERNALLY u8 LCDFontListSize
 

Macro Definition Documentation

◆ IS_MODE

#define IS_MODE (   mode,
  flag 
)    (((mode) & (flag)) != 0)

Definition at line 16 of file glcd_processor.c.

◆ SET_POINT

#define SET_POINT (   mode,
  color,
  x,
 
)
Value:
{ \
if (IS_MODE(mode, MD_DRAW_BBOX)) \
LCD_SetPointColor(color, (LCD_Coordinate){x, y}); \
else if (IS_MODE(mode, MD_DELETE)) \
LCD_SetPointColor(LCDCurrentBGColor, (LCD_Coordinate){x, y}); \
else \
{ \
(void)(color); \
(void)(x); \
(void)(y); \
} \
}
_DECL_EXTERNALLY LCD_Color LCDCurrentBGColor
#define IS_MODE(mode, flag)
@ MD_DELETE
@ MD_DRAW_BBOX

Definition at line 27 of file glcd_processor.c.

28 { \
29 if (IS_MODE(mode, MD_DRAW_BBOX)) \
30 LCD_SetPointColor(color, (LCD_Coordinate){x, y}); \
31 else if (IS_MODE(mode, MD_DELETE)) \
32 LCD_SetPointColor(LCDCurrentBGColor, (LCD_Coordinate){x, y}); \
33 else \
34 { \
35 (void)(color); \
36 (void)(x); \
37 (void)(y); \
38 } \
39 }

◆ SWAP

#define SWAP (   type,
  src,
  dst 
)
Value:
{ \
type tmp = src; \
src = dst; \
dst = tmp; \
}

Definition at line 18 of file glcd_processor.c.

19 { \
20 type tmp = src; \
21 src = dst; \
22 dst = tmp; \
23 }

Enumeration Type Documentation

◆ PrintCharError

Enumerator
PRINT_CHR_OK 
PRINT_CHR_NOTHINGNESS 
PRINT_CHR_ERR_NULL_PARAMS 
PRINT_CHR_ERR_SHOULD_NEWLINE 
PRINT_CHR_ERR_OUT_OF_VERTICAL_BOUNDS 

Definition at line 340 of file glcd_processor.c.

341{
342 PRINT_CHR_OK = 0,
PrintCharError
@ PRINT_CHR_NOTHINGNESS
@ PRINT_CHR_ERR_SHOULD_NEWLINE
@ PRINT_CHR_ERR_OUT_OF_VERTICAL_BOUNDS
@ PRINT_CHR_OK
@ PRINT_CHR_ERR_NULL_PARAMS

Function Documentation

◆ __LCD_PROC_DoProcessObject()

bool __LCD_PROC_DoProcessObject ( const LCD_Obj *const  obj,
LCD_BBox out_bbox,
u8  mode 
)

Definition at line 642 of file glcd_processor.c.

643{
644 if (!obj || !obj->comps || obj->comps_size == 0)
645 return false;
646
647 bool res = true;
648 LCD_Component *comp;
649 for (u16 i = 0; i < obj->comps_size && res; i++)
650 {
651 comp = &obj->comps[i];
652 switch (comp->type)
653 {
654 case LCD_COMP_LINE:
655 // Cannot delete faster, skipping MD_FAST check
656 res = process_line(comp->object.line, &comp->cached_bbox, mode);
657 break;
658 case LCD_COMP_RECT:
659 // Cannot delete faster, skipping MD_FAST check
660 res = process_rect(comp->object.rect, comp->pos, &comp->cached_bbox, mode);
661 break;
662 case LCD_COMP_CIRCLE:
663 // Maybe can delete faster?
664 res = process_circle(comp->object.circle, &comp->cached_bbox, mode);
665 break;
666 case LCD_COMP_IMAGE: {
667 if (IS_MODE(mode, MD_DELETE))
668 {
669 res = process_rect(
670 &(LCD_Rect){
671 .width = comp->object.image->width,
672 .height = comp->object.image->height,
673 .fill_color = LCDCurrentBGColor,
674 .edge_color = LCDCurrentBGColor,
675 },
676 comp->pos, NULL, MD_DELETE);
677 }
678 else
679 res = process_img_rle(comp->object.image, comp->pos, &comp->cached_bbox, MD_DRAW_BBOX);
680 break;
681 }
682 case LCD_COMP_TEXT:
683 if (IS_MODE(mode, MD_DELETE | MD_DELETE_FAST))
684 {
685 // If we're deleting in fast mode, we don't delete char by char, but we simply paint
686 // the whole text's bounding box (i.e. a rectangle) with the background color. Faster?
687 LCD_BBox bbox;
688 if (!(res = process_text(comp->object.text, comp->pos, &bbox, MD_BBOX)))
689 break;
690
691 res = process_rect(
692 &(LCD_Rect){
693 .width = abs(bbox.top_left.x - bbox.bottom_right.x),
694 .height = abs(bbox.top_left.y - bbox.bottom_right.y),
695 },
696 comp->pos, NULL, MD_DELETE);
697 break;
698 }
699 else
700 res = process_text(comp->object.text, comp->pos, &comp->cached_bbox, mode);
701 break;
702 case LCD_COMP_BUTTON: {
703 if (IS_MODE(mode, MD_DELETE))
704 res = delete_button(comp->object.button, comp->pos);
705 else
706 res = process_button(comp->object.button, comp->pos, &comp->cached_bbox, mode);
707 break;
708 }
709 }
710 }
711
712 if (!res)
713 return false;
714
715 // If we need to calculate the bounding box of the object, we need to calculate the union of all
716 // the bounding boxes of the components. This is needed to determine the actual dimensions of the
717 // object, so that the caller can use them to position it correctly.
718 if (out_bbox && IS_MODE(mode, MD_BBOX | MD_DRAW_BBOX))
719 *out_bbox = get_union_bbox(obj->comps, obj->comps_size);
720
721 return true;
722}
_PRIVATE bool process_rect(const LCD_Rect *const rect, LCD_Coordinate pos, LCD_BBox *out_bbox, u8 mode)
_PRIVATE bool process_text(const LCD_Text *const text, LCD_Coordinate pos, LCD_BBox *out_bbox, u8 mode)
Prints the string onto the screen, or calculates its dimensions without the overhead of printing.
_PRIVATE bool delete_button(const LCD_Button *const button, LCD_Coordinate pos)
_PRIVATE LCD_BBox get_union_bbox(LCD_Component *comps, u16 comps_sz)
_PRIVATE bool process_button(const LCD_Button *const button, LCD_Coordinate pos, LCD_BBox *out_bbox, u8 mode)
_PRIVATE bool process_img_rle(const LCD_Image *const img, LCD_Coordinate pos, LCD_BBox *out_bbox, u8 mode)
_PRIVATE bool process_line(const LCD_Line *const line, LCD_BBox *out_bbox, u8 mode)
_PRIVATE bool process_circle(const LCD_Circle *const circle, LCD_BBox *out_bbox, u8 mode)
@ MD_DELETE_FAST
@ MD_BBOX
@ LCD_COMP_RECT
Definition glcd_types.h:159
@ LCD_COMP_BUTTON
Definition glcd_types.h:163
@ LCD_COMP_IMAGE
Definition glcd_types.h:161
@ LCD_COMP_CIRCLE
Definition glcd_types.h:160
@ LCD_COMP_TEXT
Definition glcd_types.h:162
@ LCD_COMP_LINE
Definition glcd_types.h:158
LCD_Coordinate top_left
Definition glcd_types.h:62
LCD_Coordinate bottom_right
Definition glcd_types.h:62
Used to store a drawable component of any type.
Definition glcd_types.h:168
LCD_Circle * circle
Definition glcd_types.h:175
LCD_Coordinate pos
Definition glcd_types.h:170
LCD_Text * text
Definition glcd_types.h:177
LCD_Button * button
Definition glcd_types.h:178
LCD_Line * line
Definition glcd_types.h:173
LCD_ComponentType type
Definition glcd_types.h:169
LCD_Rect * rect
Definition glcd_types.h:174
union LCD_Component::@0 object
LCD_Image * image
Definition glcd_types.h:176
LCD_BBox cached_bbox
Definition glcd_types.h:171
u8 comps_size
Definition glcd_types.h:192
LCD_Component * comps
Definition glcd_types.h:191
uint16_t u16
Definition types.h:7

◆ delete_button()

_PRIVATE bool delete_button ( const LCD_Button *const  button,
LCD_Coordinate  pos 
)

Definition at line 571 of file glcd_processor.c.

572{
573 if (!button)
574 return false;
575
576 // We need to delete the label, and retain it's bbox, since we need the
577 // dimensions for deleting the border too.
578
579 LCD_BBox label_bbox;
580 if (!process_text(
581 &(LCD_Text){
582 .text = button->label.text,
583 .font = button->label.font,
584 .text_color = LCDCurrentBGColor,
585 .bg_color = LCD_COL_NONE, // BG is never drawn w/ labels.
586 .char_spacing = button->label.char_spacing,
587 .line_spacing = button->label.line_spacing,
588 },
589 pos, &label_bbox, MD_DELETE | MD_BBOX))
590 return false;
591
592 // If edge_color and/or fill_color are defined, we only need to delete the label
593 if (button->edge_color == LCD_COL_NONE && button->fill_color == LCD_COL_NONE)
594 return true;
595
596 LCD_Dimension label_dim = {
597 .width = abs(label_bbox.bottom_right.x - label_bbox.top_left.x),
598 .height = abs(label_bbox.bottom_right.y - label_bbox.top_left.y),
599 };
600
601 // Otherwise, we need to delete the border too.
602 const LCD_Rect border = {
603 .width = label_dim.width + button->padding.left + button->padding.right,
604 .height = label_dim.height + button->padding.top + button->padding.bottom,
605 .edge_color = LCDCurrentBGColor,
606 .fill_color = LCDCurrentBGColor,
607 };
608
609 process_rect(&border, pos, NULL, MD_DELETE);
610 return true;
611}
@ LCD_COL_NONE
Definition glcd_types.h:33
LCD_FontID font
Definition glcd_types.h:137
LCD_ButtonLabel label
Definition glcd_types.h:144
LCD_Padding padding
Definition glcd_types.h:146
LCD_Color edge_color
Definition glcd_types.h:145
LCD_Color fill_color
Definition glcd_types.h:145

◆ get_union_bbox()

_PRIVATE LCD_BBox get_union_bbox ( LCD_Component comps,
u16  comps_sz 
)
inline

Definition at line 615 of file glcd_processor.c.

616{
617 if (!comps || comps_sz == 0)
618 return (LCD_BBox){0};
619
620 LCD_BBox bbox = comps[0].cached_bbox, *current_comp_bbox;
621 for (u16 i = 0; i < comps_sz; i++)
622 {
623 current_comp_bbox = &comps[i].cached_bbox;
624 if (current_comp_bbox->top_left.x < bbox.top_left.x)
625 bbox.top_left.x = current_comp_bbox->top_left.x;
626
627 if (current_comp_bbox->top_left.y < bbox.top_left.y)
628 bbox.top_left.y = current_comp_bbox->top_left.y;
629
630 if (current_comp_bbox->bottom_right.x > bbox.bottom_right.x)
631 bbox.bottom_right.x = current_comp_bbox->bottom_right.x;
632
633 if (current_comp_bbox->bottom_right.y > bbox.bottom_right.y)
634 bbox.bottom_right.y = current_comp_bbox->bottom_right.y;
635 }
636
637 return bbox;
638}

◆ print_char()

_PRIVATE PrintCharError print_char ( u8  chr,
const LCD_Font *const  font,
LCD_Coordinate  where,
u8  mode,
LCD_Color  txt_col,
LCD_Color  bg_col,
u16 out_char_w,
u16 out_char_h 
)

Definition at line 349 of file glcd_processor.c.

351{
352 // We can't print non-ASCII printable chars, and other invalid values
353 if (!font || chr < ASCII_FONT_MIN_VALUE || chr > ASCII_FONT_MAX_VALUE)
355
356 // Each line of the array contains the char data, and chars are stored in ASCII order. Each line is
357 // made up of font->char_height different u32 values, each one representing a row of the given char.
358 // Hence, for every char, I need to retrieve font->char_height u32 values from the array line given
359 // by chr - ASCII_FONT_MIN_VALUE, since the first printable ASCII char is 32.
360 // For example: A (=65) - 32 = 33, so starting from the 33rd line of the array, I need to read
361 // font->char_height u32 values.
362 const u16 index = chr - ASCII_FONT_MIN_VALUE;
363
364 // Considering the baseline offset of the current char to align it correctly (in case of letters with
365 // descenders like 'g' or 'y' compared to letters like 'a' or 'b'). If the font data has been created
366 // with the ttf2c script, chances are that the baseline offsets are stored in the baseline_offsets array.
367 const u16 baseline_offset = font->baseline_offsets ? font->baseline_offsets[index] : 0;
368
369 // We're moving the char down by baseline_offset pixels, so that when it's printed
370 // by moving up, it's gonna have its top-left corner at the expected position.
371 where.y += font->max_baseline_offset;
372
373 // Getting the char height/width from the char_heights/widths array, which stores them in ASCII order.
374 // If any of these arrays is NULL (e.g. for the preloaded fonts), then max_char_height/width is used.
375
376 // We need to determine the width of the selected char, so we can move forward to the next char
377 // leaving just the right amount of space between them. If the font data has been created with
378 // the ttf2c script, chances are that the width of the char is stored in the char_widths array.
379 // This also applies to the char_heights array.
380 *out_char_h = font->char_heights ? font->char_heights[index] : font->max_char_height;
381 *out_char_w = font->char_widths ? font->char_widths[index] : font->max_char_width;
382
383 // If the char has no width, it's really nothingness, so we return immediately.
384 if (*out_char_w == 0)
386
387 // Verifying this before the x check, because the char might be completely outside the screen
388 if (where.y - baseline_offset < 0 || where.y - baseline_offset >= LCDMaxY)
390
391 // If the char is completely outside the screen, return immediately, but with the char details set.
392 if (where.x < 0 || where.x + *out_char_w >= LCDMaxX)
394
395 // If we don't want to actually print/delete the char, we just return the width of the char.
396 // Additionally, if we want to print/delete but the char has no height data, just return,
397 // so that print_text can move to the next char and leave some space between them.
398 if (((mode & (MD_DRAW_BBOX | MD_DELETE)) == 0) || *out_char_h == 0)
399 return PRINT_CHR_OK;
400
401 // We need to move to the correct row of the array, which contains the char data.
402 // Problem is, the length of the rows before the one we need is variable, hence we can't
403 // simply move the pointer by a fixed quantity index * char_h, because char_h is the length
404 // of the specific row we need!
405 const u32 *font_data_copy = font->data;
406 for (u16 i = 0; i < index; i++)
407 font_data_copy += font->char_heights ? font->char_heights[i] : font->max_char_height;
408
409 u32 value;
410 bool pixel_has_value;
411 for (u16 i = 0; i < *out_char_h; i++) // For each char row, we have font->char_width bits
412 {
413 for (u16 j = 0; j < *out_char_w; j++)
414 {
415 // Since a char value is not necessarily 32 bits long, but its length depends on
416 // the char width, we mask the MSB that are not part of the char data.
417 // E.g. 8 bits, we & with 0xFFFFFFFF >> (32 - 8) = 0xFFFFFFFF >> 24 = 0x000000FF
418 value = font_data_copy[i] & (0xFFFFFFFF >> (32 - *out_char_w));
419
420 // E.g 8 bit font data: mask 0xFF and data 0xC3 = 0b11000011
421 // Starting from the leftmost bit -> 0b11000011 >> 7=(char_w=8 - j=0 - 1) = 0b00000011 & 0x1 = 1
422 pixel_has_value = (value >> (*out_char_w - j - 1)) & 0x1;
423 SET_POINT(mode, pixel_has_value ? txt_col : bg_col, where.x + j, where.y + i - baseline_offset);
424 }
425 }
426
427 return PRINT_CHR_OK;
428}
_DECL_EXTERNALLY u16 LCDMaxY
#define SET_POINT(mode, color, x, y)
_DECL_EXTERNALLY u16 LCDMaxX
#define ASCII_FONT_MAX_VALUE
Definition glcd_types.h:94
#define ASCII_FONT_MIN_VALUE
Definition glcd_types.h:93
const u16 * char_widths
Definition glcd_types.h:80
const u32 * data
Definition glcd_types.h:75
const u16 * char_heights
Definition glcd_types.h:80
u16 max_char_width
Definition glcd_types.h:76
const u16 * baseline_offsets
Definition glcd_types.h:87
u16 max_char_height
Definition glcd_types.h:76
u16 max_baseline_offset
Definition glcd_types.h:88
uint32_t u32
Definition types.h:6

◆ process_button()

_PRIVATE bool process_button ( const LCD_Button *const  button,
LCD_Coordinate  pos,
LCD_BBox out_bbox,
u8  mode 
)

Definition at line 515 of file glcd_processor.c.

516{
517 if (!button || !mode)
518 return false;
519
520 const LCD_Text label_as_text = {
521 .text = button->label.text,
522 .font = button->label.font,
523 .text_color = button->label.text_color,
524 .bg_color = LCD_COL_NONE,
525 .char_spacing = button->label.char_spacing,
526 .line_spacing = button->label.line_spacing,
527 };
528
529 // There are two cases: the button has no border, and the button has a border.
530 // If the button has no border, we only need to consider the label:
531 if (button->edge_color == LCD_COL_NONE && button->fill_color == LCD_COL_NONE)
532 {
533 // With no border, we only need to consider the label. Again, two more cases:
534 // if the mode is MD_DRAW_BBOX, we need to print the label, otherwise we only need to calculate
535 // its bounding box, so that the caller can use it to position the button correctly.
536 return process_text(&label_as_text, pos, out_bbox, mode);
537 }
538
539 // If the button has a border, we need to consider the label and the border itself.
540 // First of all, let's calculate the bounding box of the label, so that we can center it
541 LCD_BBox label_bbox;
542 if (!process_text(&label_as_text, pos, &label_bbox, MD_BBOX))
543 return false;
544
545 const LCD_Dimension label_bbox_dim = {
546 .width = abs(label_bbox.bottom_right.x - label_bbox.top_left.x),
547 .height = abs(label_bbox.bottom_right.y - label_bbox.top_left.y),
548 };
549
550 const LCD_Rect border = {
551 .width = label_bbox_dim.width + button->padding.left + button->padding.right,
552 .height = label_bbox_dim.height + button->padding.top + button->padding.bottom,
553 .edge_color = button->edge_color,
554 .fill_color = button->fill_color,
555 };
556
557 // If the button has a border, its bbox is the border itself, hence we're setting it
558 // right from the process_rect function.
559 process_rect(&border, pos, out_bbox, mode);
560
561 // Now we need to center the label in the button
562 const LCD_Coordinate label_coords = {
563 .x = pos.x + (border.width - label_bbox_dim.width) / 2,
564 .y = pos.y + (border.height - label_bbox_dim.height) / 2,
565 };
566
567 process_text(&label_as_text, label_coords, NULL, mode);
568 return true;
569}
LCD_Color text_color
Definition glcd_types.h:136
char * text
Definition glcd_types.h:126

◆ process_circle()

_PRIVATE bool process_circle ( const LCD_Circle *const  circle,
LCD_BBox out_bbox,
u8  mode 
)

Definition at line 188 of file glcd_processor.c.

189{
190 if (!circle || !mode || circle->radius == 0)
191 return false;
192
193 const LCD_Coordinate center = circle->center;
194 const u16 radius = circle->radius;
195
196 if (IS_MODE(mode, MD_DRAW_BBOX) || IS_MODE(mode, MD_DELETE))
197 {
198 // Printing 4 cardinal points of the circle: note that if the radius is subtracted from y,
199 // from the center, the pixel will be actually colored at the other side, because smaller
200 // numbers mean higher positions in the screen.
201 SET_POINT(mode, circle->edge_color, center.x + radius, center.y); // Right side of the center
202 SET_POINT(mode, circle->edge_color, center.x - radius, center.y); // Left side
203 SET_POINT(mode, circle->edge_color, center.x, center.y + radius); // Top, but we +, it's the bottom
204 SET_POINT(mode, circle->edge_color, center.x, center.y - radius); // Bottom, but we -, it's the top
205
206 u16 x = radius, y = 0; // Working on the first octant in the fourth quadrant
207 int p = 1 - radius; // Initial value of the decision parameter
208
209 // Iterating till y (that is initially zero) becomes = x, meaning that
210 // we reached the end of the octant. That's because we're actually iterating
211 // over the points of that octant only. The other ones are printed using symmetry.
212 while (x > y++)
213 {
214 // The decision parameter is needed to figure out if the X position at which
215 // we're drawing needs to be decreased by 1, i.e. moved closer to the circle,
216 // so that a curved line is formed. Y is constanty incremented in the while
217 // loop, meaning that we're moving upwords in the octant, but really downward
218 // on the screen, since we get higher pixel values if we move to the bottom of it.
219 if (p <= 0) // The midpoint is inside or on the border of the circle, x stays fixed.
220 p += (2 * y + 1); // 2y + 1 accounts for the distance increase due to Y++
221 else // Outside the circle
222 {
223 x--; // We move closer to the center
224 p += (2 * (y - x) + 1); // 2(y-x) + 1 accounts for the decreased X and increased Y
225 }
226
227 if (y >= x) // We reached the end of the octant (y=x)
228 break;
229
230 // Printing the points in the other octants using symmetry
231 SET_POINT(mode, circle->edge_color, x + center.x, y + center.y);
232 SET_POINT(mode, circle->edge_color, -x + center.x, y + center.y);
233 SET_POINT(mode, circle->edge_color, x + center.x, -y + center.y);
234 SET_POINT(mode, circle->edge_color, -x + center.x, -y + center.y);
235 SET_POINT(mode, circle->edge_color, y + center.x, x + center.y);
236 SET_POINT(mode, circle->edge_color, -y + center.x, x + center.y);
237 SET_POINT(mode, circle->edge_color, y + center.x, -x + center.y);
238 SET_POINT(mode, circle->edge_color, -y + center.x, -x + center.y);
239 }
240
241 if (circle->fill_color != LCD_COL_NONE)
242 {
243 i16 x_diff, y_diff, rad_sq;
244 for (u16 i = center.x - radius + 1; i < center.x + radius; i++)
245 {
246 for (u16 j = center.y - radius + 1; j < center.y + radius; j++)
247 {
248 x_diff = (i - center.x) * (i - center.x);
249 y_diff = (j - center.y) * (j - center.y);
250 rad_sq = radius * radius;
251 if (x_diff + y_diff <= rad_sq)
252 SET_POINT(mode, circle->fill_color, i, j);
253 }
254 }
255 }
256 }
257
258 if (out_bbox && IS_MODE(mode, MD_BBOX | MD_DRAW_BBOX))
259 {
260 out_bbox->top_left = (LCD_Coordinate){center.x - radius, center.y - radius};
261 out_bbox->bottom_right = (LCD_Coordinate){center.x + radius, center.y + radius};
262 }
263
264 return true;
265}
LCD_Color edge_color
Definition glcd_types.h:114
LCD_Coordinate center
Definition glcd_types.h:112
LCD_Color fill_color
Definition glcd_types.h:114
int16_t i16
Definition types.h:11

◆ process_img_rle()

_PRIVATE bool process_img_rle ( const LCD_Image *const  img,
LCD_Coordinate  pos,
LCD_BBox out_bbox,
u8  mode 
)

Definition at line 267 of file glcd_processor.c.

268{
269 if (!img || !img->pixels || !mode)
270 return false;
271
272 u16 width = img->width, height = img->height;
273 if (width == 0 || height == 0)
274 return false;
275
276 // Pos is the top-left corner of the image.
277 if (pos.x >= LCDMaxX || pos.y >= LCDMaxY)
278 return false; // Image is completely outside the screen
279
280 // Not drawing images partially out of the screen.
281 if (pos.x + width > LCDMaxX || pos.y + height > LCDMaxY)
282 return false;
283
284 if (IS_MODE(mode, MD_DRAW_BBOX) || IS_MODE(mode, MD_DELETE))
285 {
286 const u32 *pixels_copy = img->pixels;
287 u32 pixel_data,
288 rgb888; // Pixel is a 32-bit or 24-bit value: 0xAARRGGBB if alpha is present, 0x00RRGGBB otherwise
289
290 u8 alpha_data;
291 u16 current_x, pixels_left, count;
292 for (u16 i = 0; i < height; i++)
293 {
294 current_x = pos.x; // Start at the beginning of the row
295 pixels_left = width; // Remaining pixels to draw in the row
296
297 while (pixels_left > 0)
298 {
299 count = *pixels_copy++;
300 pixel_data = *pixels_copy++;
301
302 // Draw pixels, ensuring we stay within the row
303 for (u16 j = 0; j < count && pixels_left > 0; j++)
304 {
305 if (img->has_alpha)
306 {
307 // If the alpha is present, then pixel_data is of type 0xAARRGGBB.
308 alpha_data = (u8)(pixel_data >> 24);
309 rgb888 = (u32)(pixel_data & 0x00FFFFFF);
310
311 if (alpha_data) // Alpha is != 0
312 SET_POINT(mode, RGB8_TO_RGB565(rgb888), current_x, pos.y + i);
313
314 current_x++; // Move to the next pixel, regardless of the alpha value
315 }
316 else
317 {
318 // No alpha, pixel_data is of type 0x00RRGGBB
319 rgb888 = (u32)(pixel_data & 0x00FFFFFF);
320 SET_POINT(mode, RGB8_TO_RGB565(rgb888), current_x++, pos.y + i);
321 }
322
323 pixels_left--;
324 }
325 }
326 }
327 }
328
329 if (out_bbox && IS_MODE(mode, MD_BBOX | MD_DRAW_BBOX))
330 {
331 out_bbox->top_left = pos;
332 out_bbox->bottom_right = (LCD_Coordinate){pos.x + width, pos.y + height};
333 }
334
335 return true;
336}
#define RGB8_TO_RGB565(rgb)
Converts RGB (24 bit) into RGB565 (16 bit):
Definition glcd.h:12
bool has_alpha
Definition glcd_types.h:121
const u32 * pixels
Definition glcd_types.h:119
uint8_t u8
Definition types.h:8

◆ process_line()

_PRIVATE bool process_line ( const LCD_Line *const  line,
LCD_BBox out_bbox,
u8  mode 
)

Definition at line 43 of file glcd_processor.c.

44{
45 if (!line || !mode)
46 return false;
47
48 // If the starting point is to the right of the ending point (both for x and/or y), swap.
49 LCD_Coordinate from = line->from, to = line->to;
50 LCD_Coordinate original_from = from, original_to = to;
51
52 int dx = abs(to.x - from.x); // Absolute difference
53 int dy = abs(to.y - from.y);
54
55 // Determine the step directions
56 int x_step = (from.x < to.x) ? 1 : -1;
57 int y_step = (from.y < to.y) ? 1 : -1;
58
59 // Special cases: Vertical or Horizontal lines
60 if (dx == 0) // Vertical line
61 {
62 while (from.y != to.y + y_step)
63 {
64 SET_POINT(mode, line->color, from.x, from.y);
65 from.y += y_step;
66 }
67 }
68 else if (dy == 0) // Horizontal line
69 {
70 while (from.x != to.x + x_step)
71 {
72 SET_POINT(mode, line->color, from.x, from.y);
73 from.x += x_step;
74 }
75 }
76 else if (dx > dy) // Bresenham's algorithm: slope < 1
77 {
78 int tmp = 2 * dy - dx;
79 while (from.x != to.x + x_step)
80 {
81 SET_POINT(mode, line->color, from.x, from.y);
82 from.x += x_step;
83 if (tmp > 0)
84 {
85 from.y += y_step;
86 tmp += 2 * dy - 2 * dx;
87 }
88 else
89 tmp += 2 * dy;
90 }
91 }
92 else // Bresenham's algorithm: slope >= 1
93 {
94 int tmp = 2 * dx - dy;
95 while (from.y != to.y + y_step)
96 {
97 SET_POINT(mode, line->color, from.x, from.y);
98 from.y += y_step;
99 if (tmp > 0)
100 {
101 from.x += x_step;
102 tmp += 2 * dx - 2 * dy;
103 }
104 else
105 tmp += 2 * dx;
106 }
107 }
108
109 if (out_bbox && IS_MODE(mode, MD_BBOX | MD_DRAW_BBOX))
110 {
111 // Swapping original coordinates if needed
112 if (original_from.x > original_to.x)
113 SWAP(u16, original_from.x, original_to.x)
114
115 if (original_from.y > original_to.y)
116 SWAP(u16, original_from.y, original_to.y)
117
118 out_bbox->top_left = original_from;
119 out_bbox->bottom_right = original_to;
120 }
121
122 return true;
123}
#define SWAP(type, src, dst)
LCD_Coordinate to
Definition glcd_types.h:100
LCD_Color color
Definition glcd_types.h:101
LCD_Coordinate from
Definition glcd_types.h:100

◆ process_rect()

_PRIVATE bool process_rect ( const LCD_Rect *const  rect,
LCD_Coordinate  pos,
LCD_BBox out_bbox,
u8  mode 
)

Definition at line 125 of file glcd_processor.c.

126{
127 if (!rect || !mode)
128 return false;
129
130 // Rect object now contains width and height, not the start/end coordinates.
131 // This, to support the rendering of the rectangle at various positions on the
132 // screen, based on the pos parameter. pos is the top left corner of the rectangle.
133 if (rect->width == 0 || rect->height == 0)
134 return false;
135
136 LCD_Coordinate from = pos;
137 LCD_Coordinate to = {from.x + rect->width, from.y + rect->height};
138 if (from.x >= LCDMaxX || from.y >= LCDMaxY)
139 return false; // Rectangle is completely outside the screen
140
141 // If the ending point is outside the screen, adjust it.
142 if (to.x >= LCDMaxX)
143 to.x = LCDMaxX - 1;
144 if (to.y >= LCDMaxY)
145 to.y = LCDMaxY - 1;
146
147 // If the starting point is to the right of the ending point (both for x and/or y), swap.
148 if (from.x > to.x)
149 SWAP(u16, to.x, from.x)
150 if (from.y > to.y)
151 SWAP(u16, to.y, from.y)
152
153 if (IS_MODE(mode, MD_DRAW_BBOX) || IS_MODE(mode, MD_DELETE))
154 {
155 // Drawing the edges of the rectangle
156 LCD_Line line = {.color = rect->edge_color};
157
158 line.from = from;
159 line.to = (LCD_Coordinate){to.x, from.y};
160 process_line(&line, NULL, mode); // Top horizontal edge
161 line.to = (LCD_Coordinate){from.x, to.y};
162 process_line(&line, NULL, mode); // Left vertical edge
163
164 line.from = to;
165 line.to = (LCD_Coordinate){to.x, from.y};
166 process_line(&line, NULL, mode); // Right vertical edge
167 line.to = (LCD_Coordinate){from.x, to.y};
168 process_line(&line, NULL, mode); // Bottom horizontal edge
169
170 if (rect->fill_color != LCD_COL_NONE)
171 {
172 // Filling the rectangle
173 for (u16 i = from.x + 1; i < to.x; i++)
174 for (u16 j = from.y + 1; j < to.y; j++)
175 SET_POINT(mode, rect->fill_color, i, j);
176 }
177 }
178
179 if (out_bbox && IS_MODE(mode, MD_BBOX | MD_DRAW_BBOX))
180 {
181 out_bbox->top_left = from;
182 out_bbox->bottom_right = to;
183 }
184
185 return true;
186}
LCD_Color edge_color
Definition glcd_types.h:107
LCD_Color fill_color
Definition glcd_types.h:107

◆ process_text()

_PRIVATE bool process_text ( const LCD_Text *const  text,
LCD_Coordinate  pos,
LCD_BBox out_bbox,
u8  mode 
)

Prints the string onto the screen, or calculates its dimensions without the overhead of printing.

Parameters
textThe text to print
posThe top-left corner (considering the eventual baseline offset) of the text
dont_actually_printIf true, the text is not printed, but the width is calculated. Used to determine the width of the text without actually printing it.
out_dim[OUTPUT] The width and height of the text, regardless of the actual printing.

Definition at line 436 of file glcd_processor.c.

437{
438 if (!text || !text->text || !mode || text->font >= LCDFontListSize)
439 return false;
440
441 const LCD_Font font = LCDFontList[text->font];
442 if (!font.data)
443 return false;
444
445 if (pos.x >= LCDMaxX || pos.y >= LCDMaxY)
446 return false; // Text is completely outside the screen
447
448 u8 chr, *str = (u8 *)(text->text);
449 u16 start_x = pos.x, start_y = pos.y; // Saving the starting (x, y) coords
450
451 // Track the max width (for multi-line) and the total height of the text (min. is one line, i.e. font height)
452 u16 cur_width = 0, max_width = 0, total_height = font.max_char_height;
453
454 PrintCharError err;
455 i16 x_diff;
456 bool no_more_space = false;
457 u16 char_w, char_h, x_inc, y_inc;
458 while ((chr = *str) && !no_more_space)
459 {
460 err = print_char(chr, &font, pos, mode, text->text_color, text->bg_color, &char_w, &char_h);
461 if (err == PRINT_CHR_ERR_NULL_PARAMS)
462 return false; // Invalid, return.
463
464 // String is incremented only if the char has been printed correctly, otherwise we
465 // may need to re-print it (e.g. if err = PRINT_CHR_ERR_SHOULD_NEWLINE)
466 if (err == PRINT_CHR_OK)
467 str++;
468
469 x_inc = char_w + text->char_spacing;
470 y_inc = font.max_char_height + text->line_spacing;
471
472 if ((pos.x + x_inc) < LCDMaxX)
473 {
474 // While there's space on the x axis, move on this axis by x_inc
475 pos.x += x_inc;
476 }
477 else if ((pos.y + y_inc) < LCDMaxY)
478 {
479 // If there's no space on the x axis, but there's space on the y axis, move to the next line
480 pos.x = start_x; // =0 OR start_x, to keep the same x position for all lines or start at the very left.
481 pos.y += y_inc; // Move to the next line
482 total_height += y_inc; // Increment the total height of the text
483 }
484 else
485 {
486 // assert(err == PRINT_CHR_ERR_OUT_OF_VERTICAL_BOUNDS);
487 no_more_space = true; // Stop printing if there's no more space
488 }
489
490 x_diff = pos.x - start_x;
491 if ((pos.x + x_inc) < LCDMaxX)
492 cur_width = (x_diff < LCDMaxX) ? x_diff : LCDMaxX;
493 else
494 cur_width = (x_diff + char_w) < LCDMaxX ? (x_diff + char_w) : LCDMaxX;
495
496 // assert(cur_width >= 0); // Should never be < 0, if @ line 800 we specify to start at start_x, not 0
497 max_width = (cur_width > max_width) ? cur_width : max_width;
498 }
499
500 // If the string is short and doesn't wrap, set max_width correctly
501 if (max_width == 0)
502 max_width = pos.x - start_x;
503
504 if (out_bbox && IS_MODE(mode, MD_BBOX | MD_DRAW_BBOX))
505 {
506 out_bbox->top_left = (LCD_Coordinate){start_x, start_y};
507 out_bbox->bottom_right = (LCD_Coordinate){start_x + max_width, start_y + total_height};
508 }
509
510 return true;
511}
_DECL_EXTERNALLY LCD_Font LCDFontList[]
_DECL_EXTERNALLY u8 LCDFontListSize
_PRIVATE PrintCharError print_char(u8 chr, const LCD_Font *const font, LCD_Coordinate where, u8 mode, LCD_Color txt_col, LCD_Color bg_col, u16 *out_char_w, u16 *out_char_h)
i8 char_spacing
Definition glcd_types.h:129
LCD_Color text_color
Definition glcd_types.h:127
LCD_Color bg_color
Definition glcd_types.h:127
LCD_FontID font
Definition glcd_types.h:128
i8 line_spacing
Definition glcd_types.h:130

Variable Documentation

◆ LCDCurrentBGColor

_DECL_EXTERNALLY LCD_Color LCDCurrentBGColor

Definition at line 9 of file glcd_processor.c.

◆ LCDFontList

_DECL_EXTERNALLY LCD_Font LCDFontList[]

Definition at line 11 of file glcd_processor.c.

◆ LCDFontListSize

_DECL_EXTERNALLY u8 LCDFontListSize

Definition at line 12 of file glcd_processor.c.

◆ LCDMaxX

Definition at line 8 of file glcd_processor.c.

◆ LCDMaxY

Definition at line 8 of file glcd_processor.c.