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