]> Pileus Git - grits/blob - src/objects/grits-poly.c
Fix extra mouse-over bug
[grits] / src / objects / grits-poly.c
1 /*
2  * Copyright (C) 2010-2011 Andy Spencer <andy753421@gmail.com>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 /**
19  * SECTION:grits-poly
20  * @short_description: Single point polys
21  *
22  * Each #GritsPoly represents a 3 dimentional polygon.
23  */
24
25 #include <config.h>
26 #include <GL/gl.h>
27 #include <GL/glu.h>
28 #include "grits-poly.h"
29
30 /* Drawing */
31 static void grits_poly_tess(gdouble (**points)[3])
32 {
33         //g_debug("GritsPoly: tess");
34         GLUtesselator *tess = gluNewTess();
35         gluTessCallback(tess, GLU_TESS_BEGIN,  (_GLUfuncptr)glBegin);
36         gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)glVertex3dv);
37         gluTessCallback(tess, GLU_TESS_END,    (_GLUfuncptr)glEnd);
38         for (int pi = 0; points[pi]; pi++) {
39                 gluTessBeginPolygon(tess, NULL);
40                 gluTessBeginContour(tess);
41                 for (int ci = 0; points[pi][ci][0]; ci++) {
42                         gluTessVertex(tess,
43                                 points[pi][ci],
44                                 points[pi][ci]);
45                 }
46                 gluTessEndContour(tess);
47                 gluTessEndPolygon(tess);
48         }
49         gluDeleteTess(tess);
50 }
51
52 static void grits_poly_outline(gdouble (**points)[3])
53 {
54         //g_debug("GritsPoly: outline");
55         for (int pi = 0; points[pi]; pi++) {
56                 glBegin(GL_POLYGON);
57                 for (int ci = 0; points[pi][ci][0] &&
58                                  points[pi][ci][1] &&
59                                  points[pi][ci][2]; ci++)
60                         glVertex3dv(points[pi][ci]);
61                 glEnd();
62         }
63 }
64
65 static gboolean grits_poly_runlist(GritsPoly *poly, int i,
66                 void (*render)(gdouble(**)[3]))
67 {
68         //g_debug("GritsPoly: genlist");
69         if (poly->list[i]) {
70                 glCallList(poly->list[i]);
71         } else {
72                 guint list = glGenLists(1);
73                 glNewList(list, GL_COMPILE_AND_EXECUTE);
74                 render(poly->points);
75                 glEndList();
76                 poly->list[i] = list;
77         }
78         return FALSE;
79 }
80
81 static void grits_poly_draw(GritsObject *_poly, GritsOpenGL *opengl)
82 {
83         //g_debug("GritsPoly: draw");
84         GritsPoly *poly = GRITS_POLY(_poly);
85
86         glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_CURRENT_BIT |
87                         GL_POINT_BIT | GL_LINE_BIT | GL_POLYGON_BIT);
88         glDisable(GL_TEXTURE_2D);
89         glDisable(GL_ALPHA_TEST);
90         glDisable(GL_CULL_FACE);
91         glDisable(GL_LIGHTING);
92
93         glEnable(GL_POLYGON_OFFSET_FILL);
94         glEnable(GL_POLYGON_OFFSET_LINE);
95         glEnable(GL_POLYGON_OFFSET_POINT);
96
97         if (poly->color[3]) {
98                 /* Draw background farthest back */
99                 glPolygonOffset(3, 3);
100                 glColor4dv(poly->color);
101                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
102                 grits_poly_runlist(poly, 0, grits_poly_tess);
103         }
104
105         glEnable(GL_POLYGON_SMOOTH);
106         glEnable(GL_LINE_SMOOTH);
107         glEnable(GL_POINT_SMOOTH);
108
109         if (!poly->color[3] && poly->border[3] && poly->width > 1) {
110                 /* Draw line border in the middle */
111                 glColor4d(0,0,0,1);
112
113                 glPointSize(poly->width*2);
114                 glLineWidth(poly->width*2);
115
116                 glPolygonOffset(2, 2);
117
118                 glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
119                 grits_poly_runlist(poly, 1, grits_poly_outline);
120                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
121                 grits_poly_runlist(poly, 1, grits_poly_outline);
122         }
123
124         if (poly->border[3]) {
125                 /* Draw border front-most */
126                 glColor4dv(poly->border);
127
128                 glPointSize(poly->width);
129                 glLineWidth(poly->width);
130
131                 glPolygonOffset(1, 1);
132                 if (poly->width > 1) {
133                         glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
134                         grits_poly_runlist(poly, 1, grits_poly_outline);
135                 }
136                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
137                 grits_poly_runlist(poly, 1, grits_poly_outline);
138         }
139
140         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
141         glPopAttrib();
142 }
143
144 static void grits_poly_pick(GritsObject *_poly, GritsOpenGL *opengl)
145 {
146         //g_debug("GritsPoly: pick");
147         GritsPoly *poly = GRITS_POLY(_poly);
148         glPushAttrib(GL_ENABLE_BIT);
149         glDisable(GL_CULL_FACE);
150         grits_poly_runlist(poly, 0, grits_poly_tess);
151         glPopAttrib();
152 }
153
154 static gboolean grits_poly_delete(gpointer list)
155 {
156         glDeleteLists((guint)list, 1);
157         return FALSE;
158 }
159
160 /**
161  * grits_poly_new:
162  * @points:  TODO
163  * @npoints: TODO
164  *
165  * Create a new GritsPoly which TODO.
166  *
167  * Returns: the new #GritsPoly.
168  */
169 GritsPoly *grits_poly_new(gdouble (**points)[3])
170 {
171         //g_debug("GritsPoly: new - %p", points);
172         GritsPoly *poly = g_object_new(GRITS_TYPE_POLY, NULL);
173         poly->points    = points;
174         return poly;
175 }
176
177 static void _free_points(gdouble (**points)[3])
178 {
179         for (int i = 0; points[i]; i++)
180                 g_free(points[i]);
181         g_free(points);
182 }
183
184 GritsPoly *grits_poly_parse(const gchar *str,
185                 const gchar *poly_sep, const gchar *point_sep, const gchar *coord_sep)
186 {
187         /* Split and count polygons */
188         gchar **spolys = g_strsplit(str, poly_sep, -1);
189         int     npolys = g_strv_length(spolys);
190
191         GritsBounds bounds = {-90, 90, -180, 180};
192         gdouble (**polys)[3] = (gpointer)g_new0(double*, npolys+1);
193         for (int pi = 0; pi < npolys; pi++) {
194                 /* Split and count coordinates */
195                 gchar **scoords = g_strsplit(spolys[pi], point_sep, -1);
196                 int     ncoords = g_strv_length(scoords);
197
198                 /* Create binary coords */
199                 gdouble (*coords)[3] = (gpointer)g_new0(gdouble, 3*(ncoords+1));
200                 for (int ci = 0; ci < ncoords; ci++) {
201                         gdouble lat, lon;
202                         sscanf(scoords[ci], "%lf,%lf", &lat, &lon);
203                         if (lat > bounds.n) bounds.n = lat;
204                         if (lat < bounds.s) bounds.s = lat;
205                         if (lon > bounds.e) bounds.e = lon;
206                         if (lon < bounds.w) bounds.w = lon;
207                         lle2xyz(lat, lon, 0,
208                                         &coords[ci][0],
209                                         &coords[ci][1],
210                                         &coords[ci][2]);
211                 }
212
213                 /* Insert coords into poly array */
214                 polys[pi] = coords;
215                 g_strfreev(scoords);
216         }
217         g_strfreev(spolys);
218
219         /* Create GritsPoly */
220         GritsPoly *poly = grits_poly_new(polys);
221         GRITS_OBJECT(poly)->center.lat  = (bounds.n + bounds.s)/2;
222         GRITS_OBJECT(poly)->center.lon  = lon_avg(bounds.e, bounds.w);
223         GRITS_OBJECT(poly)->center.elev = 0;
224         GRITS_OBJECT(poly)->skip        = GRITS_SKIP_CENTER;
225         g_object_weak_ref(G_OBJECT(poly), (GWeakNotify)_free_points, polys);
226         return poly;
227 }
228
229 /* GObject code */
230 G_DEFINE_TYPE(GritsPoly, grits_poly, GRITS_TYPE_OBJECT);
231 static void grits_poly_init(GritsPoly *poly)
232 {
233         poly->border[0] = 1;
234         poly->border[1] = 1;
235         poly->border[2] = 1;
236         poly->border[3] = 0.2;
237         poly->width     = 1;
238         GRITS_OBJECT(poly)->skip = GRITS_SKIP_STATE;
239 }
240
241 static void grits_poly_finalize(GObject *_poly)
242 {
243         //g_debug("GritsPoly: finalize");
244         GritsPoly *poly = GRITS_POLY(_poly);
245         if (poly->list[0]) g_idle_add(grits_poly_delete, (gpointer)poly->list[0]);
246         if (poly->list[1]) g_idle_add(grits_poly_delete, (gpointer)poly->list[1]);
247 }
248
249 static void grits_poly_class_init(GritsPolyClass *klass)
250 {
251         g_debug("GritsPoly: class_init");
252         GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
253         gobject_class->finalize = grits_poly_finalize;
254
255         GritsObjectClass *object_class = GRITS_OBJECT_CLASS(klass);
256         object_class->draw = grits_poly_draw;
257         object_class->pick = grits_poly_pick;
258 }