281 lines
10 KiB
C++
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);
|
|
}
|
|
} |