#include "font.h" #include "LCD_driver.h" uint16_t GFX_DrawChar( uint16_t x, uint16_t y, char c, const GFXfont *font, uint16_t fg_color, uint16_t bg_color) { if (c < font->firstChar || c > font->lastChar) { return x; } uint16_t glyphIndex = c - font->firstChar; const GFXglyph *glyph = &font->glyphs[glyphIndex]; int16_t startX = x + glyph->xOffset; int16_t startY = y + glyph->yOffset; if (startX + glyph->width <= 0 || startX >= LCD_WIDTH) return x; if (startY + glyph->height <= 0 || startY >= LCD_HEIGHT) return x; LCD_Set_Address(startX, startY, startX + glyph->width - 1, startY + glyph->height - 1); uint16_t pendingPixelCount = 0; uint8_t pendingPixelBit = 0; uint16_t bitPos = 0; for (uint8_t row = 0; row < glyph->height; row++) { for (uint8_t col = 0; col < glyph->width; col++) { uint16_t byteIndex = glyph->bitmapOffset + (bitPos / 8); uint8_t bitIndex = bitPos % 8; uint8_t pixelBit = (font->bitmaps[byteIndex] & (0x80 >> bitIndex)) ? 1 : 0; if (pixelBit == pendingPixelBit) { pendingPixelCount++; } else { if (pendingPixelCount != 0) { LCD_Draw_Colour_Burst(pendingPixelBit ? fg_color : bg_color, pendingPixelCount); pendingPixelCount = 1; } pendingPixelBit = pixelBit; } // Per pixel way: slower // uint16_t pixelColor = pixelBit ? fg_color : bg_color; // // int16_t absX = startX + col; // int16_t absY = startY + row; // // if (absX >= 0 && absX < LCD_WIDTH && absY >= 0 && absY < LCD_HEIGHT) { // LCD_Draw_Pixel(absX, absY, pixelColor); // } bitPos++; } } if (pendingPixelCount != 0) { LCD_Draw_Colour_Burst(pendingPixelBit ? fg_color : bg_color, pendingPixelCount); } return x + glyph->advance; } uint16_t GFX_ClearChar( uint16_t x, uint16_t y, char c, const GFXfont *font, uint16_t bg_color) { if (c < font->firstChar || c > font->lastChar) { return x; } uint16_t glyphIndex = c - font->firstChar; const GFXglyph *glyph = &font->glyphs[glyphIndex]; int16_t startX = x + glyph->xOffset; int16_t startY = y + glyph->yOffset; if (startX + glyph->width <= 0 || startX >= LCD_WIDTH) return x; if (startY + glyph->height <= 0 || startY >= LCD_HEIGHT) return x; LCD_Set_Address(startX, startY, startX + glyph->width - 1, startY + glyph->height - 1); LCD_Draw_Colour_Burst(bg_color, glyph->height * glyph->width); return x + glyph->advance; } uint16_t GFX_DrawCharScaled( uint16_t x, uint16_t y, char c, const GFXfont *font, uint16_t fg_color, uint16_t bg_color, uint8_t scale) { if (c < font->firstChar || c > font->lastChar || scale == 0) { return x; } uint16_t glyphIndex = c - font->firstChar; const GFXglyph *glyph = &font->glyphs[glyphIndex]; // Calcul des dimensions cibles après mise à l'échelle uint16_t target_width = (glyph->width + scale - 1) / scale; uint16_t target_height = (glyph->height + scale - 1) / scale; int16_t startX = x + (glyph->xOffset / scale); int16_t startY = y + (glyph->yOffset / scale); // Vérification des limites avec les dimensions cibles if (startX + target_width <= 0 || startX >= LCD_WIDTH) return x; if (startY + target_height <= 0 || startY >= LCD_HEIGHT) return x; // Mode standard (sans anti-crénelage) if (scale == 1) { LCD_Set_Address(startX, startY, startX + glyph->width - 1, startY + glyph->height - 1); uint16_t pendingPixelCount = 0; uint8_t pendingPixelBit = 0; uint16_t bitPos = 0; for (uint8_t row = 0; row < glyph->height; row++) { for (uint8_t col = 0; col < glyph->width; col++) { uint16_t byteIndex = glyph->bitmapOffset + (bitPos / 8); uint8_t bitIndex = bitPos % 8; uint8_t pixelBit = (font->bitmaps[byteIndex] & (0x80 >> bitIndex)) ? 1 : 0; if (pixelBit == pendingPixelBit) { pendingPixelCount++; } else { if (pendingPixelCount != 0) { LCD_Draw_Colour_Burst(pendingPixelBit ? fg_color : bg_color, pendingPixelCount); pendingPixelCount = 1; } pendingPixelBit = pixelBit; } bitPos++; } } if (pendingPixelCount != 0) { LCD_Draw_Colour_Burst(pendingPixelBit ? fg_color : bg_color, pendingPixelCount); } return x + glyph->advance; } // Mode anti-crénelage (scale > 1) const uint16_t scale_sq = scale * scale; const uint8_t bg_R = (bg_color >> 11) & 0x1F; const uint8_t bg_G = (bg_color >> 5) & 0x3F; const uint8_t bg_B = bg_color & 0x1F; const uint8_t fg_R = (fg_color >> 11) & 0x1F; const uint8_t fg_G = (fg_color >> 5) & 0x3F; const uint8_t fg_B = fg_color & 0x1F; for (uint16_t tr = 0; tr < target_height; tr++) { for (uint16_t tc = 0; tc < target_width; tc++) { uint16_t count = 0; const uint16_t src_row_start = tr * scale; const uint16_t src_col_start = tc * scale; // Comptage des pixels actifs dans le bloc source for (uint8_t sr = 0; sr < scale; sr++) { for (uint8_t sc = 0; sc < scale; sc++) { const uint16_t src_row = src_row_start + sr; const uint16_t src_col = src_col_start + sc; if (src_row >= glyph->height || src_col >= glyph->width) continue; const uint32_t bitPos = (src_row * glyph->width) + src_col; const uint16_t byteIndex = glyph->bitmapOffset + (bitPos / 8); const uint8_t bitIndex = bitPos % 8; if (font->bitmaps[byteIndex] & (0x80 >> bitIndex)) { count++; } } } // Calcul de la couleur interpolée (RGB565) const uint8_t coverage = (count * 100) / scale_sq;// Pour éviter la division flottante const uint8_t R = (bg_R * (100 - coverage) + fg_R * coverage) / 100; const uint8_t G = (bg_G * (100 - coverage) + fg_G * coverage) / 100; const uint8_t B = (bg_B * (100 - coverage) + fg_B * coverage) / 100; const uint16_t blended_color = (R << 11) | (G << 5) | B; // Dessin du pixel cible si dans les limites const int16_t absX = startX + tc; const int16_t absY = startY + tr; if (absX >= 0 && absX < LCD_WIDTH && absY >= 0 && absY < LCD_HEIGHT) { LCD_Draw_Pixel(absX, absY, blended_color); } } } return x + (glyph->advance / scale); } uint16_t GFX_GetTextWidth( const char *text, const GFXfont *font, int8_t letter_spacing) { uint16_t width = 0; while (*text != '\0') { if (*text >= font->firstChar && *text <= font->lastChar) { uint16_t glyphIndex = *text - font->firstChar; width += font->glyphs[glyphIndex].advance; width += letter_spacing; } else { // Default advance for unsupported characters width += 10; } text++; } return width; } uint16_t GFX_DrawText( uint16_t x, uint16_t y, const char *text, const GFXfont *font, uint16_t fg_color, uint16_t bg_color, uint8_t alignment, int8_t letter_spacing) { // Adjust x position based on alignment switch (alignment) { case 1:// Center x -= GFX_GetTextWidth(text, font, letter_spacing) / 2; break; case 2:// Right x -= GFX_GetTextWidth(text, font, letter_spacing); break; // Default: Left alignment (no adjustment) } // Draw each character uint16_t cursorX = x; uint16_t cursorY = y; while (*text != '\0') { cursorX = GFX_DrawChar(cursorX, cursorY, *text, font, fg_color, bg_color); cursorX += letter_spacing; text++; } if (alignment == 2) { return x; } return cursorX; } uint16_t GFX_ClearText( uint16_t x, uint16_t y, const char *text, const GFXfont *font, uint16_t bg_color, uint8_t alignment, int8_t letter_spacing) { // Adjust x position based on alignment switch (alignment) { case 1:// Center x -= GFX_GetTextWidth(text, font, letter_spacing) / 2; break; case 2:// Right x -= GFX_GetTextWidth(text, font, letter_spacing); break; // Default: Left alignment (no adjustment) } // Draw each character uint16_t cursorX = x; uint16_t cursorY = y; while (*text != '\0') { cursorX = GFX_ClearChar(cursorX, cursorY, *text, font, bg_color); cursorX += letter_spacing; text++; } if (alignment == 2) { return x; } return cursorX; } uint16_t GFX_DrawTextScaled( uint16_t x, uint16_t y, const char *text, const GFXfont *font, uint16_t fg_color, uint16_t bg_color, uint8_t alignment, int8_t letter_spacing, uint8_t scale) { uint16_t text_width = GFX_GetTextWidth(text, font, letter_spacing * scale); if (scale != 1) { text_width /= scale; } // Adjust x position based on alignment switch (alignment) { case 1:// Center x -= text_width / 2; break; case 2:// Right x -= text_width; break; // Default: Left alignment (no adjustment) } // Draw each character uint16_t cursorX = x; uint16_t cursorY = y; while (*text != '\0') { cursorX = GFX_DrawCharScaled(cursorX, cursorY, *text, font, fg_color, bg_color, scale); cursorX += letter_spacing; text++; } if (alignment == 2) { return x; } return cursorX; }