Anonymous's picture

OpenGL tessellator

Hello Everybody,

I'm quite new to OpenGL, but I need to use its tessellation algorithm to retrieve the resulting triangles.
I've seen that OpenTK contains the tessellation class but being completely new to the toolkit I'm having problems to understand what to do and I couldn't find any sample.
Yesterday i spent some time trying to do the same with the TaoFramework only to discover that their implementation is bugged.

Forgive me if the problem sounds silly.
What I'm now trying to achieve is really simple (to describe).

Eventually I'll need to tessellate a polygon with a hole inside but for the moment a simple rectangle tessellation would be ok.

Apparently i should use something like

Dim rect As Double()() = New Double(4)() {New Double() {50, 50, 0}, New Double() {200, 50, 0}, New Double() {200, 200, 0}, New Double() {50, 200, 0}, New Double() {0, 125, 0}}
 
Dim mydata As IntPtr = IntPtr.Zero
Dim mycallback As IntPtr
 
Dim t As Integer = OpenTK.OpenGL.Glu.NewTes()
 
OpenTK.OpenGL.Glu.TessCallback(t, OpenTK.OpenGL.Enums.TessCallback.End, mycallback)
 
OpenTK.OpenGL.Glu.BeginPolygon(t)
OpenTK.OpenGL.Glu.TessBeginContour(t)
OpenTK.OpenGL.Glu.TessVertex(t, rect(0), mydata)
OpenTK.OpenGL.Glu.TessVertex(t, rect(1), mydata)
OpenTK.OpenGL.Glu.TessVertex(t, rect(2), mydata)
OpenTK.OpenGL.Glu.TessVertex(t, rect(3), mydata)
OpenTK.OpenGL.Glu.TessEndContour(t)
OpenTK.OpenGL.Glu.EndPolygon(t)

But what kind of of structure should be behind the two IntPtr's?

I don't need to display the resulting triangles but to retrieve a list of them along with vertex coordinates.

Please note that although I'm patching a VB application any c# code will be ok for me.
Any help will be highly appreciated,
Claudio


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Anonymous's picture

The Glu tesselator does in fact work, and I very happy to finally have a fully functional triangulation program in C#.

The Tao project attempted to bind the tesselator, but it crashes with an access violation. Even their sample program!

If anyone is interested I'd be willing to share some code. Otherwise, I have posted a few additional (and hopefully helpful) comments on Fiddler's post on the 0.9.1 progress update here:

http://www.opentk.com/news/0.9.1_progress_on_glu_tesselation#attachments

Inertia's picture

Some working Glu tesselator sample would be appreciated, adding a tutorial for it is on the todo-list for 0.9.2

Anonymous's picture

Here is my implementation of a triangulation class using the OpenTK Glu bindings; I hope someone finds it useful.

It should be able to be ported to any C# project with little to no modification. Anyone who wishes to use it can do so freely.

-Justin Nordin

using System;
using System.Collections.Generic;
using System.Xml;
using OpenTK.OpenGL; //for triangulating paths with the GLU tesselator
using System.Runtime.InteropServices;
using System.Diagnostics;
 
namespace J3D
{
    //
    //This class use the OpenGL GLU tessellation
    //functions to triangulate a simple polygon.
    //
    //This code is based largely on Michael Foetsch
    //triangulation tutorial that can be found, as of
    //February 2, 2008, at http://www.geocities.com/foetsch/articles.htm.
    //
    //It interfaces with OpenGL through OpenTK.
    //
 
    public static class J3DTriangulate
    {
        // Some of this code is lifted from the OpenTK tesselation sample:
        // Define the signatures for the callback functions, and declare the callbacks.
        delegate void BeginCallbackDelegate(int mode);
        delegate void EndCallbackDelegate();
        delegate void VertexCallbackDelegate(IntPtr v);
        delegate void EdgeFlagCallbackDelegate(int flag);
        delegate void ErrorCallbackDelegate(int code);
        unsafe delegate void CombineCallbackDelegate(
            [MarshalAs(UnmanagedType.LPArray, SizeConst = 3)]double[] coordinates,
            [MarshalAs(UnmanagedType.LPArray, SizeConst = 4)]double*[] vertexData,
            [MarshalAs(UnmanagedType.LPArray, SizeConst = 4)]float[] weight,
            double** dataOut);
 
        static OpenTK.GLControl glControl = null;
 
