qp_tft_panel.c (5549B)
1 // Copyright 2021 Nick Brassel (@tzarc) 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 4 #include "color.h" 5 #include "qp_internal.h" 6 #include "qp_comms.h" 7 #include "qp_draw.h" 8 #include "qp_tft_panel.h" 9 10 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 11 // Quantum Painter API implementations 12 13 // Power control 14 bool qp_tft_panel_power(painter_device_t device, bool power_on) { 15 painter_driver_t *driver = (painter_driver_t *)device; 16 tft_panel_dc_reset_painter_driver_vtable_t *vtable = (tft_panel_dc_reset_painter_driver_vtable_t *)driver->driver_vtable; 17 qp_comms_command(device, power_on ? vtable->opcodes.display_on : vtable->opcodes.display_off); 18 return true; 19 } 20 21 // Screen clear 22 bool qp_tft_panel_clear(painter_device_t device) { 23 painter_driver_t *driver = (painter_driver_t *)device; 24 driver->driver_vtable->init(device, driver->rotation); // Re-init the LCD 25 return true; 26 } 27 28 // Screen flush 29 bool qp_tft_panel_flush(painter_device_t device) { 30 // No-op, as there's no framebuffer in RAM for this device. 31 return true; 32 } 33 34 // Viewport to draw to 35 bool qp_tft_panel_viewport(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) { 36 painter_driver_t *driver = (painter_driver_t *)device; 37 tft_panel_dc_reset_painter_driver_vtable_t *vtable = (tft_panel_dc_reset_painter_driver_vtable_t *)driver->driver_vtable; 38 39 // Fix up the drawing location if required 40 left += driver->offset_x; 41 right += driver->offset_x; 42 top += driver->offset_y; 43 bottom += driver->offset_y; 44 45 // Check if we need to manually swap the window coordinates based on whether or not we're in a sideways rotation 46 if (vtable->swap_window_coords && (driver->rotation == QP_ROTATION_90 || driver->rotation == QP_ROTATION_270)) { 47 uint16_t temp; 48 49 temp = left; 50 left = top; 51 top = temp; 52 53 temp = right; 54 right = bottom; 55 bottom = temp; 56 } 57 58 if (vtable->num_window_bytes == 1) { 59 // Set up the x-window 60 uint8_t xbuf[2] = {left & 0xFF, right & 0xFF}; 61 qp_comms_command_databuf(device, vtable->opcodes.set_column_address, xbuf, sizeof(xbuf)); 62 63 // Set up the y-window 64 uint8_t ybuf[2] = {top & 0xFF, bottom & 0xFF}; 65 qp_comms_command_databuf(device, vtable->opcodes.set_row_address, ybuf, sizeof(ybuf)); 66 } else if (vtable->num_window_bytes == 2) { 67 // Set up the x-window 68 uint8_t xbuf[4] = {left >> 8, left & 0xFF, right >> 8, right & 0xFF}; 69 qp_comms_command_databuf(device, vtable->opcodes.set_column_address, xbuf, sizeof(xbuf)); 70 71 // Set up the y-window 72 uint8_t ybuf[4] = {top >> 8, top & 0xFF, bottom >> 8, bottom & 0xFF}; 73 qp_comms_command_databuf(device, vtable->opcodes.set_row_address, ybuf, sizeof(ybuf)); 74 } 75 76 // Lock in the window 77 qp_comms_command(device, vtable->opcodes.enable_writes); 78 return true; 79 } 80 81 // Stream pixel data to the current write position in GRAM 82 bool qp_tft_panel_pixdata(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count) { 83 painter_driver_t *driver = (painter_driver_t *)device; 84 qp_comms_send(device, pixel_data, native_pixel_count * driver->native_bits_per_pixel / 8); 85 return true; 86 } 87 88 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 89 // Convert supplied palette entries into their native equivalents 90 91 bool qp_tft_panel_palette_convert_rgb565_swapped(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) { 92 for (int16_t i = 0; i < palette_size; ++i) { 93 rgb_t rgb = hsv_to_rgb_nocie(palette[i].hsv888); 94 uint16_t rgb565 = (((uint16_t)rgb.r) >> 3) << 11 | (((uint16_t)rgb.g) >> 2) << 5 | (((uint16_t)rgb.b) >> 3); 95 palette[i].rgb565 = __builtin_bswap16(rgb565); 96 } 97 return true; 98 } 99 100 bool qp_tft_panel_palette_convert_rgb888(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) { 101 for (int16_t i = 0; i < palette_size; ++i) { 102 palette[i].rgb888 = hsv_to_rgb_nocie(palette[i].hsv888); 103 } 104 return true; 105 } 106 107 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 108 // Append pixels to the target location, keyed by the pixel index 109 110 bool qp_tft_panel_append_pixels_rgb565(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices) { 111 uint16_t *buf = (uint16_t *)target_buffer; 112 for (uint32_t i = 0; i < pixel_count; ++i) { 113 buf[pixel_offset + i] = palette[palette_indices[i]].rgb565; 114 } 115 return true; 116 } 117 118 bool qp_tft_panel_append_pixels_rgb888(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices) { 119 for (uint32_t i = 0; i < pixel_count; ++i) { 120 target_buffer[(pixel_offset + i) * 3 + 0] = palette[palette_indices[i]].rgb888.r; 121 target_buffer[(pixel_offset + i) * 3 + 1] = palette[palette_indices[i]].rgb888.g; 122 target_buffer[(pixel_offset + i) * 3 + 2] = palette[palette_indices[i]].rgb888.b; 123 } 124 return true; 125 } 126 127 bool qp_tft_panel_append_pixdata(painter_device_t device, uint8_t *target_buffer, uint32_t pixdata_offset, uint8_t pixdata_byte) { 128 target_buffer[pixdata_offset] = pixdata_byte; 129 return true; 130 }