Post Reply 
Drawing a Spherical Mesh
01-20-2014, 08:07 PM (This post was last modified: 01-20-2014 08:11 PM by jgreenb2.)
Post: #1
Drawing a Spherical Mesh
Wondering if any of you who are graphics whizzes on the Prime know how to implement a spherical mesh generator?

I tried to make a PPL version of the classical icosahedron mesh but the depth of recursion appears to flummox the prime. Here's the original OpenGL/C version that can be found in the redbook and other places:

Code:
//
//  sphereMesh.c
//
//  draws a sphercial mesh
//

#include <stdio.h>
#include <math.h>

#if !defined(__GLU_H__)
#if defined(WIN32)
#include <windows.h>
#include <GL/glu.h>
#elif defined(__MACH__)
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#endif
#endif // !__GL_H__
#define X .525731112119133606
#define Z .850650808352039932

static GLfloat vdata[12][3] = {
    {-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z},
    {0.0, Z, X}, {0.0, Z, -X}, {0.0, -Z, X}, {0.0, -Z, -X},
    {Z, X, 0.0}, {-Z, X, 0.0}, {Z, -X, 0.0}, {-Z, -X, 0.0}
};
static GLuint tindices[20][3] = {
    {0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},
    {8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},
    {7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},
    {6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11} };

void normalize(GLfloat *a) {
    GLfloat d=sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);
    a[0]/=d; a[1]/=d; a[2]/=d;
}

void drawtri(GLfloat *a, GLfloat *b, GLfloat *c, int div, float r) {
    if (div<=0) {
        glNormal3fv(a); glVertex3f(a[0]*r, a[1]*r, a[2]*r);
        glNormal3fv(b); glVertex3f(b[0]*r, b[1]*r, b[2]*r);
        glNormal3fv(c); glVertex3f(c[0]*r, c[1]*r, c[2]*r);
    } else {
        GLfloat ab[3], ac[3], bc[3];
        for (int i=0;i<3;i++) {
            ab[i]=(a[i]+b[i])/2;
            ac[i]=(a[i]+c[i])/2;
            bc[i]=(b[i]+c[i])/2;
        }
        normalize(ab); normalize(ac); normalize(bc);
        drawtri(a, ab, ac, div-1, r);
        drawtri(b, bc, ab, div-1, r);
        drawtri(c, ac, bc, div-1, r);
        drawtri(ab, bc, ac, div-1, r);  //<--Comment this line and sphere looks really cool!
    }
}

void drawsphere(int ndiv, float radius) {
    glBegin(GL_TRIANGLES);
    for (int i=0;i<20;i++)
        drawtri(vdata[tindices[i][0]], vdata[tindices[i][1]], vdata[tindices[i][2]], ndiv, radius);
    glEnd();
}

I'm assuming that the glNormal3fv calls can be converted to TRIANGLE calls on the Prime (although shading doesn't appear to be supported). But the program never gets that far -- it hangs somewhere in the drawtri recursion for values of "div" > 2 or 3.

Converted to PPL the equivalent of the above code would be
Code:

XX=.525731112119133606;
ZZ=.850650808352039932;
vdata={
    {-XX, 0.0, ZZ}, {XX, 0.0, ZZ}, {-XX, 0.0, -ZZ}, {XX, 0.0, -ZZ},
    {0.0, ZZ, XX}, {0.0, ZZ, -XX}, {0.0, -ZZ, XX}, {0.0, -ZZ, -XX},
    {ZZ, XX, 0.0}, {-ZZ, XX, 0.0}, {ZZ, -XX, 0.0}, {-ZZ, -XX, 0.0}
    };
tindices = {
    {0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},
    {8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},
    {7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},
    {6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11} };

drawSphere()
begin
    local i,radius=50,ndiv=12;
    local white;
    
    white:=rgb(255,255,255);
    dimgrob_p(G1,320,240,white);

    for i from 1 to 20 do
        drawtri(vdata(tindices(i,1)+1),
                vdata(tindices(i,2)+1),
                vdata(tindices(i,3)+1),ndiv,radius);
    end;
    blit_p(G0,G1);
end;

normalize(aa)
begin
    local dd;
    dd:=sqrt(aa(1)*aa(1)+aa(2)*aa(2)+aa(3)*aa(3));
    aa(1):=aa(1)/dd; aa(2):=aa(2)/dd; aa(3):=aa(3)/dd;
    return aa;
