How to manage code to display animation only once? - c++

i am making a program to animate a ball over a field
it goes like,
void display()
{
/*
code to draw a field
*/
loop:1 to 5
loop:1 to 6
/*
here comes the code to animate the ball over the field
*/
}
I want whenever user press "right_Arrow" the whole scene get rotated by
some angle
problem:whenever the user presses "right_Arrow" key it rotate the scene by some angle but also display whole animation again...but i want animation to be displayed only once(after maximazing window) and then the user can rotate the whole scene
by some angle without displaying any animation on pressing "right_Arrow" key
How should i do this in my code?

Again your problem lies in your mistake to do the animation completely in the display function. I extended my example I wrote you yesterday a bit; After starting the program, the animation will play for 5 seconds, then stop. Pressing [R] resets the animation (thus starts it again), pressing [+] / [-] rotates the scene around the Y axis.
http://homepages.physik.uni-muenchen.de/~Wolfgang.Draxinger/stuff/sinsphere_rot.c
EDIT: commenting
/* This is ANSI-C - don't try to compile with a C++ compiler, it will fail! */
#include <GL/glut.h>
#include <stdlib.h>
#include <sys/time.h>
#include <math.h>
#define M_PI 3.1415926535897932384626433832795029L
#define M_PI_2 1.5707963267948966192313216916397514L
# define timersub(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
if ((result)->tv_usec < 0) { \
--(result)->tv_sec; \
(result)->tv_usec += 1000000; \
} \
} while (0)
void idle(void);
void animate(float dT);
void display(void);
void keyboard(unsigned char key, int x, int y);
void init_sphere(unsigned int rings, unsigned int sectors);
void draw_sphere(void);
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutCreateWindow("SinSphere");
glutIdleFunc(idle);
glutKeyboardFunc(keyboard);
glutDisplayFunc(display);
init_sphere(10, 30);
glutMainLoop();
return 0;
}
This is all just boilerplate code, nothing special.
struct AnimationState
{
float time;
float duration;
float sphere_speed;
float sphere_path_radius;
float sphere_path_bobbing;
float sphere_position[3];
};
static struct AnimationState animation = {
0.,
5., /* play for 5 seconds */
0.1, 3., 1.,
{1., 0., 0.}
};
AnimationState got an additional element duration; after that time the animation will stop playing, by testing if animation.time < animation.duration and only advance the animation step if so.
void animate(float dT)
{
if(animation.time < animation.duration) {
animation.time += dT;
animation.sphere_position[0] = animation.sphere_path_radius * cos(2*M_PI * animation.time * animation.sphere_speed);
animation.sphere_position[1] = animation.sphere_path_bobbing * sin(2*M_PI * animation.time * 5 * animation.sphere_speed);
animation.sphere_position[2] = animation.sphere_path_radius * sin(2*M_PI * animation.time * animation.sphere_speed);
}
}
struct ViewState {
float rotation;
float rotation_step;
};
static struct ViewState view = {
0.,
0.1
};
ViewState stores the rotation. This is really a dumbed down version, usually implements this through a view transformation matix and steppings for that.
void keyboard(unsigned char key, int x, int y)
{
switch(key) {
case 'R':
case 'r': /* restart animation */
animation.time = 0.;
break;
case '+':
view.rotation += view.rotation_step;
break;
case '-':
view.rotation -= view.rotation_step;
break;
}
glutPostRedisplay();
}
Keyboard handler function should be obvious.
GLfloat *sphere_vertices_normals;
unsigned int sphere_quads = 0;
GLushort *sphere_indices;
void init_sphere(unsigned int rings, unsigned int sectors)
{
float const R = 1./(float)(rings-1);
float const S = 1./(float)(sectors-1);
int r, s;
sphere_vertices_normals = malloc(sizeof(GLfloat)*3 * rings*sectors);
GLfloat *v = sphere_vertices_normals;
for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
float const y = sin( -M_PI_2 + M_PI * r * R );
float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R );
float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R );
v[0] = x;
v[1] = y;
v[2] = z;
v+=3;
}
sphere_indices = malloc(sizeof(GLushort) * rings * sectors * 4);
GLushort *i = sphere_indices;
for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
*i++ = r * sectors + s;
*i++ = r * sectors + (s+1);
*i++ = (r+1) * sectors + (s+1);
*i++ = (r+1) * sectors + s;
sphere_quads++;
}
}
init_sphere build us some nice vertex and index array containing sphere geometry. Exercise for the reader: Put it in a Vertex Buffer Object.
void draw_sphere()
{
glTranslatef(animation.sphere_position[0], animation.sphere_position[1], animation.sphere_position[2]);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, sphere_vertices_normals);
glNormalPointer(GL_FLOAT, 0, sphere_vertices_normals);
glDrawElements(GL_QUADS, sphere_quads*4, GL_UNSIGNED_SHORT, sphere_indices);
}
void idle()
{
glutPostRedisplay();
}
The idle function gets called after all input events have been processed. Input events are keypresses and the like. GLUT events only get processed after the display handler returns. So you must not implement the animation timer loop within the display handler. Instead you determine the time for a single display, then advance the loop by that timestep for the next display iteration. idle initiate the next display pass after event processing.
static GLfloat const light_pos[4] = {-1., 1., 1., 0.};
static GLfloat const light_color[4] = {1., 1., 1., 1.};
void display()
{
static struct timeval delta_T = {0., 0.};
struct timeval time_frame_begin, time_frame_end;
int win_width, win_height;
float win_aspect;
gettimeofday(&time_frame_begin, 0);
animate(delta_T.tv_sec + delta_T.tv_usec * 1.e-6);
win_width = glutGet(GLUT_WINDOW_WIDTH);
win_height = glutGet(GLUT_WINDOW_HEIGHT);
win_aspect = (float)win_width/(float)win_height;
glViewport(0, 0, win_width, win_height);
glClearColor(0.6, 0.6, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-win_aspect, win_aspect, -1., 1., 1., 10.);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0,0,-5.5);
glRotatef(view.rotation * 180./M_PI, 0, 1, 0);
glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color);
glPushMatrix();
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
draw_sphere();
glPopMatrix();
glutSwapBuffers();
gettimeofday(&time_frame_end, 0);
timersub(&time_frame_end, &time_frame_begin, &delta_T);
}
Instead of measureing the time spent in display a more accurate approach is measuring the time between each invocation of display to take time spent in other parts of the programm into account. This is an exercise left to the reader.

