-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathArduino_3D.h
207 lines (180 loc) · 8.38 KB
/
Arduino_3D.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
#ifndef _Arduino_3D_H_
#define _Arduino_3D_H_
/**
* Extends the UnoTFTLCD class with 3D drawing routines.
* The base classes UnoTFTLCD and UnoGFX have been modified to support
* the specific drawing routines required for 3D drawing.
*
* All drawing commands accept optional list of colors for the elements.
* If list is NULL then the foreground color is used by default.
*
* Triangle lists, edge lists, colors, and edge maps are to be stored in
* Program memory (PROGMEM). Triangles and edges are stored as tiplets and
* pairs of uint8_t indecies into vertex arrays. Edge maps additionally
* store two uint8_t indecies into the triangle array. Colors are uint16_t
* lists.
*
* Vertex lists for drawing are to be stored in RAM. Edge sets for drawing
* are to be store in RAM.
*
* Raw vertex sets (before geometry transformaton) are to be stored in
* Program memory (PROGMEM) as int8_t lists.
*
* IMPORTANT: there are no variable-length stack arrays in C++, but several
* rendering routines require scratch space to store rotated vertices
* or to compute the colors of faces and edges. The size of these buffers
* depends on the size of the 3D model. For efficiency, this library
* makes no attempt to initialize "scratch space" memory buffers. The
* arrays for storing rotated vertices, axis transformations, vertex and
* face colors, depth, and drawing order, must be managed by the client
* code. The client code must ensure that these buffers are large enough
* to store intermediate calculations.
*
* A variety of rendering modes are supported
*
* Point clouds: Render a pixel for each vertex.
* Color modes:
* Foreground color monochrome
* Depth-shaded monochrome
* User defined colors
* Vertex-normal shaded
* Line modes:
* Solid
* Dashed
*
* Mesh rendering: line-drawn triangles
* Full transparent mode: all triangles are drawn
* Partial surface mode: only triangles facing the camera are drawn
* Either mode may be "accelerated" by caching a set of edges to
* draw in advance. This is limited to very simple models as
* stack space is usually quite limited.
* Color modes:
* Foreground color monochrome
* Depth shaded monochrome
* Face-normal shaded
* User define colors
* Line modes:
* Solid
* Dashed
*
* Outline rendering: render the border of an object as a line
* Computed by detecting pairs of adjacent triangles across which the
* Z-component of the face normal changes sign.
* If an edge map is available, searching for adjacent triangles is
* greatly accelerated.
* Additionally, the outline may be cached as a set of edges for
* faster redraw-erasing later.
* Outlines only support drawing in foreground color
* but do support both soli and dashed lines.
*
* Solid surface rendering: filled triangles
* Solid foreground color
* User-supplied per-face color
* Depth-shaded monochrome face color
* Face-normal shaded
*
* Shaded surface rendering: filled triangles with interpolated colors
* User-supplied per-vertex color
* Depth-shaded per-vertex color
* Vertex-normal shaded
*
* Closed convex surfaces do not overlap themselves, and will draw correctly
* as long as only triangles facing the camera are drawn. Non-convex
* surfaces may overlap themselves. This can be avoided by drawing the
* triangles from front-to-back and avoiding drawing over regions that
* have already been painted. This requires that a draw_order be supplied
* to the rendering function.
*
*/
#include <math.h>
#include "Arduino_3D.h"
#include "Arduino_TFTLCD.h"
#include <stdint.h>
#include <avr/pgmspace.h>
#define PU8 const uint8_t *
#define P8 const int8_t *
#define PU16 const uint16_t *
/* Model struct. Pointers to PROGMEM stored vertex,
edge, triangle, and edge-map arrays. Numbers denoting
the length of said arrays. In practice, any number of
these pointser may be null. At minimum, a list of vertex
points is needed to render a model.
*/
typedef struct Model {
uint16_t NVertices;
uint16_t NEdges;
uint16_t NFaces;
P8 vertices;
PU8 edges;
PU8 faces;
P8 vertexNormals;
P8 faceNormals;
} Model;
class Arduino_3D : public Arduino_TFTLCD {
public:
Arduino_3D(void);
uint16_t X0 = 120;
uint16_t Y0 = 160;
uint8_t color_map[16];
void setColorMap(uint8_t cmap);
void setLocation(uint16_t x0, uint16_t y0);
void eraseRegion(uint8_t x0, uint16_t y0, uint8_t x1, uint16_t y1);
void eraseBoundingBox(Model *M, int8_t *vertices);
void eraseBoundingBox(int8_t *vertices,uint16_t nv);
// Main 3D drawing commands. Can draw points, meshes as specified by
// edges or by triangles, filled areas using solid colors, or shaded
// using face or vertex normals.
void drawVertices( Model *M, int8_t *vertices);
void drawVertices( Model *M, int8_t *vertices, uint16_t color);
void eraseVertices(Model *M, int8_t *vertices);
void drawEdges( Model *M, int8_t *vertices);
void drawEdges( Model *M, int8_t *vertices, uint16_t color);
void eraseEdges(Model *M, int8_t *vertices);
// face_colors may be NULL, to use the model-specified colors, or the
// current foreground color if those are not available.
// set dashed to 0 to draw solid lines. If nonzero, it behaves
// like a bitmask, and only points numbers that mask to 0 are drawn
void drawMesh( Model *M, int8_t *vertices);
void drawMesh( Model *M, int8_t *vertices, uint16_t color);
void eraseMesh(Model *M, int8_t *vertices);
// Either face_colors or vertex_colors may be NULL, to use the model-
// specified colors, or the current foreground color if those are not
// available.
// Draw order may be NUL, but if it is provided triangles are sorted
// from front to back and overdraw avoidance is used.
void fillFaces( Model *M, int8_t *vertices, uint8_t *face_colors , uint8_t *draw_order);
void shadeFaces(Model *M, int8_t *vertices, uint8_t *vertex_colors, uint8_t *draw_order);
// Routines for creating, rotating, and applying axis transformations
void getScaleTransform(float scale, float *output_transform);
void rotateTransformXY(float *input_transform, float dx, float dy, float *output_transform);
void applyTransform(Model *M, float *transform, int8_t *vertices);
// Routines for generating vertex and face colors
// from lights or from depth-shading
void computeVertexLightingColors(Model *M, float *transform, uint8_t *vertex_colors);
void computeFaceLightingColors( Model *M, float *transform, uint8_t *face_colors);
void computeVertexDepthColors(Model *M, int8_t *vertices, uint8_t *vertex_colors);
void computeFaceDepthColors( Model *M, int8_t *vertices, uint8_t *face_colors);
// Basic triangle shader functions.
// Interpolated color triangles are drawn similarly to regular triangles
// In that they are broken into horizontal scanlines. For this we need
// a fast horizontal interpolated line function. Additionally, we
// optionally support overdraw, which prevents pixels from the current
// frame from being over-drawn. This requires skipping some segments
// of the triangle.
void interpolateFlood(uint16_t y, uint16_t i, uint16_t stop, uint16_t length, uint8_t color1, uint8_t color2);
void interpolateFastHLine(int16_t x0, int16_t y0, uint8_t w, uint8_t color1, uint8_t color2);
void shadeTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color0, uint8_t color1, uint8_t color2);
uint16_t interpolate(uint8_t color1, uint8_t color2, uint8_t weight);
private:
// Non-convex 3D surfaces can overlap themselvs. Sorting triangles from
// front to back and checking to make sure we don't draw on top of areas
// that have already been drawn can avoid overlap artefacts. To support
// maintaining sortes lists of polygons across frames, theses functions
// accept a permutation list for the triangle drawing order. The
// permutation is updated to reflect the current z-order.
// Alternate versions: use previously tranformed vertices
// Helper routine for sorting triangles
void computeTriangleDepths(Model *M, int8_t *vertices, uint8_t *draw_order, uint8_t *depths);
void updateDrawingOrder(Model *M, int8_t *vertices, uint8_t *draw_order);
};
#endif