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
 jgreenb2 Member Posts: 50 Joined: Dec 2013
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++)
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 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),
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?
01-20-2014, 09:47 PM
Post: #2
 Han Senior Member Posts: 1,882 Joined: Dec 2013
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
01-20-2014, 09:58 PM (This post was last modified: 01-20-2014 10:03 PM by jgreenb2.)
Post: #3
 jgreenb2 Member Posts: 50 Joined: Dec 2013
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.
01-20-2014, 10:27 PM (This post was last modified: 01-20-2014 10:31 PM by cyrille de brébisson.)
Post: #4
 cyrille de brébisson Senior Member Posts: 1,047 Joined: Dec 2013
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 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),
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
01-21-2014, 12:15 AM (This post was last modified: 01-21-2014 12:16 AM by jgreenb2.)
Post: #5
 jgreenb2 Member Posts: 50 Joined: Dec 2013
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

BTW...TRIANGLE appears to always fill the triangles(?) I'd like to actually draw a mesh (edges, but no fill). Is this possible?
01-21-2014, 01:08 AM
Post: #6
 patrice Member Posts: 184 Joined: Dec 2013
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
01-23-2014, 10:11 PM
Post: #7
 patrice Member Posts: 184 Joined: Dec 2013
RE: Drawing a Spherical Mesh
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
 « Next Oldest | Next Newest »

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