Related

Issue with creating a sphere in OpenGL [duplicate]

I am not able to create a simple 3D sphere using the OpenGL library function glutSolidSphere() in C++.
Here's what I tried:
#include<GL/glu.h>
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,0.0,0.0);
glLoadIdentity();
glutSolidSphere( 5.0, 20.0, 20.0);
glFlush();
}
void myInit()
{
glClearColor(1.0,1.0,1.0,1.0);
glColor3f(1.0,0.0,0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,499.0,0.0,499.0);
glMatrixMode(GL_MODELVIEW);
}
void main(int argc,char **argv)
{
qobj = gluNewQuadric();
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(500,500);
glutCreateWindow("pendulum");
glutDisplayFunc(display);
myInit();
glutMainLoop();
}
In OpenGL you don't create objects, you just draw them. Once they are drawn, OpenGL no longer cares about what geometry you sent it.
glutSolidSphere is just sending drawing commands to OpenGL. However there's nothing special in and about it. And since it's tied to GLUT I'd not use it. Instead, if you really need some sphere in your code, how about create if for yourself?
#define _USE_MATH_DEFINES
#include <GL/gl.h>
#include <GL/glu.h>
#include <vector>
#include <cmath>
// your framework of choice here
class SolidSphere
{
protected:
std::vector<GLfloat> vertices;
std::vector<GLfloat> normals;
std::vector<GLfloat> texcoords;
std::vector<GLushort> indices;
public:
SolidSphere(float radius, unsigned int rings, unsigned int sectors)
{
float const R = 1./(float)(rings-1);
float const S = 1./(float)(sectors-1);
int r, s;
vertices.resize(rings * sectors * 3);
normals.resize(rings * sectors * 3);
texcoords.resize(rings * sectors * 2);
std::vector<GLfloat>::iterator v = vertices.begin();
std::vector<GLfloat>::iterator n = normals.begin();
std::vector<GLfloat>::iterator t = texcoords.begin();
for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
float const y = sin( -M_PI_2 + M_PI * r * R );
float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R );
float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R );
*t++ = s*S;
*t++ = r*R;
*v++ = x * radius;
*v++ = y * radius;
*v++ = z * radius;
*n++ = x;
*n++ = y;
*n++ = z;
}
indices.resize(rings * sectors * 4);
std::vector<GLushort>::iterator i = indices.begin();
for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
*i++ = r * sectors + s;
*i++ = r * sectors + (s+1);
*i++ = (r+1) * sectors + (s+1);
*i++ = (r+1) * sectors + s;
}
}
void draw(GLfloat x, GLfloat y, GLfloat z)
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(x,y,z);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, &vertices[0]);
glNormalPointer(GL_FLOAT, 0, &normals[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &texcoords[0]);
glDrawElements(GL_QUADS, indices.size(), GL_UNSIGNED_SHORT, &indices[0]);
glPopMatrix();
}
};
SolidSphere sphere(1, 12, 24);
void display()
{
int const win_width = …; // retrieve window dimensions from
int const win_height = …; // framework of choice here
float const win_aspect = (float)win_width / (float)win_height;
glViewport(0, 0, win_width, win_height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, win_aspect, 1, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
#ifdef DRAW_WIREFRAME
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
#endif
sphere.draw(0, 0, -5);
swapBuffers();
}
int main(int argc, char *argv[])
{
// initialize and register your framework of choice here
return 0;
}
It doesn't seem like anyone so far has addressed the actual problem with your original code, so I thought I would do that even though the question is quite old at this point.
The problem originally had to do with the projection in relation to the radius and position of the sphere. I think you'll find that the problem isn't too complicated. The program actually works correctly, it's just that what is being drawn is very hard to see.
First, an orthogonal projection was created using the call
gluOrtho2D(0.0, 499.0, 0.0, 499.0);
which "is equivalent to calling glOrtho with near = -1 and far = 1." This means that the viewing frustum has a depth of 2. So a sphere with a radius of anything greater than 1 (diameter = 2) will not fit entirely within the viewing frustum.
Then the calls
glLoadIdentity();
glutSolidSphere(5.0, 20.0, 20.0);
are used, which loads the identity matrix of the model-view matrix and then "[r]enders a sphere centered at the modeling coordinates origin of the specified radius." Meaning, the sphere is rendered at the origin, (x, y, z) = (0, 0, 0), and with a radius of 5.
Now, the issue is three-fold:
Since the window is 500x500 pixels and the width and height of the viewing frustum is almost 500 (499.0), the small radius of the sphere (5.0) makes its projected area only slightly over one fiftieth (2*5/499) of the size of the window in each dimension. This means that the apparent size of the sphere would be roughly 1/2,500th (actually pi*5^2/499^2, which is closer to about 1/3170th) of the entire window, so it might be difficult to see. This is assuming the entire circle is drawn within the area of the window. It is not, however, as we will see in point 2.
Since the viewing frustum has it's left plane at x = 0 and bottom plane at y = 0, the sphere will be rendered with its geometric center in the very bottom left corner of the window so that only one quadrant of the projected sphere will be visible! This means that what would be seen is even smaller, about 1/10,000th (actually pi*5^2/(4*499^2), which is closer to 1/12,682nd) of the window size. This would make it even more difficult to see. Especially since the sphere is rendered so close to the edges/corner of the screen where you might not think to look.
Since the depth of the viewing frustum is significantly smaller than the diameter of the sphere (less than half), only a sliver of the sphere will be within the viewing frustum, rendering only that part. So you will get more like a hollow circle on the screen than a solid sphere/circle. As it happens, the thickness of that sliver might represent less than 1 pixel on the screen which means we might even see nothing on the screen, even if part of the sphere is indeed within the viewing frustum.
The solution is simply to change the viewing frustum and radius of the sphere. For instance,
gluOrtho2D(-5.0, 5.0, -5.0, 5.0);
glutSolidSphere(5.0, 20, 20);
renders the following image.
As you can see, only a small part is visible around the "equator", of the sphere with a radius of 5. (I changed the projection to fill the window with the sphere.) Another example,
gluOrtho2D(-1.1, 1.1, -1.1, 1.1);
glutSolidSphere(1.1, 20, 20);
renders the following image.
The image above shows more of the sphere inside of the viewing frustum, but still the sphere is 0.2 depth units larger than the viewing frustum. As you can see, the "ice caps" of the sphere are missing, both the north and the south. So, if we want the entire sphere to fit within the viewing frustum which has depth 2, we must make the radius less than or equal to 1.
gluOrtho2D(-1.0, 1.0, -1.0, 1.0);
glutSolidSphere(1.0, 20, 20);
renders the following image.
I hope this has helped someone. Take care!
I don't understand how can datenwolf`s index generation can be correct. But still I find his solution rather clear. This is what I get after some thinking:
inline void push_indices(vector<GLushort>& indices, int sectors, int r, int s) {
int curRow = r * sectors;
int nextRow = (r+1) * sectors;
indices.push_back(curRow + s);
indices.push_back(nextRow + s);
indices.push_back(nextRow + (s+1));
indices.push_back(curRow + s);
indices.push_back(nextRow + (s+1));
indices.push_back(curRow + (s+1));
}
void createSphere(vector<vec3>& vertices, vector<GLushort>& indices, vector<vec2>& texcoords,
float radius, unsigned int rings, unsigned int sectors)
{
float const R = 1./(float)(rings-1);
float const S = 1./(float)(sectors-1);
for(int r = 0; r < rings; ++r) {
for(int s = 0; s < sectors; ++s) {
float const y = sin( -M_PI_2 + M_PI * r * R );
float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R );
float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R );
texcoords.push_back(vec2(s*S, r*R));
vertices.push_back(vec3(x,y,z) * radius);
push_indices(indices, sectors, r, s);
}
}
}
Here's the code:
glPushMatrix();
glTranslatef(18,2,0);
glRotatef(angle, 0, 0, 0.7);
glColor3ub(0,255,255);
glutWireSphere(3,10,10);
glPopMatrix();
I like the answer of coin. It's simple to understand and works with triangles. However the indexes of his program are sometimes over the bounds. So I post here his code with two tiny corrections:
inline void push_indices(vector<GLushort>& indices, int sectors, int r, int s) {
int curRow = r * sectors;
int nextRow = (r+1) * sectors;
int nextS = (s+1) % sectors;
indices.push_back(curRow + s);
indices.push_back(nextRow + s);
indices.push_back(nextRow + nextS);
indices.push_back(curRow + s);
indices.push_back(nextRow + nextS);
indices.push_back(curRow + nextS);
}
void createSphere(vector<vec3>& vertices, vector<GLushort>& indices, vector<vec2>& texcoords,
float radius, unsigned int rings, unsigned int sectors)
{
float const R = 1./(float)(rings-1);
float const S = 1./(float)(sectors-1);
for(int r = 0; r < rings; ++r) {
for(int s = 0; s < sectors; ++s) {
float const y = sin( -M_PI_2 + M_PI * r * R );
float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R );
float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R );
texcoords.push_back(vec2(s*S, r*R));
vertices.push_back(vec3(x,y,z) * radius);
if(r < rings-1)
push_indices(indices, sectors, r, s);
}
}
}
Datanewolf's code is ALMOST right. I had to reverse both the winding and the normals to make it work properly with the fixed pipeline. The below works correctly with cull on or off for me:
std::vector<GLfloat> vertices;
std::vector<GLfloat> normals;
std::vector<GLfloat> texcoords;
std::vector<GLushort> indices;
float const R = 1./(float)(rings-1);
float const S = 1./(float)(sectors-1);
int r, s;
vertices.resize(rings * sectors * 3);
normals.resize(rings * sectors * 3);
texcoords.resize(rings * sectors * 2);
std::vector<GLfloat>::iterator v = vertices.begin();
std::vector<GLfloat>::iterator n = normals.begin();
std::vector<GLfloat>::iterator t = texcoords.begin();
for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
float const y = sin( -M_PI_2 + M_PI * r * R );
float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R );
float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R );
*t++ = s*S;
*t++ = r*R;
*v++ = x * radius;
*v++ = y * radius;
*v++ = z * radius;
*n++ = -x;
*n++ = -y;
*n++ = -z;
}
indices.resize(rings * sectors * 4);
std::vector<GLushort>::iterator i = indices.begin();
for(r = 0; r < rings-1; r++)
for(s = 0; s < sectors-1; s++) {
/*
*i++ = r * sectors + s;
*i++ = r * sectors + (s+1);
*i++ = (r+1) * sectors + (s+1);
*i++ = (r+1) * sectors + s;
*/
*i++ = (r+1) * sectors + s;
*i++ = (r+1) * sectors + (s+1);
*i++ = r * sectors + (s+1);
*i++ = r * sectors + s;
}
Edit: There was a question on how to draw this... in my code I encapsulate these values in a G3DModel class. This is my code to setup the frame, draw the model, and end it:
void GraphicsProvider3DPriv::BeginFrame()const{
int win_width;
int win_height;// framework of choice here
glfwGetWindowSize(window, &win_width, &win_height); // retrieve window
float const win_aspect = (float)win_width / (float)win_height;
// set lighting
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
GLfloat lightpos[] = {0, 0.0, 0, 0.};
glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
// set up world transform
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT|GL_ACCUM_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, win_aspect, 1, 10);
glMatrixMode(GL_MODELVIEW);
}
void GraphicsProvider3DPriv::DrawModel(const G3DModel* model, const Transform3D transform)const{
G3DModelPriv* privModel = (G3DModelPriv *)model;
glPushMatrix();
glLoadMatrixf(transform.GetOGLData());
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, &privModel->vertices[0]);
glNormalPointer(GL_FLOAT, 0, &privModel->normals[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &privModel->texcoords[0]);
glEnable(GL_TEXTURE_2D);
//glFrontFace(GL_CCW);
glEnable(GL_CULL_FACE);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, privModel->texname);
glDrawElements(GL_QUADS, privModel->indices.size(), GL_UNSIGNED_SHORT, &privModel->indices[0]);
glPopMatrix();
glDisable(GL_TEXTURE_2D);
}
void GraphicsProvider3DPriv::EndFrame()const{
/* Swap front and back buffers */
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);
glDisable(GL_CULL_FACE);
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}

