/* * 3D starfield with unusual objects, movement and shooting :) * by andrey mirtchovski (aam396@mail.usask.ca) * */ #include #include #include #include #include int w=500, h=500; enum { SCROLL_LEFT = 1, SCROLL_RIGHT, SCROLL_UP, SCROLL_DOWN } type = SCROLL_RIGHT; typedef struct _star { float x, y, z; float vx, vy, vz; float r, g, b; // color int rotx, roty, rotz; // rotation descriptor int drotx, droty, drotz; // rotation vector int type; /* used with spheres -- type of object to display */ } star; star *stars = NULL; star shoot[20]; star sphere[10]; int num_stars = 500; int spin_x=0, spin_y=0, old_x = 0, old_y = 0; /* take care of moving around with the mouse */ float move_x=0, move_y=0; int in_window = 0; int cnt = 100; int add = 1; int shot = 0; int spheres = 1; int render_stars = 1; int render_help = 1; int num_shot = 0; /* how many shots were there == maximum 20!!*/ void init() { int i; glClearColor(0, 0, 0, 0); glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); // glOrtho(-1, 1, -1, 1, -1, 1); glOrtho(-1, 1,-1, 1,-1, 1000); // glFrustum(-1, 1,-1, 1, 0.1, 2); glMatrixMode(GL_MODELVIEW); glEnable(GL_LINE_SMOOTH); glEnable(GL_DEPTH_TEST); for(i = 0; i < num_stars; i++) { stars[i].x = (float)rand()/(float)(RAND_MAX) - 0.5; stars[i].y = (float)rand()/(float)(RAND_MAX) - 0.5; stars[i].z = (float)rand()/(float)(RAND_MAX) - 0.5; stars[i].vx =0; // (float)rand()/(float)(RAND_MAX*500) - 1/250; stars[i].vy =0; // (float)rand()/(float)(RAND_MAX*500) - 1/250; stars[i].vz = (float)rand()/(float)(RAND_MAX*500) - 1/250; stars[i].r = 300*stars[i].vz; stars[i].g = 0; //(float)rand()/(float)(RAND_MAX) + stars[i].vz; stars[i].b = 0;//(float)rand()/(float)(RAND_MAX) + stars[i].vz; } for(i = 0; i < 10; i++) { /* make all the spheres */ sphere[i].x = (float)rand()/(float)(RAND_MAX) - 0.5; sphere[i].y = (float)rand()/(float)(RAND_MAX) - 0.5; sphere[i].z = (float)rand()/(float)(RAND_MAX) - 0.5; sphere[i].vx =0; // (float)rand()/(float)(RAND_MAX*500) - 1/250; sphere[i].vy =0; // (float)rand()/(float)(RAND_MAX*500) - 1/250; sphere[i].vz = (float)rand()/(((float)RAND_MAX)*100.0); sphere[i].r = 0; sphere[i].g = 0; //(float)rand()/(float)(RAND_MAX) + sphere[i].vz; sphere[i].b = 1 - sphere[i].vz;//(float)rand()/(float)(RAND_MAX) + sphere[i].vz; sphere[i].rotx = rand()%10 - 5; sphere[i].roty = rand()%10 - 5; sphere[i].rotz = rand()%10 - 5; sphere[i].drotx = rand()%10 - 5; sphere[i].droty = rand()%10 - 5; sphere[i].drotz = rand()%10 - 5; sphere[i].type = rand()%4; } for(i = 0; i < 20; i++) { shoot[i].z = 0.001; shoot[i].vx =0; // (float)rand()/(float)(RAND_MAX*500) - 1/250; shoot[i].vy =0; // (float)rand()/(float)(RAND_MAX*500) - 1/250; shoot[i].vz = -0.008; shoot[i].r = 0; shoot[i].g = 1; //(float)rand()/(float)(RAND_MAX) + shoot[i].vz; shoot[i].b = 0;//(float)rand()/(float)(RAND_MAX) + shoot[i].vz; } glPointSize(2); } void display(void) { int i, j; float pos = 4.5; char *help[] = {"commands:", "t -- toggle star rendering", "s -- toggle wire objects", "a -- toggle type of star rendering (funny)", "h -- toggle this menu", "f -- switch to full-screen mode", "space -- shoot at nothing", "mouse -- shoot at nothing", "ESC -- quit"}; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); if(render_help) { /* help menu was requested */ glPushMatrix(); glColor3f(0.5, 0.5, 0.5); glRasterPos3f(-4, pos, -0.5); for(j = 0; j < 9; j++) { for(i = 0; i < strlen(help[j]); i++) { glutBitmapCharacter(GLUT_BITMAP_8_BY_13, help[j][i]); } pos -= 0.2; glRasterPos3f(-4, pos, -0.5); } glPopMatrix(); } glPushMatrix(); // glRotatef(spin_x, 0, 1, 0); // glRotatef(spin_y, 1, 0, 0); glTranslatef(-move_x, move_y, 0); glColor3f(0.3, 0.3, 0.3); glutWireCube(1.0); if(render_stars) for (i = 0; i < num_stars; i++) { glBegin(GL_LINE_STRIP); glColor3f(stars[i].r, stars[i].g, stars[i].b); glVertex3f(stars[i].x, stars[i].y, stars[i].z); glColor3f(0, 0, 0); if(add) glVertex3f(stars[i].x, stars[i].y, stars[i].z - 20*stars[i].vz); else glVertex3f(stars[i].x, stars[i].y, stars[i].z * 100 *stars[i].vz); glEnd(); } if(spheres) for (i = 0; i < 10; i++) { glPushMatrix(); glColor3f(sphere[i].r, sphere[i].g, sphere[i].b); glTranslatef(sphere[i].x, sphere[i].y, sphere[i].z); glRotatef(sphere[i].rotx, 1, 0, 0); glRotatef(sphere[i].roty, 0, 1, 0); glRotatef(sphere[i].rotz, 0, 0, 1); switch(sphere[i].type) { case 0: glutWireSphere(0.03, 5, 5); break; case 1: glutWireCone(0.03, 0.03, 5, 5); break; case 2: glutWireCube(0.03); break; case 3: glutWireTorus(0.03, 0.06, 5, 5); break; } glPopMatrix(); } if(shot) { for(i = 0; i < 20 ; i++) { if(shoot[i].z > 0.0) continue; glLineWidth(6); glBegin(GL_LINE_STRIP); glColor3f(shoot[i].r, shoot[i].g, shoot[i].b); glVertex3f(shoot[i].x-0.001, shoot[i].y, shoot[i].z); glColor3f(0, 0, 0.3); glVertex3f(shoot[i].x-0.001, shoot[i].y, shoot[i].z + shoot[i].vz); glEnd(); glBegin(GL_LINE_STRIP); glColor3f(shoot[i].r, shoot[i].g, shoot[i].b); glVertex3f(shoot[i].x+0.001, shoot[i].y, shoot[i].z); glColor3f(0, 0, 0.3); glVertex3f(shoot[i].x+0.001, shoot[i].y, shoot[i].z + shoot[i].vz); glEnd(); glLineWidth(1); } } glPopMatrix(); glutSwapBuffers(); } void motion(x, y) { spin_x = old_x - x; spin_y = old_y - y; glutPostRedisplay(); } void mouse(int button, int state, int x, int y) { int i; if(state == GLUT_DOWN) { switch(button) { case 0: if(++num_shot < 20) { for(i = 0; i < 20; i++) { if(shoot[i].z > 0.0) { shoot[i].x = move_x; shoot[i].y = -move_y+0.1; shoot[i].z = 0; break; } } } else { num_shot = 19; } shot = 1; break; } } glutPostRedisplay(); } void idle() { int i; if(render_stars) for(i = 0; i < num_stars; i++) { stars[i].z += stars[i].vz; stars[i].z = stars[i].z > 0 ? -0.5 : stars[i].z; } if(spheres) for(i = 0; i < 10; i++) { sphere[i].z += sphere[i].vz; sphere[i].rotx += sphere[i].drotx; sphere[i].roty += sphere[i].droty; sphere[i].rotz += sphere[i].drotz; sphere[i].z = sphere[i].z > 0.5 ? -0.5 : sphere[i].z; } if(shot) { for(i = 0; i < 20; i++) { if(shoot[i].z <= 0.0) { shoot[i].z += shoot[i].vz; } if(shoot[i].z < -0.5) { shoot[i].z = 0.001; num_shot--; } if(!num_shot) { shot = 0; break; } } } // cnt = 500 + 250*sin(cnt); glutPostRedisplay(); } void passive(int x, int y) { if(x < w && x > 0) move_x = (float)x/(float)w - 0.5; if(y < h && y > 0) move_y = (float)y/(float)h - 0.5; glutPostRedisplay(); } void entry(int ent) { in_window = ent == GLUT_ENTERED ? 1 : 0; } void keyboard(unsigned char key, int x, int y) { int i; switch (key) { case 27: exit(0); break; case 'f': glutSetCursor(GLUT_CURSOR_NONE); glutFullScreen(); break; case 'a': add = !add; break; case 's': spheres = !spheres; break; case 't': render_stars = !render_stars; break; case 'h': render_help = !render_help; break; case ' ': if(++num_shot < 20) { for(i = 0; i < 20; i++) { if(shoot[i].z > 0.0) { shoot[i].x = move_x; shoot[i].y = -move_y+0.1; shoot[i].z = 0; break; } } } else { num_shot = 19; } shot = 1; break; } } void reshape(int width, int height) { w = width; h = height; glClearColor(0, 0, 0, 0); glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1, 1,-1, 1,-1, 1000); glFrustum(-1, 1,-1, 1, 0.1, 2); glMatrixMode(GL_MODELVIEW); } int main(int argc, char** argv) { glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowPosition(50, 50); glutInitWindowSize(w, h); glutInit(&argc, argv); glutCreateWindow("Starfield"); glutDisplayFunc(display); glutIdleFunc(idle); glutMouseFunc(mouse); glutMotionFunc(motion); glutPassiveMotionFunc(passive); glutEntryFunc(entry); glutKeyboardFunc(keyboard); glutReshapeFunc(reshape); stars = (star*)malloc(sizeof(star) * num_stars); init(); glutMainLoop(); return 0; }