#include "fg_gl2.h"
#include <math.h>
-/* VC++6 in C mode doesn't have C99's sinf/cos/sqrtf */
-#ifndef HAVE_SINF
-#define sinf(x) (float)sin((double)(x))
-#endif
-#ifndef HAVE_COSF
-#define cosf(x) (float)cos((double)(x))
-#endif
-#ifndef HAVE_SQRTF
-#define sqrtf(x) (float)sqrt((double)(x))
-#endif
+/*
+ * A note: We do not use the GLuint data type for vertex index arrays
+ * in this code as Open GL ES1 only supports GLushort. This affects the
+ * cylindrical objects only (Torus, Sphere, Cylinder and Cone) and limits
+ * their number of vertices to 65535 (2^16-1). Thats about 256*256
+ * subdivisions, which is sufficient for just about any usage case, so
+ * I am not going to worry about it for now.
+ * One could do compile time detection of the gluint type through CMake,
+ * but it is likely that we'll eventually move to runtime selection
+ * of OpenGL or GLES1/2, which would make that strategy useless...
+ */
/* declare for drawing using the different OpenGL versions here so we can
have a nice code order below */
#ifndef GL_ES_VERSION_2_0
static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals,
- GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
- GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
+ GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
+ GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
);
static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
- GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart);
+ GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart);
#endif
static void fghDrawGeometryWire20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
- GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
- GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
- GLint attribute_v_coord, GLint attribute_v_normal
+ GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
+ GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
+ GLint attribute_v_coord, GLint attribute_v_normal
);
static void fghDrawGeometrySolid20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
- GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart,
- GLint attribute_v_coord, GLint attribute_v_normal);
+ GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart,
+ GLint attribute_v_coord, GLint attribute_v_normal);
+/* declare function for generating visualization of normals */
+static void fghGenerateNormalVisualization(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
+ GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart);
+#ifndef GL_ES_VERSION_2_0
+static void fghDrawNormalVisualization11();
+#endif
+static void fghDrawNormalVisualization20(GLint attribute_v_coord);
/* Drawing geometry:
* Explanation of the functions has to be separate for the polyhedra and
* Feel free to contribute better naming ;)
*/
static void fghDrawGeometryWire(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
- GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
- GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
+ GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
+ GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
)
{
GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
GLint attribute_v_coord = fgStructure.CurrentWindow->Window.attribute_v_coord;
GLint attribute_v_normal = fgStructure.CurrentWindow->Window.attribute_v_normal;
+ if (fgStructure.CurrentWindow->State.VisualizeNormals)
+ /* generate normals for each vertex to be drawn as well */
+ fghGenerateNormalVisualization(vertices, normals, numVertices,
+ vertIdxs, numParts, numVertIdxsPerPart);
+
if (fgState.HasOpenGL20 && (attribute_v_coord != -1 || attribute_v_normal != -1))
+ {
/* User requested a 2.0 draw */
fghDrawGeometrySolid20(vertices, normals, numVertices,
vertIdxs, numParts, numVertIdxsPerPart,
attribute_v_coord, attribute_v_normal);
+
+ if (fgStructure.CurrentWindow->State.VisualizeNormals)
+ /* draw normals for each vertex as well */
+ fghDrawNormalVisualization20(attribute_v_coord);
+ }
#ifndef GL_ES_VERSION_2_0
else
+ {
fghDrawGeometrySolid11(vertices, normals, numVertices,
vertIdxs, numParts, numVertIdxsPerPart);
+
+ if (fgStructure.CurrentWindow->State.VisualizeNormals)
+ /* draw normals for each vertex as well */
+ fghDrawNormalVisualization11();
+ }
#endif
}
/* Version for OpenGL (ES) 1.1 */
#ifndef GL_ES_VERSION_2_0
static void fghDrawGeometryWire11(GLfloat *vertices, GLfloat *normals,
- GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
- GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
+ GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
+ GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2
)
{
int i;
static void fghDrawGeometrySolid11(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
- GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
+ GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
{
int i;
/* Version for OpenGL (ES) >= 2.0 */
static void fghDrawGeometryWire20(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
- GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
- GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
- GLint attribute_v_coord, GLint attribute_v_normal
- )
+ GLushort *vertIdxs, GLsizei numParts, GLsizei numVertPerPart, GLenum vertexMode,
+ GLushort *vertIdxs2, GLsizei numParts2, GLsizei numVertPerPart2,
+ GLint attribute_v_coord, GLint attribute_v_normal)
{
GLuint vbo_coords = 0, vbo_normals = 0,
ibo_elements = 0, ibo_elements2 = 0;
/**
+ * Generate vertex indices for visualizing the normals.
+ */
+static GLfloat *verticesForNormalVisualization;
+static GLushort numNormalVertices = 0;
+static void fghGenerateNormalVisualization(GLfloat *vertices, GLfloat *normals, GLsizei numVertices,
+ GLushort *vertIdxs, GLsizei numParts, GLsizei numVertIdxsPerPart)
+{
+ GLushort i,j;
+ /* calc number of vertices to generate, allocate. Must be freed by caller
+ * We do the free at the end of fghDrawNormalVisualization11/fghDrawNormalVisualization20
+ */
+ if (!vertIdxs)
+ numNormalVertices = numVertices * 2;
+ else
+ numNormalVertices = numParts * numVertIdxsPerPart * 2;
+ verticesForNormalVisualization = malloc(numNormalVertices*3 * sizeof(GLfloat));
+
+ /* Now generate vertices for lines to draw the normals */
+ if (!vertIdxs)
+ {
+ for (i=0,j=0; i<numNormalVertices*3/2; i+=3, j+=6)
+ {
+ verticesForNormalVisualization[j+0] = vertices[i+0];
+ verticesForNormalVisualization[j+1] = vertices[i+1];
+ verticesForNormalVisualization[j+2] = vertices[i+2];
+ verticesForNormalVisualization[j+3] = vertices[i+0] + normals[i+0]/4.f;
+ verticesForNormalVisualization[j+4] = vertices[i+1] + normals[i+1]/4.f;
+ verticesForNormalVisualization[j+5] = vertices[i+2] + normals[i+2]/4.f;
+ }
+ }
+ else
+ {
+ for (i=0,j=0; i<numNormalVertices/2; i++, j+=6)
+ {
+ GLushort idx = vertIdxs[i]*3;
+ verticesForNormalVisualization[j+0] = vertices[idx+0];
+ verticesForNormalVisualization[j+1] = vertices[idx+1];
+ verticesForNormalVisualization[j+2] = vertices[idx+2];
+ verticesForNormalVisualization[j+3] = vertices[idx+0] + normals[idx+0]/4.f;
+ verticesForNormalVisualization[j+4] = vertices[idx+1] + normals[idx+1]/4.f;
+ verticesForNormalVisualization[j+5] = vertices[idx+2] + normals[idx+2]/4.f;
+ }
+ }
+}
+
+/* Version for OpenGL (ES) 1.1 */
+#ifndef GL_ES_VERSION_2_0
+static void fghDrawNormalVisualization11()
+{
+ GLfloat currentColor[4];
+ /* Setup draw color: (1,1,1)-shape's color */
+ glGetFloatv(GL_CURRENT_COLOR,currentColor);
+ glColor4f(1-currentColor[0],1-currentColor[1],1-currentColor[2],currentColor[3]);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ glVertexPointer(3, GL_FLOAT, 0, verticesForNormalVisualization);
+ glDrawArrays(GL_LINES, 0, numNormalVertices);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ /* Done, free memory, reset color */
+ free(verticesForNormalVisualization);
+ glColor4fv(currentColor);
+}
+#endif
+
+/* Version for OpenGL (ES) >= 2.0 */
+static void fghDrawNormalVisualization20(GLint attribute_v_coord)
+{
+ GLuint vbo_coords = 0;
+
+ if (attribute_v_coord != -1) {
+ fghGenBuffers(1, &vbo_coords);
+ fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
+ fghBufferData(FGH_ARRAY_BUFFER, numNormalVertices * 3 * sizeof(verticesForNormalVisualization[0]),
+ verticesForNormalVisualization, FGH_STATIC_DRAW);
+ }
+
+
+ if (vbo_coords) {
+ fghEnableVertexAttribArray(attribute_v_coord);
+ fghBindBuffer(FGH_ARRAY_BUFFER, vbo_coords);
+ fghVertexAttribPointer(
+ attribute_v_coord, /* attribute */
+ 3, /* number of elements per vertex, here (x,y,z) */
+ GL_FLOAT, /* the type of each element */
+ GL_FALSE, /* take our values as-is */
+ 0, /* no extra data between each position */
+ 0 /* offset of first element */
+ );
+ fghBindBuffer(FGH_ARRAY_BUFFER, 0);
+ }
+
+ glDrawArrays(GL_LINES, 0, numNormalVertices);
+
+ if (vbo_coords != 0)
+ fghDisableVertexAttribArray(attribute_v_coord);
+
+ if (vbo_coords != 0)
+ fghDeleteBuffers(1, &vbo_coords);
+
+ /* Done, free memory */
+ free(verticesForNormalVisualization);
+}
+
+/**
* Generate all combinations of vertices and normals needed to draw object.
* Optional shape decomposition to triangles:
* We'll use glDrawElements to draw all shapes that are not naturally
* vertices and normals are unique.
*/
#define DECLARE_SHAPE_CACHE(name,nameICaps,nameCaps)\
- static GLboolean name##Cached = FALSE;\
+ static GLboolean name##Cached = GL_FALSE;\
static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
static void fgh##nameICaps##Generate()\
name##_verts, name##_norms);\
}
#define DECLARE_SHAPE_CACHE_DECOMPOSE_TO_TRIANGLE(name,nameICaps,nameCaps)\
- static GLboolean name##Cached = FALSE;\
+ static GLboolean name##Cached = GL_FALSE;\
static GLfloat name##_verts[nameCaps##_VERT_ELEM_PER_OBJ];\
static GLfloat name##_norms[nameCaps##_VERT_ELEM_PER_OBJ];\
static GLushort name##_vertIdxs[nameCaps##_VERT_PER_OBJ_TRI];\
/* -- Sierpinski Sponge -- */
static unsigned int ipow (int x, unsigned int y)
{
- return y==0? 1: y==1? x: (y%2? x: 1) * ipow(x*x, y/2);
+ /* return y==0? 1: y==1? x: (y%2? x: 1) * ipow(x*x, y/2); */
+ if (y==0)
+ return 1;
+ else
+ {
+ if (y==1)
+ return x;
+ else
+ {
+ return (y%2? x: 1) * ipow(x*x, y/2);
+ }
+ }
}
static void fghSierpinskiSpongeGenerate ( int numLevels, double offset[3], GLfloat scale, GLfloat* vertices, GLfloat* normals )
for (i=1; i<size; i++)
{
- (*sint)[i] = sinf(angle*i);
- (*cost)[i] = cosf(angle*i);
+ (*sint)[i] = (GLfloat)sin(angle*i);
+ (*cost)[i] = (GLfloat)cos(angle*i);
}
*nVert = slices*(stacks-1)+2;
if ((*nVert) > 65535)
/*
- * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
- * But still:
- * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
+ * limit of glushort, thats 256*256 subdivisions, should be enough in practice. See note above
*/
fgWarning("fghGenerateSphere: too many slices or stacks requested, indices will wrap");
/* precompute values on unit circle */
- fghCircleTable(&sint1,&cost1,-slices,FALSE);
- fghCircleTable(&sint2,&cost2, stacks,TRUE);
+ fghCircleTable(&sint1,&cost1,-slices,GL_FALSE);
+ fghCircleTable(&sint2,&cost2, stacks,GL_TRUE);
/* Allocate vertex and normal buffers, bail out if memory allocation fails */
*vertices = malloc((*nVert)*3*sizeof(GLfloat));
const GLfloat rStep = (GLfloat)base / ( ( stacks > 0 ) ? stacks : 1 );
/* Scaling factors for vertex normals */
- const GLfloat cosn = ( (GLfloat)height / sqrtf( height * height + base * base ));
- const GLfloat sinn = ( (GLfloat)base / sqrtf( height * height + base * base ));
+ const GLfloat cosn = (GLfloat) (height / sqrt( height * height + base * base ));
+ const GLfloat sinn = (GLfloat) (base / sqrt( height * height + base * base ));
if ((*nVert) > 65535)
/*
- * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
- * But still:
- * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
+ * limit of glushort, thats 256*256 subdivisions, should be enough in practice. See note above
*/
fgWarning("fghGenerateCone: too many slices or stacks requested, indices will wrap");
/* Pre-computed circle */
- fghCircleTable(&sint,&cost,-slices,FALSE);
+ fghCircleTable(&sint,&cost,-slices,GL_FALSE);
/* Allocate vertex and normal buffers, bail out if memory allocation fails */
*vertices = malloc((*nVert)*3*sizeof(GLfloat));
(*vertices)[idx ] = cost[j]*r;
(*vertices)[idx+1] = sint[j]*r;
(*vertices)[idx+2] = z;
- (*normals )[idx ] = cost[j]*sinn;
- (*normals )[idx+1] = sint[j]*sinn;
- (*normals )[idx+2] = cosn;
+ (*normals )[idx ] = cost[j]*cosn;
+ (*normals )[idx+1] = sint[j]*cosn;
+ (*normals )[idx+2] = sinn;
}
z += zStep;
if ((*nVert) > 65535)
/*
- * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
- * But still:
- * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
+ * limit of glushort, thats 256*256 subdivisions, should be enough in practice. See note above
*/
fgWarning("fghGenerateCylinder: too many slices or stacks requested, indices will wrap");
/* Pre-computed circle */
- fghCircleTable(&sint,&cost,-slices,FALSE);
+ fghCircleTable(&sint,&cost,-slices,GL_FALSE);
/* Allocate vertex and normal buffers, bail out if memory allocation fails */
*vertices = malloc((*nVert)*3*sizeof(GLfloat));
if ((*nVert) > 65535)
/*
- * limit of glushort, thats 256*256 subdivisions, should be enough in practice.
- * But still:
- * TODO: must have a better solution than this low limit, at least for architectures where gluint is available
+ * limit of glushort, thats 256*256 subdivisions, should be enough in practice. See note above
*/
fgWarning("fghGenerateTorus: too many slices or stacks requested, indices will wrap");
/* precompute values on unit circle */
- fghCircleTable(&spsi,&cpsi, nRings,FALSE);
- fghCircleTable(&sphi,&cphi,-nSides,FALSE);
+ fghCircleTable(&spsi,&cpsi, nRings,GL_FALSE);
+ fghCircleTable(&sphi,&cphi,-nSides,GL_FALSE);
/* Allocate vertex and normal buffers, bail out if memory allocation fails */
*vertices = malloc((*nVert)*3*sizeof(GLfloat));
void FGAPIENTRY glutSolidSphere(double radius, GLint slices, GLint stacks)
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSphere" );
- fghSphere((GLfloat)radius, slices, stacks, FALSE );
+ fghSphere((GLfloat)radius, slices, stacks, GL_FALSE );
}
/*
void FGAPIENTRY glutWireSphere(double radius, GLint slices, GLint stacks)
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSphere" );
- fghSphere((GLfloat)radius, slices, stacks, TRUE );
+ fghSphere((GLfloat)radius, slices, stacks, GL_TRUE );
}
void FGAPIENTRY glutSolidCone( double base, double height, GLint slices, GLint stacks )
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCone" );
- fghCone((GLfloat)base, (GLfloat)height, slices, stacks, FALSE );
+ fghCone((GLfloat)base, (GLfloat)height, slices, stacks, GL_FALSE );
}
/*
void FGAPIENTRY glutWireCone( double base, double height, GLint slices, GLint stacks)
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCone" );
- fghCone((GLfloat)base, (GLfloat)height, slices, stacks, TRUE );
+ fghCone((GLfloat)base, (GLfloat)height, slices, stacks, GL_TRUE );
}
void FGAPIENTRY glutSolidCylinder(double radius, double height, GLint slices, GLint stacks)
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCylinder" );
- fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, FALSE );
+ fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, GL_FALSE );
}
/*
void FGAPIENTRY glutWireCylinder(double radius, double height, GLint slices, GLint stacks)
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCylinder" );
- fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, TRUE );
+ fghCylinder((GLfloat)radius, (GLfloat)height, slices, stacks, GL_TRUE );
}
/*
void FGAPIENTRY glutWireTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTorus" );
- fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, TRUE);
+ fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, GL_TRUE);
}
/*
void FGAPIENTRY glutSolidTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTorus" );
- fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, FALSE);
+ fghTorus((GLfloat)dInnerRadius, (GLfloat)dOuterRadius, nSides, nRings, GL_FALSE);
}
void FGAPIENTRY glutWire##nameICaps( void )\
{\
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWire"#nameICaps );\
- fgh##nameICaps( TRUE );\
+ fgh##nameICaps( GL_TRUE );\
}\
void FGAPIENTRY glutSolid##nameICaps( void )\
{\
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolid"#nameICaps );\
- fgh##nameICaps( FALSE );\
+ fgh##nameICaps( GL_FALSE );\
}
void FGAPIENTRY glutWireCube( double dSize )
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" );
- fghCube( (GLfloat)dSize, TRUE );
+ fghCube( (GLfloat)dSize, GL_TRUE );
}
void FGAPIENTRY glutSolidCube( double dSize )
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" );
- fghCube( (GLfloat)dSize, FALSE );
+ fghCube( (GLfloat)dSize, GL_FALSE );
}
DECLARE_SHAPE_INTERFACE(Dodecahedron)
void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, double offset[3], double scale )
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSierpinskiSponge" );
- fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, TRUE );
+ fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, GL_TRUE );
}
void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, double offset[3], double scale )
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSierpinskiSponge" );
- fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, FALSE );
+ fghSierpinskiSponge ( num_levels, offset, (GLfloat)scale, GL_FALSE );
}
DECLARE_SHAPE_INTERFACE(Tetrahedron)