in opengl, how to change mouse follow to mouse click, drag and move on release?

I have program in which the object (a triangle) follows the mouse as it moves around and rotates to the direction its moving. What do I have to do to make it so the object stays still, until I click it, drag it to a position and once I release the mouse, it starts to move to that position?
#include <GL/glut.h>
#include <math.h>
# define ANIMATION_STEP (1000/300)
# define PI 3.1415926535897932
struct Globals {
centre_x, centre_y, rotate;
float length;
float mouse_x, mouse_y, speed;
int animating;
} globals;
void init(void){
// Starting position of the triangle
globals.centre_x = 100;
globals.centre_y = 100;
globals.rotate = 0.0;
globals.mouse_x = 300.0;
globals.mouse_y = 300.0;
// Animation speed in pixels per second
globals.speed = 300.0;
// size of the triangle
globals.length = 27;
globals.animating = 1;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 1000.0, 0.0, 700.0);
}
void triangle(void){
glBegin(GL_POLYGON);
glVertex2f(0.5, 0.0);
glVertex2f(-0.5, -0.5);
glVertex2f(-0.5, 0.5);
glEnd();
}
void display(void){
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(globals.mouse_x, globals.mouse_y, 0.0);
glRotatef(globals.rotate, 0.0, 0.0, 1.0);
glScalef(globals.length, globals.length, 1.0);
triangle();
glFlush();
glutSwapBuffers();
}
float limit(float x, float min, float max){
if (x < min) {
x = min;
}
if (x > max) {
x = max;
}
return x;
}
void timer(int v){
// Computing elapsed time for smooth animation.
int time = glutGet(GLUT_ELAPSED_TIME);
float angle;
glutTimerFunc(ANIMATION_STEP, timer, time);
if (globals.animating) {
int delta_t = time - v;
float delta_x, delta_y, length, step_size;
// Compute vector from current location to mouse
delta_x = globals.mouse_x - globals.centre_x;
delta_y = globals.mouse_y - globals.centre_y;
// Compute length of the vector
length = sqrt (delta_x*delta_x + delta_y*delta_y);
// If the triangle is close to the mouse, then no motion is required.
step_size = globals.speed * delta_t / 1000.0;
if (length > step_size * 0.55) {
delta_x = delta_x / length;
delta_y = delta_y / length;
globals.centre_x += delta_x * step_size;
globals.centre_y += delta_y * step_size;
angle = atan2(delta_y, delta_x);
globals.rotate = angle * 180.0 / PI;
// Keep the triangle inside the world window.
globals.centre_x = limit(globals.centre_x, 0.0 + globals.length/2, 1000.0 - globals.length/2);
globals.centre_y = limit(globals.centre_y, 0.0 + globals.length/2, 700.0 - globals.length/2);
}
glutPostRedisplay();
}
}
void mousemotion(int x, int yc){
globals.mouse_x = x;
globals.mouse_y = 700 - yc;
glutPostRedisplay();
}
main(int argc, char** argv){
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(1000, 700);
glutInitWindowPosition(10, 10);
glutDisplayFunc(display);
glutTimerFunc(ANIMATION_STEP, timer, 0);
glutPassiveMotionFunc(mousemotion);
init();
glutMainLoop();
return 0;
}
I have investigated processMouse() where if state == GLUT_DOWN then it records the current position and mouse press cordinates, but the best ive been able to get is that it immediately teleports to the mouse click. Can someone please explain what I would need to do to click on it, drag, release, then move to position?
in opengl, how to change mouse...
You don't. Mouse does not exist in OpenGL. Maybe you should change the question to "How to process mouse events in windows/GLUT/SDL/whatever-framework?" for which there are dozens of duplicates.

