1 /*
2  * Copyright (c) 2004-2008 Hypertriton, Inc. <http://hypertriton.com/>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23  * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 /*
27  * Base vector graphics object.
28  */
29 
30 #include <agar/core/core.h>
31 #include <agar/gui/gui.h>
32 #include <agar/gui/primitive.h>
33 #include <agar/gui/iconmgr.h>
34 #include <agar/vg/vg.h>
35 #include <agar/vg/vg_view.h>
36 #include <agar/vg/icons.h>
37 #include <agar/vg/icons_data.h>
38 
39 #include <string.h>
40 
41 const AG_Version vgVer = { 6, 1 };
42 
43 int          vgInitedSubsystem = 0;
44 VG_NodeOps **vgNodeClasses;
45 Uint         vgNodeClassCount;
46 int          vgGUI = 1;
47 
48 extern VG_NodeOps vgPointOps;
49 extern VG_NodeOps vgLineOps;
50 extern VG_NodeOps vgPolygonOps;
51 extern VG_NodeOps vgCircleOps;
52 extern VG_NodeOps vgArcOps;
53 extern VG_NodeOps vgTextOps;
54 
55 VG_NodeOps *vgBuiltinClasses[] = {
56 	&vgPointOps,
57 	&vgLineOps,
58 	&vgPolygonOps,
59 	&vgCircleOps,
60 	&vgArcOps,
61 	&vgTextOps,
62 	NULL
63 };
64 
65 void
VG_InitSubsystem(void)66 VG_InitSubsystem(void)
67 {
68 	VG_NodeOps **vnOps;
69 
70 	if (vgInitedSubsystem)
71 		return;
72 
73 	vgNodeClasses = NULL;
74 	vgNodeClassCount = 0;
75 
76 	AG_RegisterNamespace("VG", "VG_", "http://libagar.org/");
77 	if (vgGUI) {
78 		AG_RegisterClass(&vgViewClass);
79 	}
80 	for (vnOps = &vgBuiltinClasses[0]; *vnOps != NULL; vnOps++)
81 		VG_RegisterClass(*vnOps);
82 
83 	vgIcon_Init();
84 	vgInitedSubsystem = 1;
85 }
86 
87 void
VG_DestroySubsystem(void)88 VG_DestroySubsystem(void)
89 {
90 	if (!vgInitedSubsystem)
91 		return;
92 
93 	if (vgGUI) {
94 		AG_UnregisterClass(&vgViewClass);
95 	}
96 	Free(vgNodeClasses);
97 	vgNodeClasses = NULL;
98 	vgNodeClassCount = 0;
99 
100 	AG_UnregisterNamespace("VG");
101 
102 	vgInitedSubsystem = 0;
103 }
104 
105 VG *
VG_New(Uint flags)106 VG_New(Uint flags)
107 {
108 	VG *vg;
109 
110 	vg = Malloc(sizeof(VG));
111 	VG_Init(vg, flags);
112 	return (vg);
113 }
114 
115 void
VG_Init(VG * vg,Uint flags)116 VG_Init(VG *vg, Uint flags)
117 {
118 	VG_Point *ptRoot;
119 
120 	vg->flags = flags;
121 	vg->colors = NULL;
122 	vg->nColors = 0;
123 	vg->fillColor = VG_GetColorRGB(0,0,0);
124 	vg->selectionColor = VG_GetColorRGBA(0,200,0,150);
125 	vg->mouseoverColor = VG_GetColorRGBA(250,250,0,100);
126 	vg->layers = NULL;
127 	vg->nLayers = 0;
128 	TAILQ_INIT(&vg->nodes);
129 	AG_MutexInitRecursive(&vg->lock);
130 
131 	vg->T = Malloc(sizeof(VG_Matrix));
132 	vg->nT = 1;
133 	vg->T[0] = VG_MatrixIdentity();
134 
135 	VG_PushLayer(vg, _("Layer 0"));
136 
137 	ptRoot = VG_PointNew(NULL, VGVECTOR(0.0f,0.0f));
138 	vg->root = VGNODE(ptRoot);
139 	vg->root->vg = vg;
140 	vg->root->handle = 1;
141 	VG_SetColorRGB(vg->root, 0, 150, 0);
142 }
143 
144 /* Delete and free a node (including its children). */
145 void
VG_NodeDestroy(void * p)146 VG_NodeDestroy(void *p)
147 {
148 	VG_Node *vn = p;
149 	VG_Node *vnChld, *vnNext;
150 
151 #ifdef AG_DEBUG
152 	if (vn->vg != NULL || vn->parent != NULL)
153 		AG_FatalError("VG_NodeDetach() must precede VG_NodeDestroy()");
154 #endif
155 
156 	for (vnChld = TAILQ_FIRST(&vn->cNodes);
157 	     vnChld != TAILQ_END(&vn->cNodes);
158 	     vnChld = vnNext) {
159 		vnNext = TAILQ_NEXT(vnChld, tree);
160 		TAILQ_REMOVE(&vnChld->vg->nodes, vnChld, list);
161 		VG_NodeDestroy(vnChld);
162 	}
163 	TAILQ_INIT(&vn->cNodes);
164 
165 	if (vn->ops->destroy != NULL) {
166 		vn->ops->destroy(vn);
167 	}
168 	Free(vn);
169 }
170 
171 /* Reinitialize the drawing. */
172 void
VG_Clear(VG * vg)173 VG_Clear(VG *vg)
174 {
175 	VG_ClearNodes(vg);
176 	VG_ClearColors(vg);
177 }
178 
179 /* Reinitialize the tree of entities. */
180 void
VG_ClearNodes(VG * vg)181 VG_ClearNodes(VG *vg)
182 {
183 	VG_Node *vnChld, *vnNext;
184 
185 	if (vg->root == NULL) {
186 		return;
187 	}
188 	for (vnChld = TAILQ_FIRST(&vg->root->cNodes);
189 	     vnChld != TAILQ_END(&vg->root->cNodes);
190 	     vnChld = vnNext) {
191 		vnNext = TAILQ_NEXT(vnChld, tree);
192 		VG_NodeDetach(vnChld);
193 		VG_NodeDestroy(vnChld);
194 	}
195 	TAILQ_INIT(&vg->root->cNodes);
196 	TAILQ_INIT(&vg->nodes);
197 }
198 
199 /* Reinitialize the color array. */
200 void
VG_ClearColors(VG * vg)201 VG_ClearColors(VG *vg)
202 {
203 	if (vg->colors != NULL) {
204 		Free(vg->colors);
205 		vg->colors = NULL;
206 	}
207 	vg->nColors = 0;
208 }
209 
210 void
VG_Destroy(VG * vg)211 VG_Destroy(VG *vg)
212 {
213 	VG_Clear(vg);
214 	Free(vg->layers);
215 	AG_MutexDestroy(&vg->lock);
216 }
217 
218 void
VG_RegisterClass(VG_NodeOps * vnOps)219 VG_RegisterClass(VG_NodeOps *vnOps)
220 {
221 	vgNodeClasses = Realloc(vgNodeClasses,
222 	    (vgNodeClassCount+1)*sizeof(VG_NodeOps *));
223 	vgNodeClasses[vgNodeClassCount++] = vnOps;
224 }
225 
226 void
VG_UnregisterClass(VG_NodeOps * vnOps)227 VG_UnregisterClass(VG_NodeOps *vnOps)
228 {
229 	int i;
230 
231 	for (i = 0; i < vgNodeClassCount; i++) {
232 		if (vgNodeClasses[i] == vnOps)
233 			break;
234 	}
235 	if (i == vgNodeClassCount) {
236 		return;
237 	}
238 	if (i < vgNodeClassCount-1) {
239 		memmove(&vgNodeClasses[i], &vgNodeClasses[i+1],
240 		    (vgNodeClassCount-i-1)*sizeof(VG_NodeOps *));
241 	}
242 	vgNodeClassCount--;
243 }
244 
245 
246 /* Lookup a node class by name. */
247 VG_NodeOps *
VG_LookupClass(const char * name)248 VG_LookupClass(const char *name)
249 {
250 	Uint i;
251 
252 	for (i = 0; i < vgNodeClassCount; i++) {
253 		VG_NodeOps *vnOps = vgNodeClasses[i];
254 		if (strcmp(vnOps->name, name) == 0)
255 			return (vnOps);
256 	}
257 	AG_SetError("Invalid node type: %s", name);
258 	return (NULL);
259 }
260 
261 /* Detach and free the specified node and its children. */
262 int
VG_Delete(void * pVn)263 VG_Delete(void *pVn)
264 {
265 	VG_Node *vn = pVn;
266 	VG *vg = vn->vg;
267 
268 #ifdef AG_DEBUG
269 	if (vg == NULL)
270 		AG_FatalError("VG_Delete() on unattached node %s%d",
271 		    vn->ops->name, vn->handle);
272 #endif
273 	VG_Lock(vg);
274 	if (vn->nDeps > 0) {
275 		AG_SetError("%s%u is in use", vn->ops->name, (Uint)vn->handle);
276 		goto fail;
277 	}
278 	if (vn->ops->deleteNode != NULL) {
279 		vn->ops->deleteNode(vn);
280 	}
281 	VG_NodeDetach(vn);
282 	VG_NodeDestroy(vn);
283 	VG_Unlock(vg);
284 	return (0);
285 fail:
286 	VG_Unlock(vg);
287 	return (-1);
288 }
289 
290 static void
MoveNodesRecursively(VG * vgDst,VG_Node * vn)291 MoveNodesRecursively(VG *vgDst, VG_Node *vn)
292 {
293 	VG_Node *vnChld;
294 
295 	VG_FOREACH_CHLD(vnChld, vn, vg_node) {
296 		MoveNodesRecursively(vgDst, vnChld);
297 	}
298 	vn->handle = VG_GenNodeName(vgDst, vn->ops->name);
299 	TAILQ_REMOVE(&vn->vg->nodes, vn, list);
300 	vn->vg = vgDst;
301 	TAILQ_INSERT_TAIL(&vgDst->nodes, vn, list);
302 }
303 
304 /*
305  * Move the contents of a source VG (to be discarded) to the specified
306  * destination VG, under a given node.
307  */
308 void
VG_Merge(void * pVnDst,VG * vgSrc)309 VG_Merge(void *pVnDst, VG *vgSrc)
310 {
311 	VG_Node *vnDst = pVnDst;
312 	VG_Node *vn = vgSrc->root;
313 
314 	vn->vg = vnDst->vg;
315 	vn->parent = vnDst;
316 	TAILQ_INSERT_TAIL(&vnDst->vg->nodes, vn, list);
317 	TAILQ_INSERT_TAIL(&vnDst->cNodes, vn, tree);
318 	MoveNodesRecursively(vnDst->vg, vn);
319 	vgSrc->root = NULL;
320 }
321 
322 /* Create a node reference to another node. */
323 void
VG_AddRef(void * p,void * pRef)324 VG_AddRef(void *p, void *pRef)
325 {
326 	VG_Node *vn = p;
327 
328 	if (vn->vg != NULL) { VG_Lock(vn->vg); }
329 	vn->refs = Realloc(vn->refs, (vn->nRefs+1)*sizeof(VG_Node *));
330 	vn->refs[vn->nRefs++] = VGNODE(pRef);
331 	VGNODE(pRef)->nDeps++;
332 	if (vn->vg != NULL) { VG_Unlock(vn->vg); }
333 }
334 
335 /* Remove a node reference to another node. */
336 Uint
VG_DelRef(void * pVn,void * pRef)337 VG_DelRef(void *pVn, void *pRef)
338 {
339 	VG_Node *vn = pVn;
340 	Uint newDeps;
341 	int i;
342 
343 	if (vn->vg != NULL) { VG_Lock(vn->vg); }
344 	for (i = 0; i < vn->nRefs; i++) {
345 		if (vn->refs[i] == VGNODE(pRef))
346 			break;
347 	}
348 	if (i == vn->nRefs) {
349 		AG_FatalError("No such reference");
350 	}
351 	if (i < vn->nRefs-1) {
352 		memmove(&vn->refs[i], &vn->refs[i+1],
353 		    (vn->nRefs-i-1)*sizeof(VG_Node *));
354 	}
355 	vn->nRefs--;
356 	newDeps = (--VGNODE(pRef)->nDeps);
357 	if (vn->vg != NULL) { VG_Unlock(vn->vg); }
358 	return (newDeps);
359 }
360 
VG_SetBackgroundColor(VG * vg,VG_Color c)361 void VG_SetBackgroundColor(VG *vg, VG_Color c) { vg->fillColor = c; }
VG_SetSelectionColor(VG * vg,VG_Color c)362 void VG_SetSelectionColor(VG *vg, VG_Color c) { vg->selectionColor = c; }
VG_SetMouseOverColor(VG * vg,VG_Color c)363 void VG_SetMouseOverColor(VG *vg, VG_Color c) { vg->mouseoverColor = c; }
364 
365 void
VG_NodeInit(void * p,VG_NodeOps * vnOps)366 VG_NodeInit(void *p, VG_NodeOps *vnOps)
367 {
368 	VG_Node *vn = p;
369 
370 	vn->ops = vnOps;
371 	vn->handle = 0;
372 	vn->sym[0] = '\0';
373 	vn->flags = 0;
374 	vn->layer = 0;
375 	vn->color = VG_GetColorRGB(250,250,250);
376 	vn->parent = NULL;
377 	vn->vg = NULL;
378 	vn->refs = NULL;
379 	vn->nRefs = 0;
380 	vn->nDeps = 0;
381 	vn->T = VG_MatrixIdentity();
382 	vn->p = NULL;
383 	TAILQ_INIT(&vn->cNodes);
384 
385 	if (vn->ops->init != NULL)
386 		vn->ops->init(vn);
387 }
388 
389 /* Generate a unique name for a node of the specified type. */
390 Uint32
VG_GenNodeName(VG * vg,const char * type)391 VG_GenNodeName(VG *vg, const char *type)
392 {
393 	Uint32 name = 1;
394 
395 	while (VG_FindNode(vg, name, type) != NULL) {
396 		if (++name >= VG_HANDLE_MAX)
397 			AG_FatalError("Out of node names");
398 	}
399 	return (name);
400 }
401 
402 /*
403  * Attach the specified node to a new parent. If the node has no
404  * name assigned (handle=0), one is generated.
405  */
406 void
VG_NodeAttach(void * pParent,void * pNode)407 VG_NodeAttach(void *pParent, void *pNode)
408 {
409 	VG_Node *vnParent = pParent;
410 	VG_Node *vn = pNode;
411 	VG *vg;
412 
413 	if (vnParent == NULL) {
414 		vn->parent = NULL;
415 		vn->vg = NULL;
416 		return;
417 	}
418 	vg = vnParent->vg;
419 
420 	VG_Lock(vg);
421 
422 	if (vn->handle == 0) {
423 		vn->handle = VG_GenNodeName(vg, vn->ops->name);
424 	}
425 	vn->parent = vnParent;
426 	TAILQ_INSERT_TAIL(&vnParent->cNodes, vn, tree);
427 	TAILQ_INSERT_TAIL(&vg->nodes, vn, list);
428 	vn->vg = vg;
429 	VG_Unlock(vg);
430 }
431 
432 /*
433  * Detach the specified node from its current parent. The node itself
434  * and all of its children are also detached from the VG. No reference
435  * checking is done.
436  */
437 void
VG_NodeDetach(void * p)438 VG_NodeDetach(void *p)
439 {
440 	VG_Node *vn = p;
441 	VG *vg = vn->vg;
442 	VG_Node *vnChld, *vnNext;
443 
444 #ifdef AG_DEBUG
445 	if (vg == NULL)
446 		AG_FatalError("VG_NodeDetach() on unattached node");
447 #endif
448 	VG_Lock(vg);
449 	for (vnChld = TAILQ_FIRST(&vn->cNodes);
450 	     vnChld != TAILQ_END(&vn->cNodes);
451 	     vnChld = vnNext) {
452 		vnNext = TAILQ_NEXT(vnChld, tree);
453 		VG_NodeDetach(vnChld);
454 	}
455 	TAILQ_INIT(&vn->cNodes);
456 
457 	if (vn->parent != NULL) {
458 		TAILQ_REMOVE(&vn->parent->cNodes, vn, tree);
459 		vn->parent = NULL;
460 	}
461 	TAILQ_REMOVE(&vg->nodes, vn, list);
462 	vn->vg = NULL;
463 	VG_Unlock(vg);
464 }
465 
466 /* Set the symbolic name of a node. */
467 void
VG_SetSym(void * pNode,const char * fmt,...)468 VG_SetSym(void *pNode, const char *fmt, ...)
469 {
470 	VG_Node *vn = pNode;
471 	va_list args;
472 
473 	if (vn->vg != NULL) { VG_Lock(vn->vg); }
474 	va_start(args, fmt);
475 	Vsnprintf(vn->sym, sizeof(vn->sym), fmt, args);
476 	va_end(args);
477 	if (vn->vg != NULL) { VG_Unlock(vn->vg); }
478 }
479 
480 void
VG_SetLayer(void * pNode,int layer)481 VG_SetLayer(void *pNode, int layer)
482 {
483 	VGNODE(pNode)->layer = layer;
484 }
485 
486 void
VG_SetColorv(void * pNode,const VG_Color * c)487 VG_SetColorv(void *pNode, const VG_Color *c)
488 {
489 	VG_Node *vn = pNode;
490 	vn->color.r = c->r;
491 	vn->color.g = c->g;
492 	vn->color.b = c->b;
493 	vn->color.a = c->a;
494 }
495 
496 void
VG_SetColorRGB(void * pNode,Uint8 r,Uint8 g,Uint8 b)497 VG_SetColorRGB(void *pNode, Uint8 r, Uint8 g, Uint8 b)
498 {
499 	VG_Node *vn = pNode;
500 	vn->color.r = r;
501 	vn->color.g = g;
502 	vn->color.b = b;
503 }
504 
505 void
VG_SetColorRGBA(void * pNode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)506 VG_SetColorRGBA(void *pNode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
507 {
508 	VG_Node *vn = pNode;
509 	vn->color.r = r;
510 	vn->color.g = g;
511 	vn->color.b = b;
512 	vn->color.a = a;
513 }
514 
515 /* Push a new layer onto the layer stack. */
516 VG_Layer *
VG_PushLayer(VG * vg,const char * name)517 VG_PushLayer(VG *vg, const char *name)
518 {
519 	VG_Layer *vgl;
520 
521 	VG_Lock(vg);
522 	vg->layers = Realloc(vg->layers, (vg->nLayers+1) *
523 	                                 sizeof(VG_Layer));
524 	vgl = &vg->layers[vg->nLayers];
525 	vg->nLayers++;
526 	Strlcpy(vgl->name, name, sizeof(vgl->name));
527 	vgl->visible = 1;
528 	vgl->alpha = 255;
529 	vgl->color = VG_GetColorRGB(255,255,255);
530 	VG_Unlock(vg);
531 	return (vgl);
532 }
533 
534 /* Pop the highest layer off the layer stack. */
535 void
VG_PopLayer(VG * vg)536 VG_PopLayer(VG *vg)
537 {
538 	VG_Lock(vg);
539 	if (--vg->nLayers < 1) {
540 		vg->nLayers = 1;
541 	}
542 	VG_Unlock(vg);
543 }
544 
545 static void
SaveMatrix(VG_Matrix * A,AG_DataSource * ds)546 SaveMatrix(VG_Matrix *A, AG_DataSource *ds)
547 {
548 	int m, n;
549 
550 	for (m = 0; m < 3; m++)
551 		for (n = 0; n < 3; n++)
552 			AG_WriteFloat(ds, A->m[m][n]);
553 }
554 
555 static void
LoadMatrix(VG_Matrix * A,AG_DataSource * ds)556 LoadMatrix(VG_Matrix *A, AG_DataSource *ds)
557 {
558 	int m, n;
559 
560 	for (m = 0; m < 3; m++)
561 		for (n = 0; n < 3; n++)
562 			A->m[m][n] = AG_ReadFloat(ds);
563 }
564 
565 static void
SaveNodeGeneric(VG * vg,VG_Node * vn,AG_DataSource * ds)566 SaveNodeGeneric(VG *vg, VG_Node *vn, AG_DataSource *ds)
567 {
568 	off_t nNodesOffs;
569 	Uint32 nNodes = 0;
570 	VG_Node *vnChld;
571 
572 	if (vn->flags & VG_NODE_NOSAVE)
573 		return;
574 
575 	AG_WriteString(ds, vn->ops->name);
576 	AG_WriteString(ds, vn->sym);
577 	AG_WriteUint32(ds, (Uint32)vn->handle);
578 	AG_WriteUint32(ds, (Uint32)(vn->flags & VG_NODE_SAVED_FLAGS));
579 	AG_WriteUint32(ds, (Uint32)vn->layer);
580 	VG_WriteColor(ds, &vn->color);
581 	SaveMatrix(&vn->T, ds);
582 
583 	/* Save the entities. */
584 	nNodesOffs = AG_Tell(ds);
585 	AG_WriteUint32(ds, 0);
586 	VG_FOREACH_CHLD(vnChld, vn, vg_node) {
587 		SaveNodeGeneric(vg, vnChld, ds);
588 		nNodes++;
589 	}
590 	AG_WriteUint32At(ds, nNodes, nNodesOffs);
591 }
592 
593 static int
SaveNodeData(VG * vg,VG_Node * vn,AG_DataSource * ds)594 SaveNodeData(VG *vg, VG_Node *vn, AG_DataSource *ds)
595 {
596 	VG_Node *vnChld;
597 
598 	VG_FOREACH_CHLD(vnChld, vn, vg_node) {
599 		if (SaveNodeData(vg, vnChld, ds) == -1)
600 			return (-1);
601 	}
602 	if (vn->ops->save != NULL) {
603 		vn->ops->save(vn, ds);
604 	}
605 	return (0);
606 }
607 
608 void
VG_Save(VG * vg,AG_DataSource * ds)609 VG_Save(VG *vg, AG_DataSource *ds)
610 {
611 	off_t nNodesOffs;
612 	Uint32 nNodes = 0;
613 	VG_Node *vn;
614 	Uint i;
615 
616 	AG_WriteVersion(ds, "Agar-VG", &vgVer);
617 	AG_WriteString(ds, "VG");				/* name */
618 
619 	VG_Lock(vg);
620 
621 	AG_WriteUint32(ds, (Uint32)vg->flags);
622 	VG_WriteColor(ds, &vg->fillColor);
623 	VG_WriteColor(ds, &vg->fillColor);			/* gridColor */
624 	VG_WriteColor(ds, &vg->selectionColor);
625 	VG_WriteColor(ds, &vg->mouseoverColor);
626 	AG_WriteFloat(ds, 0.0f);				/* gridIval */
627 
628 	/* Save the layer information. */
629 	AG_WriteUint32(ds, (Uint32)vg->nLayers);
630 	for (i = 0; i < vg->nLayers; i++) {
631 		VG_Layer *layer = &vg->layers[i];
632 
633 		AG_WriteString(ds, layer->name);
634 		AG_WriteUint8(ds, (Uint8)layer->visible);
635 		VG_WriteColor(ds, &layer->color);
636 		AG_WriteUint8(ds, layer->alpha);
637 	}
638 
639 	/* Save the color table. */
640 	AG_WriteUint32(ds, (Uint32)vg->nColors);
641 	for (i = 0; i < vg->nColors; i++) {
642 		VG_IndexedColor *vic = &vg->colors[i];
643 		AG_WriteString(ds, vic->name);
644 		VG_WriteColor(ds, &vic->color);
645 	}
646 
647 	/* Save the entities. */
648 	nNodesOffs = AG_Tell(ds);
649 	AG_WriteUint32(ds, 0);
650 	VG_FOREACH_CHLD(vn, vg->root, vg_node) {
651 		SaveNodeGeneric(vg, vn, ds);
652 		nNodes++;
653 	}
654 	AG_WriteUint32At(ds, nNodes, nNodesOffs);
655 	SaveNodeData(vg, vg->root, ds);
656 	VG_Unlock(vg);
657 }
658 
659 static int
LoadNodeGeneric(VG * vg,VG_Node * vnParent,AG_DataSource * ds)660 LoadNodeGeneric(VG *vg, VG_Node *vnParent, AG_DataSource *ds)
661 {
662 	char type[VG_TYPE_NAME_MAX];
663 	VG_Node *vn;
664 	VG_NodeOps *vnOps;
665 	Uint32 i, nNodes;
666 
667 	AG_CopyString(type, ds, sizeof(type));
668 	if ((vnOps = VG_LookupClass(type)) == NULL) {
669 		return (-1);
670 	}
671 	vn = Malloc(vnOps->size);
672 	VG_NodeInit(vn, vnOps);
673 	AG_CopyString(vn->sym, ds, sizeof(vn->sym));
674 	vn->handle = AG_ReadUint32(ds);
675 	vn->flags = AG_ReadUint32(ds);
676 	vn->layer = (int)AG_ReadUint32(ds);
677 	vn->color = VG_ReadColor(ds);
678 	LoadMatrix(&vn->T, ds);
679 	VG_NodeAttach(vnParent, vn);
680 
681 	nNodes = AG_ReadUint32(ds);
682 	for (i = 0; i < nNodes; i++) {
683 		if (LoadNodeGeneric(vg, vn, ds) == -1)
684 			return (-1);
685 	}
686 	return (0);
687 }
688 
689 static int
LoadNodeData(VG * vg,VG_Node * vn,AG_DataSource * ds,const AG_Version * dsVer)690 LoadNodeData(VG *vg, VG_Node *vn, AG_DataSource *ds, const AG_Version *dsVer)
691 {
692 	VG_Node *vnChld;
693 
694 	VG_FOREACH_CHLD(vnChld, vn, vg_node) {
695 		if (LoadNodeData(vg, vnChld, ds, dsVer) == -1)
696 			return (-1);
697 	}
698 	if (vn->ops->load != NULL &&
699 	    vn->ops->load(vn, ds, dsVer) == -1) {
700 		AG_SetError("%s%u: %s", vn->ops->name, (Uint)vn->handle,
701 		    AG_GetError());
702 		return (-1);
703 	}
704 	return (0);
705 }
706 
707 int
VG_Load(VG * vg,AG_DataSource * ds)708 VG_Load(VG *vg, AG_DataSource *ds)
709 {
710 	char name[VG_NAME_MAX];
711 	AG_Version dsVer;
712 	Uint32 i, nColors, nNodes;
713 
714 	if (AG_ReadVersion(ds, "Agar-VG", &vgVer, &dsVer) != 0) {
715 		return (-1);
716 	}
717 	AG_CopyString(name, ds, sizeof(name));		/* Ignore */
718 
719 	VG_Lock(vg);
720 	vg->flags = AG_ReadUint32(ds);
721 	vg->fillColor = VG_ReadColor(ds);
722 	(void)VG_ReadColor(ds);				/* gridColor */
723 	vg->selectionColor = VG_ReadColor(ds);
724 	vg->mouseoverColor = VG_ReadColor(ds);
725 	(void)AG_ReadFloat(ds);				/* gridIval */
726 
727 	/* Read the layer information. */
728 	vg->nLayers = (Uint)AG_ReadUint32(ds);
729 	vg->layers = Realloc(vg->layers, vg->nLayers*sizeof(VG_Layer));
730 	for (i = 0; i < vg->nLayers; i++) {
731 		VG_Layer *layer = &vg->layers[i];
732 
733 		AG_CopyString(layer->name, ds, sizeof(layer->name));
734 		layer->visible = (int)AG_ReadUint8(ds);
735 		layer->color = VG_ReadColor(ds);
736 		layer->alpha = AG_ReadUint8(ds);
737 	}
738 
739 	/* Read the color table. */
740 	nColors = AG_ReadUint32(ds);
741 	vg->colors = Malloc(nColors*sizeof(VG_IndexedColor *));
742 	vg->nColors = nColors;
743 	for (i = 0; i < nColors; i++) {
744 		VG_IndexedColor *vic = &vg->colors[i];
745 		AG_CopyString(vic->name, ds, sizeof(vic->name));
746 		vic->color = VG_ReadColor(ds);
747 	}
748 
749 	/* Read the entities. */
750 	VG_ClearNodes(vg);
751 	nNodes = AG_ReadUint32(ds);
752 	for (i = 0; i < nNodes; i++) {
753 		if (LoadNodeGeneric(vg, vg->root, ds) == -1)
754 			goto fail;
755 	}
756 	if (LoadNodeData(vg, vg->root, ds, &dsVer) == -1) {
757 		goto fail;
758 	}
759 	VG_Unlock(vg);
760 	return (0);
761 fail:
762 	VG_Unlock(vg);
763 	return (-1);
764 }
765 
766 void
VG_WriteVector(AG_DataSource * ds,const VG_Vector * vtx)767 VG_WriteVector(AG_DataSource *ds, const VG_Vector *vtx)
768 {
769 	AG_WriteFloat(ds, vtx->x);
770 	AG_WriteFloat(ds, vtx->y);
771 }
772 
773 void
VG_WriteColor(AG_DataSource * ds,const VG_Color * c)774 VG_WriteColor(AG_DataSource *ds, const VG_Color *c)
775 {
776 	AG_WriteUint8(ds, c->r);
777 	AG_WriteUint8(ds, c->g);
778 	AG_WriteUint8(ds, c->b);
779 	AG_WriteUint8(ds, c->a);
780 }
781 
782 VG_Vector
VG_ReadVector(AG_DataSource * ds)783 VG_ReadVector(AG_DataSource *ds)
784 {
785 	VG_Vector v;
786 
787 	v.x = AG_ReadFloat(ds);
788 	v.y = AG_ReadFloat(ds);
789 	return (v);
790 }
791 
792 VG_Color
VG_ReadColor(AG_DataSource * ds)793 VG_ReadColor(AG_DataSource *ds)
794 {
795 	VG_Color c;
796 
797 	c.r = AG_ReadUint8(ds);
798 	c.g = AG_ReadUint8(ds);
799 	c.b = AG_ReadUint8(ds);
800 	c.a = AG_ReadUint8(ds);
801 	c.idx = -1;
802 	return (c);
803 }
804 
805 /* Serialize a node->node reference. */
806 void
VG_WriteRef(AG_DataSource * ds,void * p)807 VG_WriteRef(AG_DataSource *ds, void *p)
808 {
809 	VG_Node *vn = p;
810 
811 	AG_WriteString(ds, vn->ops->name);
812 	AG_WriteUint32(ds, vn->handle);
813 }
814 
815 /* Deserialize a node->node reference. */
816 void *
VG_ReadRef(AG_DataSource * ds,void * pNode,const char * expType)817 VG_ReadRef(AG_DataSource *ds, void *pNode, const char *expType)
818 {
819 	VG_Node *vn = pNode;
820 	char rType[VG_TYPE_NAME_MAX];
821 	Uint32 handle;
822 	void *vnFound;
823 
824 	AG_CopyString(rType, ds, sizeof(rType));
825 	handle = AG_ReadUint32(ds);
826 
827 	if (expType != NULL) {
828 		if (strcmp(rType, expType) != 0) {
829 			AG_SetError("Unexpected reference type: %s "
830 			            "(expecting %s)", rType, expType);
831 			return (NULL);
832 		}
833 	}
834 	if ((vnFound = VG_FindNode(vn->vg, handle, rType)) == NULL) {
835 		AG_SetError("Reference to unexisting item: %s%u", rType,
836 		    (Uint)handle);
837 		return (NULL);
838 	}
839 	VG_AddRef(vn, vnFound);
840 	return (vnFound);
841 }
842 
843 /* Return the element closest to the given point. */
844 void *
VG_PointProximity(VG_View * vv,const char * type,const VG_Vector * vPt,VG_Vector * vC,void * ignoreNode)845 VG_PointProximity(VG_View *vv, const char *type, const VG_Vector *vPt,
846     VG_Vector *vC, void *ignoreNode)
847 {
848 	VG *vg = vv->vg;
849 	VG_Node *vn, *vnClosest = NULL;
850 	float distClosest = AG_FLT_MAX, p;
851 	VG_Vector v, vClosest = VGVECTOR(AG_FLT_MAX,AG_FLT_MAX);
852 
853 	VG_FOREACH_NODE(vn, vg, vg_node) {
854 		if (vn == ignoreNode ||
855 		    vn->ops->pointProximity == NULL) {
856 			continue;
857 		}
858 		if (type != NULL &&
859 		    strcmp(vn->ops->name, type) != 0) {
860 			continue;
861 		}
862 		v = *vPt;
863 		p = vn->ops->pointProximity(vn, vv, &v);
864 		if (p < distClosest) {
865 			distClosest = p;
866 			vnClosest = vn;
867 			vClosest = v;
868 		}
869 	}
870 	if (vC != NULL) {
871 		*vC = vClosest;
872 	}
873 	return (vnClosest);
874 }
875 
876 /*
877  * Return the element closest to the given point, ignoring all elements
878  * beyond a specified distance.
879  */
880 void *
VG_PointProximityMax(VG_View * vv,const char * type,const VG_Vector * vPt,VG_Vector * vC,void * ignoreNode,float distMax)881 VG_PointProximityMax(VG_View *vv, const char *type, const VG_Vector *vPt,
882     VG_Vector *vC, void *ignoreNode, float distMax)
883 {
884 	VG *vg = vv->vg;
885 	VG_Node *vn, *vnClosest = NULL;
886 	float distClosest = AG_FLT_MAX, p;
887 	VG_Vector v, vClosest = VGVECTOR(AG_FLT_MAX,AG_FLT_MAX);
888 
889 	VG_FOREACH_NODE(vn, vg, vg_node) {
890 		if (vn == ignoreNode ||
891 		    vn->ops->pointProximity == NULL) {
892 			continue;
893 		}
894 		if (type != NULL &&
895 		    strcmp(vn->ops->name, type) != 0) {
896 			continue;
897 		}
898 		v = *vPt;
899 		p = vn->ops->pointProximity(vn, vv, &v);
900 		if (p < distMax && p < distClosest) {
901 			distClosest = p;
902 			vnClosest = vn;
903 			vClosest = v;
904 		}
905 	}
906 	if (vC != NULL) {
907 		*vC = vClosest;
908 	}
909 	return (vnClosest);
910 }
911 
912 /*
913  * Compute the product of the transform matrices of the given node and its
914  * parents in order. T is initialized to identity.
915  */
916 void
VG_NodeTransform(void * p,VG_Matrix * T)917 VG_NodeTransform(void *p, VG_Matrix *T)
918 {
919 	VG_Node *node = p;
920 	VG_Node *cNode = node;
921 	TAILQ_HEAD_(vg_node) rNodes = TAILQ_HEAD_INITIALIZER(rNodes);
922 
923 	while (cNode != NULL) {
924 		TAILQ_INSERT_HEAD(&rNodes, cNode, reverse);
925 		if (cNode->parent == NULL) {
926 			break;
927 		}
928 		cNode = cNode->parent;
929 	}
930 	*T = VG_MatrixIdentity();
931 	TAILQ_FOREACH(cNode, &rNodes, reverse)
932 		VG_MultMatrix(T, &cNode->T);
933 }
934 
935 /* Compute the inverse of a VG transformation matrix. */
936 VG_Matrix
VG_MatrixInvert(VG_Matrix A)937 VG_MatrixInvert(VG_Matrix A)
938 {
939 	VG_Matrix B;
940 	float det, detInv;
941 	int i, j;
942 
943 	B.m[0][0] = A.m[1][1]*A.m[2][2] - A.m[1][2]*A.m[2][1];
944 	B.m[0][1] = A.m[0][2]*A.m[2][1] - A.m[0][1]*A.m[2][2];
945 	B.m[0][2] = A.m[0][1]*A.m[1][2] - A.m[0][2]*A.m[1][1];
946 	B.m[1][0] = A.m[1][2]*A.m[2][0] - A.m[1][0]*A.m[2][2];
947 	B.m[1][1] = A.m[0][0]*A.m[2][2] - A.m[0][2]*A.m[2][0];
948 	B.m[1][2] = A.m[0][2]*A.m[1][0] - A.m[0][0]*A.m[1][2];
949 	B.m[2][0] = A.m[1][0]*A.m[2][1] - A.m[1][1]*A.m[2][0];
950 	B.m[2][1] = A.m[0][1]*A.m[2][0] - A.m[0][0]*A.m[2][1];
951 	B.m[2][2] = A.m[0][0]*A.m[1][1] - A.m[0][1]*A.m[1][0];
952 
953 	det = A.m[0][0]*B.m[0][0] +
954 	      A.m[0][1]*B.m[1][0] +
955 	      A.m[0][2]*B.m[2][0];
956 	if (Fabs(det) <= 1e-6f)
957 		AG_FatalError("Singular matrix");
958 
959 	detInv = 1.0/det;
960 	for (i = 0; i < 3; i++) {
961 		for (j = 0; j < 3; j++)
962 			B.m[i][j] *= detInv;
963 	}
964 	return (B);
965 }
966 
967