#undef UNICODE #include #include #include #include #define _USE_MATH_DEFINES #define GLUT_DISABLE_ATEXIT_HACK #include #include #include "GL/glut.h" #include #include "teksture.h" using namespace std; static double x, y; static double dx = 1; static double dy = 0.5; static double cr = 0; double k; struct SParticle { GLfloat lifetime; //current lifetime of the particle GLfloat maximum_lifetime; //time of death of particle GLfloat r, g, b; // color values of the particle GLfloat xpos, ypos, zpos; // position of the particle GLfloat xspeed, yspeed, zspeed; // speed of the particle GLfloat ax, ay, az; //TODO: add new parameters if needed }; struct SVertex { GLfloat tx, ty; GLfloat x, y, z; }; const float s = 0.5; SVertex bilboard[] = { { 0, 0, -s, -s, 0 }, { 0, 1, -s, s, 0 }, { 1, 1, s, s, 0 }, { 1, 0, s, -s, 0 } }; const int MAX_PARTICLES = 500; list Particles; list::iterator particle_iter; //TODO: texture for particles - change if You want const char texture_name[] = "media//portal1.bmp"; Ctexture *bilboard_tex; //Gaussian random number generator - mean 0.0, standard deviation 1.0 float NRand() { static int q = 15; static float c1 = (1 << q) - 1; static float c2 = ((int)(c1 / 3)) + 1; static float c3 = 1.f / c1; /* random number in range 0 - 1 not including 1 */ float random = 0.f; /* the white noise */ float noise = 0.f; random = ((float)(rand()) / (float)(RAND_MAX + 1)); random = (2.f * ((random * c2) + (random * c2) + (random * c2)) - 3.f * (c2 - 1.f)) * c3; return random; } //single bilboard drawing void bilboarddrawinglist() { glNewList(1, GL_COMPILE); glPushMatrix(); // Wlaczamy tablice koordynatow tekstur glEnableClientState(GL_TEXTURE_COORD_ARRAY); // Wlaczamy tablice wspolrzednych wierzcholkow glEnableClientState(GL_VERTEX_ARRAY); glInterleavedArrays(GL_T2F_V3F, 0, (GLvoid*)bilboard); glDrawArrays(GL_QUADS, 0, 4); glPopMatrix(); glEndList(); } int initTexture(void) { glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // texture for particle bilboard_tex = new Ctexture(texture_name); //empty texture, currently not needed //tekstury[0] = new Ctexture(); return true; } void drawScene(void) { // Clear screen to background color. glClear(GL_COLOR_BUFFER_BIT); // Set foreground (or drawing) color. glColor3f(1.0, 0.0, 0.0); if (bilboard_tex)bilboard_tex->Bind(); list::iterator currP = Particles.begin(); //TODO 0: Set proper render states in OpenGL - blending and depth test glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glDisable(GL_DEPTH_TEST); //glEnable() with GL_BLEND, glBlendFunc() with GL_ONE, GL_ONE and glDisable() GL_DEPTH_TEST; //notice what happens if they are not set //... for (unsigned int i = 0; ixpos, currP->ypos, currP->zpos); glColor3f(1, 1, 1); glScalef(0.1, 0.1, 0.1); //... //Draw particle glCallList(1); glPopMatrix(); } glutSwapBuffers(); } // Initialization routine. void setup(void) { x = 0; y = 0; // Set background (or clearing) color. glClearColor(0.0, 0.0, 0.0, 0.0); initTexture(); bilboarddrawinglist(); } // OpenGL window reshape routine. void resize(int w, int h) { // Set viewport size to be entire OpenGL window. glViewport(0, 0, (GLsizei)w, (GLsizei)h); // Set matrix mode to projection. glMatrixMode(GL_PROJECTION); // Clear current projection matrix to identity. glLoadIdentity(); // Specify the orthographic (or perpendicular) projection, // i.e., define the viewing box. gluPerspective(90, (float)w / (float)h, 1, 200); //glOrtho(-10.0, 10.0, -10.0, 10.0,-10.0, 10.0); //glFrustum(-10.0, 10.0, -10.0, 10.0, 5.0, 100.0); // Set matrix mode to modelview. glMatrixMode(GL_MODELVIEW); // Clear current modelview matrix to identity. glLoadIdentity(); } void EmitParticles() { //TODO 2: //Emit particles: //set parameters for new particles (SParticle structure), //You can add new parameters to the SParticle structure //For random numbers use NRand() - Gaussian random number generator - mean 0.0, standard deviation 1.0 //You should use "for" loop. In each iteration new particle (the variable of type SParticle) should be created. //After creation new particle should be pushed front to the list of particles Particles. //... int pointsCount = 314; for (int i = 0; i < pointsCount; i++) { SParticle newPart = SParticle(); newPart.xpos = 5 * sin(i) -10; newPart.zpos = 5 * cos(i) -10; newPart.ypos = -10; newPart.yspeed = 3; newPart.zspeed = 0; //newPart.az = sin(i) * 4; //newPart.ay = 0; //newPart.ax = 0; newPart.maximum_lifetime = 0.1f + (0.5f + NRand()); Particles.push_back(newPart); } } void AffectParticles() { list ParticlesToRemove; static std::clock_t oldtime = std::clock(); std::clock_t newtime = std::clock(); double timebetweenframes = (double)(newtime - oldtime) / (double)CLOCKS_PER_SEC; int frametogrey = 7; double greyscale = 0.025; particle_iter = Particles.begin(); while (particle_iter != Particles.end()) { //TODO 3: //update particle parameters: //position, color (fading color for example), speed(gravity for example) //timebetweenframes - delta time, can be used for updating position in current frame like: particle_iter->ypos + particle_iter->yspeed*timebetweenframes //particle_iter->lifetime/particle_iter->maximum_lifetime - usefull proportion for changing color and size //... particle_iter->lifetime += timebetweenframes; particle_iter->yspeed += timebetweenframes * particle_iter->ay; particle_iter->xspeed += timebetweenframes * particle_iter->ax; particle_iter->zspeed += timebetweenframes * particle_iter->az; particle_iter->ypos += timebetweenframes * particle_iter->yspeed; particle_iter->xpos += timebetweenframes * particle_iter->xspeed; particle_iter->zpos += timebetweenframes * particle_iter->zspeed; //removing particles if (particle_iter->lifetime >= particle_iter->maximum_lifetime) { //if You need to create particles in place when other died (fireworks particle effect for example) //Then You can create them here like in TODO 1 particle_iter = Particles.erase(particle_iter); } else particle_iter++; } cout << Particles.size() << endl; oldtime = newtime; } void animate() { EmitParticles(); AffectParticles(); glutPostRedisplay(); } // Keyboard input processing routine. void keyInput(unsigned char key, int x, int y) { } // Mouse callback routine. void mouseControl(int button, int state, int x, int y) { } // Main routine: defines window properties, creates window, // registers callback routines and begins processing. int main(int argc, char **argv) { // Initialize GLUT. glutInit(&argc, argv); // Set display mode as single-buffered and RGB color. glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); // Set OpenGL window size. glutInitWindowSize(500, 500); // Set position of OpenGL window upper-left corner. glutInitWindowPosition(100, 100); // Create OpenGL window with title. glutCreateWindow("Laboratorium GK: 11_OGL"); // Initialize. setup(); // Register display routine. glutDisplayFunc(drawScene); // Register reshape routine. glutReshapeFunc(resize); // Register the mouse and keyboard callback function. glutMouseFunc(mouseControl); glutKeyboardFunc(keyInput); glutIdleFunc(animate); // Begin processing. glutMainLoop(); if (bilboard_tex) delete bilboard_tex; return 0; }