-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrender_tools.c
More file actions
278 lines (245 loc) · 10 KB
/
Copy pathrender_tools.c
File metadata and controls
278 lines (245 loc) · 10 KB
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#include "geometer.h"
void renderCursor(float x, float y) {
if (locked) SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
else SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderLine(renderer, x, y + 3, x, y - 3);
SDL_RenderLine(renderer, x + 3, y, x - 3, y);
SDL_RenderLine(renderer, x, y - 8, x, y - 14);
SDL_RenderLine(renderer, x, y + 8, x, y + 14);
SDL_RenderLine(renderer, x - 8, y, x - 14, y);
SDL_RenderLine(renderer, x + 8, y, x + 14, y);
}
void setupIP(enum UserObjectType type, int npoints) {
ip = malloc(sizeof(struct IntermediatePoints));
ip->type = type;
ip->size = 2 * npoints;
ip->filled_elems = 0;
ip->arr = malloc(sizeof(float) * ip->size);
}
struct UserObject* toUserObject(void) {
struct UserObject* obj = malloc(sizeof(struct UserObject));
obj->type = ip->type;
// This part relies on the memory layout of UserObject
// Copy the array after skipping the type element
memcpy((void*)obj + sizeof(enum UserObjectType), ip->arr, ip->size * sizeof(float));
ip->filled_elems = 0;
free(ip->arr);
ip->arr = malloc(sizeof(float) * ip->size);
return obj;
}
void addPoint(float x, float y) {
ip->arr[ip->filled_elems++] = x;
ip->arr[ip->filled_elems++] = y;
}
///// Line
struct UserObject* drawIntermediateLine(float x, float y) {
switch (ip->filled_elems/2) {
case 2: return toUserObject();
case 1: SDL_RenderLine(renderer, ip->arr[0], ip->arr[1], x, y);
case 0: return NULL;
}
__builtin_unreachable();
}
void drawLine(struct UserObject* obj) {
SDL_RenderLine(renderer, obj->p1x, obj->p1y, obj->p2x, obj->p2y);
}
void persistLine(struct UserObject* obj, FILE* file) {
fprintf(file, "\\draw[] (%fpt, %fpt) -- (%fpt, %fpt);\n",
obj->p1x, -obj->p1y, obj->p2x, -obj->p2y);
}
///// Circle
void renderArc(float r, float x, float y, float start_angle, float end_angle) {
#define ARC_RESOLUTION 100
for (int i = 0; i < ARC_RESOLUTION * (r + 10); i++) {
float t = start_angle + i * (end_angle - start_angle)/ARC_RESOLUTION;
SDL_RenderPoint(renderer, r*cos(t) + x, r*sin(t) + y);
}
}
struct UserObject* drawIntermediateCircle(float x, float y) {
switch (ip->filled_elems/2) {
case 2: return toUserObject();
case 1:
// Draw X on center (TODO factor out as render point)
SDL_RenderLine(renderer, ip->arr[0]-3, ip->arr[1]-3, ip->arr[0]+3, ip->arr[1]+3);
SDL_RenderLine(renderer, ip->arr[0]-3, ip->arr[1]+3, ip->arr[0]+3, ip->arr[1]-3);
// Draw circle
float r = sqrtf(pow(ip->arr[0] - x, 2) + pow(ip->arr[1] - y, 2));
renderArc(r, ip->arr[0], ip->arr[1], 0, 2*M_PI - 0.001);
case 0: return NULL;
}
__builtin_unreachable();
}
void drawCircle(struct UserObject* obj) {
float r = sqrtf(pow(obj->p1x - obj->p2x, 2) + pow(obj->p1y - obj->p2y, 2));
renderArc(r, obj->p1x, obj->p1y, 0, 2*M_PI - 0.001);
}
void persistCircle(struct UserObject* obj, FILE* file) {
float r = sqrtf(pow(obj->p1x - obj->p2x, 2) + pow(obj->p1y - obj->p2y, 2));
fprintf(file, "\\draw[] (%fpt, %fpt) circle (%fpt);\n", obj->p1x, -obj->p1y, r);
}
struct UserObject* drawIntermediateArc(float x, float y) {
switch (ip->filled_elems/2) {
case 3: return toUserObject();
case 2:
// Draw X on center (TODO factor out)
SDL_RenderLine(renderer, ip->arr[0]-3, ip->arr[1]-3, ip->arr[0]+3, ip->arr[1]+3);
SDL_RenderLine(renderer, ip->arr[0]-3, ip->arr[1]+3, ip->arr[0]+3, ip->arr[1]-3);
// Calculate angles
float ax = ip->arr[2] - ip->arr[0], ay = ip->arr[3] - ip->arr[1],
bx = x - ip->arr[0], by = y - ip->arr[1];
float start_angle = atan2f(ay, ax);
float end_angle = atan2f(by, bx);
// Draw circle
float r = sqrtf(ax*ax + ay*ay);
renderArc(r, ip->arr[0], ip->arr[1], start_angle, end_angle);
// TODO draw (dotted) line
return NULL;
case 1:
case 0:
return drawIntermediateCircle(x, y);
}
__builtin_unreachable();
}
void drawArc(struct UserObject* obj) {
float ax = obj->p2x - obj->p1x, ay = obj->p2y - obj->p1y,
bx = obj->p3x - obj->p1x, by = obj->p3y - obj->p1y;
float start_angle = atan2f(ay, ax);
float end_angle = atan2f(by, bx);
// Draw circle
float r = sqrtf(ax*ax + ay*ay);
renderArc(r, obj->p1x, obj->p1y, start_angle, end_angle);
}
// TODO finish arc! everything (except persist is already there!)
struct UserObject* drawIntermediateText(float x, float y) { // Stupid and unintuitive interface FIXME
switch (ip->filled_elems/2) {
case 1:
struct UserObject* obj = toUserObject();
obj->text = malloc(256 * sizeof(char));
memcpy(obj->text, buffer, sizeof(buffer));
memset(buffer, '\0', sizeof(buffer));
return obj;
case 0:
SDL_RenderDebugText(renderer, x, y, buffer);
return NULL;
}
__builtin_unreachable();
}
void drawText(struct UserObject* obj) {
SDL_RenderDebugText(renderer, obj->p1x, obj->p1y, obj->text);
}
void persistText(struct UserObject* obj, FILE* file) {
fprintf(file, "\\node[anchor=north west] at (%fpt, -%fpt) {%s};\n",
obj->p1x, obj->p1y, obj->text);
}
// TODO write bezier
#define BEZIER_RESOLUTION 100
void bezierFunction(float* pi) {
// pi is a list of p1x, p1y, p2x, p2y...
// Look at the point order in the following function
SDL_FPoint arr[BEZIER_RESOLUTION];
for (int n = 0; n < BEZIER_RESOLUTION; n++) {
float t = (float)n/BEZIER_RESOLUTION;
arr[n].x = t*t*t * pi[0] + 3 * t*t*(1-t) * pi[2] + 3 * t*(1-t)*(1-t) * (2*pi[4] - pi[6]) + (1-t)*(1-t)*(1-t) * pi[4];
arr[n].y = t*t*t * pi[1] + 3 * t*t*(1-t) * pi[3] + 3 * t*(1-t)*(1-t) * (2*pi[5] - pi[7]) + (1-t)*(1-t)*(1-t) * pi[5];
}
SDL_RenderLines(renderer, arr, BEZIER_RESOLUTION);
}
struct UserObject* drawIntermediateBezier(float x, float y) {
// point order: p1, c1, p2, c2
switch (ip->filled_elems/2) {
case 4:
// TODO also set a new IP so it can continue!
float temp_arr[4];
memcpy(temp_arr, ip->arr + 4, sizeof(float) * 4);
struct UserObject* res_obj = toUserObject();
//setupIP(OBJ_BEZIER, 4);
addPoint(temp_arr[0], temp_arr[1]);
addPoint(temp_arr[2], temp_arr[3]);
return res_obj;
case 2:
// Fallthrough, the control and endpoint are the same here
ip->arr[ip->filled_elems + 2] = x;
ip->arr[ip->filled_elems + 3] = y;
case 3:
// I swear to god, my code gets more cursed every day...
ip->arr[ip->filled_elems] = x;
ip->arr[ip->filled_elems + 1] = y;
bezierFunction(ip->arr);
SDL_RenderLine(renderer, ip->arr[0], ip->arr[1], ip->arr[2], ip->arr[3]);
SDL_RenderLine(renderer, ip->arr[4], ip->arr[5], x, y);
return NULL;
case 1:
SDL_RenderLine(renderer, ip->arr[0], ip->arr[1], x, y);
case 0:
return NULL;
}
}
void drawBezier(struct UserObject* obj) {
bezierFunction(&(obj->p1x)); // Should work?
}
void persistBezier(struct UserObject* obj, FILE* file) {
fprintf(file, "\\draw (%fpt, -%fpt) .. controls (%fpt, -%fpt) and (%fpt, -%fpt) .. (%fpt, -%fpt);\n",
obj->p1x, obj->p1y, obj->p2x, obj->p2y, 2*obj->p3x - obj->p4x, 2*obj->p3y - obj->p4y, obj->p3x, obj->p3y);
}
void append(struct UserObjectList* l, struct UserObject* obj) {
if (l->head == NULL) {
l->head = l->tail = malloc(sizeof(struct UserObjectSeq));
l->head->here = obj;
l->head->next = NULL;
} else {
l->tail->next = malloc(sizeof(struct UserObjectSeq));
l->tail->next->here = obj;
l->tail->next->next = NULL;
l->tail = l->tail->next;
}
}
void remove_obj(struct UserObjectList* l, struct UserObject* obj) { // Never thought I'd have to implement LL methods...
struct UserObjectSeq* prev = NULL;
for (struct UserObjectSeq* seq = l->head; seq != NULL; seq = seq->next) {
if (seq->here == obj) {
if (prev == NULL) l->head = seq->next;
else prev->next = seq->next;
if (seq->next == NULL) l->tail = prev;
free(seq->here);
free(seq);
return;
}
prev = seq;
}
}
const struct ObjectType types[] = {
{ OBJ_LINE, "-- LINE --", drawIntermediateLine, drawLine, persistLine },
{ OBJ_CIRCLE, "-- CIRCLE --", drawIntermediateCircle, drawCircle, persistCircle },
{ OBJ_TEXT, "-- TEXT --", drawIntermediateText, drawText, persistText },
{ OBJ_BEZIER, "-- BEZIER --", drawIntermediateBezier, drawBezier, persistBezier },
{ OBJ_ARC, "-- ARC --", drawIntermediateArc, drawArc, NULL },
{ -100, NULL, NULL, NULL, NULL } // Sentinel value?
};
struct UserObject* drawIntermediate(enum UserObjectType type, float x, float y) {
for (int i = 0; i < sizeof(types); i++) {
if (types[i].name == NULL) return NULL;
if (types[i].type == type) return types[i].intermediate(x, y);
}
__builtin_unreachable(); // Maybe add a check here for weird types? For that matter:
// TODO: better error handling
}
void draw(struct UserObject* obj) {
if (obj == locked_on && mode == MO_DELETE)
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
else
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
for (int i = 0; i < sizeof(types); i++)
if (types[i].type == obj->type)
return types[i].draw(obj);
}
void persist(struct UserObject* obj, FILE* file) {
for (int i = 0; i < sizeof(types); i++)
if (types[i].type == obj->type)
return types[i].persist(obj, file);
}
void generate(char* filename) {
FILE* file = fopen(filename, "w");
for (struct UserObjectSeq* item = objects.head; item != NULL; item = item->next)
persist(item->here, file);
fclose(file);
}