Files
Arduino/ESP32_WAVESHARE_7x5/Ecran.cpp
Jérôme Delacotte 7b30d6e298 first commit
2025-03-06 11:15:32 +01:00

281 lines
10 KiB
C++

#include "Ecran.h"
#include "Ctrl.h"
//////////////////////////////////////////
// Connections for e.g. LOLIN D32
//static const uint8_t EPD_BUSY = 4; // to EPD BUSY
//static const uint8_t EPD_CS = 5; // to EPD CS
//static const uint8_t EPD_RST = 16; // to EPD RST
//static const uint8_t EPD_DC = 17; // to EPD DC
//static const uint8_t EPD_SCK = 18; // to EPD CLK
//static const uint8_t EPD_MISO = 19; // Master-In Slave-Out not used, as no data from display
//static const uint8_t EPD_MOSI = 23; // to EPD DIN
static const uint8_t EPD_BUSY = 25;
static const uint8_t EPD_CS = 15;
static const uint8_t EPD_RST = 26;
static const uint8_t EPD_DC = 27;
static const uint8_t EPD_SCK = 13;
static const uint8_t EPD_MISO = 12; // Master-In Slave-Out not used, as no data from display
static const uint8_t EPD_MOSI = 14;
//use GxEPD_BLACK or GxEPD_WHITE or GxEPD_RED or GxEPD_YELLOW depending on display type
//GxEPD2_3C<GxEPD2_750c, GxEPD2_750c::HEIGHT> display(GxEPD2_750c(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW075Z09 640x384, UC8179 (IL0371)
GxEPD2_3C<GxEPD2_750c_Z08, GxEPD2_750c_Z08::HEIGHT / 2> display(GxEPD2_750c_Z08(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); // GDEW075Z08 800x480, GD7965
//GxEPD2_3C<GxEPD2_750c_Z90, GxEPD2_750c_Z90::HEIGHT / 2> display(GxEPD2_750c_Z90(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEH075Z90 880x528, SSD1677
Ecran::Ecran()
{
printf("--------------------------------------");
printf("Init Ecran");
_display = &display;
}
void Ecran::clear(void)
{
if (debug) Serial.println("Font set");
_display->fillScreen(GxEPD_WHITE);
if (debug) Serial.println("fill screen");
_display->setFullWindow();
if (debug) Serial.println("Full window");
}
void Ecran::initialise(void)
{
if (debug) Serial.println("screen init");
fonts.begin(display);
if (debug) Serial.println("font init");
_display->init(115200, true, 2, false); // init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration, bool pulldown_rst_mode)
// display.init(); for older Waveshare HAT's
if (debug) Serial.println("display init");
SPI.end();
SPI.begin(EPD_SCK, EPD_MISO, EPD_MOSI, EPD_CS);
if (debug) Serial.println("SPI init");
//fonts.begin(_display); // connect u8g2 procedures to Adafruit GFX
fonts.setFontMode(1); // use u8g2 transparent mode (this is default)
fonts.setFontDirection(0); // left to right (this is default)
fonts.setForegroundColor(GxEPD_BLACK); // apply Adafruit GFX color
fonts.setBackgroundColor(GxEPD_WHITE); // apply Adafruit GFX color
fonts.setFont(FONT_10); // select u8g2 font from here: https://github.com/olikraus/u8g2/wiki/fntlistall
}
//#########################################################################################
void Ecran::drawString(int x, int y, String text, alignment align, uint16_t color) {
int16_t x1, y1; //the bounds of x,y and w and h of the variable 'text' in pixels.
uint16_t w, h;
fonts.setForegroundColor(color);
_display->setTextColor(color); //, GxEPD_RED);
_display->setTextWrap(false);
_display->getTextBounds(text, x, y, &x1, &y1, &w, &h);
if (align == RIGHT) x = x - w;
if (align == CENTER) x = x - w / 2;
fonts.setCursor(x, y + h);
fonts.print(text);
}
//#########################################################################################
void Ecran::arrow(int x, int y, int asize, float aangle, int pwidth, int plength) {
float dx = (asize + 28) * cos((aangle - 90) * PI / 180) + x; // calculate X position
float dy = (asize + 28) * sin((aangle - 90) * PI / 180) + y; // calculate Y position
float x1 = 0; float y1 = plength;
float x2 = pwidth / 2; float y2 = pwidth / 2;
float x3 = -pwidth / 2; float y3 = pwidth / 2;
float angle = aangle * PI / 180;
float xx1 = x1 * cos(angle) - y1 * sin(angle) + dx;
float yy1 = y1 * cos(angle) + x1 * sin(angle) + dy;
float xx2 = x2 * cos(angle) - y2 * sin(angle) + dx;
float yy2 = y2 * cos(angle) + x2 * sin(angle) + dy;
float xx3 = x3 * cos(angle) - y3 * sin(angle) + dx;
float yy3 = y3 * cos(angle) + x3 * sin(angle) + dy;
_display->fillTriangle(xx1, yy1, xx3, yy3, xx2, yy2, GxEPD_RED);
}
//#########################################################################################
void Ecran::drawStringMaxWidth(int x, int y, unsigned int text_width, String text, alignment align) {
int16_t x1, y1; //the bounds of x,y and w and h of the variable 'text' in pixels.
uint16_t w, h;
_display->getTextBounds(text, x, y, &x1, &y1, &w, &h);
if (align == RIGHT) x = x - w;
if (align == CENTER) x = x - w / 2;
fonts.setCursor(x, y);
if (text.length() > text_width * 2) {
fonts.setFont(FONT_10);
text_width = 42;
y = y - 3;
}
fonts.println(text.substring(0, text_width));
if (text.length() > text_width) {
fonts.setCursor(x, y + h + 15);
String secondLine = text.substring(text_width);
secondLine.trim(); // Remove any leading spaces
fonts.println(secondLine);
}
}
void Ecran::drawAngledLine(int x, int y, int x1, int y1, int size, int color) {
float dx = (size / 2.0) * (y - y1) / sqrt(sq(x - x1) + sq(y - y1));
float dy = (size / 2.0) * (x - x1) / sqrt(sq(x - x1) + sq(y - y1));
_display->fillTriangle(x + dx, y - dy, x - dx, y + dy, x1 + dx, y1 - dy, color);
_display->fillTriangle(x - dx, y + dy, x1 - dx, y1 + dy, x1 + dx, y1 - dy, color);
}
void Ecran::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint8_t scale, bool inverted) {
// uint8_t new_bitmap[512];
// replaceFullBlack(bitmap, new_bitmap, w, h, 4);
if (inverted) {
if (scale != 1) {
drawScaledInvertedBitmap(x, y, bitmap, w, h, color, scale);
}
else {
_display->drawInvertedBitmap(x, y, bitmap, w, h, color);
}
}
else {
if (scale != 1) {
drawScaledBitmap(x, y, bitmap, w, h, color, scale);
}
else {
_display->drawBitmap(x, y, bitmap, w, h, color);
}
}
}
void Ecran::drawScaledBitmap(int16_t x, int16_t y,
const uint8_t *bitmap, int16_t w, int16_t h,
uint16_t color, uint8_t scale) {
int16_t i, j, byteWidth = (w + 7) / 8;
for(j = 0; j < h; j++) {
for(i = 0; i < w; i++) {
if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
// Interpolate pixel values according to the scale factor
for (uint8_t sy = 0; sy < scale; sy++) {
for (uint8_t sx = 0; sx < scale; sx++) {
int16_t px = x + i * scale + sx;
int16_t py = y + j * scale + sy;
// Calculate bilinear interpolation coefficients
float fx = static_cast<float>(i * scale + sx) / static_cast<float>(w * scale);
float fy = static_cast<float>(j * scale + sy) / static_cast<float>(h * scale);
// Perform bilinear interpolation
uint16_t interpolatedColor = bilinearInterpolation(x, y, w, h, color, fx, fy);
// Draw the interpolated pixel
_display->drawPixel(px, py, interpolatedColor);
}
}
}
}
}
}
void Ecran::drawScaledInvertedBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color, uint8_t scale)
{
int16_t byteWidth = (w + 7) / 8; // Largeur d'une ligne en octets = ligne entière
uint8_t byte = 0;
for (int16_t j = 0; j < h; j++)
{
for (int16_t i = 0; i < w; i++)
{
if (i & 7)
byte <<= 1;
else
{
#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
#else
byte = bitmap[j * byteWidth + i / 8];
#endif
}
if (!(byte & 0x80))
{
// Interpoler les valeurs de pixels en fonction du facteur de redimensionnement
for (uint8_t sy = 0; sy < scale; sy++)
{
for (uint8_t sx = 0; sx < scale; sx++)
{
int16_t px = x + i * scale + sx;
int16_t py = y + j * scale + sy;
// Calculer les coefficients d'interpolation bilinéaire
float fx = static_cast<float>(i * scale + sx) / static_cast<float>(w * scale);
float fy = static_cast<float>(j * scale + sy) / static_cast<float>(h * scale);
// Effectuer l'interpolation bilinéaire
uint16_t interpolatedColor = bilinearInterpolation(x, y, w, h, color, fx, fy);
// Dessiner le pixel interpolé
_display->drawPixel(px, py, interpolatedColor);
}
}
}
}
}
}
// Bilinear interpolation function
uint16_t Ecran::bilinearInterpolation(int16_t x, int16_t y, int16_t width, int16_t height,
uint16_t color, float fx, float fy) {
int16_t x0 = static_cast<int16_t>(floor(fx * width));
int16_t y0 = static_cast<int16_t>(floor(fy * height));
int16_t x1 = x0 + 1;
int16_t y1 = y0 + 1;
float wx = fx * width - x0;
float wy = fy * height - y0;
// Perform bilinear interpolation
uint16_t result = static_cast<uint16_t>(
(1.0 - wx) * (1.0 - wy) * color +
wx * (1.0 - wy) * color +
(1.0 - wx) * wy * color +
wx * wy * color
);
return result;
}
void Ecran::replaceFullBlack(const uint8_t *bitmap, uint8_t * new_bitmap, int largeur, int hauteur, int tailleCarre) {
for (int y = 0; y < hauteur; y += tailleCarre) {
for (int x = 0; x < largeur; x += tailleCarre) {
// Remplacer chaque carré par un maillage alternant blanc et noir
for (int dy = 0; dy < tailleCarre; dy++) {
for (int dx = 0; dx < tailleCarre; dx++) {
int pixelX = x + dx;
int pixelY = y + dy;
if (pixelX < largeur && pixelY < hauteur) {
if ((pixelX + pixelY) % 2 == 0) {
// Pixel blanc
new_bitmap[pixelY * largeur + pixelX] = 0xff;
} else {
// Pixel noir
new_bitmap[pixelY * largeur + pixelX] = 0x00;
}
}
}
}
}
}
}
// Fonction pour dessiner un arc de cercle
void Ecran::drawArc(int16_t x, int16_t y, int16_t radius, int16_t start_angle, int16_t end_angle, uint16_t color) {
float deg_to_rad = 3.14159265358979323846 / 180.0;
float angle_step = 1.0; // Ajustez cela pour changer la résolution de l'arc
for (float angle = start_angle; angle <= end_angle; angle += angle_step) {
float radian_angle = angle * deg_to_rad;
int16_t x_pos = x + radius * cos(radian_angle);
int16_t y_pos = y + radius * sin(radian_angle);
_display->drawPixel(x_pos, y_pos, color);
}
}