end;

drawtri(aa,bb,cc,div,r)
begin
    local ab={},ac={},bc={};
    local grey,i;
    
    grey:=rgb(25,25,25);
    if div <= 0 then
        triangle_p(G1,{aa(1),aa(2),grey,aa(3)},{bb(1),bb(2),grey,bb(3)},{cc(1),cc(2​),grey,cc(3)});
    else
        for i from 1 to 3 do
            ab(i):=(aa(i)+bb(i))/2;
            ac(i):=(aa(i)+cc(i))/2;
            bc(i):=(bb(i)+cc(i))/2;
        end;
        ab:=normalize(ab);
        ac:=normalize(ac);
        bc:=normalize(bc);
        drawtri(aa,ab,ac,div-1,r);
        drawtri(bb,bc,ab,div-1,r);
        drawtri(cc,ac,bc,div-1,r);
        drawtri(ab,bc,ac,div-1,r);
    end;
end;

It seems likely that I've botched the TRIANGLE command since I've never used it but, again, things seem to go bad before that point. BTW, the above is only a fragment. If you want to try it you'll need to embed it in a more complete program like Han's Graph3D.

Suggestions welcome. Or is this just beyond what we can expect the Prime to do at this point?
Find all posts by this user
Quote this message in a reply
01-20-2014, 09:47 PM
Post: #2
RE: Drawing a Spherical Mesh
You can always insert a debug() statement into your program to determine if the HP Prime fails after a certain number of recursions.

Code:
if div<4 then debug(); end;

You can also insert a debug() statement right after the triangle command and then abort the program. Then, at the command line, type:

Code:
blit_p(G0,G1); freeze;

This will allow you to see if your code is drawing each triangle like you want. You can even skip debugging and just put:

Code:
blit_p(G0,G1); WAIT(-1);

to see it draw each individual triangle (press a key to continue).

Graph 3D | QPI | SolveSys
Find all posts by this user
Quote this message in a reply
01-20-2014, 09:58 PM (This post was last modified: 01-20-2014 10:03 PM by jgreenb2.)
Post: #3
RE: Drawing a Spherical Mesh
Han,

Thanks. I've actually done most of those things. I'll try some of your other suggestions. However, the drawing isn't the issue (it may not be right) -- the recursion itself seems to get lost after a short while and the program hangs. Given the limited debugging environment on the Prime, I haven't been able to make much more progress.

The real questions are these:
  • Is there a known problem handling deep recursion on the Prime?
  • What's the best way to implement something like a sphereical mesh?

Simple tail recursion -- like a factorial -- appear to work without issue. But when div is large the Prime stack appears to lose its place and drawSphere won't terminate.
Find all posts by this user
Quote this message in a reply
01-20-2014, 10:27 PM (This post was last modified: 01-20-2014 10:31 PM by cyrille de brébisson.)
Post: #4
RE: Drawing a Spherical Mesh
Hello,

A couple of problems in your code...
First, your coordinates are in cartesian coordinates, from -1 to 1...
you should use triangle instead of triangle_p. Make sure that you set the xmin/xmax, ymin, ymax to -1, 1, -1, 1 if you want to see something...

ndiv=12 correspond to a HUGE number of triangles. put it to 6 or so to get started and debug... it does work with 12, but takes a LOT of time...

Code:

XX=.525731112119133606;
ZZ=.850650808352039932;
vdata={
    {-XX, 0.0, ZZ}, {XX, 0.0, ZZ}, {-XX, 0.0, -ZZ}, {XX, 0.0, -ZZ},
    {0.0, ZZ, XX}, {0.0, ZZ, -XX}, {0.0, -ZZ, XX}, {0.0, -ZZ, -XX},
    {ZZ, XX, 0.0}, {-ZZ, XX, 0.0}, {ZZ, -XX, 0.0}, {-ZZ, -XX, 0.0}
    };
tindices = {
    {0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},
    {8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},
    {7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},
    {6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11} };

normalize(aa)
begin
    local dd;
    dd:=sqrt(aa(1)*aa(1)+aa(2)*aa(2)+aa(3)*aa(3));
    aa(1):=aa(1)/dd; aa(2):=aa(2)/dd; aa(3):=aa(3)/dd;
    return aa;
