Initial Commit
This commit is contained in:
817
database/perl/vendor/lib/OpenGL/Tessellation.pod
vendored
Normal file
817
database/perl/vendor/lib/OpenGL/Tessellation.pod
vendored
Normal file
@@ -0,0 +1,817 @@
|
||||
=head1 NAME
|
||||
|
||||
OpenGL::Tessellation - discussion of tessellation in POGL
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# somewhere in your drawing routine or drawlist compilation
|
||||
|
||||
my $tess = gluNewTess();
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_BEGIN, 'DEFAULT');
|
||||
gluTessCallback($tess, GLU_TESS_END, 'DEFAULT');
|
||||
gluTessCallback($tess, GLU_TESS_VERTEX, 'DEFAULT');
|
||||
gluTessCallback($tess, GLU_TESS_COMBINE, 'DEFAULT');
|
||||
gluTessCallback($tess, GLU_TESS_ERROR, 'DEFAULT');
|
||||
gluTessCallback($tess, GLU_TESS_EDGE_FLAG, 'DEFAULT');
|
||||
|
||||
gluTessBeginPolygon($tess);
|
||||
gluTessBeginContour($tess);
|
||||
|
||||
gluTessVertex_p($tess, 0, 200, 0);
|
||||
gluTessVertex_p($tess, 150, -200, 0);
|
||||
gluTessVertex_p($tess, 0, -100, 0);
|
||||
gluTessVertex_p($tess, -150, -200, 0);
|
||||
|
||||
gluTessEndContour($tess);
|
||||
gluTessEndPolygon($tess);
|
||||
|
||||
gluDeleteTess($tess);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
OpenGL rendering hardware typically does not have support for drawing
|
||||
concave polygons or drawing polygons with windows. OpenGL provides
|
||||
glu extentions that allow for translating concave polygon vertices
|
||||
into triangles that can be rendered quickly on GL hardware. The
|
||||
OpenGL red book chapter 11 has the full discussion of Tessellators and
|
||||
the OpenGL functions (http://glprogramming.com/red/chapter11.html, or
|
||||
use your favorite search engine and search for "opengl gluNewTess").
|
||||
It is a good idea to read that chapter before reading the rest of this
|
||||
document.
|
||||
|
||||
As much as possible, the POGL implementation of the tessellation
|
||||
functions tries to remain faithful to the OpenGL specification. Where
|
||||
it doesn't match exactly, POGL follows the spirit of the specification,
|
||||
but offloads what it can to c based implementations.
|
||||
|
||||
Tessellation functions are safe to call during drawlist creation. It
|
||||
is advisable to use drawlists, or to store the generated polygon data
|
||||
into OpenGL::Array objects as these methods offer faster redraws.
|
||||
|
||||
=head1 FUNCTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<gluNewTess>
|
||||
|
||||
my $tess = gluNewTess();
|
||||
|
||||
Returns a reference that can be passed to the remaining tesselation
|
||||
functions.
|
||||
|
||||
Note: this isn't the c-reference returned by the normal gluNewTess() c
|
||||
function, it is a struct which contains that reference as well as
|
||||
other members allowing callbacks to interface cleanly with the perl
|
||||
code. This means that if you have loaded other c-libraries that use
|
||||
standard opengl tessellation, you will not be able to use this perl
|
||||
reference directly.
|
||||
|
||||
The POGL implementation of gluNewTess() allows for two additional
|
||||
parameters to be passed. The first is a boolean value indicating that
|
||||
default c callbacks and perl callbacks should be passed rgba color
|
||||
data. The second is a boolean value indicating that xyz normal data
|
||||
should be passed. Eventually one additional flag indicating that
|
||||
texture data should be passed will be added as well.
|
||||
|
||||
my $tess = gluNewTess();
|
||||
# gluTessVertex_p should be passed only x,y,z vertex data
|
||||
# as in gluTessVertex_p($tess, $x, $y, $z);
|
||||
|
||||
my $tess = gluNewTess('do_colors');
|
||||
# gluTessVertex_p should be passed x,y,z AND r,g,b,a vertex data
|
||||
# as in gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a);
|
||||
|
||||
my $tess = gluNewTess('do_colors', 'do_normals');
|
||||
# gluTessVertex_p should be passed x,y,z AND r,g,b,a AND nx,ny,nz vertex data
|
||||
# as in gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a, $nx, $ny, $nz);
|
||||
|
||||
my $tess = gluNewTess(undef, 'do_normals');
|
||||
# gluTessVertex_p should be passed x,y,z AND nx,ny,nz vertex data (no colors)
|
||||
# as in gluTessVertex_p($tess, $x, $y, $z, $nx, $ny, $nz);
|
||||
|
||||
Any true value can be passed in place of 'do_colors' and 'do_normals'
|
||||
though using 'do_colors' and 'do_normals' acts as documentation.
|
||||
|
||||
Behavior in these modes will be discussed further for functions to
|
||||
which they apply.
|
||||
|
||||
=item C<gluDeleteTess>
|
||||
|
||||
gluDeleteTess($tess);
|
||||
|
||||
This deletes the tessellation structure and frees up any remaining
|
||||
associated memory.
|
||||
|
||||
=item C<gluTessCallback>
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_BEGIN, 'DEFAULT');
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_BEGIN, \&glBegin);
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_BEGIN, sub { my $enum = shift; glBegin($enum) });
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_BEGIN); # unsets current handler
|
||||
|
||||
Registers handlers for each of the tessellation callback types. Takes
|
||||
a tessellation reference generated by gluNewTess, a type, and a
|
||||
coderef or the word 'DEFAULT'. If the word 'DEFAULT' is passed, a
|
||||
default c-level callback will be installed (which will be discussed
|
||||
for each callback). If no 3rd argument is given, then any handler
|
||||
currently set will be removed. Valid callback types are
|
||||
|
||||
GLU_TESS_BEGIN
|
||||
GLU_TESS_END
|
||||
GLU_TESS_VERTEX
|
||||
GLU_TESS_COMBINE
|
||||
GLU_TESS_ERROR
|
||||
GLU_TESS_EDGE_FLAG
|
||||
|
||||
GLU_TESS_BEGIN_DATA
|
||||
GLU_TESS_END_DATA
|
||||
GLU_TESS_VERTEX_DATA
|
||||
GLU_TESS_COMBINE_DATA
|
||||
GLU_TESS_ERROR_DATA
|
||||
GLU_TESS_EDGE_FLAG_DATA
|
||||
|
||||
These types and their passed parameters will be discussed in the
|
||||
CALLBACKS section.
|
||||
|
||||
The types ending with "_DATA" are similar to their non-_DATA
|
||||
counterpart, but when called are passed the option $polygon_data that
|
||||
can be set during gluTessBeginPolygon.
|
||||
|
||||
=item C<gluTessBeginPolygon>
|
||||
|
||||
gluTessBeginPolygon($tess);
|
||||
|
||||
gluTessBeginPolygon($tess, $polygon_data);
|
||||
|
||||
Begins the tessellation transaction. It must eventually be
|
||||
ended with a gluTessEndPolygon before the tessellator will normally
|
||||
begin work.
|
||||
|
||||
An optional second argument can be passed which can be any perl
|
||||
scalar or reference. If a callback is registered using a type ending
|
||||
in _DATA, this perl scalar or reference will be passed as an additional
|
||||
argument to that callback.
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_END_DATA, sub {
|
||||
my $polygon_data = shift;
|
||||
glEnd();
|
||||
print "glEnd: (".($polygon_data->[2] eq 8 ? "YES" : "NO").")\n";
|
||||
});
|
||||
|
||||
gluTessBeginPoly($tess, [6,7,8]); # arrayref will be passed to _DATA callbacks
|
||||
|
||||
A sample Object Oriented tesselation sample listed at the end of this
|
||||
document makes use of this "opaque" polygon data.
|
||||
|
||||
=item C<gluTessEndPolygon>
|
||||
|
||||
gluTessEndPolygon($tess);
|
||||
|
||||
Finishes the tessellation transaction, which normally will immediately
|
||||
fire the necessary callbacks generated by the tessellation process.
|
||||
Once finished, it cleans up any accumulated temporary vertice data.
|
||||
|
||||
=item C<gluTessBeginContour>
|
||||
|
||||
gluTessBeginContour($tess);
|
||||
|
||||
Starts a new contour of the tessellation of the current polygon.
|
||||
Please read the OpenGL documentation, and red book chapter on
|
||||
tessellation for more help on when to use different contours. Should
|
||||
eventually be followed by a gluTessEndContour call.
|
||||
|
||||
(At a high level, tessellated polygons may have windows and multiple
|
||||
separate portions. Each inner and outer border of these portions
|
||||
should be represented by a different contour.)
|
||||
|
||||
=item C<gluTessVertex_p>
|
||||
|
||||
gluTessVertex_p($tess, $x, $y, $z);
|
||||
|
||||
gluTessVertex_p($tess, $x, $y, $z, $vertex_data);
|
||||
|
||||
Adds a vertex to the current contour of the current polygon being
|
||||
tessellated.
|
||||
|
||||
If the vertex callback type is set to GLU_TESS_VERTEX, the optional
|
||||
$vertex_data argument will be passed to the vertex callback, and to
|
||||
the combine callback (if GLU_TESS_VERTEX_DATA is used, then the
|
||||
$polygon_data passed to gluTessBeginPolygon will be passed instead).
|
||||
This optional opaque vertex data can be any perl scalar or reference
|
||||
and can be used to pass useful information along during the
|
||||
tessellation process.
|
||||
|
||||
If the 'do_colors' or 'do_normals' parameters were passed to gluNewTess,
|
||||
then those additional properties MUST be passed as additional arguments.
|
||||
|
||||
# my $tess = gluNewTess('do_colors');
|
||||
gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a);
|
||||
gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a, $vertex_data);
|
||||
|
||||
# my $tess = gluNewTess('do_colors', 'do_normals');
|
||||
gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a, $nx, $ny, $nz);
|
||||
gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a, $nx, $ny, $nz, $vertex_data);
|
||||
|
||||
# my $tess = gluNewTess(undef, 'do_normals');
|
||||
gluTessVertex_p($tess, $x, $y, $z, $nx, $ny, $nz);
|
||||
gluTessVertex_p($tess, $x, $y, $z, $nx, $ny, $nz, $vertex_data);
|
||||
|
||||
=back
|
||||
|
||||
=head1 CALLBACKS
|
||||
|
||||
All of the callbacks support a 'DEFAULT' handler that can be installed
|
||||
by passing the word 'DEFAULT' in place of the callback code reference.
|
||||
The DEFAULT c implementations are there to avoid needing to round trip
|
||||
out to perl. The defaults employed are described for each of the
|
||||
callback types.
|
||||
|
||||
With the exception of the COMBINE callback, return values from
|
||||
callbacks are discarded.
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<GLU_TESS_BEGIN>
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_BEGIN, 'DEFAULT');
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_BEGIN, \&glBegin);
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_BEGIN, sub {
|
||||
my $enum = shift;
|
||||
glBegin($enum);
|
||||
});
|
||||
|
||||
The 'DEFAULT' option installs a c-handler that calls the glBegin c
|
||||
function directly without round-tripping out to perl.
|
||||
|
||||
If $polygon_data was set during gluTessBeginPolygon, it is discarded.
|
||||
|
||||
=item C<GLU_TESS_BEGIN_DATA>
|
||||
|
||||
Similar to GLU_TESS_BEGIN but will be passed optional $polygon_data
|
||||
set in gluTessBeginPolygon if any. The 'DEFAULT' handler will ignore
|
||||
this data.
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_BEGIN_DATA, sub {
|
||||
my ($enum, $polygon_data) = @_;
|
||||
glBegin($enum);
|
||||
print "glBegin - and I received polygon_data\n" if $polygon_data;
|
||||
});
|
||||
|
||||
=item C<GLU_TESS_END>
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_END, 'DEFAULT');
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_END, \&glEnd);
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_END, sub { glEnd() });
|
||||
|
||||
The 'DEFAULT' option installs a c-handler that calls the glEnd c
|
||||
function directly without round-tripping out to perl.
|
||||
|
||||
If $polygon_data was set during gluTessBeginPolygon, it is discarded.
|
||||
|
||||
=item C<GLU_TESS_END_DATA>
|
||||
|
||||
Similar to GLU_TESS_END but will be passed optional $polygon_data set
|
||||
in gluTessBeginPolygon if any. The 'DEFAULT' handler will ignore this
|
||||
data.
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_END_DATA, sub {
|
||||
my ($polygon_data) = @_;
|
||||
glEnd();
|
||||
print "glEnd - and I received polygon_data\n" if $polygon_data;
|
||||
});
|
||||
|
||||
=item C<GLU_TESS_VERTEX>
|
||||
|
||||
The GLU_TESS_VERTEX callback handler has slightly different
|
||||
behavior depending on how gluNewTess was called. The optional behaviors
|
||||
allow for sane default processing of colors and normals without needing
|
||||
to roundtrip out to perl.
|
||||
|
||||
my $tess = gluNewTess();
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_VERTEX, 'DEFAULT');
|
||||
|
||||
# the following will break if vertex_data is passed to gluTessVertex_p
|
||||
gluTessCallback($tess, GLU_TESS_VERTEX, \&glVertex3f);
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_VERTEX, sub {
|
||||
my ($x, $y, $z) = @_;
|
||||
glVertex3f($x, $y, $z);
|
||||
});
|
||||
|
||||
# you can also pass vertex_data to gluTessVertex_p
|
||||
gluTessCallback($tess, GLU_TESS_VERTEX, sub {
|
||||
my ($x, $y, $z, $vertex_data) = @_;
|
||||
glVertex3f($x, $y, $z);
|
||||
print "glVertex - and I received vertex_data\n" if $vertex_data;
|
||||
});
|
||||
|
||||
The 'DEFAULT' option installs a c-handler that calls the glVertex c
|
||||
function directly without round-tripping out to perl. The DEFAULT
|
||||
handler discards any polygon_data or vertex_data.
|
||||
|
||||
IF $vertex_data was set during gluTessVertex_p it will be passed as the final
|
||||
argument.
|
||||
|
||||
If gluNewTess was passed 'do_colors' then the GLU_TESS_VERTEX callback
|
||||
will also be passed the rgba information. The 'DEFAULT' option
|
||||
will pass the color information to glColor4f before calling glVertex3f.
|
||||
|
||||
my $tess = gluNewTess('do_colors');
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_VERTEX, sub {
|
||||
my ($x, $y, $z, $r, $g, $b, $a, $vertex_data) = @_;
|
||||
glColor4f($r, $g, $b, $a);
|
||||
glVertex3f($x, $y, $z);
|
||||
});
|
||||
|
||||
If gluNewTess was passed 'do_normals' then the GLU_TESS_VERTEX callback
|
||||
will also be passed the normal x,y,z information. The 'DEFAULT' option
|
||||
will pass the normal information to glNormal3f before calling glVertex3f.
|
||||
|
||||
my $tess = gluNewTess('do_colors', 'do_normals');
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_VERTEX, sub {
|
||||
my ($x, $y, $z, $r, $g, $b, $a, $nx, $ny, $nz, $vertex_data) = @_;
|
||||
glColor4f($r, $g, $b, $a);
|
||||
glNormalf($nx, $ny, $nz);
|
||||
glVertex3f($x, $y, $z);
|
||||
});
|
||||
|
||||
# OR
|
||||
|
||||
my $tess = gluNewTess(undef, 'do_normals');
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_VERTEX, sub {
|
||||
my ($x, $y, $z, $nx, $ny, $nz, $vertex_data) = @_;
|
||||
glNormalf($nx, $ny, $nz);
|
||||
glVertex3f($x, $y, $z);
|
||||
});
|
||||
|
||||
In all cases, any optional vertex_data will be passed as the final argument.
|
||||
|
||||
=item C<GLU_TESS_VERTEX_DATA>
|
||||
|
||||
Similar to GLU_TESS_VERTEX but will be passed optional $polygon_data
|
||||
set in gluTessBeginPolygon (if any) rather than the optional
|
||||
$vertex_data passed to gluTessVertex_p. The 'DEFAULT' handler will
|
||||
ignore this data.
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_VERTEX_DATA, sub {
|
||||
my ($x, $y, $z, $vertex_data) = @_;
|
||||
glVertex3f($x, $y, $z);
|
||||
print "glVertex - and I received vertex_data\n" if $vertex_data;
|
||||
});
|
||||
|
||||
=item C<GLU_TESS_COMBINE>
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_COMBINE, 'DEFAULT');
|
||||
# works with gluTessCallback($tess, GLU_TESS_VERTEX, 'DEFAULT');
|
||||
|
||||
|
||||
# OR
|
||||
|
||||
|
||||
# the following callback is valid for gluNewTess() (no do_colors or do_normals)
|
||||
# using gluTessVertex_p($tess, $x, $y, $z);
|
||||
my $tess = gluNewTess();
|
||||
gluTessCallback($tess, GLU_TESS_COMBINE, sub {
|
||||
my ($x, $y, $z, # new vertex location
|
||||
$v0, $v1, $v2, $v3, # border vertex arrayrefs
|
||||
$w0, $w1, $w2, $w3, # border vertex weights
|
||||
$polygon_data) = @_; # optional data passed to gluTessBeginPolygon
|
||||
return ($x, $y, $z);
|
||||
});
|
||||
# works with gluTessCallback($tess, GLU_TESS_VERTEX, 'DEFAULT');
|
||||
|
||||
|
||||
# OR
|
||||
|
||||
|
||||
# the following callback is valid for gluNewTess() when vertex data is passed
|
||||
# using gluTessVertex_p($tess, $x, $y, $z, [$r, $g, $b, $a]);
|
||||
# The DEFAULT callback cannot automatically proceess this type of data
|
||||
# but passing data to a custom handler this way could handle any arbitrary data passed to it
|
||||
my $tess = gluNewTess();
|
||||
use constant _r => 0;
|
||||
use constant _g => 1;
|
||||
use constant _b => 2;
|
||||
use constant _a => 3;
|
||||
gluTessCallback($tess, GLU_TESS_COMBINE, sub {
|
||||
my ($x, $y, $z, # new vertex location
|
||||
$v0, $v1, $v2, $v3, # border vertex arrayrefs
|
||||
$w0, $w1, $w2, $w3, # border vertex weights
|
||||
$polygon_data) = @_; # optional data passed to gluTessBeginPolygon
|
||||
|
||||
# $v0 will contain [$x, $y, $z, [$r, $g, $b, $a]]
|
||||
my @rgba = map {$_->[3]} $v0, $v1, $v2, $v3;
|
||||
|
||||
# generate a point with color weighted from the surrounding vertices
|
||||
# then return that color information in the same way we received it (an rgba arrayref)
|
||||
return (
|
||||
$x, $y, $z,
|
||||
[$w0*$rgba[0]->[_r] + $w1*$rgba[1]->[_r] + $w2*$rgba[2]->[_r] + $w3*$rgba[3]->[_r],
|
||||
$w0*$rgba[0]->[_g] + $w1*$rgba[1]->[_g] + $w2*$rgba[2]->[_g] + $w3*$rgba[3]->[_g],
|
||||
$w0*$rgba[0]->[_b] + $w1*$rgba[1]->[_b] + $w2*$rgba[2]->[_b] + $w3*$rgba[3]->[_b],
|
||||
$w0*$rgba[0]->[_a] + $w1*$rgba[1]->[_a] + $w2*$rgba[2]->[_a] + $w3*$rgba[3]->[_a]],
|
||||
);
|
||||
});
|
||||
# works with gluTessCallback($tess, GLU_TESS_VERTEX, sub {
|
||||
# my ($x, $y, $z, $rgba) = @_;
|
||||
# glColor4f(@$rgba);
|
||||
# glVertex3f($x, $y, $z);
|
||||
# });
|
||||
|
||||
|
||||
# OR
|
||||
|
||||
|
||||
# the following callback is valid for gluNewTess('do_colors')
|
||||
# using gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a);
|
||||
# the DEFAULT callback COULD automatically proceess this type of data as well if additional vertex data is not passed
|
||||
my $tess = gluNewTess('do_colors');
|
||||
use constant _r => 3;
|
||||
use constant _g => 4;
|
||||
use constant _b => 5;
|
||||
use constant _a => 6;
|
||||
gluTessCallback($tess, GLU_TESS_COMBINE, sub {
|
||||
my ($x, $y, $z, # new vertex location
|
||||
$v0, $v1, $v2, $v3, # border vertex arrayrefs
|
||||
$w0, $w1, $w2, $w3, # border vertex weights
|
||||
$polygon_data) = @_; # optional data passed to gluTessBeginPolygon
|
||||
|
||||
# $v0 will contain [$x, $y, $z, $r, $g, $b, $a]
|
||||
|
||||
return ( # generate a point with color weighted from the surrounding vertices
|
||||
$x, $y, $z,
|
||||
$w0*$v0->[_r] + $w1*$v1->[_r] + $w2*$v2->[_r] + $w3*$v3->[_r],
|
||||
$w0*$v0->[_g] + $w1*$v1->[_g] + $w2*$v2->[_g] + $w3*$v3->[_g],
|
||||
$w0*$v0->[_b] + $w1*$v1->[_b] + $w2*$v2->[_b] + $w3*$v3->[_b],
|
||||
$w0*$v0->[_a] + $w1*$v1->[_a] + $w2*$v2->[_a] + $w3*$v3->[_a],
|
||||
($v0->[7] || $v1->[7] || $v2->[7] || $v3->[7]), # if we received vertex data - return some for the new vertex
|
||||
);
|
||||
});
|
||||
# works with gluTessCallback($tess, GLU_TESS_VERTEX, 'DEFAULT');
|
||||
# OR
|
||||
# works with gluTessCallback($tess, GLU_TESS_VERTEX, sub {
|
||||
# my ($x, $y, $z, $r, $g, $b, $a, $vertex_data) = @_;
|
||||
# glColor4f($r, $g, $b, $a);
|
||||
# glVertex3f($x, $y, $z);
|
||||
# });
|
||||
|
||||
The combine callback is called if the tessellator decides a new vertex
|
||||
is needed. This will happen with self intersecting polygons. In this
|
||||
case, the COMBINE callback can be used to interpolate appropriate
|
||||
values for normals, and colors, or for any desired information.
|
||||
|
||||
The combine callback will be passed the following:
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<$x, $y, $z>
|
||||
|
||||
The x y and z coordinates of the new vertex being created.
|
||||
|
||||
=item C<$v0, $v1, $v2, $v3>
|
||||
|
||||
Arrayrefs of vertex information for the vertices bordering this
|
||||
new vertex (the ones that caused the new vertex to be created).
|
||||
|
||||
By default if gluNewTess() is called, these arrayrefs will be passed:
|
||||
|
||||
my ($x, $y, $z, $vertex_data) = @$v0;
|
||||
# received from gluTessVertex_p($tess, $x, $y, $z, $vertex_data);
|
||||
|
||||
If gluNewTess('do_colors') is called, the following will be passed:
|
||||
|
||||
my ($x, $y, $z, $r, $g, $b, $a, $vertex_data) = @$v0;
|
||||
# received from gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a, $vertex_data);
|
||||
|
||||
If gluNewTess('do_colors', 'do_normals') is called, the following will be passed:
|
||||
|
||||
my ($x, $y, $z, $r, $g, $b, $a, $nx, $ny, $nz, $vertex_data) = @$v0;
|
||||
# received from gluTessVertex_p($tess, $x, $y, $z, $r, $g, $b, $a, $nx, $ny, $nz, $vertex_data);
|
||||
|
||||
If gluNewTess(undef, 'do_normals') is called, the following will be passed:
|
||||
|
||||
my ($x, $y, $z, $nx, $ny, $nz, $vertex_data) = @$v0;
|
||||
# received from gluTessVertex_p($tess, $x, $y, $z, $nx, $ny, $nz, $vertex_data);
|
||||
|
||||
In all cases, the data returned by the COMBINE callback should be in the same
|
||||
format that each of the vertices are in when passed into the COMBINE callback.
|
||||
|
||||
=item C<$w0, $w1, $w2, $w3>
|
||||
|
||||
Weights of the participating vertices (weight $w0 corresponds to vertex $v0).
|
||||
|
||||
=item C<optional $polygon_data>
|
||||
|
||||
Any optional data passed to gluTessBeginPolygon. Normally this would
|
||||
only be passed to GLU_TESS_COMBINE_DATA, but GLU_TESS_COMBINE_DATA
|
||||
and GLU_TESS_COMBINE share the same code implementation.
|
||||
|
||||
=back
|
||||
|
||||
=item C<GLU_TESS_COMBINE_DATA>
|
||||
|
||||
Identical in function to the GLU_TESS_COMBINE handler. They
|
||||
use the same callback implementation.
|
||||
|
||||
=item C<GLU_TESS_ERROR>
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_ERROR, 'DEFAULT');
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_ERROR, \&glEdgeFlag);
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_ERROR, sub {
|
||||
my $errno = shift;
|
||||
my $err = gluErrorString($errno);
|
||||
warn "Received a glu tess error ($errno - $err)\n";
|
||||
});
|
||||
|
||||
The 'DEFAULT' option installs a c-handler that warns with the
|
||||
appropriate gluErrorString.
|
||||
|
||||
If $polygon_data was set during gluTessBeginPolygon, it is discarded.
|
||||
|
||||
=item C<GLU_TESS_ERROR_DATA>
|
||||
|
||||
Similar to GLU_TESS_ERROR but will be passed optional $polygon_data
|
||||
set in gluTessBeginPolygon if any. The 'DEFAULT' handler will ignore
|
||||
this data.
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_ERROR_DATA, sub {
|
||||
my ($errno, $polygon_data) = @_;
|
||||
my $err = gluErrorString($errno);
|
||||
warn "Received a glu tess error ($errno - $err)\n";
|
||||
warn "And I received polygon_data\n" if $polygon_data;
|
||||
});
|
||||
|
||||
=item C<GLU_TESS_EDGE_FLAG>
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_EDGE_FLAG, 'DEFAULT');
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_EDGE_FLAG, \&glEdgeFlag);
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_EDGE_FLAG, sub {
|
||||
my ($flag) = @_;
|
||||
glEdgeFlag($flag);
|
||||
});
|
||||
|
||||
The 'DEFAULT' option installs a c-handler that calls the glEdgeFlag c
|
||||
function directly without round-tripping out to perl.
|
||||
|
||||
If $polygon_data was set during gluTessBeginPolygon, it is discarded.
|
||||
|
||||
=item C<GLU_TESS_EDGE_FLAG_DATA>
|
||||
|
||||
Similar to GLU_TESS_EDGE_FLAG but will be passed $polygon_data set in
|
||||
gluTessBeginPolygon if any. The 'DEFAULT' handler will ignore this
|
||||
data.
|
||||
|
||||
gluTessCallback($tess, GLU_TESS_EDGE_FLAG_DATA, sub {
|
||||
my ($flag, $polygon_data) = @_;
|
||||
glEdgeFlag($flag);
|
||||
print "glEdgeFlag - and I received polygon_data\n" if $polygon_data;
|
||||
});
|
||||
|
||||
=back
|
||||
|
||||
=head1 Example: Basic Arrowhead
|
||||
|
||||
use OpenGL qw(:all);
|
||||
|
||||
glutInit();
|
||||
glutInitWindowSize(501, 501);
|
||||
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
|
||||
glutCreateWindow("Tessellation");
|
||||
glMatrixMode(GL_PROJECTION());
|
||||
glLoadIdentity();
|
||||
glOrtho(-250,250,-250,250,-1.0,1.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
my $view_triangles = 1; # set to zero to show polygon
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) if $view_triangles;
|
||||
|
||||
glutDisplayFunc(sub {
|
||||
glColor3f(1,1,1);
|
||||
|
||||
my $tess = gluNewTess();
|
||||
gluTessCallback($tess, GLU_TESS_BEGIN, 'DEFAULT');
|
||||
gluTessCallback($tess, GLU_TESS_END, 'DEFAULT');
|
||||
gluTessCallback($tess, GLU_TESS_VERTEX, 'DEFAULT');
|
||||
gluTessCallback($tess, GLU_TESS_COMBINE, 'DEFAULT');
|
||||
gluTessCallback($tess, GLU_TESS_ERROR, 'DEFAULT');
|
||||
gluTessCallback($tess, GLU_TESS_EDGE_FLAG, 'DEFAULT') if ! $view_triangles;
|
||||
gluTessBeginPolygon($tess);
|
||||
gluTessBeginContour($tess);
|
||||
|
||||
gluTessVertex_p($tess, 0, 200, 0);
|
||||
gluTessVertex_p($tess, 150, -200, 0);
|
||||
gluTessVertex_p($tess, 0, -100, 0);
|
||||
gluTessVertex_p($tess, -150, -200, 0);
|
||||
|
||||
gluTessEndContour($tess);
|
||||
gluTessEndPolygon($tess);
|
||||
gluDeleteTess($tess);
|
||||
|
||||
glutSwapBuffers();
|
||||
});
|
||||
|
||||
glutMainLoop();
|
||||
|
||||
=head1 Example: Multiple contours
|
||||
|
||||
use OpenGL qw(:all);
|
||||
|
||||
glutInit();
|
||||
glutInitWindowSize(501, 501);
|
||||
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
|
||||
glutCreateWindow("Tessellation");
|
||||
glMatrixMode(GL_PROJECTION());
|
||||
glLoadIdentity();
|
||||
glOrtho(-250,250,-250,250,-1.0,1.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
my $view_triangles = 1; # set to zero to show polygon
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) if $view_triangles;
|
||||
|
||||
glutDisplayFunc(sub {
|
||||
glColor3f(1,1,1);
|
||||
my $v = [[[125,0,0], [150,150,0], [0,125,0], [-150,150,0],
|
||||
[-125,0,0], [-150,-150,0], [0,-125,0], [150,-150,0], [125,0,0]],
|
||||
[[75,0,0], [100,100,0], [0,75,0], [-100,100,0],
|
||||
[-75,0,0], [-100,-100,0], [0,-75,0], [100,-100,0], [75,0,0]]
|
||||
];
|
||||
|
||||
my $tess = gluNewTess();
|
||||
gluTessCallback($tess, GLU_TESS_BEGIN, 'DEFAULT');
|
||||
gluTessCallback($tess, GLU_TESS_END, 'DEFAULT');
|
||||
gluTessCallback($tess, GLU_TESS_VERTEX, 'DEFAULT');
|
||||
gluTessCallback($tess, GLU_TESS_COMBINE, 'DEFAULT');
|
||||
gluTessCallback($tess, GLU_TESS_ERROR, 'DEFAULT');
|
||||
gluTessCallback($tess, GLU_TESS_EDGE_FLAG, 'DEFAULT') if ! $view_triangles;
|
||||
gluTessBeginPolygon($tess);
|
||||
foreach (@$v) {
|
||||
gluTessBeginContour($tess);
|
||||
foreach (@$_) {
|
||||
gluTessVertex_p($tess, @$_);
|
||||
}
|
||||
gluTessEndContour($tess);
|
||||
}
|
||||
gluTessEndPolygon($tess);
|
||||
gluDeleteTess($tess);
|
||||
|
||||
glutSwapBuffers();
|
||||
});
|
||||
|
||||
glutMainLoop();
|
||||
|
||||
=head1 Example: Sample OO Tessellation interface using polygon_data
|
||||
|
||||
|
||||
use OpenGL qw(:all);
|
||||
|
||||
glutInit();
|
||||
glutInitWindowSize(501, 501);
|
||||
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
|
||||
glutCreateWindow("Tessellation");
|
||||
glMatrixMode(GL_PROJECTION());
|
||||
glLoadIdentity();
|
||||
glOrtho(-250,250,-250,250,-1.0,1.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
my $view_triangles = 0;
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) if $view_triangles;
|
||||
|
||||
glutDisplayFunc(sub {
|
||||
glColor3f(1,1,1);
|
||||
my $v = [[[125,0,0], [150,150,0, 0,1,0], [0,125,0], [-150,150,0, 1,0,0],
|
||||
[-125,0,0], [-150,-150,0, 0,0,1], [0,-125,0], [150,-150,0, 1,1,0], [125,0,0]],
|
||||
[[75,0,0], [100,100,0], [0,75,0], [-100,100,0],
|
||||
[-75,0,0], [-100,-100,0], [0,-75,0], [100,-100,0], [75,0,0]]
|
||||
];
|
||||
|
||||
OpenGL::Tess->new(do_colors => 1, no_edge_flag => $view_triangles)->draw_contours(@$v);
|
||||
|
||||
glutSwapBuffers();
|
||||
});
|
||||
|
||||
glutMainLoop();
|
||||
|
||||
###----------------------------------------------------------------###
|
||||
|
||||
|
||||
package OpenGL::Tess;
|
||||
|
||||
# Sample object oriented Tessellator
|
||||
# OpenGL::Tess->new(do_colors => 1, no_edge_flag => $view_triangles)->draw_contours(@$v);
|
||||
|
||||
use strict;
|
||||
|
||||
sub new {
|
||||
my $class = shift;
|
||||
my $self = bless {@_}, $class;
|
||||
my $tess = $self->{'_tess'} = OpenGL::gluNewTess($self->do_colors);
|
||||
for my $cb (qw(begin end vertex combine error edge_flag)) {
|
||||
my $enum = OpenGL->can("GLU_TESS_\U${cb}_DATA") || die "Couldn't find callback for $cb";
|
||||
my $name = "_$cb";
|
||||
OpenGL::gluTessCallback($tess, $enum->(), sub { $_[-1]->$name(@_) });
|
||||
}
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub DESTROY {
|
||||
my $tess = shift->{'_tess'};
|
||||
OpenGL::gluDeleteTess($tess) if $tess;
|
||||
}
|
||||
|
||||
sub tess {
|
||||
my $self = shift;
|
||||
return $self->{'_tess'} || die "Missing tess";
|
||||
}
|
||||
|
||||
sub do_colors { shift->{'do_colors'} }
|
||||
|
||||
sub begin_polygon {
|
||||
my $self = shift;
|
||||
my $tess = $self->tess;
|
||||
# self will be passed as last arg ([-1]) to all callbacks as opaque polygon data
|
||||
return OpenGL::gluTessBeginPolygon($tess, $self);
|
||||
}
|
||||
|
||||
sub end_polygon { OpenGL::gluTessEndPolygon( shift->tess) }
|
||||
sub begin_contour { OpenGL::gluTessBeginContour(shift->tess) }
|
||||
sub end_contour { OpenGL::gluTessEndContour( shift->tess) }
|
||||
|
||||
sub draw_contours {
|
||||
my $self = shift;
|
||||
$self->begin_polygon;
|
||||
foreach my $c (@_) {
|
||||
$self->begin_contour;
|
||||
$self->add_vertex(@$_) for @$c;
|
||||
$self->end_contour;
|
||||
}
|
||||
$self->end_polygon;
|
||||
}
|
||||
|
||||
sub add_vertex {
|
||||
my $self = shift;
|
||||
die 'Usage $self->add_vertex($x,$y,$z)' if @_ < 3;
|
||||
if ($self->do_colors) {
|
||||
push @_, 1 for @_ .. 6;
|
||||
OpenGL::gluTessVertex_p($self->tess, @_[0..6]);
|
||||
} else {
|
||||
OpenGL::gluTessVertex_p($self->tess, @_[0..3]);
|
||||
}
|
||||
}
|
||||
|
||||
sub _begin {
|
||||
my ($self, $enum) = @_;
|
||||
OpenGL::glBegin($enum);
|
||||
}
|
||||
|
||||
sub _end { OpenGL::glEnd() }
|
||||
|
||||
sub _vertex {
|
||||
my ($self, $x, $y, $z, $r, $g, $b, $a) = @_;
|
||||
OpenGL::glColor4f($r, $g, $b, $a) if $self->do_colors;
|
||||
OpenGL::glVertex3f($x, $y, $z);
|
||||
}
|
||||
|
||||
sub _edge_flag {
|
||||
my ($self, $flag) = @_;
|
||||
return if $self->{'no_edge_flag'};
|
||||
OpenGL::glEdgeFlag($flag);
|
||||
}
|
||||
|
||||
sub _error {
|
||||
my ($self, $errno) = @_;
|
||||
warn __PACKAGE__ ." error: ".OpenGL::gluErrorString($errno);
|
||||
}
|
||||
|
||||
sub _combine {
|
||||
my ($self, $x, $y, $z, $v0, $v1, $v2, $v3, $w0, $w1, $w2, $w3) = @_;
|
||||
return ($x, $y, $z) if !$self->do_colors;
|
||||
return ($x, $y, $z,
|
||||
$w0*$v0->[3] + $w1*$v1->[3] + $w2*$v2->[3] + $w3*$v3->[3],
|
||||
$w0*$v0->[4] + $w1*$v1->[4] + $w2*$v2->[4] + $w3*$v3->[4],
|
||||
$w0*$v0->[5] + $w1*$v1->[5] + $w2*$v2->[5] + $w3*$v3->[5],
|
||||
$w0*$v0->[6] + $w1*$v1->[6] + $w2*$v2->[6] + $w3*$v3->[6]);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Paul Seamons - paul AT seamons dot com - 2011
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user