/* * An example of using GLASS active points * * Copyright (C) 2001-2003 Robert Ancell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* compile with make */ #include #include #include #include typedef struct _Particle { GLfloat pos[3], vel[3], age; struct _Particle *last; struct _Particle *next; } Particle; void init_glass(void); void init_glut(void); void reshape(int x, int y); void keyboard(unsigned char, int, int); void mouse(int, int, int, int); void mouse_motion(int, int); void add_particle(void); void remove_particle(Particle *particle); void move_particles(GLfloat dt); void animate(void); void draw_particles(void); void display(void); int main(int argc, char **argv); GlassModel *arm_model; int base_rot, elbow_rot_1, elbow_rot_2, arm_tip; GLfloat old_base_rot, old_elbow_rot_1, old_elbow_rot_2; GLfloat target_base_rot, target_elbow_rot_1, target_elbow_rot_2; static Particle *particles = NULL; int mbutton, oldx, oldy, current_variable = 0; float view_theta = 180.0f, view_phi = 0.0f, view_radius = 15.0f; int screen_width, screen_height; int is_light = 0; void init_glass(void) { /* Load the glass model */ if((arm_model = glassLoadModel("models/apoint.glm")) == NULL) { fprintf(stderr, "Cannot find glass model \"models/apoint.glm\", did you delete it?\n"); exit(-1); } /* Extract the variables from the model */ base_rot = glassFindVariable(arm_model, "base rotate"); elbow_rot_1 = glassFindVariable(arm_model, "arm rotate 1"); elbow_rot_2 = glassFindVariable(arm_model, "arm rotate 2"); /* Extract the active point (the tip of the arm) from the model */ arm_tip = glassFindActivePoint(arm_model, "arm tip"); /* Get the initial values, and randomize some targets */ old_base_rot = glassGetVariableValue(arm_model, base_rot); old_elbow_rot_1 = glassGetVariableValue(arm_model, elbow_rot_1); old_elbow_rot_2 = glassGetVariableValue(arm_model, elbow_rot_2); target_base_rot = 360.0 * (GLfloat)rand() / (GLfloat)RAND_MAX; target_elbow_rot_1 = 90.0 * (GLfloat)rand() / (GLfloat)RAND_MAX; target_elbow_rot_2 = 90.0 * (GLfloat)rand() / (GLfloat)RAND_MAX; } void init_glut(void) { /* Set up glut */ glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(400, 400); glutCreateWindow("An example of an active point"); /* Attach the functions */ glutMouseFunc(mouse); glutMotionFunc(mouse_motion); glutKeyboardFunc(keyboard); glutReshapeFunc(reshape); glutIdleFunc(animate); glutDisplayFunc(display); glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_LIGHT0); glEnable(GL_TEXTURE_2D); glPointSize(2.0); } void reshape(int w, int h) { glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 0.5, 10000.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); screen_width = w; screen_height = h; } void keyboard(unsigned char key, int x, int y) { switch(key) { case 'l': case 'L': is_light = !is_light; if(is_light) glEnable(GL_LIGHTING); else glDisable(GL_LIGHTING); break; case 27: /* esc */ exit(0); break; } glutPostRedisplay(); } void mouse(int button, int state, int x, int y) { mbutton = button; oldx = x; oldy = y; } void mouse_motion(int x, int y) { int dx = x - oldx, dy = y - oldy; switch(mbutton) { case GLUT_LEFT_BUTTON: view_theta += 1.0f * (float) dx; view_phi += 1.0f * (float) dy; break; case GLUT_RIGHT_BUTTON: view_radius += 1.0f * (float) dy; break; } oldx = x; oldy = y; glutPostRedisplay(); } void add_particle(void) { Particle *particle; GLfloat *tip_pos, *tip_dir, stream_speed = 0.8; /* Create a new particle and add it to the front of the list */ particle = malloc(sizeof(Particle)); particle->last = NULL; particle->next = particles; if(particle->next != NULL) particle->next->last = particle; particles = particle; glassDrawModel(arm_model); tip_pos = glassGetActivePointPos(arm_model, arm_tip); tip_dir = glassGetActivePointDir(arm_model, arm_tip); particle->age = 0.0; particle->pos[0] = tip_pos[0]; particle->pos[1] = tip_pos[1]; particle->pos[2] = tip_pos[2]; particle->vel[0] = stream_speed * tip_dir[0]; particle->vel[1] = stream_speed * tip_dir[1]; particle->vel[2] = stream_speed * tip_dir[2]; } void remove_particle(Particle *particle) { if(particle->last != NULL) particle->last->next = particle->next; else particles = particle->next; if(particle->next != NULL) particle->next->last = particle->last; free(particle); } void move_particles(GLfloat dt) { Particle *par_ptr = particles, *tmp_ptr; while(par_ptr != NULL) { par_ptr->age += dt; /* (scaled by 12, because the arm is 12m high, which is too much -- scaled to 1m high) */ par_ptr->pos[0] += dt * 12.0 * par_ptr->vel[0]; par_ptr->pos[1] += dt * 12.0 * (par_ptr->vel[1] - 0.5*9.81*dt); par_ptr->pos[2] += dt * 12.0 * par_ptr->vel[2]; tmp_ptr = par_ptr->next; /* If hit the ground, or over 10s old, remove */ if(par_ptr->pos[1] < 0.0 || par_ptr->age > 10.0) remove_particle(par_ptr); par_ptr = tmp_ptr; } } void animate(void) #define CHANGE_TIME 3000 { static int last_ticks = -1, count_ticks = 0; int ticks, elapsed; GLfloat percent, dt; if(last_ticks == -1) last_ticks = glutGet(GLUT_ELAPSED_TIME); /* Get how many ticks (time, 1000 ticks = 1sec) have elapsed */ ticks = glutGet(GLUT_ELAPSED_TIME); elapsed = ticks - last_ticks; dt = elapsed / 1000.0; last_ticks = ticks; count_ticks += elapsed; /* Get the percentage through the rotations */ if(count_ticks > CHANGE_TIME) count_ticks = CHANGE_TIME; percent = (GLfloat)count_ticks / (GLfloat)CHANGE_TIME; /* Rotate the arms */ glassSetVariable(arm_model, base_rot, percent * target_base_rot + (1.0 - percent) * old_base_rot); glassSetVariable(arm_model, elbow_rot_1, percent * target_elbow_rot_1 + (1.0 - percent) * old_elbow_rot_1); glassSetVariable(arm_model, elbow_rot_2, percent * target_elbow_rot_2 + (1.0 - percent) * old_elbow_rot_2); /* If hit the target */ if(count_ticks == CHANGE_TIME) { count_ticks = 0; old_base_rot = target_base_rot; old_elbow_rot_1 = target_elbow_rot_1; old_elbow_rot_2 = target_elbow_rot_2; target_base_rot = 360.0 * (GLfloat)rand() / (GLfloat)RAND_MAX; target_elbow_rot_1 = 90.0 * (GLfloat)rand() / (GLfloat)RAND_MAX; target_elbow_rot_2 = 90.0 * (GLfloat)rand() / (GLfloat)RAND_MAX; } /* Move the particles */ move_particles(dt); /* Add a particle */ add_particle(); /* Redraw the scene */ glutPostRedisplay(); } void draw_particles(void) { Particle *par_ptr = particles; GLfloat col; glBegin(GL_POINTS); while(par_ptr != NULL) { col = 1.0 - par_ptr->age / 10.0; glColor3f(col, col, 0.0); glVertex3f(par_ptr->pos[0], par_ptr->pos[1], par_ptr->pos[2]); par_ptr = par_ptr->next; } glEnd(); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0f, -5.0, -view_radius); glRotatef(view_phi, 1.0f, 0.0f, 0.0f); glRotatef(view_theta, 0.0f, 1.0f, 0.0f); /* Draw a reflection of our arm, and the particles */ glPushMatrix(); glScalef(1.0, -1.0, 1.0); glassDrawModel(arm_model); draw_particles(); glPopMatrix(); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glColor4f(1.0, 0.0, 0.0, 0.3); glBegin(GL_QUADS); glVertex3f(-100.0, 0.0, 100.0); glVertex3f(100.0, 0.0, 100.0); glVertex3f(100.0, 0.0, -100.0); glVertex3f(-100.0, 0.0, -100.0); glEnd(); glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); /* Draw our glass model */ glassDrawModel(arm_model); draw_particles(); /* Draw the overlay */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0f, screen_width, 0.0f, screen_height, -1.0f, 0.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, (GLfloat) screen_width/(GLfloat) screen_height, 0.5, 10000.0); glutSwapBuffers(); } int main(int argc, char **argv) { glutInit(&argc, argv); init_glut(); init_glass(); glutMainLoop(); return 0; }