www.pudn.com > Particles_OGL.zip > win_main.cpp
// Done by TheTutor -- 12/07/03 /* Particles and particle emitters are typically responsible for all the kick-nut eye candy you see in your favorite games. Particles are usually formed one of two ways. The first way is to texture a quad and billboard it so it is always facing the camera. The second way is to use point sprites which are usually implemented as triangle strips or the point primitive. This tutorial is going to use the first method to display it's particles. So what makes up a particle? Well you can have lots of different variables but here's what we're going to use: Position -- Holds the world coordinates of the center of the particle Velocity -- Specifies the direction and speed in which a particle is moving Color -- A 32-bit color for the particle Size -- The width and height of the particle quad Life -- Length of time in seconds of how long a particle is active (ie visible) Angle -- An angle of rotation for the particle's UVs A Texture -- A class that stores a texture Also all of particles are effected by a gravity. The same gravity applies to all particles. Some other examples of variables you could have with your particle are: wind velocity, fade out time, individual gravity, parent (what object emitted it), and so on and so forth. Ultimately what you do and don't store in your particle is up to you. To demonstrate this particle madness, this app makes a flame effect. The orange color used for the effect is: red = 215, green = 115, and blue = 40. Because of the blend mode chosen, the flame effect will look the same as long as the frame buffer color, for each component, is less than the color of orange for the particle. To demonstrate this we slowly change the background color. You notice as the background color approaches a lighter whitish color, so does the flame effect. Still not crystal clear? Well what better way to answer all your questions than jumping into the thick of the code... */ // Make sure we load all the libraries we need #pragma comment(lib,"opengl32.lib") #pragma comment(lib,"glu32.lib") #define class_name "GT_OGL_Particles" #define WIN_WID 640 // width of our window #define WIN_HGT 480 // height of our window #define TEXTURE_NAME "image.bmp" // Name of the file holding our texture #define MAX_PARTICLES 256 // Maximum number of particles #include "gl_obj.h" #include "gl_texture.h" #include "particle.h" #include// Globals *** CGLObj gGLObj; // Our OpenGL object CParticle gParticles[MAX_PARTICLES]; // An array of particles float gRGB[3] = {0}; // The current RGB background color of the scene // *** End of Globals void UpdateBkgrndColor(); // Slowly changes the background color of the scene bool LockFrameRate(int fps = 60); // Locks the frame rate to "fps" // WinProc LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); // WinMain int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprev, PSTR cmdline, int ishow) { MSG msg = {0}; HWND hwnd = NULL; WNDCLASSEX wndclassex = {0}; // Fill the fields we care about wndclassex.cbSize = sizeof(WNDCLASSEX); wndclassex.style = CS_HREDRAW | CS_VREDRAW; wndclassex.lpfnWndProc = WinProc; wndclassex.hInstance = hinstance; wndclassex.lpszClassName = class_name; wndclassex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wndclassex.hCursor = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(IDC_ARROW), IMAGE_CURSOR, 0, 0, LR_SHARED); RegisterClassEx(&wndclassex); // Register the class RECT rect = { 0, 0, WIN_WID, WIN_HGT }; // Desired window client rect DWORD winStyleEx = WS_EX_APPWINDOW; DWORD winStyle = WS_CAPTION | WS_SYSMENU; // Window style // Adjust window rect so it gives us our desired client rect when we // create the window AdjustWindowRectEx(&rect, winStyle, false, winStyleEx); // Create our window hwnd = CreateWindowEx(winStyleEx, class_name, "www.GameTutorials.com -- Particles", winStyle, CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, // Window width rect.bottom - rect.top, // Window height NULL, NULL, hinstance, NULL); // Error Check if(!hwnd) return EXIT_FAILURE; // Something bad happened // Get the client RECT GetClientRect(hwnd, &rect); // If the client width or height isn't what we requested, there's been // an error somewhere and we're going to bail ship if(rect.right != WIN_WID || rect.bottom != WIN_HGT) return EXIT_FAILURE; // Something bad happened srand(GetTickCount()); // Seed random number generator HDC hdc = GetDC(hwnd); // Get the window's HDC // Initialize OpenGL if(gGLObj.init(hdc, 32, 16) == false) { ReleaseDC(hwnd, hdc); // Free up the HDC return EXIT_FAILURE; // Something bad happened } // Set up the view port gGLObj.setViewPort(WIN_WID,WIN_HGT,60.0); // Show and update window ShowWindow(hwnd, ishow); UpdateWindow(hwnd); for(int i = 0; i < MAX_PARTICLES; ++i) { // If we fail to initialize any of the particles, exit the app if(!gParticles[i].init(CPos(0,0,0), CVector(RAND(-0.25f, 0.25f), RAND(0.5f, 1.5f), 0.0f), RAND(1.0f, 2.0f), 0.75f, 30.0f, ARGB(255, 215, 115, 40), "particle.bmp")) { ReleaseDC(hwnd, hdc); return EXIT_FAILURE; } } // Variables for our timer float beginTime = GetTickCount() * .001f; float endTime = beginTime; float dt = 0.0f; // Delta time (time slice for each rendered frame) while(1) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } else if(LockFrameRate()) // If it's time to draw { beginTime = GetTickCount() * 0.001f; // Get time frame began dt = beginTime - endTime; // Set dt // Clear the background color of the scene, to the color in "gRGB" glClearColor(gRGB[0], gRGB[1], gRGB[2], 1.0f); gGLObj.begin(); // Draw and process all the particles for(int i = 0; i < MAX_PARTICLES; ++i) { gParticles[i].render(); gParticles[i].process(dt); } gGLObj.end(); UpdateBkgrndColor(); // Get time the frame ended endTime = GetTickCount() * 0.001f; } } // end of while(1) ReleaseDC(hwnd, hdc); // Free up the HDC UnregisterClass(class_name,hinstance); // Free up the WNDCLASSEX return (int)msg.wParam; } // Simple WinProc LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { switch(message) { case WM_KEYDOWN: switch(wparam) { case VK_ESCAPE: // On ESC quit the application SendMessage(hwnd, WM_CLOSE, 0, 0); // Send the window close message break; } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } // end of switch(message) return DefWindowProc(hwnd, message, wparam, lparam); } // Updates the background color for the scene void UpdateBkgrndColor() { // How much to increase the red, green, and blue component of the // background color respectively static float inc[3] = { 0.005f, 0.005f, 0.005f }; int which = rand()%3; // Randomly select a color component to add to for(int i = 0; i < 3; ++i) { if(i == which) { gRGB[i] += inc[i]; // Keep the RGB within 0-1 if(gRGB[i] > 1.0f) { gRGB[i] = 1.0f; inc[i] = -inc[i]; } else if(gRGB[i] < 0.0f) { gRGB[i] = 0.0f; inc[i] = -inc[i]; } } } } // Locks the frame rate at "frame_rate" // Returns true when it's okay to draw, false otherwise bool LockFrameRate(int frame_rate) { static float lastTime = 0.0f; // Get current time in seconds (milliseconds * .001 = seconds) float currentTime = GetTickCount() * 0.001f; // Get the elapsed time by subtracting the current time from the last time // If the desired frame rate amount of seconds has passed -- return true (ie Blit()) if((currentTime - lastTime) > (1.0f / frame_rate)) { // Reset the last time lastTime = currentTime; return true; } return false; } /* Particle Rewind -- Hopefully you've got a first step grasp of what a particle is and you have a new insight of how you might go and program your very own particle engine. A few short cuts that this tutorial took should be mentioned. First, we never do any billboarding of the particles. Since it's the only thing we're drawing and we never move the camera, we simply always drawn them in the XY plane. Second we don't have a emitter object. Robust particle systems, usually contain particles and emitters, with the emitter being responsible for the overall particle effect. And last but not least, if we wanted to take advantage of an alpha component with our particle, either in the texture of in the color, we'd have to change up how we our doing the blending. So keep these things in mind when you go to make your own kickin' particle system %) If you have any questions regarding particles be sure to post them at: www.GameTutorials.com */ /*----------------------------*\ | TheTutor | | thetutor@gametutorials.com | | © 2000-2003 GameTutorials | \*----------------------------*/