parent
79232c5d2c
commit
fb7002e68b
@ -0,0 +1,232 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2022/11/12.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "user_interface.h" |
||||||
|
#include "framebuffer.h" |
||||||
|
#include "ssd1306.h" |
||||||
|
|
||||||
|
/* Tiny framebuffer */ |
||||||
|
#define FBW DISPLAY_W |
||||||
|
#define FBH DISPLAY_H |
||||||
|
|
||||||
|
#define MIN(a,b) ((a)>(b)?(b):(a)) |
||||||
|
#define MAX(a,b) ((a)>(b)?(a):(b)) |
||||||
|
|
||||||
|
static uint8_t fb[(FBH/8)*FBW]; |
||||||
|
|
||||||
|
/** Fill with a vertical pattern, 1 byte */ |
||||||
|
void fb_fill(uint8_t pattern) { |
||||||
|
memset(fb, pattern, sizeof(fb)); |
||||||
|
} |
||||||
|
|
||||||
|
void fb_clear() { |
||||||
|
fb_fill(0); |
||||||
|
} |
||||||
|
|
||||||
|
void fb_px(uint8_t x, uint8_t y, uint8_t color) { |
||||||
|
if (x >= FBW || y >= FBH) return; |
||||||
|
const uint8_t row = y / 8; |
||||||
|
const uint8_t rowrem = y % 8; |
||||||
|
const uint16_t cell = (uint16_t) x + (uint16_t) row * FBW; |
||||||
|
if (color) { |
||||||
|
fb[cell] |= (1 << rowrem); |
||||||
|
} else { |
||||||
|
fb[cell] &= ~(1 << rowrem); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void fb_hline(uint8_t x, uint8_t y, uint8_t w, uint8_t color) { |
||||||
|
if (x >= FBW || y >= FBH) return; |
||||||
|
w = MIN(FBW - x, w); |
||||||
|
const uint8_t row = y / 8; |
||||||
|
const uint8_t rowrem = y % 8; |
||||||
|
uint16_t cell = (uint16_t) x + (uint16_t) row * FBW; |
||||||
|
for(uint8_t i = 0; i < w; i++) { |
||||||
|
if (color) { |
||||||
|
fb[cell] |= (1 << rowrem); |
||||||
|
} else { |
||||||
|
fb[cell] &= ~(1 << rowrem); |
||||||
|
} |
||||||
|
cell++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void fb_vline(uint8_t x, uint8_t y, uint8_t h, uint8_t color) { |
||||||
|
if (x >= FBW || y >= FBH) return; |
||||||
|
h = MIN(FBH - y - 1, h); |
||||||
|
const uint8_t row = y / 8; |
||||||
|
const uint8_t rowrem = y % 8; |
||||||
|
uint16_t cell = (uint16_t) x + (uint16_t) row * FBW; |
||||||
|
|
||||||
|
if (rowrem + h < 8) { |
||||||
|
// all within one cell
|
||||||
|
uint8_t mask = (0xFF << rowrem) & (0xFF >> (h-rowrem)); |
||||||
|
if (color) { |
||||||
|
fb[cell] |= mask; |
||||||
|
} else { |
||||||
|
fb[cell] &= ~mask; |
||||||
|
} |
||||||
|
return; |
||||||
|
} else { |
||||||
|
// First
|
||||||
|
uint8_t mask = (0xFF << rowrem); |
||||||
|
if (color) { |
||||||
|
fb[cell] |= mask; |
||||||
|
} else { |
||||||
|
fb[cell] &= ~mask; |
||||||
|
} |
||||||
|
h -= rowrem; |
||||||
|
|
||||||
|
uint8_t whole_cells = h / 8; |
||||||
|
h -= whole_cells * 8; |
||||||
|
for(uint8_t i = 0; i < whole_cells; i++) { |
||||||
|
cell += FBW; |
||||||
|
if (color) { |
||||||
|
fb[cell] = 0xFF; |
||||||
|
} else { |
||||||
|
fb[cell] = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// last
|
||||||
|
mask = (0xFF >> (8-h)); |
||||||
|
if (color) { |
||||||
|
fb[cell] |= mask; |
||||||
|
} else { |
||||||
|
fb[cell] &= ~mask; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void fb_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color) { |
||||||
|
if (x >= FBW || y >= FBH) return; |
||||||
|
w = MIN(FBW - x - 1, w); |
||||||
|
h = MIN(FBH - y - 1, h); |
||||||
|
const uint8_t row = y / 8; |
||||||
|
const uint8_t rowrem = y % 8; |
||||||
|
uint16_t cell = (uint16_t) x + (uint16_t) row * FBW; |
||||||
|
|
||||||
|
if (rowrem + h <= 8) { |
||||||
|
// all within one cell
|
||||||
|
uint8_t mask = (0xFF << rowrem) & (0xFF >> (8 - (h - rowrem))); |
||||||
|
|
||||||
|
for(uint8_t i = 0; i < w; i++) { |
||||||
|
if (color) { |
||||||
|
fb[cell + i] |= mask; |
||||||
|
} else { |
||||||
|
fb[cell + i] &= ~mask; |
||||||
|
} |
||||||
|
} |
||||||
|
return; |
||||||
|
} else { |
||||||
|
// First
|
||||||
|
uint8_t mask = (0xFF << rowrem); |
||||||
|
for(uint8_t i = 0; i < w; i++) { |
||||||
|
if (color) { |
||||||
|
fb[cell + i] |= mask; |
||||||
|
} else { |
||||||
|
fb[cell + i] &= ~mask; |
||||||
|
} |
||||||
|
} |
||||||
|
h -= 8 - rowrem; |
||||||
|
|
||||||
|
uint8_t whole_cells = h / 8; |
||||||
|
h -= whole_cells * 8; |
||||||
|
for(uint8_t j = 0; j < whole_cells; j++) { |
||||||
|
cell += FBW; |
||||||
|
for(uint8_t i = 0; i < w; i++) { |
||||||
|
if (color) { |
||||||
|
fb[cell + i] = 0xFF; |
||||||
|
} else { |
||||||
|
fb[cell + i] = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
cell += FBW; |
||||||
|
|
||||||
|
// last
|
||||||
|
mask = (0xFF >> (8-h)); |
||||||
|
for(uint8_t i = 0; i < w; i++) { |
||||||
|
if (color) { |
||||||
|
fb[cell + i] |= mask; |
||||||
|
} else { |
||||||
|
fb[cell + i] &= ~mask; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void fb_bitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t color) { |
||||||
|
if (x >= FBW || y >= FBH) return; |
||||||
|
const uint8_t w0 = w; |
||||||
|
const uint8_t h0 = h; |
||||||
|
w = MIN(FBW - x - 1, w); |
||||||
|
h = MIN(FBH - y - 1, h); |
||||||
|
const uint8_t row = y / 8; |
||||||
|
const uint8_t rowrem = y % 8; |
||||||
|
uint16_t cell = (uint16_t) x + (uint16_t) row * FBW; |
||||||
|
|
||||||
|
if (rowrem + h <= 8) { |
||||||
|
for(uint8_t i = 0; i < w; i++) { |
||||||
|
// all within one cell
|
||||||
|
uint8_t mask = (map[i] & (0xFF >> (8-h))) << rowrem; |
||||||
|
if (color) { |
||||||
|
fb[cell + i] |= mask; |
||||||
|
} else { |
||||||
|
fb[cell + i] &= ~mask; |
||||||
|
} |
||||||
|
} |
||||||
|
return; |
||||||
|
} else if (rowrem == 0) { |
||||||
|
// Optimization
|
||||||
|
|
||||||
|
// First
|
||||||
|
for(uint8_t i = 0; i < w; i++) { |
||||||
|
uint8_t mask = map[i]; |
||||||
|
if (color) { |
||||||
|
fb[cell + i] |= mask; |
||||||
|
} else { |
||||||
|
fb[cell + i] &= ~mask; |
||||||
|
} |
||||||
|
} |
||||||
|
h -= 8; |
||||||
|
|
||||||
|
// Middle
|
||||||
|
uint8_t whole_cells = h / 8; |
||||||
|
h -= whole_cells * 8; |
||||||
|
for(uint8_t j = 0; j < whole_cells; j++) { |
||||||
|
cell += FBW; |
||||||
|
for(uint8_t i = 0; i < w; i++) { |
||||||
|
uint8_t mask = map[i + (j+1)*w0]; |
||||||
|
if (color) { |
||||||
|
fb[cell + i] |= mask; |
||||||
|
} else { |
||||||
|
fb[cell + i] &= ~mask; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// last
|
||||||
|
cell += FBW; |
||||||
|
|
||||||
|
// last
|
||||||
|
for(uint8_t i = 0; i < w; i++) { |
||||||
|
uint8_t mask = map[i + (whole_cells+1)*w0] & (0xFF >> (8-h)); |
||||||
|
if (color) { |
||||||
|
fb[cell + i] |= mask; |
||||||
|
} else { |
||||||
|
fb[cell + i] &= ~mask; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
// TODO wild combination, unaligned multi-row
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void fb_blit() { |
||||||
|
ssd1306_drawBuffer(0, 0, FBW, FBH, fb); |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2022/11/12.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef FRAMEBUFFER_H |
||||||
|
#define FRAMEBUFFER_H |
||||||
|
|
||||||
|
#include <stdbool.h> |
||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
void fb_fill(uint8_t pattern); |
||||||
|
void fb_clear(void); |
||||||
|
void fb_px(uint8_t x, uint8_t y, uint8_t color); |
||||||
|
void fb_hline(uint8_t x, uint8_t y, uint8_t w, uint8_t color); |
||||||
|
void fb_vline(uint8_t x, uint8_t y, uint8_t h, uint8_t color); |
||||||
|
void fb_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color); |
||||||
|
void fb_bitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t color); |
||||||
|
void fb_blit(void); |
||||||
|
|
||||||
|
#endif //FRAMEBUFFER_H
|
Loading…
Reference in new issue