How to correctly translate objects independently of one another?

I am attempting to translate one circle independent of a separate, stationary circle, utilizing glTranslatef();. However, with my current, full code, each of my circles remains immobile. To investigate why this may be so, I have researched several answers, each comparable to those found here and here. Additionally, I read up on glLoadIdentity as well as the differences between GL_MODELVIEW and GL_PROJECTION, just to see if their details would offer any further clarification. I've also consulted the OpenGL API for the proper definitions of each of the above.
In the style of these solutions, I produced the following do...while loop:
do{
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, fb_width, fb_height, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(0,1,0);
drawCircle(1280 * 0.50, 720 * 0.25,e[2]);
glPopMatrix();
glPushMatrix();
glTranslatef(0,0,0);
drawTarget(1280 * 0.50, 720 * 0.75,50);
glPopMatrix();
glfwSwapBuffers(w);
glfwPollEvents();
}
while (!glfwWindowShouldClose(w));
In this snippet, the drawCircle drawing remains stationary, but I would like for it to follow the written glTranslatef(0,1,0) instead. Is the stationary nature of the circle due to misplaced a glMatrixMode or glLoadIdentity, or perhaps due to the fact that they are being called within the do...while loop and the proper matrix is never really being utilized? I would appreciate any guidance you may have as to why the aforementioned and accepted answers are not functioning quite as well within my program.
For the sake of full transparency, here is the entirety of my code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#include <stddef.h>
#include <stdbool.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
GLFWwindow *w;
int fb_width, fb_height;
static void error(int error, const char *desc)
{
fputs(desc, stderr);
}
static void key_callback(GLFWwindow *w, int key, int scancode, int action, int mods)
{
if ((key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) && action == GLFW_PRESS)
glfwSetWindowShouldClose(w, GL_TRUE);
}
void drawCircle(float cx, float cy, float radius)
{
float num_segments = 360;
float theta = 2 * 3.1415926 / num_segments;
float c = cosf(theta);//precalculate the sine and cosine
float s = sinf(theta);
float t;
float x = radius;//we start at angle = 0
float y = 0;
glBegin(GL_TRIANGLE_FAN);
glColor3f(1, 0, 1);
for(int ii = 0; ii < num_segments; ii++)
{
glVertex2f(x + cx, y + cy);//output vertex
//apply the rotation matrix
t = x;
x = c * x - s * y;
y = s * t + c * y;
}
glEnd();
}
void drawTarget(float cx, float cy, float radius)
{
float num_segments = 360;
float theta = 2 * 3.1415926 / num_segments;
float c = cosf(theta);//precalculate the sine and cosine
float s = sinf(theta);
float t;
float x = radius;//we start at angle = 0
float y = 0;
glBegin(GL_LINE_LOOP);
glColor3f(1, 1, 1);
for(int ii = 0; ii < num_segments; ii++)
{
glVertex2f(x + cx, y + cy);//output vertex
//apply the rotation matrix
t = x;
x = c * x - s * y;
y = s * t + c * y;
}
glEnd();
}
int main(void)
{
int i;
float e[3] = {140,120,100};
float m[3] = {90,80,70};
float h[3] = {60,50,40};
glfwSetErrorCallback(error);
if (!glfwInit())
exit(EXIT_FAILURE);
w = glfwCreateWindow(1280, 720, "AxTest", NULL, NULL);
if (!w)
{
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(w);
glfwSetKeyCallback(w, key_callback);
glfwGetFramebufferSize(w, &fb_width, &fb_height);
do{
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, fb_width, fb_height, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(0,1,0);
drawCircle(1280 * 0.50, 720 * 0.25,e[2]);
glPopMatrix();
glPushMatrix();
glTranslatef(0,0,0);
drawTarget(1280 * 0.50, 720 * 0.75,50);
glPopMatrix();
glfwSwapBuffers(w);
glfwPollEvents();
}
while (!glfwWindowShouldClose(w));
glfwDestroyWindow(w);
glfwTerminate();
exit(EXIT_SUCCESS);
return 0;
}
The values for the vertex positions with which you draw your circles are in the order of hundreds (likely, because you want to address pixels as indicated by the values for the projection matrix). But glTranslates sees only a small number, so the shift is miniscule (one pixel) and hence you think nothing did happen. If you rewrite your code so that you don't specify the circle/target center by explicit modification of the vertex position offset it'd be clearer.
void drawCircle(float radius)
{
/* ... */
for(int ii = 0; ii < num_segments; ii++)
{
glVertex2f(x, y); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/* ... */
}
void drawTarget(float radius)
{
/* ... */
for(int ii = 0; ii < num_segments; ii++)
{
glVertex2f(x, y); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/* ... */
}
int main(void)
{
/* ... */
glPushMatrix();
glTranslatef(1280*0.50, 720*0.25, 0);
drawCircle(e[2]);
glPopMatrix();
glPushMatrix();
glTranslatef(1280 * 0.50, 720 * 0.25, 0);
drawTarget(50);
glPopMatrix();
/* ... */
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, fb_width, fb_height, 0, 0, 1);
You don't have to make the projection matrix at every loop, put it before the loop.
Then the error you have is surely due to :
glMatrixMode(GL_MODELVIEW);
// it miss glLoadIdentity() here
glPushMatrix();
glTranslatef(0,1,0);

Explanation of openGL particle effect [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
So I have this code that produces fireworks using what appears to be a particle effect, but I don't understand what is going on in the code. Could someone explain it to me, particularly the initialize function and the draw blast blast function. If you could annotate it with notes that would be super.
/* fireworks.c - simulate fireworks with particle systems */
#include <GL/glut.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef WIN32
//to correct ASCI deviations in Microsoft VC++ 6.0
#define M_PI (3.1415926535897932384626433832795)
double drand48()
{ return (rand()%10000)/10000.0; }
//end of corrections
#endif
#define MAX_POINTS 5000
int numPoints;
GLfloat curx, cury;
GLfloat x[MAX_POINTS], y[MAX_POINTS];
GLfloat xacc[MAX_POINTS], yacc[MAX_POINTS];
GLfloat red, green, blue;
int step; int length;
void initialize()
{ int j; double temp, temp2;
numPoints = drand48()*(MAX_POINTS-1);
curx = -0.5 + drand48();
cury = 0.0 + drand48();
red = 0.5 + 0.5*drand48();
green = 0.5 + 0.5*drand48();
blue = 0.5 + 0.5*drand48();
glPointSize(1.5);
step = 0;
length = 700 + 300*drand48();
/* initialize the blast */
for (j=0 ; j<numPoints ; j++ ) {
x[j] = curx;
y[j] = cury;
temp = drand48();
temp2 = drand48()*2.0*M_PI;
xacc[j] = (cos(temp2) * temp)/length;
yacc[j] = (sin(temp2) * temp)/length;
}
}
void draw_blast(void)
{ int i;
double glow = (length - step) / (double)length;
glColor3f(red*glow, green*glow, blue*glow);
glBegin(GL_POINTS);
for (i=0;i<numPoints;i++) {
x[i] += xacc[i];
y[i] += yacc[i];
glVertex2f(x[i], y[i]);
}
glEnd();
glFlush();
glutSwapBuffers();
}
void display(void)
{ int i;
glClear(GL_COLOR_BUFFER_BIT);
if (step < 0.9*length) {
for (i=0; i<numPoints; i++)
yacc[i] -= 0.02 / length; // gravity
draw_blast();
}
step ++;
if (step > length) initialize();
}
void idle(void)
{
glutPostRedisplay();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27: exit(0); break;
}
}
void reshape (int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-1.0, 1.0,
-1.0*(GLfloat)h/(GLfloat)w, 1.0*(GLfloat)h/(GLfloat)w,
-1.0, 1.0);
else
glOrtho(-1.0*(GLfloat)w/(GLfloat)h, 1.0*(GLfloat)w/(GLfloat)h,
-1.0, 1.0,
-1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize (800, 800);
glutInitWindowPosition(0, 0);
glutCreateWindow ("Fireworks");
glClearColor (0.0, 0.0, 0.0, 0.0);
initialize();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}
Yes, it is a particle system. However - not a particularly efficient one.
Let's go through it step by step:
GLfloat x[MAX_POINTS], y[MAX_POINTS];
GLfloat xacc[MAX_POINTS], yacc[MAX_POINTS];
x and y hold the particles' positions. xacc and yacc hold their velocities.
In initialize:
numPoints = drand48()*(MAX_POINTS-1);
This sets a random number of particles...
curx = -0.5 + drand48();
cury = 0.0 + drand48();
red = 0.5 + 0.5*drand48();
green = 0.5 + 0.5*drand48();
blue = 0.5 + 0.5*drand48();
glPointSize(1.5);
step = 0;
length = 700 + 300*drand48();
... with a random center position, color, and radius (length).
for (j=0 ; j<numPoints ; j++ ) {
This starts the initialization for every particle.
x[j] = curx;
y[j] = cury;
Sets the particle's position the the center position.
temp = drand48();
temp2 = drand48()*2.0*M_PI;
xacc[j] = (cos(temp2) * temp)/length;
yacc[j] = (sin(temp2) * temp)/length;
Sets a random direction of the particle (temp2) and a random velocity based on the system's radius (temp / length).
In drawBlast():
double glow = (length - step) / (double)length;
glColor3f(red*glow, green*glow, blue*glow);
Slowly fades the particles' color to black.
x[i] += xacc[i];
y[i] += yacc[i];
Advance the particle by their velocity. This assumes a constant frame rate.
glVertex2f(x[i], y[i]);
Draw the particle as a point.
In display():
yacc[i] -= 0.02 / length; // gravity
Accelerate every particle downwards. I.e. simulate that the particles fall.

Creating a 3D sphere in Opengl using Visual C++

I am not able to create a simple 3D sphere using the OpenGL library function glutSolidSphere() in C++.
Here's what I tried:
#include<GL/glu.h>
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,0.0,0.0);
glLoadIdentity();
glutSolidSphere( 5.0, 20.0, 20.0);
glFlush();
}
void myInit()
{
glClearColor(1.0,1.0,1.0,1.0);
glColor3f(1.0,0.0,0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,499.0,0.0,499.0);
glMatrixMode(GL_MODELVIEW);
}
void main(int argc,char **argv)
{
qobj = gluNewQuadric();
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(500,500);
glutCreateWindow("pendulum");
glutDisplayFunc(display);
myInit();
glutMainLoop();
}
In OpenGL you don't create objects, you just draw them. Once they are drawn, OpenGL no longer cares about what geometry you sent it.
glutSolidSphere is just sending drawing commands to OpenGL. However there's nothing special in and about it. And since it's tied to GLUT I'd not use it. Instead, if you really need some sphere in your code, how about create if for yourself?
#define _USE_MATH_DEFINES
#include <GL/gl.h>
#include <GL/glu.h>
#include <vector>
#include <cmath>
// your framework of choice here
class SolidSphere
{
protected:
std::vector<GLfloat> vertices;
std::vector<GLfloat> normals;
std::vector<GLfloat> texcoords;
std::vector<GLushort> indices;
public:
SolidSphere(float radius, unsigned int rings, unsigned int sectors)
{
float const R = 1./(float)(rings-1);
float const S = 1./(float)(sectors-1);
int r, s;
vertices.resize(rings * sectors * 3);
normals.resize(rings * sectors * 3);
texcoords.resize(rings * sectors * 2);
std::vector<GLfloat>::iterator v = vertices.begin();
std::vector<GLfloat>::iterator n = normals.begin();
std::vector<GLfloat>::iterator t = texcoords.begin();
for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
float const y = sin( -M_PI_2 + M_PI * r * R );
float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R );
float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R );
*t++ = s*S;
*t++ = r*R;
*v++ = x * radius;
*v++ = y * radius;
*v++ = z * radius;
*n++ = x;
*n++ = y;
*n++ = z;
}
indices.resize(rings * sectors * 4);
std::vector<GLushort>::iterator i = indices.begin();
for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
*i++ = r * sectors + s;
*i++ = r * sectors + (s+1);
*i++ = (r+1) * sectors + (s+1);
*i++ = (r+1) * sectors + s;
}
}
void draw(GLfloat x, GLfloat y, GLfloat z)
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(x,y,z);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, &vertices[0]);
glNormalPointer(GL_FLOAT, 0, &normals[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &texcoords[0]);
glDrawElements(GL_QUADS, indices.size(), GL_UNSIGNED_SHORT, &indices[0]);
glPopMatrix();
}
};
SolidSphere sphere(1, 12, 24);
void display()
{
int const win_width = …; // retrieve window dimensions from
int const win_height = …; // framework of choice here
float const win_aspect = (float)win_width / (float)win_height;
glViewport(0, 0, win_width, win_height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, win_aspect, 1, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
#ifdef DRAW_WIREFRAME
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
#endif
sphere.draw(0, 0, -5);
swapBuffers();
}
int main(int argc, char *argv[])
{
// initialize and register your framework of choice here
return 0;
}
It doesn't seem like anyone so far has addressed the actual problem with your original code, so I thought I would do that even though the question is quite old at this point.
The problem originally had to do with the projection in relation to the radius and position of the sphere. I think you'll find that the problem isn't too complicated. The program actually works correctly, it's just that what is being drawn is very hard to see.
First, an orthogonal projection was created using the call
gluOrtho2D(0.0, 499.0, 0.0, 499.0);
which "is equivalent to calling glOrtho with near = -1 and far = 1." This means that the viewing frustum has a depth of 2. So a sphere with a radius of anything greater than 1 (diameter = 2) will not fit entirely within the viewing frustum.
Then the calls
glLoadIdentity();
glutSolidSphere(5.0, 20.0, 20.0);
are used, which loads the identity matrix of the model-view matrix and then "[r]enders a sphere centered at the modeling coordinates origin of the specified radius." Meaning, the sphere is rendered at the origin, (x, y, z) = (0, 0, 0), and with a radius of 5.
Now, the issue is three-fold:
Since the window is 500x500 pixels and the width and height of the viewing frustum is almost 500 (499.0), the small radius of the sphere (5.0) makes its projected area only slightly over one fiftieth (2*5/499) of the size of the window in each dimension. This means that the apparent size of the sphere would be roughly 1/2,500th (actually pi*5^2/499^2, which is closer to about 1/3170th) of the entire window, so it might be difficult to see. This is assuming the entire circle is drawn within the area of the window. It is not, however, as we will see in point 2.
Since the viewing frustum has it's left plane at x = 0 and bottom plane at y = 0, the sphere will be rendered with its geometric center in the very bottom left corner of the window so that only one quadrant of the projected sphere will be visible! This means that what would be seen is even smaller, about 1/10,000th (actually pi*5^2/(4*499^2), which is closer to 1/12,682nd) of the window size. This would make it even more difficult to see. Especially since the sphere is rendered so close to the edges/corner of the screen where you might not think to look.
Since the depth of the viewing frustum is significantly smaller than the diameter of the sphere (less than half), only a sliver of the sphere will be within the viewing frustum, rendering only that part. So you will get more like a hollow circle on the screen than a solid sphere/circle. As it happens, the thickness of that sliver might represent less than 1 pixel on the screen which means we might even see nothing on the screen, even if part of the sphere is indeed within the viewing frustum.
The solution is simply to change the viewing frustum and radius of the sphere. For instance,
gluOrtho2D(-5.0, 5.0, -5.0, 5.0);
glutSolidSphere(5.0, 20, 20);
renders the following image.
As you can see, only a small part is visible around the "equator", of the sphere with a radius of 5. (I changed the projection to fill the window with the sphere.) Another example,
gluOrtho2D(-1.1, 1.1, -1.1, 1.1);
glutSolidSphere(1.1, 20, 20);
renders the following image.
The image above shows more of the sphere inside of the viewing frustum, but still the sphere is 0.2 depth units larger than the viewing frustum. As you can see, the "ice caps" of the sphere are missing, both the north and the south. So, if we want the entire sphere to fit within the viewing frustum which has depth 2, we must make the radius less than or equal to 1.
gluOrtho2D(-1.0, 1.0, -1.0, 1.0);
glutSolidSphere(1.0, 20, 20);
renders the following image.
I hope this has helped someone. Take care!
I don't understand how can datenwolf`s index generation can be correct. But still I find his solution rather clear. This is what I get after some thinking:
inline void push_indices(vector<GLushort>& indices, int sectors, int r, int s) {
int curRow = r * sectors;
int nextRow = (r+1) * sectors;
indices.push_back(curRow + s);
indices.push_back(nextRow + s);
indices.push_back(nextRow + (s+1));
indices.push_back(curRow + s);
indices.push_back(nextRow + (s+1));
indices.push_back(curRow + (s+1));
}
void createSphere(vector<vec3>& vertices, vector<GLushort>& indices, vector<vec2>& texcoords,
float radius, unsigned int rings, unsigned int sectors)
{
float const R = 1./(float)(rings-1);
float const S = 1./(float)(sectors-1);
for(int r = 0; r < rings; ++r) {
for(int s = 0; s < sectors; ++s) {
float const y = sin( -M_PI_2 + M_PI * r * R );
float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R );
float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R );
texcoords.push_back(vec2(s*S, r*R));
vertices.push_back(vec3(x,y,z) * radius);
push_indices(indices, sectors, r, s);
}
}
}
Here's the code:
glPushMatrix();
glTranslatef(18,2,0);
glRotatef(angle, 0, 0, 0.7);
glColor3ub(0,255,255);
glutWireSphere(3,10,10);
glPopMatrix();
I like the answer of coin. It's simple to understand and works with triangles. However the indexes of his program are sometimes over the bounds. So I post here his code with two tiny corrections:
inline void push_indices(vector<GLushort>& indices, int sectors, int r, int s) {
int curRow = r * sectors;
int nextRow = (r+1) * sectors;
int nextS = (s+1) % sectors;
indices.push_back(curRow + s);
indices.push_back(nextRow + s);
indices.push_back(nextRow + nextS);
indices.push_back(curRow + s);
indices.push_back(nextRow + nextS);
indices.push_back(curRow + nextS);
}
void createSphere(vector<vec3>& vertices, vector<GLushort>& indices, vector<vec2>& texcoords,
float radius, unsigned int rings, unsigned int sectors)
{
float const R = 1./(float)(rings-1);
float const S = 1./(float)(sectors-1);
for(int r = 0; r < rings; ++r) {
for(int s = 0; s < sectors; ++s) {
float const y = sin( -M_PI_2 + M_PI * r * R );
float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R );
float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R );
texcoords.push_back(vec2(s*S, r*R));
vertices.push_back(vec3(x,y,z) * radius);
if(r < rings-1)
push_indices(indices, sectors, r, s);
}
}
}
Datanewolf's code is ALMOST right. I had to reverse both the winding and the normals to make it work properly with the fixed pipeline. The below works correctly with cull on or off for me:
std::vector<GLfloat> vertices;
std::vector<GLfloat> normals;
std::vector<GLfloat> texcoords;
std::vector<GLushort> indices;
float const R = 1./(float)(rings-1);
float const S = 1./(float)(sectors-1);
int r, s;
vertices.resize(rings * sectors * 3);
normals.resize(rings * sectors * 3);
texcoords.resize(rings * sectors * 2);
std::vector<GLfloat>::iterator v = vertices.begin();
std::vector<GLfloat>::iterator n = normals.begin();
std::vector<GLfloat>::iterator t = texcoords.begin();
for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
float const y = sin( -M_PI_2 + M_PI * r * R );
float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R );
float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R );
*t++ = s*S;
*t++ = r*R;
*v++ = x * radius;
*v++ = y * radius;
*v++ = z * radius;
*n++ = -x;
*n++ = -y;
*n++ = -z;
}
indices.resize(rings * sectors * 4);
std::vector<GLushort>::iterator i = indices.begin();
for(r = 0; r < rings-1; r++)
for(s = 0; s < sectors-1; s++) {
/*
*i++ = r * sectors + s;
*i++ = r * sectors + (s+1);
*i++ = (r+1) * sectors + (s+1);
*i++ = (r+1) * sectors + s;
*/
*i++ = (r+1) * sectors + s;
*i++ = (r+1) * sectors + (s+1);
*i++ = r * sectors + (s+1);
*i++ = r * sectors + s;
}
Edit: There was a question on how to draw this... in my code I encapsulate these values in a G3DModel class. This is my code to setup the frame, draw the model, and end it:
void GraphicsProvider3DPriv::BeginFrame()const{
int win_width;
int win_height;// framework of choice here
glfwGetWindowSize(window, &win_width, &win_height); // retrieve window
float const win_aspect = (float)win_width / (float)win_height;
// set lighting
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
GLfloat lightpos[] = {0, 0.0, 0, 0.};
glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
// set up world transform
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT|GL_ACCUM_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, win_aspect, 1, 10);
glMatrixMode(GL_MODELVIEW);
}
void GraphicsProvider3DPriv::DrawModel(const G3DModel* model, const Transform3D transform)const{
G3DModelPriv* privModel = (G3DModelPriv *)model;
glPushMatrix();
glLoadMatrixf(transform.GetOGLData());
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, &privModel->vertices[0]);
glNormalPointer(GL_FLOAT, 0, &privModel->normals[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &privModel->texcoords[0]);
glEnable(GL_TEXTURE_2D);
//glFrontFace(GL_CCW);
glEnable(GL_CULL_FACE);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, privModel->texname);
glDrawElements(GL_QUADS, privModel->indices.size(), GL_UNSIGNED_SHORT, &privModel->indices[0]);
glPopMatrix();
glDisable(GL_TEXTURE_2D);
}
void GraphicsProvider3DPriv::EndFrame()const{
/* Swap front and back buffers */
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);
glDisable(GL_CULL_FACE);
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}