1 /* Public domain */
2
3 #ifndef _AGAR_VG_H_
4 #define _AGAR_VG_H_
5
6 #include <agar/vg/begin.h>
7
8 #define VG_NAME_MAX 128
9 #define VG_LAYER_NAME_MAX 128
10 #define VG_STYLE_NAME_MAX 16
11 #define VG_TYPE_NAME_MAX 32
12 #define VG_SYM_NAME_MAX 16
13 #define VG_HANDLE_MAX (0xffffffff-1)
14
15 enum vg_alignment {
16 VG_ALIGN_TL, VG_ALIGN_TC, VG_ALIGN_TR,
17 VG_ALIGN_ML, VG_ALIGN_MC, VG_ALIGN_MR,
18 VG_ALIGN_BL, VG_ALIGN_BC, VG_ALIGN_BR
19 };
20
21 typedef struct vg_vertex {
22 float x, y;
23 } VG_Vector;
24
25 typedef struct vg_rect {
26 float x, y;
27 float w, h;
28 } VG_Rect;
29
30 typedef struct vg_color {
31 int idx; /* Index into VG color array */
32 Uint8 r, g, b, a; /* RGBA color value */
33 } VG_Color;
34
35 typedef struct vg_indexed_color {
36 char name[VG_STYLE_NAME_MAX]; /* Identifier */
37 VG_Color color; /* Color value (or reference) */
38 } VG_IndexedColor;
39
40 struct vg;
41 struct vg_view;
42 struct vg_node;
43 struct ag_static_icon;
44
45 #include <agar/vg/vg_snap.h>
46 #include <agar/vg/vg_ortho.h>
47
48 typedef struct vg_node_ops {
49 const char *name;
50 struct ag_static_icon *icon;
51 size_t size;
52
53 void (*init)(void *);
54 void (*destroy)(void *);
55 int (*load)(void *, AG_DataSource *, const AG_Version *);
56 void (*save)(void *, AG_DataSource *);
57 void (*draw)(void *, struct vg_view *);
58 void (*extent)(void *, struct vg_view *, VG_Vector *a,
59 VG_Vector *b);
60 float (*pointProximity)(void *, struct vg_view *, VG_Vector *p);
61 float (*lineProximity)(void *, struct vg_view *, VG_Vector *p1,
62 VG_Vector *p2);
63 void (*deleteNode)(void *);
64 void (*moveNode)(void *, VG_Vector vAbs, VG_Vector vRel);
65 void *(*edit)(void *, struct vg_view *);
66 } VG_NodeOps;
67
68 typedef struct vg_layer {
69 char name[VG_LAYER_NAME_MAX]; /* Layer name */
70 int visible; /* Flag of visibility */
71 VG_Color color; /* Per-layer default color */
72 Uint8 alpha; /* Per-layer alpha value */
73 } VG_Layer;
74
75 typedef struct vg_matrix {
76 float m[3][3];
77 } VG_Matrix;
78
79 typedef struct vg_node {
80 VG_NodeOps *ops; /* Node class information */
81 Uint32 handle; /* Instance handle */
82 char sym[VG_SYM_NAME_MAX]; /* Symbolic name */
83
84 Uint flags;
85 #define VG_NODE_NOSAVE 0x01 /* Don't save with drawing */
86 #define VG_NODE_SELECTED 0x02 /* Selection flag */
87 #define VG_NODE_MOUSEOVER 0x04 /* Mouse overlap flag */
88 #define VG_NODE_SAVED_FLAGS 0
89
90 struct vg *vg; /* Back pointer to VG */
91 struct vg_node *parent; /* Back pointer to parent node */
92 struct vg_node **refs; /* Referenced nodes */
93 Uint nRefs; /* Referenced node count */
94 Uint nDeps; /* Dependency count */
95
96 VG_Color color; /* Element color */
97 int layer; /* Layer index */
98 VG_Matrix T; /* Transformation matrix */
99 void *p; /* User pointer */
100
101 AG_TAILQ_HEAD_(vg_node) cNodes; /* Child nodes */
102 AG_TAILQ_ENTRY(vg_node) tree; /* Entry in tree */
103 AG_TAILQ_ENTRY(vg_node) list; /* Entry in global list */
104 AG_TAILQ_ENTRY(vg_node) reverse; /* For VG_NodeTransform() */
105 AG_TAILQ_ENTRY(vg_node) user; /* Entry in user list */
106 } VG_Node;
107
108 #define VGNODE(p) ((VG_Node *)(p))
109
110 typedef struct vg {
111 Uint flags;
112 #define VG_NO_ANTIALIAS 0x01 /* Disable anti-aliasing */
113
114 AG_Mutex lock;
115
116 VG_IndexedColor *colors; /* Global color table */
117 Uint nColors; /* Color count */
118 VG_Color fillColor; /* Background color */
119 VG_Color selectionColor; /* Selected item/block color */
120 VG_Color mouseoverColor; /* Mouse overlap item color */
121
122 VG_Layer *layers; /* Layer information */
123 Uint nLayers; /* Layer count */
124
125 VG_Matrix *T; /* Stack of viewing matrices */
126 Uint nT;
127
128 VG_Node *root; /* Tree of entities */
129 AG_TAILQ_HEAD_(vg_node) nodes; /* List of entities */
130 AG_TAILQ_ENTRY(vg) user; /* Entry in user list */
131 } VG;
132
133 extern VG_NodeOps **vgNodeClasses;
134 extern Uint vgNodeClassCount;
135 extern int vgGUI;
136
137 #include <agar/vg/vg_math.h>
138
139 #define VG_FOREACH_NODE(node, vg, ntype) \
140 for((node) = (struct ntype *)AG_TAILQ_FIRST(&(vg)->nodes); \
141 (node) != (struct ntype *)AG_TAILQ_END(&(vg)->nodes); \
142 (node) = (struct ntype *)AG_TAILQ_NEXT(VGNODE(node),list))
143 #define VG_FOREACH_NODE_CLASS(node, vg, ntype, cn) \
144 VG_FOREACH_NODE(node,vg,ntype) \
145 if (!VG_NodeIsClass(VGNODE(node),(cn))) { \
146 continue; \
147 } else
148 #define VG_FOREACH_CHLD(node, pnode, ntype) \
149 for((node) = (struct ntype *)AG_TAILQ_FIRST(&VGNODE(pnode)->cNodes); \
150 (node) != (struct ntype *)AG_TAILQ_END(&VGNODE(pnode)->cNodes); \
151 (node) = (struct ntype *)AG_TAILQ_NEXT(VGNODE(node),tree))
152 #define VG_FOREACH_CHLD_CLASS(node, pnode, ntype, cn) \
153 VG_FOREACH_CHLD(node,pnode,ntype) \
154 if (!VG_NodeIsClass(VGNODE(node),(cn))) { \
155 continue; \
156 } else
157
158 __BEGIN_DECLS
159 void VG_InitSubsystem(void);
160 void VG_DestroySubsystem(void);
161
162 VG *VG_New(Uint);
163 void VG_Init(VG *, Uint);
164 void VG_Destroy(VG *);
165 void VG_Clear(VG *);
166 void VG_ClearNodes(VG *);
167 void VG_ClearColors(VG *);
168 void VG_Save(VG *, AG_DataSource *);
169 int VG_Load(VG *, AG_DataSource *);
170
171 VG_NodeOps *VG_LookupClass(const char *);
172 void VG_RegisterClass(VG_NodeOps *);
173 void VG_UnregisterClass(VG_NodeOps *);
174
175 void VG_NodeInit(void *, VG_NodeOps *);
176 void VG_NodeAttach(void *, void *);
177 void VG_NodeDetach(void *);
178 void VG_NodeDestroy(void *);
179 int VG_Delete(void *);
180 void VG_Merge(void *, VG *);
181 void VG_AddRef(void *, void *);
182 Uint VG_DelRef(void *, void *);
183 void VG_NodeTransform(void *, VG_Matrix *);
184 Uint32 VG_GenNodeName(VG *, const char *);
185
186 void VG_SetBackgroundColor(VG *, VG_Color);
187 void VG_SetSelectionColor(VG *, VG_Color);
188 void VG_SetMouseOverColor(VG *, VG_Color);
189
190 VG_Layer *VG_PushLayer(VG *, const char *);
191 void VG_PopLayer(VG *);
192
193 void VG_SetSym(void *, const char *, ...);
194 void VG_SetLayer(void *, int);
195 void VG_SetColorv(void *, const VG_Color *);
196 void VG_SetColorRGB(void *, Uint8, Uint8, Uint8);
197 void VG_SetColorRGBA(void *, Uint8, Uint8, Uint8, Uint8);
198
199 VG_Vector VG_ReadVector(AG_DataSource *);
200 void VG_WriteVector(AG_DataSource *, const VG_Vector *);
201 VG_Color VG_ReadColor(AG_DataSource *);
202 void VG_WriteColor(AG_DataSource *, const VG_Color *);
203 void VG_WriteRef(AG_DataSource *, void *);
204 void *VG_ReadRef(AG_DataSource *, void *, const char *);
205
206 void *VG_PointProximity(struct vg_view *, const char *, const VG_Vector *,
207 VG_Vector *, void *);
208 void *VG_PointProximityMax(struct vg_view *, const char *,
209 const VG_Vector *, VG_Vector *, void *, float);
210 VG_Matrix VG_MatrixInvert(VG_Matrix);
211
212 /* Acquire the VG lock. */
213 static __inline__ void
VG_Lock(VG * vg)214 VG_Lock(VG *vg)
215 {
216 AG_MutexLock(&vg->lock);
217 }
218
219 /* Release the VG lock. */
220 static __inline__ void
VG_Unlock(VG * vg)221 VG_Unlock(VG *vg)
222 {
223 AG_MutexUnlock(&vg->lock);
224 }
225
226 /* Evaluate whether a node belongs to a class. */
227 static __inline__ int
VG_NodeIsClass(void * p,const char * name)228 VG_NodeIsClass(void *p, const char *name)
229 {
230 return (strcmp(VGNODE(p)->ops->name, name) == 0);
231 }
232
233 /* Return the VG_Color representing a RGB triplet. */
234 static __inline__ VG_Color
VG_GetColorRGB(Uint8 r,Uint8 g,Uint8 b)235 VG_GetColorRGB(Uint8 r, Uint8 g, Uint8 b)
236 {
237 VG_Color vc;
238 vc.r = r;
239 vc.g = g;
240 vc.b = b;
241 vc.a = 255;
242 vc.idx = -1;
243 return (vc);
244 }
245
246 /* Return the VG_Color from RGBA components. */
247 static __inline__ VG_Color
VG_GetColorRGBA(Uint8 r,Uint8 g,Uint8 b,Uint8 a)248 VG_GetColorRGBA(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
249 {
250 VG_Color vc;
251 vc.r = r;
252 vc.g = g;
253 vc.b = b;
254 vc.a = a;
255 vc.idx = -1;
256 return (vc);
257 }
258
259 /* Convert a VG_Color to opaque AG_Color */
260 static __inline__ AG_Color
VG_MapColorRGB(VG_Color vc)261 VG_MapColorRGB(VG_Color vc)
262 {
263 return AG_ColorRGB(vc.r, vc.g, vc.b);
264 }
265
266 /* Convert a VG_Color to AG_Color */
267 static __inline__ AG_Color
VG_MapColorRGBA(VG_Color vc)268 VG_MapColorRGBA(VG_Color vc)
269 {
270 return AG_ColorRGBA(vc.r, vc.g, vc.b, vc.a);
271 }
272
273 /* Alpha-blend colors cDst and cSrc and return in cDst. */
274 static __inline__ void
VG_BlendColors(VG_Color * cDst,VG_Color cSrc)275 VG_BlendColors(VG_Color *cDst, VG_Color cSrc)
276 {
277 cDst->r = (((cSrc.r - cDst->r)*cSrc.a) >> 8) + cDst->r;
278 cDst->g = (((cSrc.g - cDst->g)*cSrc.a) >> 8) + cDst->g;
279 cDst->b = (((cSrc.b - cDst->b)*cSrc.a) >> 8) + cDst->b;
280 cDst->a = (cDst->a+cSrc.a >= 255) ? 255 : (cDst->a+cSrc.a);
281 }
282
283 /* Search a node by symbol. */
284 static __inline__ void *
VG_FindNodeSym(VG * vg,const char * sym)285 VG_FindNodeSym(VG *vg, const char *sym)
286 {
287 VG_Node *vn;
288
289 AG_TAILQ_FOREACH(vn, &vg->nodes, list) {
290 if (strcmp(vn->sym, sym) == 0)
291 return (vn);
292 }
293 return (NULL);
294 }
295
296 /* Search a node by handle and class. Used for loading datafiles. */
297 static __inline__ void *
VG_FindNode(VG * vg,Uint32 handle,const char * type)298 VG_FindNode(VG *vg, Uint32 handle, const char *type)
299 {
300 VG_Node *vn;
301
302 AG_TAILQ_FOREACH(vn, &vg->nodes, list) {
303 if (vn->handle == handle &&
304 strcmp(vn->ops->name, type) == 0)
305 return (vn);
306 }
307 return (NULL);
308 }
309
310 /* Push the transformation matrix stack. */
311 static __inline__ void
VG_PushMatrix(VG * vg)312 VG_PushMatrix(VG *vg)
313 {
314 vg->T = (VG_Matrix *)AG_Realloc(vg->T, (vg->nT+1)*sizeof(VG_Matrix));
315 memcpy(&vg->T[vg->nT], &vg->T[vg->nT-1], sizeof(VG_Matrix));
316 vg->nT++;
317 }
318
319 /* Pop the transformation matrix stack. */
320 static __inline__ void
VG_PopMatrix(VG * vg)321 VG_PopMatrix(VG *vg)
322 {
323 #ifdef AG_DEBUG
324 if (vg->nT == 1) { AG_FatalError("VG_PopMatrix"); }
325 #endif
326 vg->nT--;
327 }
328
329 /* Load identity matrix for the given node. */
330 static __inline__ void
VG_LoadIdentity(void * pNode)331 VG_LoadIdentity(void *pNode)
332 {
333 VG_Node *vn = (VG_Node *)pNode;
334
335 vn->T.m[0][0] = 1.0f; vn->T.m[0][1] = 0.0f; vn->T.m[0][2] = 0.0f;
336 vn->T.m[1][0] = 0.0f; vn->T.m[1][1] = 1.0f; vn->T.m[1][2] = 0.0f;
337 vn->T.m[2][0] = 0.0f; vn->T.m[2][1] = 0.0f; vn->T.m[2][2] = 1.0f;
338 }
339
340 /* Set the position of the given node relative to its parent. */
341 static __inline__ void
VG_SetPositionInParent(void * pNode,VG_Vector v)342 VG_SetPositionInParent(void *pNode, VG_Vector v)
343 {
344 VG_Node *vn = (VG_Node *)pNode;
345
346 vn->T.m[0][2] = v.x;
347 vn->T.m[1][2] = v.y;
348 }
349
350 /* Translate the given node. */
351 static __inline__ void
VG_Translate(void * pNode,VG_Vector v)352 VG_Translate(void *pNode, VG_Vector v)
353 {
354 VG_Node *vn = (VG_Node *)pNode;
355 VG_Matrix T;
356
357 T.m[0][0] = 1.0f; T.m[0][1] = 0.0f; T.m[0][2] = v.x;
358 T.m[1][0] = 0.0f; T.m[1][1] = 1.0f; T.m[1][2] = v.y;
359 T.m[2][0] = 0.0f; T.m[2][1] = 0.0f; T.m[2][2] = 1.0f;
360
361 VG_MultMatrix(&vn->T, &T);
362 }
363
364 /* Apply uniform scaling to the current viewing matrix. */
365 static __inline__ void
VG_Scale(void * pNode,float s)366 VG_Scale(void *pNode, float s)
367 {
368 VG_Node *vn = (VG_Node *)pNode;
369 VG_Matrix T;
370
371 T.m[0][0] = s; T.m[0][1] = 0.0f; T.m[0][2] = 0.0f;
372 T.m[1][0] = 0.0f; T.m[1][1] = s; T.m[1][2] = 0.0f;
373 T.m[2][0] = 0.0f; T.m[2][1] = 0.0f; T.m[2][2] = s;
374
375 VG_MultMatrix(&vn->T, &T);
376 }
377
378 /* Apply a rotation to the current viewing matrix. */
379 static __inline__ void
VG_Rotate(void * pNode,float theta)380 VG_Rotate(void *pNode, float theta)
381 {
382 VG_Node *vn = (VG_Node *)pNode;
383 VG_Matrix T;
384 float rCos = VG_Cos(theta);
385 float rSin = VG_Sin(theta);
386
387 T.m[0][0] = +rCos; T.m[0][1] = -rSin; T.m[0][2] = 0.0f;
388 T.m[1][0] = +rSin; T.m[1][1] = +rCos; T.m[1][2] = 0.0f;
389 T.m[2][0] = 0.0f; T.m[2][1] = 0.0f; T.m[2][2] = 1.0f;
390
391 VG_MultMatrix(&vn->T, &T);
392 }
393
394 /* Reflection about vertical line going through the origin. */
395 static __inline__ void
VG_FlipVert(void * pNode)396 VG_FlipVert(void *pNode)
397 {
398 VG_Node *vn = (VG_Node *)pNode;
399 VG_Matrix T;
400
401 T.m[0][0] = 1.0f; T.m[0][1] = 0.0f; T.m[0][2] = 0.0f;
402 T.m[1][0] = 0.0f; T.m[1][1] = -1.0f; T.m[1][2] = 0.0f;
403 T.m[2][0] = 0.0f; T.m[2][1] = 0.0f; T.m[2][2] = 1.0f;
404
405 VG_MultMatrix(&vn->T, &T);
406 }
407
408 /* Reflection about horizontal line going through the origin. */
409 static __inline__ void
VG_FlipHoriz(void * pNode)410 VG_FlipHoriz(void *pNode)
411 {
412 VG_Node *vn = (VG_Node *)pNode;
413 VG_Matrix T;
414
415 T.m[0][0] = -1.0f; T.m[0][1] = 0.0f; T.m[0][2] = 0.0f;
416 T.m[1][0] = 0.0f; T.m[1][1] = 1.0f; T.m[1][2] = 0.0f;
417 T.m[2][0] = 0.0f; T.m[2][1] = 0.0f; T.m[2][2] = 1.0f;
418
419 VG_MultMatrix(&vn->T, &T);
420 }
421
422 /* Mark node as selected. */
423 static __inline__ void
VG_Select(void * pNode)424 VG_Select(void *pNode)
425 {
426 VGNODE(pNode)->flags |= VG_NODE_SELECTED;
427 }
428
429 /* Remove the selection flag from node. */
430 static __inline__ void
VG_Unselect(void * pNode)431 VG_Unselect(void *pNode)
432 {
433 VGNODE(pNode)->flags |= VG_NODE_SELECTED;
434 }
435
436 /* Mark all nodes selected. */
437 static __inline__ void
VG_SelectAll(VG * vg)438 VG_SelectAll(VG *vg)
439 {
440 VG_Node *vn;
441 AG_TAILQ_FOREACH(vn, &vg->nodes, list)
442 vn->flags |= VG_NODE_SELECTED;
443 }
444
445 /* Remove the selection flag from all nodes. */
446 static __inline__ void
VG_UnselectAll(VG * vg)447 VG_UnselectAll(VG *vg)
448 {
449 VG_Node *vn;
450 AG_TAILQ_FOREACH(vn, &vg->nodes, list)
451 vn->flags &= ~(VG_NODE_SELECTED);
452 }
453
454 /* Return the effective position of the given node relative to the VG origin. */
455 static __inline__ VG_Vector
VG_Pos(void * node)456 VG_Pos(void *node)
457 {
458 VG_Matrix T;
459 VG_Vector v = { 0.0f, 0.0f };
460
461 VG_NodeTransform(node, &T);
462 VG_MultMatrixByVector(&v, &v, &T);
463 return (v);
464 }
465
466 /* Set the position of the given node relative to the VG origin. */
467 static __inline__ void
VG_SetPosition(void * pNode,VG_Vector v)468 VG_SetPosition(void *pNode, VG_Vector v)
469 {
470 VG_Node *vn = (VG_Node *)pNode;
471 VG_Vector vParent;
472
473 vn->T.m[0][2] = v.x;
474 vn->T.m[1][2] = v.y;
475 if (vn->parent != NULL) {
476 vParent = VG_Pos(vn->parent);
477 vn->T.m[0][2] -= vParent.x;
478 vn->T.m[1][2] -= vParent.y;
479 }
480 }
481 __END_DECLS
482
483 #include <agar/vg/vg_point.h>
484 #include <agar/vg/vg_line.h>
485 #include <agar/vg/vg_circle.h>
486 #include <agar/vg/vg_arc.h>
487 #include <agar/vg/vg_text.h>
488 #include <agar/vg/vg_polygon.h>
489
490 #include <agar/vg/close.h>
491 #endif /* _AGAR_VG_H_ */
492