See attached... 

This is the same as the previous patch, but with the test actually checked in.
From fffbd9ead1f2eab87473fb8c6383fdab23188fcd Mon Sep 17 00:00:00 2001
From: Charles Daniels <[email protected]>
Date: Fri, 13 Sep 2019 16:49:55 -0400
Subject: [PATCH 1/2] Implemented support for Bezier curves

---
 ChangeLogs/Release-1.6.0.txt |   1 +
 math/Makefile                |   3 +-
 math/m_bezier.c              | 167 +++++++++++++++++++++++++++++++++++
 math/m_bezier.h              |  11 +++
 math/m_bezier_primitives.c   |  82 +++++++++++++++++
 math/m_bezier_primitives.h   |  17 ++++
 math/m_geometry.h            |   1 +
 math/m_gui.h                 |   1 +
 tests/Makefile               |   2 +
 tests/agartest.c             |   2 +
 10 files changed, 286 insertions(+), 1 deletion(-)
 create mode 100644 math/m_bezier.c
 create mode 100644 math/m_bezier.h
 create mode 100644 math/m_bezier_primitives.c
 create mode 100644 math/m_bezier_primitives.h

diff --git a/ChangeLogs/Release-1.6.0.txt b/ChangeLogs/Release-1.6.0.txt
index 4ba337a5d..ccde3bbee 100644
--- a/ChangeLogs/Release-1.6.0.txt
+++ b/ChangeLogs/Release-1.6.0.txt
@@ -46,3 +46,4 @@ particular order.
   AG_QuadraticPositive, AG_QuadraticNegative, AG_Distance
 - GUI: add AG_DrawArrowLine for drawing lines with arrowheads
 - GUI: AG_Graph now supports directed graphs
+- MATH: Implemented M_Bezier module for computing Bézier curves.
diff --git a/math/Makefile b/math/Makefile
index e49a7d40a..f6192f1a1 100644
--- a/math/Makefile
+++ b/math/Makefile
@@ -27,7 +27,8 @@ SRCS=	m_math.c m_complex.c m_quaternion.c \
 	m_coordinates.c m_heapsort.c m_mergesort.c m_qsort.c m_radixsort.c \
 	m_point_set.c m_color.c m_sphere.c m_polyhedron.c \
 	m_matrix_sparse.c m_sparse_allocate.c m_sparse_build.c m_sparse_eda.c \
-	m_sparse_factor.c m_sparse_output.c m_sparse_solve.c m_sparse_utils.c
+	m_sparse_factor.c m_sparse_output.c m_sparse_solve.c m_sparse_utils.c \
+	m_bezier.c m_bezier_primitives.c
 
 CFLAGS+=${GUI_CFLAGS} \
 	${CORE_CFLAGS} \
