/
graphics.h
241 lines (211 loc) · 12.7 KB
/
graphics.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* Graphics Draw Functions
* ----------------------------------------------------------------------------
*/
#ifndef _GRAPHICS_H
#define _GRAPHICS_H
#include "jsutils.h"
#include "jsvar.h"
#ifdef SAVE_ON_FLASH
#define NO_VECTOR_FONT
#ifndef PIXLJS
#define NO_MODIFIED_AREA
#endif
#else // !SAVE_ON_FLASH
#ifndef ESPRUINOBOARD
#define GRAPHICS_DRAWIMAGE_ROTATED // Allow rotating images
#define GRAPHICS_THEME // Keep a 'theme'
#endif
#endif
#if defined(LINUX) || defined(BANGLEJS)
#define GRAPHICS_FAST_PATHS // execute more optimised code when no rotation/etc
#endif
typedef enum {
JSGRAPHICSTYPE_ARRAYBUFFER, ///< Write everything into an ArrayBuffer
JSGRAPHICSTYPE_JS, ///< Call JavaScript when we want to write something
JSGRAPHICSTYPE_FSMC, ///< FSMC (or fake FSMC) ILI9325 16bit-wide LCDs
JSGRAPHICSTYPE_SDL, ///< SDL graphics library for linux
JSGRAPHICSTYPE_SPILCD, ///< SPI LCD library
JSGRAPHICSTYPE_ST7789_8BIT, ///< ST7789 in 8 bit mode
JSGRAPHICSTYPE_MEMLCD, ///< Memory LCD
JSGRAPHICSTYPE_LCD_SPI_UNBUF ///< LCD SPI unbuffered 16 bit driver
} JsGraphicsType;
typedef enum {
JSGRAPHICSFLAGS_NONE,
JSGRAPHICSFLAGS_ARRAYBUFFER_ZIGZAG = 1, ///< ArrayBuffer: zig-zag (even rows reversed)
JSGRAPHICSFLAGS_ARRAYBUFFER_VERTICAL_BYTE = 2, ///< ArrayBuffer: if 1 bpp, treat bytes as stacked vertically
JSGRAPHICSFLAGS_ARRAYBUFFER_MSB = 4, ///< ArrayBuffer: store pixels MSB first
JSGRAPHICSFLAGS_ARRAYBUFFER_INTERLEAVEX = 8, //< ArrayBuffer: Pixels 0,2,4,etc are from the top half of the image, 1,3,5,etc from the bottom half. Used for P3 LED panels
JSGRAPHICSFLAGS_SWAP_XY = 16, //< All devices: swap X and Y over
JSGRAPHICSFLAGS_INVERT_X = 32, //< All devices: x = getWidth() - (x+1) - where x is DEVICE X
JSGRAPHICSFLAGS_INVERT_Y = 64, //< All devices: y = getHeight() - (y+1) - where y is DEVICE Y
JSGRAPHICSFLAGS_COLOR_BASE = 128,
JSGRAPHICSFLAGS_COLOR_RGB = 0,
JSGRAPHICSFLAGS_COLOR_BRG = JSGRAPHICSFLAGS_COLOR_BASE, //< All devices: color order is BRG
JSGRAPHICSFLAGS_COLOR_BGR = JSGRAPHICSFLAGS_COLOR_BASE*2, //< All devices: color order is BGR
JSGRAPHICSFLAGS_COLOR_GBR = JSGRAPHICSFLAGS_COLOR_BASE*3, //< All devices: color order is GBR
JSGRAPHICSFLAGS_COLOR_GRB = JSGRAPHICSFLAGS_COLOR_BASE*4, //< All devices: color order is GRB
JSGRAPHICSFLAGS_COLOR_RBG = JSGRAPHICSFLAGS_COLOR_BASE*5, //< All devices: color order is RBG
JSGRAPHICSFLAGS_COLOR_MASK = JSGRAPHICSFLAGS_COLOR_BASE*7, //< All devices: color order is BRG
/// If any bits here are set, X and Y get modified before being used
JSGRAPHICSFLAGS_MAPPEDXY = JSGRAPHICSFLAGS_SWAP_XY|JSGRAPHICSFLAGS_INVERT_X|JSGRAPHICSFLAGS_INVERT_Y,
/// If any bits in this mark are set, pixel data is not laid out linearly
JSGRAPHICSFLAGS_NONLINEAR = JSGRAPHICSFLAGS_ARRAYBUFFER_ZIGZAG|JSGRAPHICSFLAGS_ARRAYBUFFER_VERTICAL_BYTE|JSGRAPHICSFLAGS_ARRAYBUFFER_INTERLEAVEX
} JsGraphicsFlags;
typedef enum {
/** The size of the font
For bitmap fonts we can also pack X and Y scale in here. X is 0..63, Y is (0..63)<<6 */
JSGRAPHICS_FONTSIZE_SCALE_MASK = 8191,
JSGRAPHICS_FONTSIZE_SCALE_X_Y = 4096, ///< set if X and Y are packed into scale
JSGRAPHICS_FONTSIZE_SCALE_Y_SHIFT = 6,
JSGRAPHICS_FONTSIZE_SCALE_X_MASK = 63,
JSGRAPHICS_FONTSIZE_SCALE_Y_MASK = 63 << JSGRAPHICS_FONTSIZE_SCALE_Y_SHIFT,
JSGRAPHICS_FONTSIZE_FONT_MASK = 7 << 13, ///< the type of the font
JSGRAPHICS_FONTSIZE_VECTOR = 0,
JSGRAPHICS_FONTSIZE_4X6 = 1 << 13, // a bitmap font
#ifdef USE_FONT_6X8
JSGRAPHICS_FONTSIZE_6X8 = 2 << 13, // a bitmap font
#endif
#ifndef SAVE_ON_FLASH
JSGRAPHICS_FONTSIZE_CUSTOM_1BPP = 4 << 13,// a custom bitmap font made from fields in the graphics object (See below)
JSGRAPHICS_FONTSIZE_CUSTOM_2BPP = 5 << 13,// a custom bitmap font made from fields in the graphics object (See below)
JSGRAPHICS_FONTSIZE_CUSTOM_4BPP = 6 << 13,// a custom bitmap font made from fields in the graphics object (See below)
#ifdef ESPR_PBF_FONTS
JSGRAPHICS_FONTSIZE_CUSTOM_PBF = 7 << 13,// a custom bitmap font using PBF format (in JSGRAPHICS_CUSTOMFONT_BMP)
#endif // ESPR_PBF_FONTS
JSGRAPHICS_FONTSIZE_CUSTOM_BIT = 4 << 13 // all custom fonts have this bit set
#endif
} JsGraphicsFontSize;
#define JSGRAPHICS_CUSTOMFONT_BMP JS_HIDDEN_CHAR_STR"fnB"
#define JSGRAPHICS_CUSTOMFONT_WIDTH JS_HIDDEN_CHAR_STR"fnW"
#define JSGRAPHICS_CUSTOMFONT_HEIGHT JS_HIDDEN_CHAR_STR"fnH"
#define JSGRAPHICS_CUSTOMFONT_FIRSTCHAR JS_HIDDEN_CHAR_STR"fn1"
typedef struct {
unsigned short x1,y1;
unsigned short x2,y2;
} PACKED_FLAGS JsGraphicsClipRect;
typedef struct {
JsGraphicsType type;
JsGraphicsFlags flags;
unsigned short width, height; // DEVICE width and height (flags could mean the device is rotated)
unsigned char bpp;
unsigned int fgColor, bgColor; ///< current foreground and background colors
unsigned short fontSize; ///< See JSGRAPHICS_FONTSIZE_ constants
short cursorX, cursorY; ///< current cursor positions
#ifndef SAVE_ON_FLASH
unsigned char fontAlignX : 2;
unsigned char fontAlignY : 2;
unsigned char fontRotate : 2;
#endif
#ifndef NO_MODIFIED_AREA
JsGraphicsClipRect clipRect;
short modMinX, modMinY, modMaxX, modMaxY; ///< area that has been modified
#endif
} PACKED_FLAGS JsGraphicsData;
typedef struct JsGraphics {
JsVar *graphicsVar; // this won't be locked again - we just know that it is already locked by something else
JsGraphicsData data;
void *backendData; ///< Data used by the graphics backend
void (*setPixel)(struct JsGraphics *gfx, int x, int y, unsigned int col); ///< x/y guaranteed to be in range
void (*fillRect)(struct JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col); ///< x/y guaranteed to be in range
unsigned int (*getPixel)(struct JsGraphics *gfx, int x, int y); ///< x/y guaranteed to be in range
void (*blit)(struct JsGraphics *gfx, int x1, int y1, int w, int h, int x2, int y2); ///< blit a WxH area of x1y1 to x2y2 - all guaranteed to be in range
void (*scroll)(struct JsGraphics *gfx, int xdir, int ydir, int x1, int y1, int x2, int y2); ///< scroll - leave unscrolled area undefined (all values guaranteed to be in range)
} PACKED_FLAGS JsGraphics;
typedef void (*JsGraphicsSetPixelFn)(struct JsGraphics *gfx, int x, int y, unsigned int col);
#ifdef GRAPHICS_THEME
#if LCD_BPP && LCD_BPP<=16
typedef unsigned short JsGraphicsThemeColor;
#else
typedef unsigned int JsGraphicsThemeColor;
#endif
/// Standard color scheme colour structure
typedef struct {
JsGraphicsThemeColor fg; ///< Foreground
JsGraphicsThemeColor bg; ///< Background
JsGraphicsThemeColor fg2; ///< Accented Foreground
JsGraphicsThemeColor bg2; ///< Accented Background
JsGraphicsThemeColor fgH; ///< Foreground when highlighted
JsGraphicsThemeColor bgH; ///< Background when highlighted
bool dark; ///< Is background dark (eg. foreground should be a light colour)
} PACKED_FLAGS JsGraphicsTheme;
/// Global color scheme colours
extern JsGraphicsTheme graphicsTheme;
#endif
#ifdef ESPR_GRAPHICS_INTERNAL
/// Internal instance of Graphics structure (eg for built-in LCD) so we don't have to store all state in a var
extern JsGraphics graphicsInternal;
/// This is defined by whatever sets up graphicsInternal - it handles outputting to the screen (if that's needed)
void graphicsInternalFlip();
#endif
// ---------------------------------- these are in graphics.c
/// Reset graphics structure state (eg font size, color, etc)
void graphicsStructResetState(JsGraphics *gfx);
/// Completely reset graphics structure including flags. gfx->type should be set beforehand
void graphicsStructInit(JsGraphics *gfx, int width, int height, int bpp);
/// Access the Graphics Instance JsVar and get the relevant info in a JsGraphics structure. True on success
bool graphicsGetFromVar(JsGraphics *gfx, JsVar *parent);
/// Access the Graphics Instance JsVar and set the relevant info from JsGraphics structure
void graphicsSetVar(JsGraphics *gfx);
// Like graphicsSetVar but to be called when the Graphics is first created (and the field needs to be created)
void graphicsSetVarInitial(JsGraphics *gfx);
/// Set up the callbacks for this graphics instance (usually done by graphicsGetFromVar)
bool graphicsSetCallbacks(JsGraphics *gfx);
// ----------------------------------------------------------------------------------------------
/// Get the memory requires for this graphics's pixels if everything was packed as densely as possible
size_t graphicsGetMemoryRequired(const JsGraphics *gfx);
// If graphics is flipped or rotated then the coordinates need modifying
void graphicsToDeviceCoordinates(const JsGraphics *gfx, int *x, int *y);
// If graphics is flipped or rotated then the coordinates need modifying. This is to go back - eg for touchscreens
void deviceToGraphicsCoordinates(const JsGraphics *gfx, int *x, int *y);
unsigned short graphicsGetWidth(const JsGraphics *gfx);
unsigned short graphicsGetHeight(const JsGraphics *gfx);
// Set the area modified by a draw command and also clip to the screen/clipping bounds. Returns true if clipped. If coordsRotatedAlready we assume the coordinates have gone through deviceToGraphicsCoordinates already
bool graphicsSetModifiedAndClip(JsGraphics *gfx, int *x1, int *y1, int *x2, int *y2, bool coordsRotatedAlready);
// Set the area modified by a draw command
void graphicsSetModified(JsGraphics *gfx, int x1, int y1, int x2, int y2);
/// Get a setPixel function (assuming coordinates already clipped with graphicsSetModifiedAndClip) - if all is ok it can choose a faster draw function
JsGraphicsSetPixelFn graphicsGetSetPixelFn(JsGraphics *gfx);
/// Get a setPixel function and set modified area (assuming no clipping) (inclusive of x2,y2) - if all is ok it can choose a faster draw function
JsGraphicsSetPixelFn graphicsGetSetPixelUnclippedFn(JsGraphics *gfx, int x1, int y1, int x2, int y2, bool coordsRotatedAlready);
/// Merge one color into another based on current bit depth (amt is 0..256)
uint32_t graphicsBlendColor(JsGraphics *gfx, unsigned int fg, unsigned int bg, int iamt);
/// Merge one color into another based on current bit depth (amt is 0..256)
uint32_t graphicsBlendGfxColor(JsGraphics *gfx, int iamt);
// drawing functions - all coordinates are in USER coordinates, not DEVICE coordinates
void graphicsSetPixel(JsGraphics *gfx, int x, int y, unsigned int col);
unsigned int graphicsGetPixel(JsGraphics *gfx, int x, int y);
void graphicsClear(JsGraphics *gfx);
void graphicsFillRect(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col);
void graphicsFallbackFillRect(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col); // Simple fillrect - doesn't call device-specific FR
void graphicsFillRectDevice(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col); // fillrect using device coordinates
void graphicsFallbackScroll(JsGraphics *gfx, int xdir, int ydir, int x1, int y1, int x2, int y2);
void graphicsDrawRect(JsGraphics *gfx, int x1, int y1, int x2, int y2);
void graphicsDrawEllipse(JsGraphics *gfx, int x, int y, int x2, int y2);
void graphicsFillEllipse(JsGraphics *gfx, int x, int y, int x2, int y2);
void graphicsFillAnnulus(JsGraphics *gfx, int x, int y, int r1, int r2, unsigned short quadrants);
void graphicsDrawLine(JsGraphics *gfx, int x1, int y1, int x2, int y2);
void graphicsDrawLineAA(JsGraphics *gfx, int ix1, int iy1, int ix2, int iy2); ///< antialiased drawline. each pixel is 1/16th
void graphicsDrawCircleAA(JsGraphics *gfx, int x, int y, int r);
void graphicsFillPoly(JsGraphics *gfx, int points, short *vertices); ///< each pixel is 1/16th a pixel may overwrite vertices...
/// Draw a simple 1bpp image in foreground colour
void graphicsDrawImage1bpp(JsGraphics *gfx, int x1, int y1, int width, int height, const unsigned char *pixelData);
/// Scroll the graphics device (in user coords). X>0 = to right, Y >0 = down
void graphicsScroll(JsGraphics *gfx, int xdir, int ydir);
void graphicsSplash(JsGraphics *gfx); ///< splash screen
void graphicsIdle(); ///< called when idling
#define GRAPHICS_COL_16_TO_3(x) ((((x)&0x8000)?4:0)|(((x)&0x0400)?2:0)|(((x)&0x0010)?1:0))
#define GRAPHICS_COL_3_TO_16(x) ((((x)&4)?0xF800:0)|(((x)&2)?0x07E0:0)|(((x)&1)?0x001F:0))
#define GRAPHICS_COL_RGB_TO_16(R,G,B) ((((R)&0xF8)<<8)|(((G)&0xFC)<<3)|(((B)&0xF8)>>3))
void graphicsFallbackSetPixel(JsGraphics *gfx, int x, int y, unsigned int col); ///< Does nothing, used when not implemented
unsigned int graphicsFallbackGetPixel(JsGraphics *gfx, int x, int y); ///< Does nothing, used when not implemented
#endif // GRAPHICS_H