        // Triangulate
        // "Input" is a list of Vector2's that hold the point data to be triangulated.
        //(Vector2 is not shown but is a structure that has two floating points members X and Y).
        // "VertsPerContour" is an array that determines where to break up the contours in the
        //list of points in Input. VertsPerContour must sum to the number of entries in Input.
        //
        //Note: Outer contours must be given in counter-clockwise order while inner contours
        //      (holes) must be given in clock-wise order.
        //
        //Returns true on successfull triangulation, false on failure or error
        //
        unsafe static public bool Triangulate(Vector2[] Input, int[] VertsPerContour)
        {
            InvalidPolygon = false;
            Indices = new List<int>();
 
            IntPtr tess = IntPtr.Zero;
 
            // create tesselation object
            if (glControl == null)
            {
                glControl = new OpenTK.GLControl();
            }
 
            tess = Glu.NewTess();
 
            // register tesselation callbacks
            Glu.TessCallback(tess, OpenTK.OpenGL.Enums.TessCallback.TessBegin, new BeginCallbackDelegate(BeginCallback));
            Glu.TessCallback(tess, OpenTK.OpenGL.Enums.TessCallback.TessEdgeFlag, new EdgeFlagCallbackDelegate(EdgeCallback));
            Glu.TessCallback(tess, OpenTK.OpenGL.Enums.TessCallback.TessVertex, new VertexCallbackDelegate (VertexCallback));
            Glu.TessCallback(tess, OpenTK.OpenGL.Enums.TessCallback.TessEnd, new EndCallbackDelegate(EndCallback));
            Glu.TessCallback(tess, OpenTK.OpenGL.Enums.TessCallback.TessCombine, new CombineCallbackDelegate(CombineCallback));
            Glu.TessCallback(tess, OpenTK.OpenGL.Enums.TessCallback.TessError, new ErrorCallbackDelegate(ErrorCallback));
 
            //copy input into a linear array of floats
            double[] Vertices = new double[3 * Input.Length];
            for(int v=0;v<Input.Length;v++)
            {
                Vertices[v*3+0] = Input[v].X;
                Vertices[v*3+1] = Input[v].Y;
                Vertices[v*3+2] = 0.0;
            }
 
            // begin polygon
            Glu.TessBeginPolygon(tess, IntPtr.Zero);
 
            // go through the contours
            int CurrentContour = 0;
            int VertsThisContour = 0;
 
            for(int v=0;v<Input.Length;v++)
            {
                if(v == 0)
                    Glu.TessBeginContour(tess);
 
                // pass the corresponding vertex to the tesselator object
                double[] VertsToPass = new double[3];
                VertsToPass[0] = Vertices[v * 3 + 0];
                VertsToPass[1] = Vertices[v * 3 + 1];
                VertsToPass[2] = Vertices[v * 3 + 2];
                Glu.TessVertex(tess,VertsToPass,v);
 
                if(InvalidPolygon)
                    break;
 
                VertsThisContour++;
 
                if(VertsThisContour >= VertsPerContour[CurrentContour])
                {
                    VertsThisContour = 0;
                    Glu.TessEndContour(tess);
 
                    CurrentContour++;
 
                    if(CurrentContour < (long)VertsPerContour.Length)
                    {
                        Glu.TessBeginContour(tess);
                    }
                }
            }
 
            if(InvalidPolygon)
            {
                // destroy the tesselation object
                Glu.DeleteTess(tess);
                tess = IntPtr.Zero;
 
                return false; //error in polygon definition
            }
            else
            {
                // end polygon
                Glu.TessEndPolygon(tess);
 
                // destroy the tessellation object
                Glu.DeleteTess(tess);
                tess = IntPtr.Zero;
 
                //The Indices object is now valid.
                return true;
            }
        }
 
        //After a successful call to Triangulate, this public list holds the indices
        //for the given input.
        public static List<int> Indices;
        static bool InvalidPolygon;
 
        //GLU callback functions
        static void BeginCallback(int type)
        {
        }
 
        static void EdgeCallback(int flag)
        {
        }
 
        static void VertexCallback(IntPtr vertexIndex)
        {
            unsafe
            {
                Indices.Add(*((int*)vertexIndex));
            }
        }
 
        static void EndCallback()
        {
        }
 
        unsafe static void CombineCallback(double[] coords, double*[] vertexData, float[] weight, double** outData)
        {
            //This means the polygon is self-intersecting.
            //See the OpenTK tesselation example for a working version of the
            //combine callback.
            InvalidPolygon = true;
        }
 
        static void ErrorCallback(int errno)
        {
            //some error ocurred, mark this triangulation as invalid
            InvalidPolygon = true;
        }
 
    }
}
Anonymous's picture

We have a complete port of the GLU tesselator from mesa to unmanaged c#.

You can find it in the SVN repository at:

https://sourceforge.net/projects/agg-sharp

I am currently planing on using OpenTK for our hardware abstraction layer.