end;

drawtri(aa,bb,cc,div,r)
begin
    local ab={},ac={},bc={};
    local grey,i;
    
    grey:=rgb(25,125,25);
    if div <= 0 then

        triangle({aa(1),aa(2),grey,aa(3)},{bb(1),bb(2),grey,bb(3)},{cc(1),cc(2),gre​y,cc(3)});
//kill;
    else
        for i from 1 to 3 do
            ab(i):=(aa(i)+bb(i))/2;
            ac(i):=(aa(i)+cc(i))/2;
            bc(i):=(bb(i)+cc(i))/2;
        end;
        ab:=normalize(ab);
        ac:=normalize(ac);
        bc:=normalize(bc);
        drawtri(aa,ab,ac,div-1,r);
        drawtri(bb,bc,ab,div-1,r);
        drawtri(cc,ac,bc,div-1,r);
        drawtri(ab,bc,ac,div-1,r);
    end;
end;

export drawSphere()
begin
    local i,radius=50,ndiv=6;
    local white;
    
    white:=rgb(255,255,255);
    dimgrob_p(G1,320,240,white);
rect_p;

    for i from 1 to 20 do
        drawtri(vdata(tindices(i,1)+1),
                vdata(tindices(i,2)+1),
                vdata(tindices(i,3)+1),ndiv,radius);
    end;
//    blit_p(G0,G1);
end;

If it still does not work, it might be due to confusion on the triangle inputs with the other forms (for full 3D drawing). Since my version of the app is later than the one that you have, I do not remember exactly how it was before...
you could try a form along the lines of:
triangle(x1, y1, z2, x2, y2, z2, x3, y3, z3, c1, c2, c3);

Cyrille
Find all posts by this user
Quote this message in a reply
01-21-2014, 12:15 AM (This post was last modified: 01-21-2014 12:16 AM by jgreenb2.)
Post: #5
RE: Drawing a Spherical Mesh
Cyrille,

You're right on both counts...thanks. Also, I realized I wasn't scaling the vertices by the radius -- that didn't help either. The next step is to accumulate all the vertices into a matrix and execute a single TRIANGLE call with a transformation matrix, z-plane and perspective transform. We'll see how that goes Smile

BTW...TRIANGLE appears to always fill the triangles(?) I'd like to actually draw a mesh (edges, but no fill). Is this possible?
Find all posts by this user
Quote this message in a reply
01-21-2014, 01:08 AM
Post: #6
RE: Drawing a Spherical Mesh
Quote:BTW...TRIANGLE appears to always fill the triangles(?) I'd like to actually draw a mesh (edges, but no fill). Is this possible?
Draw each vertice using LINE.
3 LINEs for each TRIANGLE if you don't avoid duplicates.

Patrice
“Everything should be made as simple as possible, but no simpler.” Albert Einstein
Find all posts by this user
Quote this message in a reply
01-23-2014, 10:11 PM
Post: #7
RE: Drawing a Spherical Mesh
Put this instead of your TRIANGLE command
Code:
    LINE(aa(1),aa(2),bb(1),bb(2),rgb(128+aa(1)*128,128+aa(2)*128,128+aa(3)*128)​);
    LINE(bb(1),bb(2),cc(1),cc(2),rgb(128+bb(1)*128,128+bb(2)*128,128+bb(3)*128)​);
    LINE(cc(1),cc(2),aa(1),aa(2),rgb(128+cc(1)*128,128+cc(2)*128,128+cc(3)*128)​);
Note that the LINE command compute a color depending on coordinates.
I did it because the TRIANCLE make a flat convex thing on screen.
MY changed TRIANGLE
Code:
triangle ({aa(1),aa(2),rgb(128+aa(1)*128,128+aa(2)*128,128+aa(3)*128),aa(3)},{bb(1),​bb(2),rgb(128+bb(1)*128,128+bb(2)*128,128+bb(3)*128),bb(3)},{cc(1),cc(2),rgb(128​+cc(1)*128,128+cc(2)*128,128+cc(3)*128),cc(3)});

Patrice
“Everything should be made as simple as possible, but no simpler.” Albert Einstein
Find all posts by this user
Quote this message in a reply
Post Reply 




User(s) browsing this thread: 3 Guest(s)