1Tessellation(3) User Contributed Perl Documentation Tessellation(3)
2
3
4
6 OpenGL::Tessellation - discussion of tessellation in POGL
7
9 # somewhere in your drawing routine or drawlist compilation
10
11 my $tess = gluNewTess();
12
13 gluTessCallback($tess, GLU_TESS_BEGIN, 'DEFAULT');
14 gluTessCallback($tess, GLU_TESS_END, 'DEFAULT');
15 gluTessCallback($tess, GLU_TESS_VERTEX, 'DEFAULT');
16 gluTessCallback($tess, GLU_TESS_COMBINE, 'DEFAULT');
17 gluTessCallback($tess, GLU_TESS_ERROR, 'DEFAULT');
18 gluTessCallback($tess, GLU_TESS_EDGE_FLAG, 'DEFAULT');
19
20 gluTessBeginPolygon($tess);
21 gluTessBeginContour($tess);
22
23 gluTessVertex_p($tess, 0, 200, 0);
24 gluTessVertex_p($tess, 150, -200, 0);
25 gluTessVertex_p($tess, 0, -100, 0);
26 gluTessVertex_p($tess, -150, -200, 0);
27
28 gluTessEndContour($tess);
29 gluTessEndPolygon($tess);
30
31 gluDeleteTess($tess);
32
34 OpenGL rendering hardware typically does not have support for drawing
35 concave polygons or drawing polygons with windows. OpenGL provides glu
36 extentions that allow for translating concave polygon vertices into
37 triangles that can be rendered quickly on GL hardware. The OpenGL red
38 book chapter 11 has the full discussion of Tessellators and the OpenGL
39 functions (http://glprogramming.com/red/chapter11.html, or use your
40 favorite search engine and search for "opengl gluNewTess"). It is a
41 good idea to read that chapter before reading the rest of this
42 document.
43
44 As much as possible, the POGL implementation of the tessellation
45 functions tries to remain faithful to the OpenGL specification. Where
46 it doesn't match exactly, POGL follows the spirit of the specification,
47 but offloads what it can to c based implementations.
48
49 Tessellation functions are safe to call during drawlist creation. It
50 is advisable to use drawlists, or to store the generated polygon data
51 into OpenGL::Array objects as these methods offer faster redraws.
52
54 "gluNewTess"
55 my $tess = gluNewTess();
56
57 Returns a reference that can be passed to the remaining tesselation
58 functions.
59
60 Note: this isn't the c-reference returned by the normal
61 gluNewTess() c function, it is a struct which contains that
62 reference as well as other members allowing callbacks to interface
63 cleanly with the perl code. This means that if you have loaded
64 other c-libraries that use standard opengl tessellation, you will
65 not be able to use this perl reference directly.
66
67 The POGL implementation of gluNewTess() allows for two additional
68 parameters to be passed. The first is a boolean value indicating
69 that default c callbacks and perl callbacks should be passed rgba
70 color data. The second is a boolean value indicating that xyz
71 normal data should be passed. Eventually one additional flag
72 indicating that texture data should be passed will be added as
73 well.
74
75 my $tess = gluNewTess();
76 # gluTessVertex_p should be passed only x,y,z vertex data
77 # as in gluTessVertex_p($tess, $x, $y, $z);
78
79 my $tess = gluNewTess('do_colors');
80 # gluTessVertex_p should be passed x,y,z AND r,g,b,a vertex data
81 # as in gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a);
82
83 my $tess = gluNewTess('do_colors', 'do_normals');
84 # gluTessVertex_p should be passed x,y,z AND r,g,b,a AND nx,ny,nz vertex data
85 # as in gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a, $nx, $ny, $nz);
86
87 my $tess = gluNewTess(undef, 'do_normals');
88 # gluTessVertex_p should be passed x,y,z AND nx,ny,nz vertex data (no colors)
89 # as in gluTessVertex_p($tess, $x, $y, $z, $nx, $ny, $nz);
90
91 Any true value can be passed in place of 'do_colors' and
92 'do_normals' though using 'do_colors' and 'do_normals' acts as
93 documentation.
94
95 Behavior in these modes will be discussed further for functions to
96 which they apply.
97
98 "gluDeleteTess"
99 gluDeleteTess($tess);
100
101 This deletes the tessellation structure and frees up any remaining
102 associated memory.
103
104 "gluTessCallback"
105 gluTessCallback($tess, GLU_TESS_BEGIN, 'DEFAULT');
106
107 gluTessCallback($tess, GLU_TESS_BEGIN, \&glBegin);
108
109 gluTessCallback($tess, GLU_TESS_BEGIN, sub { my $enum = shift; glBegin($enum) });
110
111 gluTessCallback($tess, GLU_TESS_BEGIN); # unsets current handler
112
113 Registers handlers for each of the tessellation callback types.
114 Takes a tessellation reference generated by gluNewTess, a type, and
115 a coderef or the word 'DEFAULT'. If the word 'DEFAULT' is passed,
116 a default c-level callback will be installed (which will be
117 discussed for each callback). If no 3rd argument is given, then
118 any handler currently set will be removed. Valid callback types
119 are
120
121 GLU_TESS_BEGIN
122 GLU_TESS_END
123 GLU_TESS_VERTEX
124 GLU_TESS_COMBINE
125 GLU_TESS_ERROR
126 GLU_TESS_EDGE_FLAG
127
128 GLU_TESS_BEGIN_DATA
129 GLU_TESS_END_DATA
130 GLU_TESS_VERTEX_DATA
131 GLU_TESS_COMBINE_DATA
132 GLU_TESS_ERROR_DATA
133 GLU_TESS_EDGE_FLAG_DATA
134
135 These types and their passed parameters will be discussed in the
136 CALLBACKS section.
137
138 The types ending with "_DATA" are similar to their non-_DATA
139 counterpart, but when called are passed the option $polygon_data
140 that can be set during gluTessBeginPolygon.
141
142 "gluTessBeginPolygon"
143 gluTessBeginPolygon($tess);
144
145 gluTessBeginPolygon($tess, $polygon_data);
146
147 Begins the tessellation transaction. It must eventually be ended
148 with a gluTessEndPolygon before the tessellator will normally begin
149 work.
150
151 An optional second argument can be passed which can be any perl
152 scalar or reference. If a callback is registered using a type
153 ending in _DATA, this perl scalar or reference will be passed as an
154 additional argument to that callback.
155
156 gluTessCallback($tess, GLU_TESS_END_DATA, sub {
157 my $polygon_data = shift;
158 glEnd();
159 print "glEnd: (".($polygon_data->[2] eq 8 ? "YES" : "NO").")\n";
160 });
161
162 gluTessBeginPoly($tess, [6,7,8]); # arrayref will be passed to _DATA callbacks
163
164 A sample Object Oriented tesselation sample listed at the end of
165 this document makes use of this "opaque" polygon data.
166
167 "gluTessEndPolygon"
168 gluTessEndPolygon($tess);
169
170 Finishes the tessellation transaction, which normally will
171 immediately fire the necessary callbacks generated by the
172 tessellation process. Once finished, it cleans up any accumulated
173 temporary vertice data.
174
175 "gluTessBeginContour"
176 gluTessBeginContour($tess);
177
178 Starts a new contour of the tessellation of the current polygon.
179 Please read the OpenGL documentation, and red book chapter on
180 tessellation for more help on when to use different contours.
181 Should eventually be followed by a gluTessEndContour call.
182
183 (At a high level, tessellated polygons may have windows and
184 multiple separate portions. Each inner and outer border of these
185 portions should be represented by a different contour.)
186
187 "gluTessVertex_p"
188 gluTessVertex_p($tess, $x, $y, $z);
189
190 gluTessVertex_p($tess, $x, $y, $z, $vertex_data);
191
192 Adds a vertex to the current contour of the current polygon being
193 tessellated.
194
195 If the vertex callback type is set to GLU_TESS_VERTEX, the optional
196 $vertex_data argument will be passed to the vertex callback, and to
197 the combine callback (if GLU_TESS_VERTEX_DATA is used, then the
198 $polygon_data passed to gluTessBeginPolygon will be passed
199 instead). This optional opaque vertex data can be any perl scalar
200 or reference and can be used to pass useful information along
201 during the tessellation process.
202
203 If the 'do_colors' or 'do_normals' parameters were passed to
204 gluNewTess, then those additional properties MUST be passed as
205 additional arguments.
206
207 # my $tess = gluNewTess('do_colors');
208 gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a);
209 gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a, $vertex_data);
210
211 # my $tess = gluNewTess('do_colors', 'do_normals');
212 gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a, $nx, $ny, $nz);
213 gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a, $nx, $ny, $nz, $vertex_data);
214
215 # my $tess = gluNewTess(undef, 'do_normals');
216 gluTessVertex_p($tess, $x, $y, $z, $nx, $ny, $nz);
217 gluTessVertex_p($tess, $x, $y, $z, $nx, $ny, $nz, $vertex_data);
218
220 All of the callbacks support a 'DEFAULT' handler that can be installed
221 by passing the word 'DEFAULT' in place of the callback code reference.
222 The DEFAULT c implementations are there to avoid needing to round trip
223 out to perl. The defaults employed are described for each of the
224 callback types.
225
226 With the exception of the COMBINE callback, return values from
227 callbacks are discarded.
228
229 "GLU_TESS_BEGIN"
230 gluTessCallback($tess, GLU_TESS_BEGIN, 'DEFAULT');
231
232 gluTessCallback($tess, GLU_TESS_BEGIN, \&glBegin);
233
234 gluTessCallback($tess, GLU_TESS_BEGIN, sub {
235 my $enum = shift;
236 glBegin($enum);
237 });
238
239 The 'DEFAULT' option installs a c-handler that calls the glBegin c
240 function directly without round-tripping out to perl.
241
242 If $polygon_data was set during gluTessBeginPolygon, it is
243 discarded.
244
245 "GLU_TESS_BEGIN_DATA"
246 Similar to GLU_TESS_BEGIN but will be passed optional $polygon_data
247 set in gluTessBeginPolygon if any. The 'DEFAULT' handler will
248 ignore this data.
249
250 gluTessCallback($tess, GLU_TESS_BEGIN_DATA, sub {
251 my ($enum, $polygon_data) = @_;
252 glBegin($enum);
253 print "glBegin - and I received polygon_data\n" if $polygon_data;
254 });
255
256 "GLU_TESS_END"
257 gluTessCallback($tess, GLU_TESS_END, 'DEFAULT');
258
259 gluTessCallback($tess, GLU_TESS_END, \&glEnd);
260
261 gluTessCallback($tess, GLU_TESS_END, sub { glEnd() });
262
263 The 'DEFAULT' option installs a c-handler that calls the glEnd c
264 function directly without round-tripping out to perl.
265
266 If $polygon_data was set during gluTessBeginPolygon, it is
267 discarded.
268
269 "GLU_TESS_END_DATA"
270 Similar to GLU_TESS_END but will be passed optional $polygon_data
271 set in gluTessBeginPolygon if any. The 'DEFAULT' handler will
272 ignore this data.
273
274 gluTessCallback($tess, GLU_TESS_END_DATA, sub {
275 my ($polygon_data) = @_;
276 glEnd();
277 print "glEnd - and I received polygon_data\n" if $polygon_data;
278 });
279
280 "GLU_TESS_VERTEX"
281 The GLU_TESS_VERTEX callback handler has slightly different
282 behavior depending on how gluNewTess was called. The optional
283 behaviors allow for sane default processing of colors and normals
284 without needing to roundtrip out to perl.
285
286 my $tess = gluNewTess();
287
288 gluTessCallback($tess, GLU_TESS_VERTEX, 'DEFAULT');
289
290 # the following will break if vertex_data is passed to gluTessVertex_p
291 gluTessCallback($tess, GLU_TESS_VERTEX, \&glVertex3f);
292
293 gluTessCallback($tess, GLU_TESS_VERTEX, sub {
294 my ($x, $y, $z) = @_;
295 glVertex3f($x, $y, $z);
296 });
297
298 # you can also pass vertex_data to gluTessVertex_p
299 gluTessCallback($tess, GLU_TESS_VERTEX, sub {
300 my ($x, $y, $z, $vertex_data) = @_;
301 glVertex3f($x, $y, $z);
302 print "glVertex - and I received vertex_data\n" if $vertex_data;
303 });
304
305 The 'DEFAULT' option installs a c-handler that calls the glVertex c
306 function directly without round-tripping out to perl. The DEFAULT
307 handler discards any polygon_data or vertex_data.
308
309 IF $vertex_data was set during gluTessVertex_p it will be passed as
310 the final argument.
311
312 If gluNewTess was passed 'do_colors' then the GLU_TESS_VERTEX
313 callback will also be passed the rgba information. The 'DEFAULT'
314 option will pass the color information to glColor4f before calling
315 glVertex3f.
316
317 my $tess = gluNewTess('do_colors');
318
319 gluTessCallback($tess, GLU_TESS_VERTEX, sub {
320 my ($x, $y, $z, $r, $g, $b, $a, $vertex_data) = @_;
321 glColor4f($r, $g, $b, $a);
322 glVertex3f($x, $y, $z);
323 });
324
325 If gluNewTess was passed 'do_normals' then the GLU_TESS_VERTEX
326 callback will also be passed the normal x,y,z information. The
327 'DEFAULT' option will pass the normal information to glNormal3f
328 before calling glVertex3f.
329
330 my $tess = gluNewTess('do_colors', 'do_normals');
331
332 gluTessCallback($tess, GLU_TESS_VERTEX, sub {
333 my ($x, $y, $z, $r, $g, $b, $a, $nx, $ny, $nz, $vertex_data) = @_;
334 glColor4f($r, $g, $b, $a);
335 glNormalf($nx, $ny, $nz);
336 glVertex3f($x, $y, $z);
337 });
338
339 # OR
340
341 my $tess = gluNewTess(undef, 'do_normals');
342
343 gluTessCallback($tess, GLU_TESS_VERTEX, sub {
344 my ($x, $y, $z, $nx, $ny, $nz, $vertex_data) = @_;
345 glNormalf($nx, $ny, $nz);
346 glVertex3f($x, $y, $z);
347 });
348
349 In all cases, any optional vertex_data will be passed as the final
350 argument.
351
352 "GLU_TESS_VERTEX_DATA"
353 Similar to GLU_TESS_VERTEX but will be passed optional
354 $polygon_data set in gluTessBeginPolygon (if any) rather than the
355 optional $vertex_data passed to gluTessVertex_p. The 'DEFAULT'
356 handler will ignore this data.
357
358 gluTessCallback($tess, GLU_TESS_VERTEX_DATA, sub {
359 my ($x, $y, $z, $vertex_data) = @_;
360 glVertex3f($x, $y, $z);
361 print "glVertex - and I received vertex_data\n" if $vertex_data;
362 });
363
364 "GLU_TESS_COMBINE"
365 gluTessCallback($tess, GLU_TESS_COMBINE, 'DEFAULT');
366 # works with gluTessCallback($tess, GLU_TESS_VERTEX, 'DEFAULT');
367
368
369 # OR
370
371
372 # the following callback is valid for gluNewTess() (no do_colors or do_normals)
373 # using gluTessVertex_p($tess, $x, $y, $z);
374 my $tess = gluNewTess();
375 gluTessCallback($tess, GLU_TESS_COMBINE, sub {
376 my ($x, $y, $z, # new vertex location
377 $v0, $v1, $v2, $v3, # border vertex arrayrefs
378 $w0, $w1, $w2, $w3, # border vertex weights
379 $polygon_data) = @_; # optional data passed to gluTessBeginPolygon
380 return ($x, $y, $z);
381 });
382 # works with gluTessCallback($tess, GLU_TESS_VERTEX, 'DEFAULT');
383
384
385 # OR
386
387
388 # the following callback is valid for gluNewTess() when vertex data is passed
389 # using gluTessVertex_p($tess, $x, $y, $z, [$r, $g, $b, $a]);
390 # The DEFAULT callback cannot automatically proceess this type of data
391 # but passing data to a custom handler this way could handle any arbitrary data passed to it
392 my $tess = gluNewTess();
393 use constant _r => 0;
394 use constant _g => 1;
395 use constant _b => 2;
396 use constant _a => 3;
397 gluTessCallback($tess, GLU_TESS_COMBINE, sub {
398 my ($x, $y, $z, # new vertex location
399 $v0, $v1, $v2, $v3, # border vertex arrayrefs
400 $w0, $w1, $w2, $w3, # border vertex weights
401 $polygon_data) = @_; # optional data passed to gluTessBeginPolygon
402
403 # $v0 will contain [$x, $y, $z, [$r, $g, $b, $a]]
404 my @rgba = map {$_->[3]} $v0, $v1, $v2, $v3;
405
406 # generate a point with color weighted from the surrounding vertices
407 # then return that color information in the same way we received it (an rgba arrayref)
408 return (
409 $x, $y, $z,
410 [$w0*$rgba[0]->[_r] + $w1*$rgba[1]->[_r] + $w2*$rgba[2]->[_r] + $w3*$rgba[3]->[_r],
411 $w0*$rgba[0]->[_g] + $w1*$rgba[1]->[_g] + $w2*$rgba[2]->[_g] + $w3*$rgba[3]->[_g],
412 $w0*$rgba[0]->[_b] + $w1*$rgba[1]->[_b] + $w2*$rgba[2]->[_b] + $w3*$rgba[3]->[_b],
413 $w0*$rgba[0]->[_a] + $w1*$rgba[1]->[_a] + $w2*$rgba[2]->[_a] + $w3*$rgba[3]->[_a]],
414 );
415 });
416 # works with gluTessCallback($tess, GLU_TESS_VERTEX, sub {
417 # my ($x, $y, $z, $rgba) = @_;
418 # glColor4f(@$rgba);
419 # glVertex3f($x, $y, $z);
420 # });
421
422
423 # OR
424
425
426 # the following callback is valid for gluNewTess('do_colors')
427 # using gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a);
428 # the DEFAULT callback COULD automatically proceess this type of data as well if additional vertex data is not passed
429 my $tess = gluNewTess('do_colors');
430 use constant _r => 3;
431 use constant _g => 4;
432 use constant _b => 5;
433 use constant _a => 6;
434 gluTessCallback($tess, GLU_TESS_COMBINE, sub {
435 my ($x, $y, $z, # new vertex location
436 $v0, $v1, $v2, $v3, # border vertex arrayrefs
437 $w0, $w1, $w2, $w3, # border vertex weights
438 $polygon_data) = @_; # optional data passed to gluTessBeginPolygon
439
440 # $v0 will contain [$x, $y, $z, $r, $g, $b, $a]
441
442 return ( # generate a point with color weighted from the surrounding vertices
443 $x, $y, $z,
444 $w0*$v0->[_r] + $w1*$v1->[_r] + $w2*$v2->[_r] + $w3*$v3->[_r],
445 $w0*$v0->[_g] + $w1*$v1->[_g] + $w2*$v2->[_g] + $w3*$v3->[_g],
446 $w0*$v0->[_b] + $w1*$v1->[_b] + $w2*$v2->[_b] + $w3*$v3->[_b],
447 $w0*$v0->[_a] + $w1*$v1->[_a] + $w2*$v2->[_a] + $w3*$v3->[_a],
448 ($v0->[7] || $v1->[7] || $v2->[7] || $v3->[7]), # if we received vertex data - return some for the new vertex
449 );
450 });
451 # works with gluTessCallback($tess, GLU_TESS_VERTEX, 'DEFAULT');
452 # OR
453 # works with gluTessCallback($tess, GLU_TESS_VERTEX, sub {
454 # my ($x, $y, $z, $r, $g, $b, $a, $vertex_data) = @_;
455 # glColor4f($r, $g, $b, $a);
456 # glVertex3f($x, $y, $z);
457 # });
458
459 The combine callback is called if the tessellator decides a new
460 vertex is needed. This will happen with self intersecting
461 polygons. In this case, the COMBINE callback can be used to
462 interpolate appropriate values for normals, and colors, or for any
463 desired information.
464
465 The combine callback will be passed the following:
466
467 "$x, $y, $z"
468 The x y and z coordinates of the new vertex being created.
469
470 "$v0, $v1, $v2, $v3"
471 Arrayrefs of vertex information for the vertices bordering this
472 new vertex (the ones that caused the new vertex to be created).
473
474 By default if gluNewTess() is called, these arrayrefs will be
475 passed:
476
477 my ($x, $y, $z, $vertex_data) = @$v0;
478 # received from gluTessVertex_p($tess, $x, $y, $z, $vertex_data);
479
480 If gluNewTess('do_colors') is called, the following will be
481 passed:
482
483 my ($x, $y, $z, $r, $g, $b, $a, $vertex_data) = @$v0;
484 # received from gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a, $vertex_data);
485
486 If gluNewTess('do_colors', 'do_normals') is called, the
487 following will be passed:
488
489 my ($x, $y, $z, $r, $g, $b, $a, $nx, $ny, $nz, $vertex_data) = @$v0;
490 # received from gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a, $nx, $ny, $nz, $vertex_data);
491
492 If gluNewTess(undef, 'do_normals') is called, the following
493 will be passed:
494
495 my ($x, $y, $z, $nx, $ny, $nz, $vertex_data) = @$v0;
496 # received from gluTessVertex_p($tess, $x, $y, $z, $nx, $ny, $nz, $vertex_data);
497
498 In all cases, the data returned by the COMBINE callback should
499 be in the same format that each of the vertices are in when
500 passed into the COMBINE callback.
501
502 "$w0, $w1, $w2, $w3"
503 Weights of the participating vertices (weight $w0 corresponds
504 to vertex $v0).
505
506 "optional $polygon_data"
507 Any optional data passed to gluTessBeginPolygon. Normally this
508 would only be passed to GLU_TESS_COMBINE_DATA, but
509 GLU_TESS_COMBINE_DATA and GLU_TESS_COMBINE share the same code
510 implementation.
511
512 "GLU_TESS_COMBINE_DATA"
513 Identical in function to the GLU_TESS_COMBINE handler. They use
514 the same callback implementation.
515
516 "GLU_TESS_ERROR"
517 gluTessCallback($tess, GLU_TESS_ERROR, 'DEFAULT');
518
519 gluTessCallback($tess, GLU_TESS_ERROR, \&glEdgeFlag);
520
521 gluTessCallback($tess, GLU_TESS_ERROR, sub {
522 my $errno = shift;
523 my $err = gluErrorString($errno);
524 warn "Received a glu tess error ($errno - $err)\n";
525 });
526
527 The 'DEFAULT' option installs a c-handler that warns with the
528 appropriate gluErrorString.
529
530 If $polygon_data was set during gluTessBeginPolygon, it is
531 discarded.
532
533 "GLU_TESS_ERROR_DATA"
534 Similar to GLU_TESS_ERROR but will be passed optional $polygon_data
535 set in gluTessBeginPolygon if any. The 'DEFAULT' handler will
536 ignore this data.
537
538 gluTessCallback($tess, GLU_TESS_ERROR_DATA, sub {
539 my ($errno, $polygon_data) = @_;
540 my $err = gluErrorString($errno);
541 warn "Received a glu tess error ($errno - $err)\n";
542 warn "And I received polygon_data\n" if $polygon_data;
543 });
544
545 "GLU_TESS_EDGE_FLAG"
546 gluTessCallback($tess, GLU_TESS_EDGE_FLAG, 'DEFAULT');
547
548 gluTessCallback($tess, GLU_TESS_EDGE_FLAG, \&glEdgeFlag);
549
550 gluTessCallback($tess, GLU_TESS_EDGE_FLAG, sub {
551 my ($flag) = @_;
552 glEdgeFlag($flag);
553 });
554
555 The 'DEFAULT' option installs a c-handler that calls the glEdgeFlag
556 c function directly without round-tripping out to perl.
557
558 If $polygon_data was set during gluTessBeginPolygon, it is
559 discarded.
560
561 "GLU_TESS_EDGE_FLAG_DATA"
562 Similar to GLU_TESS_EDGE_FLAG but will be passed $polygon_data set
563 in gluTessBeginPolygon if any. The 'DEFAULT' handler will ignore
564 this data.
565
566 gluTessCallback($tess, GLU_TESS_EDGE_FLAG_DATA, sub {
567 my ($flag, $polygon_data) = @_;
568 glEdgeFlag($flag);
569 print "glEdgeFlag - and I received polygon_data\n" if $polygon_data;
570 });
571
573 use OpenGL qw(:all);
574
575 glutInit();
576 glutInitWindowSize(501, 501);
577 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
578 glutCreateWindow("Tessellation");
579 glMatrixMode(GL_PROJECTION());
580 glLoadIdentity();
581 glOrtho(-250,250,-250,250,-1.0,1.0);
582 glMatrixMode(GL_MODELVIEW);
583
584 my $view_triangles = 1; # set to zero to show polygon
585 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) if $view_triangles;
586
587 glutDisplayFunc(sub {
588 glColor3f(1,1,1);
589
590 my $tess = gluNewTess();
591 gluTessCallback($tess, GLU_TESS_BEGIN, 'DEFAULT');
592 gluTessCallback($tess, GLU_TESS_END, 'DEFAULT');
593 gluTessCallback($tess, GLU_TESS_VERTEX, 'DEFAULT');
594 gluTessCallback($tess, GLU_TESS_COMBINE, 'DEFAULT');
595 gluTessCallback($tess, GLU_TESS_ERROR, 'DEFAULT');
596 gluTessCallback($tess, GLU_TESS_EDGE_FLAG, 'DEFAULT') if ! $view_triangles;
597 gluTessBeginPolygon($tess);
598 gluTessBeginContour($tess);
599
600 gluTessVertex_p($tess, 0, 200, 0);
601 gluTessVertex_p($tess, 150, -200, 0);
602 gluTessVertex_p($tess, 0, -100, 0);
603 gluTessVertex_p($tess, -150, -200, 0);
604
605 gluTessEndContour($tess);
606 gluTessEndPolygon($tess);
607 gluDeleteTess($tess);
608
609 glutSwapBuffers();
610 });
611
612 glutMainLoop();
613
615 use OpenGL qw(:all);
616
617 glutInit();
618 glutInitWindowSize(501, 501);
619 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
620 glutCreateWindow("Tessellation");
621 glMatrixMode(GL_PROJECTION());
622 glLoadIdentity();
623 glOrtho(-250,250,-250,250,-1.0,1.0);
624 glMatrixMode(GL_MODELVIEW);
625
626 my $view_triangles = 1; # set to zero to show polygon
627 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) if $view_triangles;
628
629 glutDisplayFunc(sub {
630 glColor3f(1,1,1);
631 my $v = [[[125,0,0], [150,150,0], [0,125,0], [-150,150,0],
632 [-125,0,0], [-150,-150,0], [0,-125,0], [150,-150,0], [125,0,0]],
633 [[75,0,0], [100,100,0], [0,75,0], [-100,100,0],
634 [-75,0,0], [-100,-100,0], [0,-75,0], [100,-100,0], [75,0,0]]
635 ];
636
637 my $tess = gluNewTess();
638 gluTessCallback($tess, GLU_TESS_BEGIN, 'DEFAULT');
639 gluTessCallback($tess, GLU_TESS_END, 'DEFAULT');
640 gluTessCallback($tess, GLU_TESS_VERTEX, 'DEFAULT');
641 gluTessCallback($tess, GLU_TESS_COMBINE, 'DEFAULT');
642 gluTessCallback($tess, GLU_TESS_ERROR, 'DEFAULT');
643 gluTessCallback($tess, GLU_TESS_EDGE_FLAG, 'DEFAULT') if ! $view_triangles;
644 gluTessBeginPolygon($tess);
645 foreach (@$v) {
646 gluTessBeginContour($tess);
647 foreach (@$_) {
648 gluTessVertex_p($tess, @$_);
649 }
650 gluTessEndContour($tess);
651 }
652 gluTessEndPolygon($tess);
653 gluDeleteTess($tess);
654
655 glutSwapBuffers();
656 });
657
658 glutMainLoop();
659
661 use OpenGL qw(:all);
662
663 glutInit();
664 glutInitWindowSize(501, 501);
665 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
666 glutCreateWindow("Tessellation");
667 glMatrixMode(GL_PROJECTION());
668 glLoadIdentity();
669 glOrtho(-250,250,-250,250,-1.0,1.0);
670 glMatrixMode(GL_MODELVIEW);
671
672 my $view_triangles = 0;
673 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) if $view_triangles;
674
675 glutDisplayFunc(sub {
676 glColor3f(1,1,1);
677 my $v = [[[125,0,0], [150,150,0, 0,1,0], [0,125,0], [-150,150,0, 1,0,0],
678 [-125,0,0], [-150,-150,0, 0,0,1], [0,-125,0], [150,-150,0, 1,1,0], [125,0,0]],
679 [[75,0,0], [100,100,0], [0,75,0], [-100,100,0],
680 [-75,0,0], [-100,-100,0], [0,-75,0], [100,-100,0], [75,0,0]]
681 ];
682
683 OpenGL::Tess->new(do_colors => 1, no_edge_flag => $view_triangles)->draw_contours(@$v);
684
685 glutSwapBuffers();
686 });
687
688 glutMainLoop();
689
690 ###----------------------------------------------------------------###
691
692
693 package OpenGL::Tess;
694
695 # Sample object oriented Tessellator
696 # OpenGL::Tess->new(do_colors => 1, no_edge_flag => $view_triangles)->draw_contours(@$v);
697
698 use strict;
699
700 sub new {
701 my $class = shift;
702 my $self = bless {@_}, $class;
703 my $tess = $self->{'_tess'} = OpenGL::gluNewTess($self->do_colors);
704 for my $cb (qw(begin end vertex combine error edge_flag)) {
705 my $enum = OpenGL->can("GLU_TESS_\U${cb}_DATA") || die "Couldn't find callback for $cb";
706 my $name = "_$cb";
707 OpenGL::gluTessCallback($tess, $enum->(), sub { $_[-1]->$name(@_) });
708 }
709 return $self;
710 }
711
712 sub DESTROY {
713 my $tess = shift->{'_tess'};
714 OpenGL::gluDeleteTess($tess) if $tess;
715 }
716
717 sub tess {
718 my $self = shift;
719 return $self->{'_tess'} || die "Missing tess";
720 }
721
722 sub do_colors { shift->{'do_colors'} }
723
724 sub begin_polygon {
725 my $self = shift;
726 my $tess = $self->tess;
727 # self will be passed as last arg ([-1]) to all callbacks as opaque polygon data
728 return OpenGL::gluTessBeginPolygon($tess, $self);
729 }
730
731 sub end_polygon { OpenGL::gluTessEndPolygon( shift->tess) }
732 sub begin_contour { OpenGL::gluTessBeginContour(shift->tess) }
733 sub end_contour { OpenGL::gluTessEndContour( shift->tess) }
734
735 sub draw_contours {
736 my $self = shift;
737 $self->begin_polygon;
738 foreach my $c (@_) {
739 $self->begin_contour;
740 $self->add_vertex(@$_) for @$c;
741 $self->end_contour;
742 }
743 $self->end_polygon;
744 }
745
746 sub add_vertex {
747 my $self = shift;
748 die 'Usage $self->add_vertex($x,$y,$z)' if @_ < 3;
749 if ($self->do_colors) {
750 push @_, 1 for @_ .. 6;
751 OpenGL::gluTessVertex_p($self->tess, @_[0..6]);
752 } else {
753 OpenGL::gluTessVertex_p($self->tess, @_[0..3]);
754 }
755 }
756
757 sub _begin {
758 my ($self, $enum) = @_;
759 OpenGL::glBegin($enum);
760 }
761
762 sub _end { OpenGL::glEnd() }
763
764 sub _vertex {
765 my ($self, $x, $y, $z, $r, $g, $b, $a) = @_;
766 OpenGL::glColor4f($r, $g, $b, $a) if $self->do_colors;
767 OpenGL::glVertex3f($x, $y, $z);
768 }
769
770 sub _edge_flag {
771 my ($self, $flag) = @_;
772 return if $self->{'no_edge_flag'};
773 OpenGL::glEdgeFlag($flag);
774 }
775
776 sub _error {
777 my ($self, $errno) = @_;
778 warn __PACKAGE__ ." error: ".OpenGL::gluErrorString($errno);
779 }
780
781 sub _combine {
782 my ($self, $x, $y, $z, $v0, $v1, $v2, $v3, $w0, $w1, $w2, $w3) = @_;
783 return ($x, $y, $z) if !$self->do_colors;
784 return ($x, $y, $z,
785 $w0*$v0->[3] + $w1*$v1->[3] + $w2*$v2->[3] + $w3*$v3->[3],
786 $w0*$v0->[4] + $w1*$v1->[4] + $w2*$v2->[4] + $w3*$v3->[4],
787 $w0*$v0->[5] + $w1*$v1->[5] + $w2*$v2->[5] + $w3*$v3->[5],
788 $w0*$v0->[6] + $w1*$v1->[6] + $w2*$v2->[6] + $w3*$v3->[6]);
789 }
790
791 1;
792
794 Paul Seamons - paul AT seamons dot com - 2011
795
796
797
798perl v5.36.0 2022-07-22 Tessellation(3)