diff --git a/math/m_bezier.c b/math/m_bezier.c
new file mode 100644
index 000000000..8576e7aed
--- /dev/null
+++ b/math/m_bezier.c
@@ -0,0 +1,167 @@
+/* Copyright (c) Charles A. Daniels <http://cdaniels.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This module is based on code published in Graphics Gems V by Alan W. Paeth
+ * (ch IV.8, pp206) and written by Rober D. Miller. Said code was Copyright (c)
+ * 1995 Academic Press Inc. and distributed under the license:
+ *
+ * EULA: The Graphics Gems code is copyright-protected. In other words, you
+ * cannot claim the text of the code as your own and resell it. Using the code
+ * is permitted in any program, product, or library, non-commercial or
+ * commercial. Giving credit is not required, though is a nice gesture. The
+ * code comes as-is, and if there are any flaws or problems with any Gems code,
+ * nobody involved with Gems - authors, editors, publishers, or webmasters -
+ * are to be held responsible. Basically, don't be a jerk, and remember that
+ * anything free comes with no guarantee.
+ */
+
+#include <agar/core/core.h>
+#include <agar/math/m.h>
+
+#include <agar/config/enable_gui.h>
+
+#ifdef ENABLE_GUI
+# include <agar/gui/gui.h>
+#include <agar/gui/widget.h>
+#include <agar/math/m_bezier_primitives.h>
+#endif
+
+
+/* Setup Bezier coefficient array once for each control polygon. */
+void M_BezierForm2(M_PointSet2* p, M_PointSet2* c)
+{
+	int k;
+	M_Real n, choose;
+	n = p->n - 1;
+
+	M_PointSetAlloc2(c, p->n);
+
+	/* XXX: should be an error condition of n < c->n */
+
+	for(k = 0; k <= n; k++) {
+		if (k == 0) choose = 1;
+		else if (k == 1) choose = n;
+		else choose = choose *(n-k+1)/k;
+		c->p[k].x = p->p[k].x *choose;
+		c->p[k].y = p->p[k].y *choose;
+		c->n++;
+	};
+
+}
+
+/* Setup Bezier coefficient array once for each control polygon. */
+void M_BezierForm3(M_PointSet3* p, M_PointSet3* c)
+{
+	int k;
+	M_Real n, choose;
+	n = p->n - 1;
+
+	M_PointSetAlloc3(c, p->n);
+
+	/* XXX: should be an error condition of n < c->n */
+
+	for(k = 0; k <= n; k++) {
+		if (k == 0) choose = 1;
+		else if (k == 1) choose = n;
+		else choose = choose *(n-k+1)/k;
+		c->p[k].x = p->p[k].x *choose;
+		c->p[k].y = p->p[k].y *choose;
+		c->p[k].z = p->p[k].z *choose;
+	};
+}
+
+/* Return Point pt(t), t <= 0 <= 1 from c, given the number of Points in
+ * control polygon. BezierForm must be called once for any given control
+ * polygon. */
+void M_BezierCurve2(M_PointSet2* c, M_Real t, M_Vector2* pt)
+{
+	int k, n;
+	M_Real t1, tt, u;
+	M_PointSet2 b;
+
+	M_PointSetInit2(&b);
+	M_PointSetAlloc2(&b, c->n);
+
+	/* XXX: need to do bounds checking on c */
+
+	n = c->n - 1;
+	u = t;
+	b.p[0].x = c->p[0].x;
+	b.p[0].y = c->p[0].y;
+	for(k =1; k <=n; k++) {
+		b.p[k].x = c->p[k].x *u;
+		b.p[k].y = c->p[k].y *u;
+		u =u*t;
+	};
+
+	pt->x = b.p[n].x;
+	pt->y = b.p[n].y;
+	t1 = 1-t;          tt = t1;
+	for(k =n-1; k >=0; k--) {
+		pt->x += b.p[k].x *tt;
+		pt->y += b.p[k].y *tt;
+		tt =tt*t1;
+	}
+
+	M_PointSetFree2(&b);
+}
+
+/* Return Point pt(t), t <= 0 <= 1 from c, given the number of Points in
+ * control polygon. BezierForm must be called once for any given control
+ * polygon. */
+void M_BezierCurve3(M_PointSet3* c, M_Real t, M_Vector3* pt)
+{
+	int k, n;
+	M_Real t1, tt, u;
+	M_PointSet3 b;
+
+	M_PointSetInit3(&b);
+	M_PointSetAlloc3(&b, c->n);
+
+	/* XXX: need to do bounds checking on c */
+
+	n = c->n - 1;
+	u = t;
+	b.p[0].x = c->p[0].x;
+	b.p[0].y = c->p[0].y;
+	b.p[0].z = c->p[0].z;
+	for(k =1; k <=n; k++) {
+		b.p[k].x = c->p[k].x *u;
+		b.p[k].y = c->p[k].y *u;
+		b.p[k].z = c->p[k].z *u;
+		u =u*t;
+	};
+
+	pt->x = b.p[n].x;
+	pt->y = b.p[n].y;
+	pt->z = b.p[n].z;
+	t1 = 1-t;          tt = t1;
+	for(k =n-1; k >=0; k--) {
+		pt->x += b.p[k].x *tt;
+		pt->y += b.p[k].y *tt;
+		pt->z += b.p[k].z *tt;
+		tt =tt*t1;
+	}
+
+	M_PointSetFree3(&b);
+}
+
diff --git a/math/m_bezier.h b/math/m_bezier.h
new file mode 100644
index 000000000..1b4941273
--- /dev/null
+++ b/math/m_bezier.h
@@ -0,0 +1,11 @@
+/*	Public domain	*/
+
+__BEGIN_DECLS
+
+
+void M_BezierForm2(M_PointSet2*, M_PointSet2*);
+void M_BezierForm3(M_PointSet3* , M_PointSet3*);
+void M_BezierCurve2(M_PointSet2*, M_Real, M_Vector2*);
+void M_BezierCurve3(M_PointSet3*, M_Real, M_Vector3*);
+
+__END_DECLS
diff --git a/math/m_bezier_primitives.c b/math/m_bezier_primitives.c
new file mode 100644
index 000000000..7eb5fa73b
--- /dev/null
+++ b/math/m_bezier_primitives.c
@@ -0,0 +1,82 @@
+/* Copyright (c) Charles A. Daniels <http://cdaniels.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <agar/core/core.h>
+
+#include <agar/math/m.h>
+#include <agar/math/m_bezier.h>
+
+#include <agar/gui/gui.h>
+#include <agar/gui/widget.h>
+#include <agar/gui/primitive.h>
+
+#include <agar/math/m_bezier_primitives.h>
+
+/* Draw a 2 endpoint 2 control point 2D bezier curve. This is a widget drawing
+ * primitive, so it should only be called during Draw().
+ *
+ * Detail specifies the number of line segments to use.
+ * */
+void M_DrawBezier2(AG_Widget* widget,
+		M_Real x1, M_Real y1,		/* start point */
+		M_Real x2, M_Real y2,		/* end point */
+		M_Real cx1, M_Real cy1,		/* control point 1 */
+		M_Real cx2, M_Real cy2,		/* control point 2 */
+		int detail, AG_Color* c
+	)
+{
+	M_PointSet2 points;
+	M_PointSet2 ctrl;
+	M_Vector2 pt;
+	M_Vector2 prev;
+
+	pt.x = 0;
+	pt.y = 0;
+	prev.x = 0;
+	prev.y = 0;
+
+	M_PointSetInit2(&points);
+	M_PointSetInit2(&ctrl);
+	M_PointSetAlloc2(&points, 4);
+	M_PointSetAlloc2(&ctrl, 4);
+
+	M_PointSetAdd2(&points, (M_Vector2) {.x = x1, .y = y1});
+	M_PointSetAdd2(&points, (M_Vector2) {.x = x2, .y = y2});
+	M_PointSetAdd2(&points, (M_Vector2) {.x = cx1, .y = cy1});
+	M_PointSetAdd2(&points, (M_Vector2) {.x = cx2, .y = cy2});
+
+	M_BezierForm2(&points, &ctrl);
+
+	for (int k = 0 ; k < detail ; k++) {
+		prev = pt;
+		M_BezierCurve2(&ctrl, ((float) k) / ((float) detail), &pt);
+		if (k != 0) {
+			AG_DrawLine(widget, prev.x, prev.y, pt.x, pt.y, c);
+		}
+	}
+
+	M_PointSetFree2(&points);
+	M_PointSetFree2(&ctrl);
+
+}
+
diff --git a/math/m_bezier_primitives.h b/math/m_bezier_primitives.h
new file mode 100644
index 000000000..933de8b35
--- /dev/null
+++ b/math/m_bezier_primitives.h
@@ -0,0 +1,17 @@
+/*	Public domain	*/
+
+#ifndef M_BEZIER_PRIMITIVES_H
+#define M_BEZIER_PRIMITIVES_H
+
+#include <agar/math/begin.h>
+
+__BEGIN_DECLS
+
+void M_DrawBezier2(AG_Widget*, M_Real, M_Real, M_Real, M_Real, M_Real, 
+		M_Real, M_Real, M_Real, int, AG_Color*);
+
+__END_DECLS
+
+#include <agar/math/close.h>
+
+#endif /* M_BEZIER_PRIMITIVES_H */
diff --git a/math/m_geometry.h b/math/m_geometry.h
index e76d9afe1..a82162e14 100644
--- a/math/m_geometry.h
+++ b/math/m_geometry.h
@@ -223,6 +223,7 @@ typedef struct m_point_set3i {
 #include <agar/math/m_polygon.h>
 #include <agar/math/m_polyhedron.h>
 #include <agar/math/m_point_set.h>
+#include <agar/math/m_bezier.h>
 
 __BEGIN_DECLS
 
diff --git a/math/m_gui.h b/math/m_gui.h
index 155b56fe1..836d3b647 100644
--- a/math/m_gui.h
+++ b/math/m_gui.h
@@ -50,5 +50,6 @@ __END_DECLS
 
 #include <agar/math/m_plotter.h>
 #include <agar/math/m_matview.h>
+#include <agar/math/m_bezier_primitives.h>
 
 #endif /* _AGAR_MATH_M_GUI_H_ */
diff --git a/tests/Makefile b/tests/Makefile
index 8e196c6cd..436518896 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -24,6 +24,8 @@ SRCS=	agartest.c ${SRCS_EXTRA} \
 	console.c \
 	customwidget.c \
 	customwidget_mywidget.c \
+	bezier.c \
+	bezier_widget.c \
 	fixedres.c \
 	focusing.c \
 	fonts.c \
diff --git a/tests/agartest.c b/tests/agartest.c
index b231efc4a..7502868d6 100644
--- a/tests/agartest.c
+++ b/tests/agartest.c
@@ -71,6 +71,7 @@ extern const AG_TestCase userTest;
 #endif
 extern const AG_TestCase widgetsTest;
 extern const AG_TestCase windowsTest;
+extern const AG_TestCase bezierTest;
 
 const AG_TestCase *testCases[] = {
 #ifdef AG_UNICODE
@@ -128,6 +129,7 @@ const AG_TestCase *testCases[] = {
 #endif
 	&widgetsTest,
 	&windowsTest,
+	&bezierTest,
 	NULL
 };
 
-- 
2.17.1


From 050a3ef840f24bac45e283e1cf693659446ed25e Mon Sep 17 00:00:00 2001
From: Charles Daniels <[email protected]>
Date: Fri, 13 Sep 2019 21:57:40 -0400
Subject: [PATCH 2/2] check in bezier test

---
 tests/bezier.c        |  44 +++++++++
 tests/bezier_widget.c | 206 ++++++++++++++++++++++++++++++++++++++++++
 tests/bezier_widget.h |  27 ++++++
 3 files changed, 277 insertions(+)
 create mode 100644 tests/bezier.c
 create mode 100644 tests/bezier_widget.c
 create mode 100644 tests/bezier_widget.h

diff --git a/tests/bezier.c b/tests/bezier.c
new file mode 100644
index 000000000..c9dac2804
--- /dev/null
+++ b/tests/bezier.c
@@ -0,0 +1,44 @@
+/*	Public domain	*/
+/*
+ * Demonstrate use of M_Bezier to draw a bezier curve.
+ */
+
+#include "agartest.h"
+#include "bezier_widget.h"
+
+static int inited = 0;
+
+static int
+Init(void *obj)
+{
+	if (inited++ == 0) {
+		AG_RegisterClass(&bezierWidgetClass);
+	}
+	return (0);
+}
+
+static int
+TestGUI(void *obj, AG_Window *win)
+{
+	BezierWidget *my;
+
+	my = BezierWidgetNew(win, "foo");
+	my->ti = obj;
+	AG_Expand(my);
+
+	AG_WindowSetGeometryAligned(win, AG_WINDOW_MC, 320, 240);
+	return (0);
+}
+
+const AG_TestCase bezierTest = {
+	"bezierWidget",
+	N_("Test Bezier curve drawing"),
+	"1.6.0",
+	0,
+	sizeof(AG_TestInstance),
+	Init,
+	NULL,		/* destroy */
+	NULL,		/* test */
+	TestGUI,
+	NULL		/* bench */
+};
diff --git a/tests/bezier_widget.c b/tests/bezier_widget.c
new file mode 100644
index 000000000..1297e28c4
--- /dev/null
+++ b/tests/bezier_widget.c
@@ -0,0 +1,206 @@
+/*	Public domain	*/
+
+/*
+ * Implementation of a typical Agar widget which uses surface mappings to
+ * efficiently draw surfaces, regardless of the underlying graphics system.
+ *
+ * If you are not familiar with the way the Agar object system handles
+ * inheritance, see demos/objsystem.
+ */
+
+#include <stdlib.h>
+
+#include "agartest.h"
+#include "bezier_widget.h"
+#include <agar/math.h>
+
+/*
+ * This is a generic constructor function. It is completely optional, but
+ * customary of FooNew() functions to allocate, initialize and attach an
+ * instance of the class.
+ */
+BezierWidget *
+BezierWidgetNew(void *parent, const char *foo)
+{
+	BezierWidget *my;
+
+	/* Create a new instance of the BezierWidget class */
+	my = malloc(sizeof(BezierWidget));
+	AG_ObjectInit(my, &bezierWidgetClass);
+
+	/* Attach the object to the parent (no-op if parent is NULL) */
+	AG_ObjectAttach(parent, my);
+
+	return (my);
+}
+
+/*
+ * This function requests a minimal geometry for displaying the widget.
+ * It is expected to return the width and height in pixels into r.
+ *
+ * Note: Some widgets will provide FooSizeHint() functions to allow the
+ * programmer to request an initial size in pixels or some other metric
+ * FooSizeHint() typically sets some structure variable, which are then
+ * used here.
+ */
+static void
+SizeRequest(void *_Nonnull p, AG_SizeReq *_Nonnull r)
+{
+	BezierWidget *my = p;
+
+	if (my->label == -1) {
+		/*
+		 * We can use AG_TextSize() to return the dimensions of rendered
+		 * text, without rendering it.
+		 */
+		AG_TextSize("Custom widget!", &r->w, &r->h);
+	} else {
+		/*
+		 * We can use the geometry of the rendered surface. The
+		 * AGWIDGET_SURFACE() macro returns the AG_Surface given a
+		 * Widget surface handle.
+		 */
+		r->w = AGWIDGET_SURFACE(my,my->label)->w;
+		r->h = AGWIDGET_SURFACE(my,my->label)->h;
+	}
+}
+
+/*
+ * This function is called by the parent widget after it decided how much
+ * space to allocate to this widget. It is mostly useful to container
+ * widgets, but other widgets generally use it to check if the allocated
+ * geometry can be handled by Draw().
+ */
+static int
+SizeAllocate(void *_Nonnull p, const AG_SizeAlloc *_Nonnull a)
+{
+	BezierWidget *my = p;
+
+	/* If we return -1, Draw() will not be called. */
+	if (a->w < 5 || a->h < 5)
+		return (-1);
+
+	TestMsg(my->ti, "Allocated %dx%d pixels", a->w, a->h);
+	return (0);
+}
+
+/*
+ * Draw function. Invoked from GUI rendering context to draw the widget
+ * at its current location. All primitive and surface operations operate
+ * on widget coordinates.
+ */
+static void
+Draw(void *_Nonnull p)
+{
+	BezierWidget *my = p;
+	const int x = my->x;
+	const int y = my->y;
+	AG_Color c;
+	AG_Rect r;
+
+	/*
+	 * Draw a box spanning the widget area. Use the widget's
+	 * default color (the "color" style property).
+	 */
+	r.x = 0;
+	r.y = 0;
+	r.w = AGWIDGET(my)->w;
+	r.h = AGWIDGET(my)->h;
+	AG_DrawBox(my, &r, 1, &AG_WCOLOR(my,0));
+
+	if (my->label == -1) {
+		AG_TextFontPct(500);
+		my->label = AG_WidgetMapSurface(my,
+		    AG_TextRenderF("%s", "M_Bezier2 test"));
+	}
+
+	AG_ColorRGB_8(&c, 250,250,0);
+
+	/* Establish a clipping rectangle over the entire widget area. */
+	AG_PushClipRect(my, &r);
+
+	M_DrawBezier2(AGWIDGET(my),
+			100, 20,
+			120, 40,
+			140, 25,
+			160, 20,
+			20, &c);
+
+	M_DrawBezier2(AGWIDGET(my),
+			200, 200,
+			120, 40,
+			140, 300,
+			160, 20,
+			20, &c);
+
+	M_DrawBezier2(AGWIDGET(my),
+			100, 200,
+			120, 200,
+			40, 300,
+			160, 20,
+			20, &c);
+
+	M_DrawBezier2(AGWIDGET(my),
+			30, 10,
+			43, 34,
+			40, 134,
+			160, 212,
+			5, &c);
+
+	AG_PopClipRect(my);
+}
+
+
+/*
+ * Initialization routine. Note that the object system will automatically
+ * invoke the initialization routines of the parent classes first.
+ */
+static void
+Init(void *_Nonnull obj)
+{
+	BezierWidget *my = obj;
+
+	/*
+	 * May grab focus. Receive mousemotion events even if unfocused.
+	 * Use the font engine (AG_TextRender() will be needed).
+	 * Generate mouseover events.
+	 */
+	AGWIDGET(my)->flags |= (AG_WIDGET_FOCUSABLE | AG_WIDGET_UNFOCUSED_MOTION |
+	                        AG_WIDGET_USE_TEXT | AG_WIDGET_USE_MOUSEOVER);
+
+	/* Initialize instance variables. */
+	my->foo = "";
+	my->x = 0;
+	my->y = 0;
+	my->radius = 5;
+	my->lastKey = 'X';
+
+	/*
+	 * We'll eventually need to create and map a surface, but we cannot
+	 * do this from Init(), because it involves texture operations in
+	 * GL mode which are thread-unsafe. We wait until Draw() to do that.
+	 */
+	my->label = -1;
+
+}
+
+/*
+ * This structure describes our widget class. It inherits from AG_ObjectClass.
+ * Any of the function members may be NULL. See AG_Widget(3) for details.
+ */
+AG_WidgetClass bezierWidgetClass = {
+	{
+		"AG_Widget:BezierWidget",	/* Name of class */
+		sizeof(BezierWidget),	/* Size of structure */
+		{ 0,0 },		/* Version for load/save */
+		Init,			/* Initialize dataset */
+		NULL,			/* Free dataset */
+		NULL,			/* Destroy widget */
+		NULL,			/* Load widget (for GUI builder) */
+		NULL,			/* Save widget (for GUI builder) */
+		NULL			/* Edit (for GUI builder) */
+	},
+	Draw,				/* Render widget */
+	SizeRequest,			/* Default size requisition */
+	SizeAllocate			/* Size allocation callback */
+};
diff --git a/tests/bezier_widget.h b/tests/bezier_widget.h
new file mode 100644
index 000000000..cd2368a09
--- /dev/null
+++ b/tests/bezier_widget.h
@@ -0,0 +1,27 @@
+/*	Public domain	*/
+
+/* Structure describing an instance of the BezierWidget class. */
+typedef struct bezier_widget {
+	struct ag_widget _inherit;	/* Inherit from AG_Widget */
+	void *ti;			/* Agar test instance (for agartest) */
+	int label;			/* Surface handle */
+	const char *foo;		/* Some parameter */
+	int x, y;			/* Last mouse coordinates */
+	int radius;			/* Circle radius */
+	AG_KeySym lastKey;		/* Last key pressed */
+	AG_Char   lastUnicode;		/* Last key (in Unicode) */
+	AG_Timer  clickTimer;		/* Timer for mousebuttondown */
+} BezierWidget;
+
+/* Accessor macros */
+#define MYWIDGET(obj)           ((BezierWidget *)(obj))
+#define MYCWIDGET(obj)          ((const BezierWidget *)(obj))
+#define MYWIDGET_SELF()          MYWIDGET( AG_OBJECT(0,"AG_Widget:BezierWidget:*") )
+#define MYWIDGET_PTR(n)          MYWIDGET( AG_OBJECT((n),"AG_Widget:BezierWidget:*") )
+#define MYWIDGET_NAMED(n)        MYWIDGET( AG_OBJECT_NAMED((n),"AG_Widget:BezierWidget:*") )
+#define CONST_MYWIDGET_SELF()   MYCWIDGET( AG_CONST_OBJECT(0,"AG_Widget:BezierWidget:*") )
+#define CONST_MYWIDGET_PTR(n)   MYCWIDGET( AG_CONST_OBJECT((n),"AG_Widget:BezierWidget:*") )
+#define CONST_MYWIDGET_NAMED(n) MYCWIDGET( AG_CONST_OBJECT_NAMED((n),"AG_Widget:BezierWidget:*") )
+
+extern AG_WidgetClass bezierWidgetClass;
+BezierWidget *BezierWidgetNew(void *, const char *);
-- 
2.17.1

_______________________________________________
Agar mailing list
[email protected]
http://libagar.org/lists.html

Reply via email to