Root/eeshow/gfx/record.c

1/*
2 * gfx/record.c - Record graphics operations by layers and replay
3 *
4 * Written 2016 by Werner Almesberger
5 * Copyright 2016 by Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdlib.h>
15#include <limits.h>
16#include <math.h>
17
18#include "misc/util.h"
19#include "gfx/style.h"
20#include "gfx/gfx.h"
21#include "gfx/text.h"
22#include "gfx/record.h"
23
24
25struct record_obj {
26    enum ro_type {
27        ro_line,
28        ro_rect,
29        ro_poly,
30        ro_circ,
31        ro_arc,
32        ro_text,
33    } type;
34
35    int x, y;
36    int color, fill_color;
37    union {
38        struct {
39            int ex, ey;
40        } line;
41        struct {
42            int ex, ey;
43        } rect;
44        struct {
45            unsigned n;
46            int *vx, *vy;
47        } poly;
48        struct {
49            int r;
50        } circ;
51        struct {
52            int r;
53            int sa, ea;
54        } arc;
55        struct {
56            char *s;
57            unsigned size;
58            enum text_align align;
59            int rot;
60        } text;
61    } u;
62    struct record_obj *next;
63};
64
65
66static void bb(struct record *rec, int x, int y)
67{
68    if (rec->xmin > x)
69        rec->xmin = x;
70    if (rec->ymin > y)
71        rec->ymin = y;
72    if (rec->xmax < x)
73        rec->xmax = x;
74    if (rec->ymax < y)
75        rec->ymax = y;
76}
77
78
79static void bb_rot(struct record *rec, int x, int y, int rot)
80{
81    double a = -rot / 180.0 * M_PI;
82
83    // @@@ figure this out later
84return;
85    bb(rec, cos(a) * x + sin(a) * y, cos(a) * y - sin(a) * x);
86}
87
88
89static struct record_obj *new_obj(struct record *rec, enum ro_type type,
90    int color, int fill_color, unsigned layer)
91{
92    struct record_layer **curr_layer;
93    struct record_layer *new_layer;
94    struct record_obj *new_obj;
95
96    for (curr_layer = &rec->layers; *curr_layer;
97        curr_layer= &(*curr_layer)->next) {
98        if ((*curr_layer)->layer == layer)
99            goto this_layer;
100        if ((*curr_layer)->layer < layer)
101            break;
102    }
103
104    new_layer = alloc_type(struct record_layer);
105    new_layer->layer = layer;
106    new_layer->objs = NULL;
107    new_layer->next_obj = &new_layer->objs;
108    new_layer->next = *curr_layer;
109    *curr_layer = new_layer;
110
111this_layer:
112    new_obj = alloc_type(struct record_obj);
113    new_obj->type = type;
114    new_obj->color = color;
115    new_obj->fill_color = fill_color;
116    new_obj->next = NULL;
117
118    *(*curr_layer)->next_obj = new_obj;
119    (*curr_layer)->next_obj = &new_obj->next;
120
121    return new_obj;
122}
123
124
125void record_line(void *ctx, int sx, int sy, int ex, int ey,
126    int color, unsigned layer)
127{
128    struct record *rec = ctx;
129    struct record_obj *obj =
130        new_obj(rec, ro_line, color, COLOR_NONE, layer);
131
132    bb(rec, sx, sy);
133    bb(rec, ex, ey);
134
135    obj->x = sx;
136    obj->y = sy;
137    obj->u.line.ex = ex;
138    obj->u.line.ey = ey;
139}
140
141
142void record_rect(void *ctx, int sx, int sy, int ex, int ey,
143    int color, int fill_color, unsigned layer)
144{
145    struct record *rec = ctx;
146    struct record_obj *obj =
147        new_obj(rec, ro_rect, color, fill_color, layer);
148
149    bb(rec, sx, sy);
150    bb(rec, ex, ey);
151
152    obj->x = sx;
153    obj->y = sy;
154    obj->u.rect.ex = ex;
155    obj->u.rect.ey = ey;
156}
157
158
159void record_poly(void *ctx,
160    int points, const int x[points], const int y[points],
161    int color, int fill_color, unsigned layer)
162{
163    struct record *rec = ctx;
164    struct record_obj *obj =
165        new_obj(ctx, ro_poly, color, fill_color, layer);
166    int i;
167    unsigned size;
168
169    for (i = 0; i != points; i++)
170        bb(rec, x[i], y[i]);
171
172    obj->u.poly.n = points;
173    size = sizeof(int) * points;
174    obj->u.poly.vx = alloc_size(size);
175    obj->u.poly.vy = alloc_size(size);
176    memcpy(obj->u.poly.vx, x, size);
177    memcpy(obj->u.poly.vy, y, size);
178}
179
180
181void record_circ(void *ctx, int x, int y, int r,
182    int color, int fill_color, unsigned layer)
183{
184    struct record *rec = ctx;
185    struct record_obj *obj =
186        new_obj(ctx, ro_circ, color, fill_color, layer);
187
188    bb(rec, x - r, y - r);
189    bb(rec, x + r, y + r);
190
191    obj->x = x;
192    obj->y = y;
193    obj->u.circ.r = r;
194}
195
196
197void record_arc(void *ctx, int x, int y, int r, int sa, int ea,
198    int color, int fill_color, unsigned layer)
199{
200    struct record *rec = ctx;
201    struct record_obj *obj = new_obj(ctx, ro_arc, color, fill_color, layer);
202
203    bb(rec, x - r, y - r);
204    bb(rec, x + r, y + r);
205
206    obj->x = x;
207    obj->y = y;
208    obj->u.arc.r = r;
209    obj->u.arc.sa = sa;
210    obj->u.arc.ea = ea;
211}
212
213
214void record_text(void *ctx, int x, int y, const char *s, unsigned size,
215    enum text_align align, int rot, unsigned color, unsigned layer)
216{
217    struct record *rec = ctx;
218    struct record_obj *obj =
219        new_obj(ctx, ro_text, color, COLOR_NONE, layer);
220    unsigned width = rec->ops->text_width(rec->user, s, size);
221
222    bb_rot(rec, x, y - size, rot);
223    bb_rot(rec, x + width, y, rot);
224
225    obj->x = x;
226    obj->y = y;
227    obj->u.text.s = stralloc(s);
228    obj->u.text.size = size;
229    obj->u.text.align = align;
230    obj->u.text.rot = rot;
231}
232
233
234void record_init(struct record *rec, const struct gfx_ops *ops, void *user)
235{
236    rec->ops = ops;
237    rec->user = user;
238    rec->xmin = rec->ymin = INT_MAX;
239    rec->xmax = rec->ymax = INT_MIN;
240    rec->layers = NULL;
241}
242
243
244void record_wipe(struct record *rec)
245{
246    rec->layers = NULL;
247}
248
249
250void record_replay(const struct record *rec)
251{
252    const struct gfx_ops *ops = rec->ops;
253    void *ctx = rec->user;
254    const struct record_layer *layer;
255    const struct record_obj *obj;
256
257    for (layer = rec->layers; layer; layer = layer->next)
258        for (obj = layer->objs; obj; obj = obj->next)
259            switch (obj->type) {
260            case ro_line:
261                ops->line(ctx, obj->x, obj->y,
262                    obj->u.line.ex, obj->u.line.ey,
263                    obj->color, layer->layer);
264                break;
265            case ro_rect:
266                ops->rect(ctx, obj->x, obj->y,
267                    obj->u.rect.ex, obj->u.rect.ey,
268                    obj->color, obj->fill_color, layer->layer);
269                break;
270            case ro_poly:
271                ops->poly(ctx, obj->u.poly.n,
272                    obj->u.poly.vx, obj->u.poly.vy,
273                    obj->color, obj->fill_color, layer->layer);
274                break;
275            case ro_circ:
276                ops->circ(ctx, obj->x, obj->y,
277                    obj->u.circ.r,
278                    obj->color, obj->fill_color, layer->layer);
279                break;
280            case ro_arc:
281                ops->arc(ctx, obj->x, obj->y, obj->u.arc.r,
282                    obj->u.arc.sa, obj->u.arc.ea,
283                    obj->color, obj->fill_color, layer->layer);
284                break;
285            case ro_text:
286                ops->text(ctx, obj->x, obj->y, obj->u.text.s,
287                    obj->u.text.size, obj->u.text.align,
288                    obj->u.text.rot,
289                    obj->color, layer->layer);
290                break;
291            default:
292                abort();
293            }
294}
295
296
297void record_bbox(const struct record *rec, int *x, int *y, int *w, int *h)
298{
299    if (x)
300        *x = rec->xmin;
301    if (y)
302        *y = rec->ymin;
303    if (w)
304        *w = rec->xmax - rec->xmin + 1;
305    if (h)
306        *h = rec->ymax - rec->ymin + 1;
307}
308
309
310static void record_obj_destroy(struct record_obj *obj)
311{
312    switch (obj->type) {
313    case ro_poly:
314        free(obj->u.poly.vx);
315        free(obj->u.poly.vy);
316        break;
317    case ro_text:
318        free(obj->u.text.s);
319        break;
320    default:
321        break;
322    }
323    free(obj);
324}
325
326
327void record_destroy(struct record *rec)
328{
329    struct record_layer *next_layer;
330    struct record_obj *next_obj;
331
332    while (rec->layers) {
333        next_layer = rec->layers->next;
334        while (rec->layers->objs) {
335            next_obj = rec->layers->objs->next;
336            record_obj_destroy(rec->layers->objs);
337            rec->layers->objs = next_obj;
338        }
339        free(rec->layers);
340        rec->layers = next_layer;
341    }
342}
343

Archive Download this file

Branches:
master



interactive