效果图如上:
步骤:略。
实现代码如下:
main.cpp
1 /********************************************************************** 2 3 Particle Engine / Billboarding 4 5 October, 21st, 2002 6 7 This tutorial was written by Philipp Crocoll 8 Contact: 9 philipp.crocoll@web.de 10 www.codecolony.de 11 12 Every comment would be appreciated. 13 14 If you want to use parts of any code of mine: 15 let me know and 16 use it! 17 18 If you get cool effects with this particle engine, 19 I would be happy if you could send me the code. If you want to, 20 I can upload it. This code is only a part of what you can do with 21 this engine. 22 23 *********************************************************************** 24 25 26 ESC : Exit 27 w,a,s,d,r,f,x,y,c,v : move / turn 28 29 30 31 **********************************************************************/ 32 33 #include <GL\glut.h> //includes gl.h and glu.h 34 #include <GL\glaux.h> //load the texture 35 #include <stdlib.h> //random function 36 #include <math.h> //sine and cosine functions 37 38 #include "Camera.h" 39 #include "particles.h" 40 41 //Particle variables: 42 CCCParticleSystem g_ParticleSystem1; 43 CCCParticleSystem g_ParticleSystem2; 44 CCCParticleSystem g_ParticleSystem3; 45 CCCParticleSystem g_ParticleSystem4; 46 CCCParticleSystem g_ParticleSystem5; 47 CCCParticleSystem g_ParticleSystem6; 48 49 //g_Camera: 50 CCamera g_Camera; 51 52 //Time handling (note: use QueryPerformanceCounter in "real" projects!) 53 long unsigned int g_iLastRenderTime = 0; // 查询性能计数器 54 55 56 //code from the camera tutorial: // 绘制网格 57 void DrawNet(GLfloat size, GLint LinesX, GLint LinesZ) 58 { 59 glBegin(GL_LINES); 60 for (int xc = 0; xc < LinesX; xc++) 61 { 62 glVertex3f( -size / 2.0 + xc / (GLfloat)(LinesX-1)*size, 63 0.0, 64 size / 2.0); 65 glVertex3f( -size / 2.0 + xc / (GLfloat)(LinesX-1)*size, 66 0.0, 67 size / -2.0); 68 } 69 for (int zc = 0; zc < LinesX; zc++) 70 { 71 glVertex3f( size / 2.0, 72 0.0, 73 -size / 2.0 + zc / (GLfloat)(LinesZ-1)*size); 74 glVertex3f( size / -2.0, 75 0.0, 76 -size / 2.0 + zc / (GLfloat)(LinesZ-1)*size); 77 } 78 glEnd(); 79 } 80 81 82 void Display(void) 83 { 84 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 85 glLoadIdentity(); //Load a new modelview matrix -> we can apply new transformations 86 // 加载一个新的视点矩阵- >我们可以应用新的转换 87 //Update the scene: 88 long unsigned int iNowTime = timeGetTime(); // 函数以毫秒计的系统时间。该时间为从系统开启算起所经过的时间。 89 float timePassed = float(iNowTime-g_iLastRenderTime)/1000.0f; //divide by 1000 90 g_ParticleSystem1.UpdateSystem(timePassed); 91 g_ParticleSystem2.UpdateSystem(timePassed); 92 g_ParticleSystem3.UpdateSystem(timePassed); 93 g_ParticleSystem4.UpdateSystem(timePassed); 94 g_ParticleSystem5.UpdateSystem(timePassed); 95 g_ParticleSystem6.UpdateSystem(timePassed); 96 97 g_iLastRenderTime = iNowTime; 98 99 //render everything: 100 g_Camera.Render(); 101 102 103 104 //render an opaque quadrangle: (if you want to see how to do this...) 105 //glEnable(GL_DEPTH_TEST); 106 //glDisable(GL_TEXTURE_2D); 107 //glColor3f(1.0f,0.0,1.0f); 108 109 //glBegin(GL_POLYGON); 110 //glVertex3f(0.0f,0.0f,0.0f); 111 //glVertex3f(1.0f,0.0f,0.0f); 112 //glVertex3f(1.0f,1.0f,0.0f); 113 //glVertex3f(0.0f,1.0f,0.0f); 114 //glEnd(); 115 116 117 //render the nets, so switch off blending and texturing: 118 glDisable(GL_BLEND); // 关闭混合 119 glDisable(GL_TEXTURE_2D); // 关闭贴图 120 //enable depth testing (and z-buffer-writing) 121 glEnable(GL_DEPTH_TEST); // 启动深度测试 122 glDepthMask(GL_TRUE); // 可将深度缓冲区设置为可读可写形式 123 124 GLfloat size = 2.0; 125 GLint LinesX = 30; 126 GLint LinesZ = 30; 127 128 glColor3f(1.0,0.0,0.0); 129 glPushMatrix(); 130 glTranslatef(0.0,0.0 ,0.0); 131 DrawNet(size,LinesX,LinesZ); 132 glTranslatef(0.0,size,0.0); 133 DrawNet(size,LinesX,LinesZ); 134 glPopMatrix(); 135 136 137 //Render system 2 first, it's not textured: 138 139 glEnable(GL_BLEND); 140 glDepthMask(GL_FALSE); 141 glEnable(GL_DEPTH_TEST); 142 143 //Calculate the point size depending from the camera's distance to the emitter: 144 //(in order to be 100% exact we would have to pass the camera position to the 145 //particles' render function. This method would then have to calculate the point size for each particle!) 146 float zDist = g_Camera.GetPosition().z - g_ParticleSystem2.m_EmitterPosition.z; 147 float xDist = g_Camera.GetPosition().x - g_ParticleSystem2.m_EmitterPosition.x; 148 float CamDistToEmitter = sqrt(SQR(zDist)+SQR(xDist)); 149 if (CamDistToEmitter < 0.2f) //avoid too big particles 150 CamDistToEmitter = 0.2f; 151 glPointSize(1.0f/CamDistToEmitter); 152 g_ParticleSystem2.Render(); 153 154 //Now enable texturing and render the other particle systems: 155 glEnable(GL_TEXTURE_2D); 156 g_ParticleSystem1.Render(); 157 g_ParticleSystem3.Render(); 158 g_ParticleSystem4.Render(); 159 g_ParticleSystem5.Render(); 160 g_ParticleSystem6.Render(); 161 glDepthMask(GL_TRUE); 162 163 164 glFlush(); //Finish rendering 165 glutSwapBuffers(); //Swap the buffers ->make the result of rendering visible 166 } 167 void Reshape(int x, int y) 168 { 169 if (y == 0 || x == 0) return; //Nothing is visible then, so return 170 //Set a new projection matrix 171 glMatrixMode(GL_PROJECTION); 172 glLoadIdentity(); 173 //Angle of view:40 degrees 174 //Near clipping plane distance: 0.5 175 //Far clipping plane distance: 20.0 176 gluPerspective(40.0,(GLdouble)x/(GLdouble)y,0.05,10.0); 177 glMatrixMode(GL_MODELVIEW); 178 glViewport(0,0,x,y); //Use the whole window for rendering 179 180 } 181 void KeyDown(unsigned char key, int x, int y) 182 { 183 switch(key) 184 { 185 case 27: //ESC 186 exit(0); 187 break; 188 case 'a': 189 g_Camera.RotateY(5.0); 190 Display(); 191 break; 192 case 'd': 193 g_Camera.RotateY(-5.0); 194 Display(); 195 break; 196 case 'w': 197 g_Camera.MoveForwards( -0.1 ) ; 198 Display(); 199 break; 200 case 's': 201 g_Camera.MoveForwards( 0.1 ) ; 202 Display(); 203 break; 204 case 'x': 205 g_Camera.RotateX(5.0); 206 Display(); 207 break; 208 case 'y': 209 g_Camera.RotateX(-5.0); 210 Display(); 211 break; 212 case 'c': 213 g_Camera.StrafeRight(-0.1); 214 Display(); 215 break; 216 case 'v': 217 g_Camera.StrafeRight(0.1); 218 Display(); 219 break; 220 case 'f': 221 g_Camera.Move(F3dVector(0.0,-0.3,0.0)); 222 Display(); 223 break; 224 case 'r': 225 g_Camera.Move(F3dVector(0.0,0.3,0.0)); 226 Display(); 227 break; 228 229 } 230 } 231 232 void InitParticles() 233 { 234 235 //INIT SYSTEM 1 (FIRE1) 236 g_ParticleSystem1.Initialize(300); // 同一时间显示的火焰个数 237 g_ParticleSystem1.m_iParticlesCreatedPerSec = 300; 238 g_ParticleSystem1.m_fCreationVariance = 3.0f; // 创建变异 239 g_ParticleSystem1.m_bRecreateWhenDied = true; // 当消亡时,是否再创造 240 g_ParticleSystem1.m_fMinDieAge = 1.5f; // 移动的最小距离 241 g_ParticleSystem1.m_fMaxDieAge = 1.5f; // 移动的最大距离 242 g_ParticleSystem1.SetCreationColor(1.0f,0.0f,0.0f, 243 1.0f,0.5f,0.5f); // 创建时的颜色范围 244 g_ParticleSystem1.SetDieColor(0.0f,0.0f, 0.0f, 245 1.0f,0.5f,0.0f); //消亡时的颜色范围 246 247 g_ParticleSystem1.SetAlphaValues(1.0f,1.0f,0.0f,0.0f); //透明度 248 g_ParticleSystem1.SetEmitter(0.0f,0.0f,0.5f, 249 0.1f,0.0f,0.1f); 250 g_ParticleSystem1.SetAcceleration(F3dVector(0.0f,1.0f,0.0f),0.3f,0.4f); // 加速度 251 g_ParticleSystem1.SetSizeValues(0.11f,0.11f,0.13f,0.13f); //细胞的大小 252 g_ParticleSystem1.m_fMaxEmitSpeed = 1.0f; // 最大发射速度 253 g_ParticleSystem1.m_fMinEmitSpeed = 0.3f;// 最小发射速度 254 g_ParticleSystem1.SetEmissionDirection(0.0f,1.0f,0.0f, 255 0.08f,0.5f,0.08f); // 设置发射方向 256 g_ParticleSystem1.m_bParticlesLeaveSystem = true; // 粒子离开系统 257 g_ParticleSystem1.SetSpinSpeed(-0.82*PI,0.82*PI); // 设置旋转速度 258 g_ParticleSystem1.m_iBillboarding = BILLBOARDING_PERPTOVIEWDIR; // 布告板=调整粒子方向垂直于视图 259 g_ParticleSystem1.LoadTextureFromFile("particle1.tga"); 260 261 //INIT SYSTEM 2 (POINTS, FIREWORK) // 右后侧的白色喷泉 262 g_ParticleSystem2.Initialize(800); //particle system must not have more than 800 particles 263 g_ParticleSystem2.m_iParticlesCreatedPerSec = 800; //we create all particles in the first second of the system's life 264 g_ParticleSystem2.m_fMinDieAge = 2.5f; //but the particles live longer than one second 265 g_ParticleSystem2.m_fMaxDieAge = 2.5f; //-> this causes the system to "shoot" periodically 266 267 g_ParticleSystem2.m_fCreationVariance = 1.0f; 268 g_ParticleSystem2.m_bRecreateWhenDied = true; 269 g_ParticleSystem2.SetCreationColor(1.0f,1.0f,1.0f, 270 0.5f,0.5f,0.5f); 271 g_ParticleSystem2.SetDieColor(0.0f,1.0f,0.0f, 272 0.0f,0.1f,0.0f); 273 g_ParticleSystem2.SetAlphaValues(1.0f,1.0f,0.0f,0.0f); 274 g_ParticleSystem2.SetEmitter(0.8f,0.0f,0.0f, 275 0.02f,0.0f,0.02f); 276 g_ParticleSystem2.SetAcceleration(F3dVector(0.0f,-1.0f,0.0f),0.83f,1.4f); 277 g_ParticleSystem2.SetSizeValues(3.0f,3.0f,4.0f,4.0f); 278 g_ParticleSystem2.m_fMaxEmitSpeed = 0.82f; 279 g_ParticleSystem2.m_fMinEmitSpeed = 1.3f; 280 g_ParticleSystem2.SetEmissionDirection(-1.0f,2.0f,0.0f, 281 0.5f,0.5f,0.5f); 282 283 g_ParticleSystem2.m_bParticlesLeaveSystem = true; 284 285 //INIT SYSTEM 3 (RAIN) 286 g_ParticleSystem3.Initialize(7000); 287 g_ParticleSystem3.m_iParticlesCreatedPerSec = 2950; 288 g_ParticleSystem3.m_fCreationVariance = 0.0f; 289 g_ParticleSystem3.m_bRecreateWhenDied = false; 290 g_ParticleSystem3.m_fMinDieAge = 2.0f; 291 g_ParticleSystem3.m_fMaxDieAge = 2.0f; 292 g_ParticleSystem3.SetCreationColor(0.9f,0.9f,0.9f, 293 0.8f,0.8f,0.8f); 294 g_ParticleSystem3.SetDieColor(0.2f,0.4f,0.2f, 295 0.0f,0.1f,0.0f); 296 297 g_ParticleSystem3.SetAlphaValues(1.0f,1.0f,1.0f,1.0f); 298 g_ParticleSystem3.SetEmitter(0.0f,2.0f,0.0f, 299 1.0f,0.0f,1.0f); 300 g_ParticleSystem3.SetAcceleration(NULL_VECTOR,0.0f,0.0f); 301 g_ParticleSystem3.SetSizeValues(0.01f,0.01f,0.01f,0.01f); 302 g_ParticleSystem3.m_fMaxEmitSpeed = 1.0f; 303 g_ParticleSystem3.m_fMinEmitSpeed = 1.0f; 304 g_ParticleSystem3.SetEmissionDirection(0.0f,-1.0f,0.0f, 305 0.00f,0.0f,0.00f); 306 g_ParticleSystem3.m_bParticlesLeaveSystem = true; 307 g_ParticleSystem3.m_iBillboarding = BILLBOARDING_PERPTOVIEWDIR_BUTVERTICAL; 308 g_ParticleSystem3.LoadTextureFromFile("particle2.tga"); 309 310 //INIT SYSTEM 4 (SMOKE) 311 g_ParticleSystem4.Initialize(150); 312 g_ParticleSystem4.m_iParticlesCreatedPerSec = 50; 313 g_ParticleSystem4.m_fCreationVariance = 0.0f; 314 g_ParticleSystem4.m_bRecreateWhenDied = false; 315 g_ParticleSystem4.m_fMinDieAge = 2.5f; 316 g_ParticleSystem4.m_fMaxDieAge = 3.5f; 317 g_ParticleSystem4.SetCreationColor(0.1f,0.1f,0.1f, 318 0.2f,0.2f,0.2f); 319 g_ParticleSystem4.SetDieColor(0.0f,0.0f,0.0f, 320 0.0f,0.0f,0.0f); 321 322 g_ParticleSystem4.SetAlphaValues(1.0f,1.0f,0.0f,0.0f); 323 g_ParticleSystem4.SetEmitter(-0.8f,0.0f,0.0f, 324 0.0f,0.0f,0.0f); 325 g_ParticleSystem4.SetAcceleration(F3dVector(0.0f,1.0f,0.0f),0.3f,0.4f); 326 g_ParticleSystem4.SetSizeValues(0.0f,0.0f,1.12f,1.22f); 327 g_ParticleSystem4.m_fMaxEmitSpeed = 0.01f; 328 g_ParticleSystem4.m_fMinEmitSpeed = 0.04f; 329 g_ParticleSystem4.SetEmissionDirection(0.0f,1.0f,0.0f, 330 0.08f,0.5f,0.08f); 331 g_ParticleSystem4.m_bParticlesLeaveSystem = true; 332 g_ParticleSystem4.m_iBillboarding = BILLBOARDING_PERPTOVIEWDIR; 333 g_ParticleSystem4.LoadTextureFromFile("particle3.tga"); 334 335 //INIT SYSTEM 5 ("ENGINE") 336 g_ParticleSystem5.Initialize(300); 337 g_ParticleSystem5.m_iParticlesCreatedPerSec = 200; 338 g_ParticleSystem5.m_fCreationVariance = 0.0f; 339 g_ParticleSystem5.m_bRecreateWhenDied = false; 340 g_ParticleSystem5.m_fMinDieAge = 1.0f; 341 g_ParticleSystem5.m_fMaxDieAge = 1.3f; 342 g_ParticleSystem5.SetCreationColor(0.5f,0.0f,0.0f, 343 0.5f,0.1f,0.1f); 344 g_ParticleSystem5.SetDieColor(0.2f,0.2f,0.0f, 345 0.8f,0.8f,0.0f); 346 347 g_ParticleSystem5.SetAlphaValues(1.0f,1.0f,0.3f,0.3f); 348 g_ParticleSystem5.SetEmitter(0.0f,0.0f,-1.0f, 349 0.02f,0.02f,0.0f); 350 g_ParticleSystem5.SetAcceleration(F3dVector(0.0f,1.0f,0.0f),0.0f,0.0f); 351 g_ParticleSystem5.SetSizeValues(0.12f,0.12f,0.06f,0.06f); 352 g_ParticleSystem5.m_fMaxEmitSpeed = 0.12f; 353 g_ParticleSystem5.m_fMinEmitSpeed = 0.14f; 354 g_ParticleSystem5.SetEmissionDirection(0.0f,0.0f,1.0f, 355 0.00f,0.0f,0.00f); 356 g_ParticleSystem5.m_bParticlesLeaveSystem = true; 357 g_ParticleSystem5.m_iBillboarding = BILLBOARDING_PERPTOVIEWDIR; 358 g_ParticleSystem5.LoadTextureFromFile("particle3.tga"); 359 360 //INIT SYSTEM 6 (FIRE2) 361 g_ParticleSystem6.Initialize(300); 362 g_ParticleSystem6.m_iParticlesCreatedPerSec = 300; 363 364 g_ParticleSystem6.m_bRecreateWhenDied = false; 365 g_ParticleSystem6.m_fMinDieAge = 0.5f; 366 g_ParticleSystem6.m_fMaxDieAge = 1.0f; 367 g_ParticleSystem6.SetCreationColor(1.0f,0.0f,0.0f, 368 1.0f,0.5f,0.0f); 369 g_ParticleSystem6.SetDieColor(1.0f,1.0f,1.0f, 370 1.0f,0.5f,0.0f); 371 372 g_ParticleSystem6.SetAlphaValues(1.0f,1.0f,0.0f,0.0f); 373 g_ParticleSystem6.SetEmitter(0.0f,0.0f,0.5f, 374 0.18f,0.0f,0.18f); 375 g_ParticleSystem6.SetAcceleration(F3dVector(0.0f,1.0f,0.0f),0.3f,0.4f); 376 g_ParticleSystem6.SetSizeValues(0.04f,0.08f,0.06f,0.12f); 377 g_ParticleSystem6.m_fMaxEmitSpeed = 0.12f; 378 g_ParticleSystem6.m_fMinEmitSpeed = 0.23f; 379 g_ParticleSystem6.SetEmissionDirection(0.0f,1.0f,0.0f, 380 0.08f,0.5f,0.08f); 381 g_ParticleSystem6.m_bParticlesLeaveSystem = true; 382 g_ParticleSystem6.SetSpinSpeed(-0.82*PI,0.82*PI); 383 g_ParticleSystem6.m_iBillboarding = BILLBOARDING_PERPTOVIEWDIR; 384 g_ParticleSystem6.LoadTextureFromFile("particle1.tga"); 385 386 } 387 388 int main(int argc, char **argv) 389 { 390 //Initialize GLUT 391 glutInit(&argc, argv); 392 //Lets use doublebuffering, RGB(A)-mode and a depth buffer 393 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); 394 glutInitWindowSize(800,600); 395 //Create a window with rendering context and everything else we need 396 glutCreateWindow("Particle Engine and Billboarding"); 397 //Init some state variables: 398 glDisable(GL_DEPTH_TEST); 399 glClearColor(0.1,0.1,0.1,1.0); 400 glEnable(GL_POINT_SMOOTH); 401 glEnable(GL_BLEND); 402 glBlendFunc(GL_SRC_ALPHA, GL_ONE); 403 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); //also try GL_LINE 404 405 g_Camera.Move(F3dVector(0.0f,0.3f,3.0f)); 406 407 408 //INITIALIZE THE PARTICLE SYSTEM: 409 InitParticles(); 410 411 //Assign the event-handling routines 412 glutDisplayFunc(Display); 413 glutReshapeFunc(Reshape); 414 glutKeyboardFunc(KeyDown); 415 glutIdleFunc(Display); //If there is no msg, we have to repaint 416 417 g_iLastRenderTime = timeGetTime(); 418 //Let GLUT get the msgs and tell us the ones we need 419 glutMainLoop(); 420 return 0; 421 }
Particles.h
1 /*************************************************************** 2 3 Particles.h 4 5 Philipp Crocoll from www.codecolony.de 6 7 Defines the classes used for the CodeColony Particle Engine: 8 9 - CCCParticle: Class to store/update a particle 10 - CCCParticleSystem: Class to store/update/render a complete particle system 11 (including an emitter) 12 13 ****************************************************************/ 14 15 //Include files needed: 16 #include "camera.h" 17 #include "textures.h" 18 19 20 class CCCParticleSystem; 21 22 23 /******************* 24 CONSTANTS 25 *******************/ 26 #define BILLBOARDING_NONE 0 27 #define BILLBOARDING_PERPTOVIEWDIR 1 //align particles perpendicular to view direction 28 #define BILLBOARDING_PERPTOVIEWDIR_BUTVERTICAL 2 //like PERPToViewDir, but Particles are vertically aligned 29 30 /******************* 31 CCCParticle 32 *******************/ 33 34 class CCCParticle 35 { 36 private: 37 //Position of the particle: NOTE: This might be the global position or the local position (depending on the system's translating behavior) 38 SF3dVector m_Position; 39 //Moving the particle: 40 //Particle's velocity: 41 SF3dVector m_Velocity; 42 //Particle's acceleration (per Sec): 43 SF3dVector m_Acceleration; 44 //Spinning the particle 45 float m_fSpinAngle; //radian measure 46 //Particle's spin speed: 47 float m_fSpinSpeed; 48 //Particle's spin acceleration: 49 float m_fSpinAcceleration; 50 //Particle's alpha value (=transparency) 51 float m_fAlpha; 52 float m_fAlphaChange; //how much is the alpha value changed per sec? 53 //Particle's color: 54 SF3dVector m_Color; //x=r, y=g, z=b 55 SF3dVector m_ColorChange; //how to change to color per sec 56 //Particle's size: (the use of this value is dependent of m_bUseTexture in the parent!) 57 float m_fSize; 58 float m_fSizeChange; 59 //Handling the lifetime: 60 float m_fDieAge; //At what "age" will the particle die? 61 float m_fAge; //Age of the particle (is updated 62 //Needed to access the system's values: 63 CCCParticleSystem * m_ParentSystem; 64 65 public: 66 bool m_bIsAlive; //Is the particle active or not? Must be visible for the System 67 void Initialize(CCCParticleSystem * ParentSystem); 68 void Update(float timePassed); //called by UpdateSystem if particle is active 69 void Render(); 70 71 }; 72 73 74 /******************* 75 CCCParticleSystem 76 *******************/ 77 78 class CCCParticleSystem 79 { 80 public: //The values how to emit a particle must be public because the particle 81 //must be able to access them in the creation function. 82 //************************************* 83 // EMISSION VALUES 84 //************************************* 85 86 //Position of the emitter: 87 SF3dVector m_EmitterPosition; 88 //How far may the particles be created from the emitter? 89 SF3dVector m_MaxCreationDeviation; //3 positive values. Declares the possible distance from the emitter 90 // Distance can be between -m_MaxCreationDeviation.? and +m_MaxCreationDeviation.? 91 //Which direction are the particles emitted to? 92 SF3dVector m_StandardEmitDirection; 93 SF3dVector m_MaxEmitDirectionDeviation; //Works like m_MaxCreationDeviation 94 95 //Which speed do they have when they are emitted? 96 //->Somewhere between these speeds: 97 float m_fMinEmitSpeed; 98 float m_fMaxEmitSpeed; 99 100 //How fast do they spin when being emitted? Speed here is angle speed (radian measure) per sec 101 float m_fMinEmitSpinSpeed; 102 float m_fMaxEmitSpinSpeed; 103 //Spinning acceleration: 104 float m_fMinSpinAcceleration; 105 float m_fMaxSpinAcceleration; 106 107 //The acceleration vector always has the same direction (normally (0/-1/0) for gravity): 108 SF3dVector m_AccelerationDirection; 109 //...but not the same amount: 110 float m_fMinAcceleration; 111 float m_fMaxAcceleration; 112 113 //How translucent are the particles when they are created? 114 float m_fMinEmitAlpha; 115 float m_fMaxEmitAlpha; 116 //How translucent are the particles when they have reached their dying age? 117 float m_fMinDieAlpha; 118 float m_fMaxDieAlpha; 119 120 //How big are the particles when they are created / when they die 121 float m_fMinEmitSize; 122 float m_fMaxEmitSize; 123 float m_fMinDieSize; 124 float m_fMaxDieSize; 125 126 127 //The same with the color: 128 SF3dVector m_MinEmitColor; 129 SF3dVector m_MaxEmitColor; 130 SF3dVector m_MinDieColor; 131 SF3dVector m_MaxDieColor; 132 133 //************************************* 134 // OTHER PARTICLE INFORMATION 135 //************************************* 136 137 //How long shall the particles live? Somewhere (randomly) between: 138 float m_fMinDieAge; 139 float m_fMaxDieAge; 140 141 bool m_bRecreateWhenDied; //Set it true so a particle will be recreate itsself as soon 142 //as it died 143 144 //************************************* 145 // RENDERING PROPERTIES 146 //************************************* 147 148 int m_iBillboarding; //See the constants above 149 150 COGLTexture * m_Texture; //Pointer to the texture (which is only an "alpha texture") 151 bool m_bUseTexture; //Set it false if you want to use GL_POINTS as particles! 152 153 bool m_bParticlesLeaveSystem; //Switch it off if the particle's positions 154 //shall be relative to the system's position (emitter position) 155 156 //************************************* 157 // STORING THE PARTICLES 158 //************************************* 159 //Particle array: 160 CCCParticle *m_pParticles; 161 //Maximum number of particles (assigned when reserving mem for the particle array) 162 int m_iMaxParticles; 163 //How many particles are currently in use? 164 int m_iParticlesInUse; 165 //How many particles are created per second? 166 //Note that this is an average value and if you set it too high, there won't be 167 //dead particles that can be created unless the lifetime is very short and/or 168 //the array of particles (m_pParticles) is big 169 int m_iParticlesCreatedPerSec; //if bRecreateWhenDied is true, this is the ADDITIONAL number of created particles! 170 float m_fCreationVariance; //Set it 0 if the number of particles created per sec 171 //should be the same each second. Otherwise use a positive value: 172 //Example: 1.0 affects that the NumParticlesCreatedPerSec varies 173 //between m_iParticlesCreatedPerSec/2 and 1.5*m_iParticlesCreatedPerSec 174 //Do not set these values: 175 float m_fCurrentPointSize; //required when rendering without particles 176 //If Billboarding is set to NONE, the following vectors are (1,0,0) and (0,1,0). 177 //If it is switched on, they are modified according to the viewdir/camera position (in Render of the System) 178 SF3dVector m_BillboardedX; 179 SF3dVector m_BillboardedY; 180 181 182 //************************************* 183 // FUNCTIONS TO ASSIGN THESE MANY VECTORS MORE EASILY 184 //************************************* 185 186 //Set the emitter position (you can pass a vector or x,y and z) 187 void SetEmitter(float x, float y, float z, float EmitterDeviationX,float EmitterDeviationY,float EmitterDeviationZ); 188 void SetEmitter(SF3dVector pos,SF3dVector dev); 189 190 //Set the emission direction: 191 void SetEmissionDirection(float x, float y, float z, //direction 192 float MaxDeviationX, float MaxDeviationY, float MaxDeviationZ); //max deviation 193 void SetEmissionDirection(SF3dVector direction, SF3dVector Deviation); 194 195 //Spin Speed 196 void SetSpinSpeed(float min, float max); 197 198 //Acceleration 199 void SetAcceleration(float x, float y, float z, float Min, float Max); 200 void SetAcceleration(SF3dVector acc, float Min, float Max); 201 202 //Color (at creation and dying age): 203 void SetCreationColor(float minr, float ming, float minb, 204 float maxr, float maxg, float maxb); 205 void SetCreationColor(SF3dVector min, SF3dVector max); 206 207 void SetDieColor (float minr, float ming, float minb, 208 float maxr, float maxg, float maxb); 209 void SetDieColor (SF3dVector min, SF3dVector max); 210 //alpha: 211 void SetAlphaValues (float MinEmit, float MaxEmit, float MinDie, float MaxDie); 212 //size: 213 void SetSizeValues (float EmitMin, float EmitMax, float DieMin, float DieMax); 214 215 //************************************* 216 // FUNCTIONS TO INITIALIZE THE SYSTEM 217 //************************************* 218 219 CCCParticleSystem(); //constructor: sets default values 220 221 bool Initialize(int iNumParticles); //reserves space for the particles 222 223 bool LoadTextureFromFile(char * Filename); 224 225 //************************************* 226 // FUNCTIONS TO UPDATE/RENDER THE SYSTEM 227 //************************************* 228 229 void UpdateSystem(float timePassed); //updates all particles alive 230 void Render(); //renders all particles alive 231 232 };
particles.cpp
1 #include "particles.h" 2 #include "math.h" 3 4 //Generates a random float in the range [0;1] 5 #define RANDOM_FLOAT (((float)rand())/RAND_MAX) 6 /************************************* 7 8 METHODS OF CCCParticle class 9 10 **************************************/ 11 12 void CCCParticle::Initialize(CCCParticleSystem *ParentSystem) 13 { 14 15 //Calculate the age, the particle will live: 16 m_fDieAge = ParentSystem->m_fMinDieAge + 17 ((ParentSystem->m_fMaxDieAge - ParentSystem->m_fMinDieAge)*RANDOM_FLOAT); 18 if (m_fDieAge == 0.0f) return; //make sure there is no div 0 19 m_fAge = 0.0f; 20 21 //set the position: 22 if (ParentSystem->m_bParticlesLeaveSystem) 23 { 24 //start with "global" coordinates (the current coordinates of the emitter position) 25 m_Position = ParentSystem->m_EmitterPosition; 26 } 27 else 28 { 29 //In this case we assume a local coordinate system: 30 m_Position = NULL_VECTOR; 31 } 32 //Add the deviation from the emitter position: 33 m_Position.x += ParentSystem->m_MaxCreationDeviation.x*(RANDOM_FLOAT*2.0f-1.0f); 34 m_Position.y += ParentSystem->m_MaxCreationDeviation.y*(RANDOM_FLOAT*2.0f-1.0f); 35 m_Position.z += ParentSystem->m_MaxCreationDeviation.z*(RANDOM_FLOAT*2.0f-1.0f); 36 //set the emission velocity 37 m_Velocity.x = ParentSystem->m_StandardEmitDirection.x + ParentSystem->m_MaxEmitDirectionDeviation.x*(RANDOM_FLOAT*2.0f-1.0f); 38 m_Velocity.y = ParentSystem->m_StandardEmitDirection.y + ParentSystem->m_MaxEmitDirectionDeviation.y*(RANDOM_FLOAT*2.0f-1.0f); 39 m_Velocity.z = ParentSystem->m_StandardEmitDirection.z + ParentSystem->m_MaxEmitDirectionDeviation.z*(RANDOM_FLOAT*2.0f-1.0f); 40 m_Velocity = m_Velocity * ((ParentSystem->m_fMinEmitSpeed + 41 (ParentSystem->m_fMaxEmitSpeed - ParentSystem->m_fMinEmitSpeed)*RANDOM_FLOAT)); 42 //set the acceleration vector: 43 m_Acceleration = ParentSystem->m_AccelerationDirection* 44 (ParentSystem->m_fMinAcceleration + (ParentSystem->m_fMaxAcceleration-ParentSystem->m_fMinAcceleration)*RANDOM_FLOAT); 45 //set the alpha / color values: 46 m_Color = ParentSystem->m_MinEmitColor + 47 ((ParentSystem->m_MaxEmitColor-ParentSystem->m_MinEmitColor) * RANDOM_FLOAT); 48 //calculate the "end color" (in order to get the ColorChange): 49 SF3dVector EndColor = ParentSystem->m_MinDieColor + 50 ((ParentSystem->m_MaxDieColor-ParentSystem->m_MinDieColor) * RANDOM_FLOAT); 51 m_ColorChange = (EndColor-m_Color) / m_fDieAge; 52 53 m_fAlpha = ParentSystem->m_fMinEmitAlpha 54 + ((ParentSystem->m_fMaxEmitAlpha - ParentSystem->m_fMinEmitAlpha) * RANDOM_FLOAT); 55 float fEndAlpha = ParentSystem->m_fMinDieAlpha 56 + ((ParentSystem->m_fMaxDieAlpha - ParentSystem->m_fMinDieAlpha) * RANDOM_FLOAT); 57 m_fAlphaChange = (fEndAlpha - m_fAlpha) / m_fDieAge; 58 59 //set the size values: 60 m_fSize = ParentSystem->m_fMinEmitSize + 61 ((ParentSystem->m_fMaxEmitSize - ParentSystem->m_fMinEmitSize) * RANDOM_FLOAT); 62 float fEndSize = ParentSystem->m_fMinDieSize + 63 ((ParentSystem->m_fMaxDieSize - ParentSystem->m_fMinDieSize) * RANDOM_FLOAT); 64 m_fSizeChange = (fEndSize - m_fSize) / m_fDieAge; 65 66 //spin values: 67 m_fSpinAngle = 0.0f; 68 m_fSpinSpeed = ParentSystem->m_fMinEmitSpinSpeed + 69 ((ParentSystem->m_fMaxEmitSpinSpeed - ParentSystem->m_fMinEmitSpinSpeed) * RANDOM_FLOAT); 70 m_fSpinAcceleration = ParentSystem->m_fMinSpinAcceleration + 71 ((ParentSystem->m_fMaxSpinAcceleration - ParentSystem->m_fMinSpinAcceleration) * RANDOM_FLOAT); 72 73 //Ok, we're done: 74 m_bIsAlive = true; 75 m_ParentSystem = ParentSystem; 76 77 } 78 79 void CCCParticle::Update(float timePassed) 80 { 81 //Update all time-dependent values: 82 m_fAge += timePassed; 83 if (m_fAge >= m_fDieAge) 84 { 85 if (m_ParentSystem->m_bRecreateWhenDied) 86 { 87 Initialize(m_ParentSystem); 88 Update(RANDOM_FLOAT * timePassed); //see comment in UpdateSystem 89 } 90 else 91 { 92 m_fAge = 0.0f; 93 m_bIsAlive = false; 94 m_ParentSystem->m_iParticlesInUse--; 95 } 96 97 return; 98 } 99 100 m_fSize += m_fSizeChange *timePassed; 101 m_fAlpha += m_fAlphaChange*timePassed; 102 m_Color = m_Color + m_ColorChange*timePassed; 103 m_Velocity = m_Velocity + m_Acceleration*timePassed; 104 //Note: exact would be: m_Position = 1/2*m_Acceleration*timePassed?+ m_VelocityOLD*timePassed; 105 //But this approach is ok, I think! 106 m_Position = m_Position + (m_Velocity*timePassed); 107 108 m_fSpinSpeed += m_fSpinAcceleration*timePassed; 109 m_fSpinAngle += m_fSpinSpeed*timePassed; 110 111 //That's all! 112 } 113 114 void CCCParticle::Render() 115 { 116 if (!m_ParentSystem->m_bUseTexture) 117 { 118 glPointSize(m_fSize*m_ParentSystem->m_fCurrentPointSize); 119 float color[4]; 120 color[0] = m_Color.x; 121 color[1] = m_Color.y; 122 color[2] = m_Color.z; 123 color[3] = m_fAlpha; 124 125 glColor4fv(&color[0]); 126 127 glBegin(GL_POINTS); 128 glVertex3fv(&m_Position.x); 129 glEnd(); 130 } 131 else 132 { 133 //render using texture: (texture was already set active by the Render method of the particle system) 134 135 float color[4]; 136 color[0] = m_Color.x; 137 color[1] = m_Color.y; 138 color[2] = m_Color.z; 139 color[3] = m_fAlpha; 140 glColor4fv(&color[0]); 141 142 SF3dVector RotatedX = m_ParentSystem->m_BillboardedX; 143 SF3dVector RotatedY = m_ParentSystem->m_BillboardedY; 144 145 146 //If spinning is switched on, rotate the particle now: 147 if (m_fSpinAngle > 0.0f) 148 { 149 RotatedX = m_ParentSystem->m_BillboardedX * cos(m_fSpinAngle) 150 + m_ParentSystem->m_BillboardedY * sin(m_fSpinAngle); 151 RotatedY = m_ParentSystem->m_BillboardedY * cos(m_fSpinAngle) 152 - m_ParentSystem->m_BillboardedX * sin(m_fSpinAngle); 153 } 154 155 156 //Render a quadrangle with the size m_fSize 157 SF3dVector coords = m_Position - (RotatedX*(0.5f*m_fSize)) 158 - (RotatedY*(0.5f*m_fSize)); 159 glBegin(GL_POLYGON); 160 glVertex3fv(&coords.x); 161 glTexCoord2f(0.0f,1.0f); 162 coords = coords + RotatedY * m_fSize; 163 glVertex3fv(&coords.x); 164 glTexCoord2f(1.0f,1.0f); 165 coords = coords + RotatedX * m_fSize; 166 glVertex3fv(&coords.x); 167 glTexCoord2f(1.0f,0.0f); 168 coords = coords - RotatedY * m_fSize; 169 glVertex3fv(&coords.x); 170 glTexCoord2f(0.0f,0.0f); 171 glEnd(); 172 173 174 } 175 176 } 177 178 /************************************* 179 180 METHODS OF CCCParticleSytem class 181 182 **************************************/ 183 184 185 CCCParticleSystem::CCCParticleSystem() 186 { 187 //Set default values: 188 189 //motion: 190 this->m_EmitterPosition = NULL_VECTOR; 191 this->m_MaxCreationDeviation = NULL_VECTOR; 192 193 this->m_StandardEmitDirection = NULL_VECTOR; 194 this->m_MaxEmitDirectionDeviation = NULL_VECTOR; 195 this->m_fMaxEmitSpeed = 0.0f; 196 this->m_fMinEmitSpeed = 0.0f; 197 198 this->m_AccelerationDirection = NULL_VECTOR; 199 this->m_fMaxAcceleration = 0.0f; 200 this->m_fMinAcceleration = 0.0f; 201 202 this->m_fMinEmitSpinSpeed = 0.0f; 203 this->m_fMaxEmitSpinSpeed = 0.0f; 204 205 this->m_fMaxSpinAcceleration = 0.0f; 206 this->m_fMinSpinAcceleration = 0.0f; 207 208 209 //look: 210 this->m_fMaxEmitAlpha = 0.0f; 211 this->m_fMinEmitAlpha = 0.0f; 212 this->m_fMaxDieAlpha = 1.0f; 213 this->m_fMinDieAlpha = 1.0f; 214 215 this->m_MaxEmitColor = NULL_VECTOR; 216 this->m_MinEmitColor = NULL_VECTOR; 217 this->m_MaxDieColor = NULL_VECTOR; 218 this->m_MinDieColor = NULL_VECTOR; 219 220 this->m_Texture = NULL; 221 this->m_bUseTexture = false; 222 this->m_iBillboarding = BILLBOARDING_NONE; 223 224 //size: 225 this->m_fMaxEmitSize = 0.0f; 226 this->m_fMinEmitSize = 0.0f; 227 this->m_fMaxDieSize = 0.0f; 228 this->m_fMinDieSize = 0.0f; 229 230 231 //behavior: 232 this->m_bRecreateWhenDied = false; 233 234 this->m_fMaxDieAge = 1.0f; 235 this->m_fMinDieAge = 1.0f; 236 237 this->m_iMaxParticles = 0; //array is not yet created 238 this->m_iParticlesInUse = 0; 239 240 this->m_iParticlesCreatedPerSec = 0; 241 this->m_fCreationVariance = 0.0f; 242 this->m_bParticlesLeaveSystem = false; 243 this->m_pParticles = NULL; 244 245 } 246 //********************************************************* 247 void CCCParticleSystem::SetEmitter(float x, float y, float z, float EmitterDeviationX,float EmitterDeviationY,float EmitterDeviationZ) 248 { 249 SetEmitter(F3dVector(x,y,z),F3dVector(EmitterDeviationX,EmitterDeviationY,EmitterDeviationZ)); 250 } 251 252 void CCCParticleSystem::SetEmitter(SF3dVector pos, SF3dVector dev) 253 { 254 m_EmitterPosition = pos; 255 m_MaxCreationDeviation = dev; 256 } 257 258 void CCCParticleSystem::SetEmissionDirection(float x, float y, float z, 259 float MaxDeviationX, float MaxDeviationY, float MaxDeviationZ) 260 { 261 SetEmissionDirection(F3dVector(x,y,z),F3dVector(MaxDeviationX,MaxDeviationY,MaxDeviationZ)); 262 } 263 264 265 void CCCParticleSystem::SetEmissionDirection(SF3dVector direction, SF3dVector Deviation) 266 { 267 m_StandardEmitDirection = direction; 268 m_MaxEmitDirectionDeviation = Deviation; 269 } 270 271 272 273 274 void CCCParticleSystem::SetSpinSpeed(float min, float max) 275 { 276 m_fMinEmitSpinSpeed = min; 277 m_fMaxEmitSpinSpeed = max; 278 } 279 280 281 void CCCParticleSystem::SetAcceleration(float x, float y, float z, float Min, float Max) 282 { 283 SetAcceleration(F3dVector(x,y,z),Min,Max); 284 } 285 286 void CCCParticleSystem::SetAcceleration(SF3dVector acc, float Min, float Max) 287 { 288 m_AccelerationDirection = acc; 289 m_fMaxAcceleration = Max; 290 m_fMinAcceleration = Min; 291 } 292 293 void CCCParticleSystem::SetCreationColor(float minr, float ming, float minb, 294 float maxr, float maxg, float maxb) 295 { 296 SetCreationColor(F3dVector(minr,ming,minb),F3dVector(maxr,maxg,maxb)); 297 } 298 299 void CCCParticleSystem::SetCreationColor(SF3dVector min, SF3dVector max) 300 { 301 m_MinEmitColor = min; 302 m_MaxEmitColor = max; 303 } 304 305 306 void CCCParticleSystem::SetDieColor (float minr, float ming, float minb, 307 float maxr, float maxg, float maxb) 308 { 309 SetDieColor(F3dVector(minr,ming,minb),F3dVector(maxr,maxg,maxb)); 310 } 311 312 void CCCParticleSystem::SetDieColor (SF3dVector min, SF3dVector max) 313 { 314 m_MinDieColor = min; 315 m_MaxDieColor = max; 316 } 317 318 void CCCParticleSystem::SetAlphaValues (float MinEmit, float MaxEmit, float MinDie, float MaxDie) 319 { 320 m_fMinEmitAlpha = MinEmit; 321 m_fMaxEmitAlpha = MaxEmit; 322 m_fMinDieAlpha = MinDie; 323 m_fMaxDieAlpha = MaxDie; 324 } 325 326 void CCCParticleSystem::SetSizeValues (float EmitMin, float EmitMax, float DieMin, float DieMax) 327 { 328 m_fMinEmitSize = EmitMin; 329 m_fMaxEmitSize = EmitMax; 330 m_fMinDieSize = DieMin; 331 m_fMaxDieSize = DieMax; 332 } 333 //********************************************************* 334 335 bool CCCParticleSystem::Initialize(int iNumParticles) 336 { 337 this->m_pParticles = new CCCParticle[iNumParticles]; 338 if (m_pParticles == NULL) 339 { 340 return false; 341 this->m_iMaxParticles = 0; 342 this->m_iParticlesInUse = 0; 343 } 344 345 this->m_iMaxParticles = iNumParticles; 346 this->m_iParticlesInUse = 0; 347 348 //Set the status of each particle to DEAD 349 for (int i = 0; i < iNumParticles; i++) 350 { 351 m_pParticles[i].m_bIsAlive = false; 352 } 353 354 return true; 355 356 357 358 } 359 360 361 void CCCParticleSystem::UpdateSystem(float timePassed) 362 { 363 //We have to 364 // -update the particles (= move the particles, change their alpha, color, speed values) 365 // -create new particles, if desired and there are "free" particles 366 367 //First get the number of particles we want to create (randomly in a certain dimension (dependent of m_CreationVariance) 368 // 我们必须 369 // - 更新粒子(=移动粒子,改变他们的阿尔法,颜色,速度值) 370 // - 创造新粒子,如果需要有“免费”粒子 371 // 首先得到粒子的数量我们想创建(随机在某些维度(m_CreationVariance依赖) 372 373 int iParticlesToCreate = (int) ((float)m_iParticlesCreatedPerSec 374 *timePassed 375 *(1.0f+m_fCreationVariance*(RANDOM_FLOAT-0.5f))); 376 377 378 //loop through the particles and update / create them 379 for (int i = 0; i < m_iMaxParticles; i++) 380 { 381 if (m_pParticles[i].m_bIsAlive) 382 { 383 m_pParticles[i].Update(timePassed); 384 } 385 386 //Should we create the particle? 387 if (iParticlesToCreate > 0) 388 { 389 if (!m_pParticles[i].m_bIsAlive) 390 { 391 m_pParticles[i].Initialize(this); 392 //Update the particle: This has an effect, as if the particle would have 393 //been emitted some milliseconds ago. This is very useful on slow PCs: 394 //Especially if you simulate something like rain, then you could see that 395 //many particles are emitted at the same time (same "UpdateSystem" call), 396 //if you would not call this function: 397 m_pParticles[i].Update(RANDOM_FLOAT*timePassed); 398 iParticlesToCreate--; 399 } 400 } 401 402 } 403 404 } 405 406 bool CCCParticleSystem::LoadTextureFromFile(char * Filename) 407 { 408 //Create the texture pointer: 409 m_Texture = new COGLTexture; 410 411 if (m_Texture == NULL) return false; 412 413 if (!m_Texture->LoadFromTGA(Filename,NULL,true)) return false; //pass NULL as 2. param (only required if you want to combine rgb and alpha maps) 414 415 m_Texture->SetActive(); 416 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 417 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 418 419 420 m_bUseTexture = true; 421 422 423 return true; 424 425 } 426 427 428 void CCCParticleSystem::Render() 429 { 430 //the calling method must switch on texturing! 431 432 if (m_bUseTexture) 433 { 434 m_Texture->SetActive(); 435 //Calculate the "billboarding vectors" (the particles only store their positions, but we need quadrangles!) 436 switch (m_iBillboarding) 437 { 438 case BILLBOARDING_NONE: 439 { 440 //independent from camera / view direction 441 m_BillboardedX = F3dVector(1.0f,0.0f,0.0f); 442 m_BillboardedY = F3dVector(0.0f,1.0f,0.0f); 443 break; 444 } 445 case BILLBOARDING_PERPTOVIEWDIR: 446 { 447 //Retrieve the up and right vector from the modelview matrix: 448 float fModelviewMatrix[16]; 449 glGetFloatv(GL_MODELVIEW_MATRIX, fModelviewMatrix); 450 451 //Assign the x-Vector for billboarding: 452 m_BillboardedX = F3dVector(fModelviewMatrix[0], fModelviewMatrix[4], fModelviewMatrix[8]); 453 454 //Assign the y-Vector for billboarding: 455 m_BillboardedY = F3dVector(fModelviewMatrix[1], fModelviewMatrix[5], fModelviewMatrix[9]); 456 break; 457 } 458 case BILLBOARDING_PERPTOVIEWDIR_BUTVERTICAL: 459 { 460 //Retrieve the right vector from the modelview matrix: 461 float fModelviewMatrix[16]; 462 glGetFloatv(GL_MODELVIEW_MATRIX, fModelviewMatrix); 463 464 //Assign the x-Vector for billboarding: 465 m_BillboardedX = F3dVector(fModelviewMatrix[0], fModelviewMatrix[4], fModelviewMatrix[8]); 466 467 //Assign the y-Vector: 468 m_BillboardedY = F3dVector(0.0f,1.0f,0.0f); 469 break; 470 } 471 } 472 } 473 else 474 { 475 glGetFloatv(GL_POINT_SIZE,&m_fCurrentPointSize); 476 } 477 for (int i = 0; i < m_iMaxParticles; i++) 478 { 479 if (m_pParticles[i].m_bIsAlive) 480 m_pParticles[i].Render(); 481 } 482 }
Textures.h
1 #ifndef INCLUDE_TEXTURES_H 2 #define INCLUDE_TEXTURES_H 3 4 #include <GL\glaux.h> 5 6 typedef struct 7 { 8 GLubyte *Data; 9 GLuint BitsPerPixel; 10 GLuint Width; 11 GLuint Height; 12 } STGAData; 13 14 class COGLTexture 15 { 16 public: 17 18 _AUX_RGBImageRec *Image; 19 20 unsigned int GetID(); 21 void LoadFromFile(char *filename); 22 bool LoadFromTGA(const char *filename, const char* AlphaMap, bool bMipMaps); 23 void SetActive(); 24 GLuint GetWidth(); 25 GLuint GetHeight(); 26 GLuint type; 27 char * m_TexFilename; 28 char * m_AlphaFilename; 29 private: 30 GLuint Width, Height; 31 unsigned int ID; 32 GLuint BitsPerPixel; 33 34 }; 35 36 #endif
Textures.cpp
1 #include "Textures.h" 2 #include <stdio.h> 3 4 #define EIGHT_BIT_FORMAT GL_ALPHA 5 6 //************** 7 //Only for loading bmps: 8 void COGLTexture::LoadFromFile(char *filename) 9 { 10 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 11 glGenTextures(1,&ID); 12 glBindTexture( GL_TEXTURE_2D, ID); 13 Image = auxDIBImageLoadA( (const char*) filename ); 14 Width = Image->sizeX; 15 Height = Image->sizeY; 16 17 gluBuild2DMipmaps( GL_TEXTURE_2D, 18 3, 19 Image->sizeX, 20 Image->sizeY, 21 GL_RGB, 22 GL_UNSIGNED_BYTE, 23 Image->data); 24 delete Image; 25 } 26 //////////////////////////////////////////////////////////////////////////// 27 /// 28 /// CODE FROM NEHE'S "LESSON 25": Loading a TGA 29 /// (modified) 30 /// 31 //////////////////////////////////////////////////////////////////////////// 32 bool LoadTGA(STGAData *TGAData, const char *filename) // Loads A TGA File Into Memory 33 { 34 GLubyte TGAheader1[12]={0,0,2,0,0,0,0,0,0,0,0,0}; // Uncompressed TGA Header for RGB / RGBA 35 GLubyte TGAheader2[12]={0,1,1,0,0,0,1,24,0,0,0,0}; // Uncompressed TGA Header for Grayscale 36 GLubyte TGAcompare[12]; // Used To Compare TGA Header 37 GLubyte header[6]; // First 6 Useful Bytes From The Header 38 GLuint bytesPerPixel; // Holds Number Of Bytes Per Pixel Used In The TGA File 39 GLuint imageSize; // Used To Store The Image Size When Setting Aside Ram 40 GLuint type=GL_RGBA; // Set The Default GL Mode To RBGA (32 BPP) 41 42 FILE *file = fopen(filename, "rb"); // Open The TGA File 43 44 if( file==NULL) 45 return false; // Does File Exist? 46 47 if (fread(TGAcompare,1,sizeof(TGAcompare),file)!=sizeof(TGAcompare) || // Are There 12 Bytes To Read? 48 ( memcmp(TGAheader1,TGAcompare,sizeof(TGAheader1))!=0 49 &&memcmp(TGAheader2,TGAcompare,sizeof(TGAheader2)) ) || // Does The Header Match What We Want? 50 fread(header,1,sizeof(header),file)!=sizeof(header)) // If So Read Next 6 Header Bytes 51 { 52 if (file == NULL) // Did The File Even Exist? *Added Jim Strong* 53 return false; // Return False 54 else 55 { 56 //fclose(file); // If Anything Failed, Close The File 57 //return false; // Return False 58 } 59 } 60 61 TGAData->Width = header[1] * 256 + header[0]; // Determine The TGA Width (highbyte*256+lowbyte) 62 TGAData->Height = header[3] * 256 + header[2]; // Determine The TGA Height (highbyte*256+lowbyte) 63 64 //I don't need to check here for the bpp. This will be done by 65 //the calling function. 66 67 68 69 TGAData->BitsPerPixel = header[4]; // Grab The TGA's Bits Per Pixel 70 bytesPerPixel = TGAData->BitsPerPixel/8; // Divide By 8 To Get The Bytes Per Pixel 71 imageSize = TGAData->Width*TGAData->Height*bytesPerPixel; // Calculate The Memory Required For The TGA Data 72 73 if (bytesPerPixel == 1) 74 { 75 GLubyte DummyData[768]; 76 fread(DummyData,1,768,file); 77 } 78 79 TGAData->Data=(GLubyte *)malloc(imageSize); // Reserve Memory To Hold The TGA Data 80 81 if( TGAData->Data==NULL || // Does The Storage Memory Exist? 82 fread(TGAData->Data, 1, imageSize, file)!=imageSize) // Does The Image Size Match The Memory Reserved? 83 { 84 if(TGAData->Data!=NULL) // Was Image Data Loaded 85 free(TGAData->Data); // If So, Release The Image Data 86 87 fclose(file); // Close The File 88 return false; // Return False 89 } 90 91 //I also do not swap Red and Blue values (this may only be done 92 //with 24/32-bpp-images). Again it's the calling routine's task. 93 94 fclose (file); // Close The File 95 96 return true; 97 } 98 99 100 101 bool COGLTexture::LoadFromTGA(const char *filename,const char *AlphaMap, bool bMipMaps) 102 { 103 STGAData TGAData; //Used to load the TGA-Texture 104 STGAData AlphaData; //Used to load the Alpha-Map (if specified) 105 106 GLubyte * RGBAData = NULL; //RGBA Data. This can be the TGA file (if it contains 32bpp) 107 //or it is the combination of TGA and alpha map. 108 //If no alpha map is requested, it contains RGB data 109 GLuint RGBADataLength; //Length of RGBA Data 110 111 type = GL_RGB; 112 113 char * LogStr; 114 115 if (filename != NULL) 116 { 117 if (!LoadTGA(&TGAData,filename)) //Load the texture file into memory 118 { 119 LogStr = new char[2000]; 120 sprintf(LogStr,"Failed to load Texture (%s, %s). Reason: Failed to load RGB file."); 121 return false; //failed. Return false. 122 } 123 124 125 if (TGAData.BitsPerPixel == 32) 126 { 127 type = GL_RGBA; //TGA is a 32 bit file (i.e. it contains the alpha information) 128 RGBAData = TGAData.Data; //The TGA Data can be used to create the texture 129 RGBADataLength = TGAData.Height*TGAData.Height*TGAData.BitsPerPixel/8; 130 } 131 Width = TGAData.Width; 132 Height = TGAData.Height; 133 } 134 else 135 type = EIGHT_BIT_FORMAT; 136 137 if (type != GL_RGBA) //ignore Alphamap if TGA has 32 bpp 138 { 139 if (AlphaMap != NULL) //Alphamap specified 140 {//AlphaMap requested: 141 if (!LoadTGA(&AlphaData,AlphaMap)) //Load alpha map from file into memory 142 { 143 LogStr = new char[2000]; 144 sprintf(LogStr,"Failed to load Texture (%s, %s). Reason: Failed to load alpha file."); 145 146 return false; //failed. Return false. 147 } 148 149 //Check if the TGA has 24 bpp: (if it even exists) 150 if ((type == GL_RGB) && (TGAData.BitsPerPixel != 24)) 151 { 152 LogStr = new char[2000]; 153 sprintf(LogStr,"Failed to load Texture (%s, %s). Reason: RGB file not in 8 Bit format!"); 154 return false; 155 } 156 //Check if the Alpha Map has 8 bpp (grayscale): 157 if (AlphaData.BitsPerPixel != 8) 158 { 159 LogStr = new char[2000]; 160 sprintf(LogStr,"Failed to load Texture (%s, %s). Reason: Alpha file not in 8 bit format."); 161 return false; 162 } 163 //Check if the size of AlphaData and TGAData is equal: (if the TGA exists) 164 if ((type == GL_RGB) && ((AlphaData.Width != TGAData.Width)||(AlphaData.Height != TGAData.Height))) 165 { 166 LogStr = new char[2000]; 167 sprintf(LogStr,"Failed to load Texture (%s, %s). Reason: Alpha size does not eqal RGB size."); 168 return false; 169 } 170 171 if (type == GL_RGB) 172 { 173 type = GL_RGBA; 174 Width = TGAData.Width; 175 Height = TGAData.Height; 176 //Now comes the tricky part: Combine the TGAData and the alpha map. 177 RGBADataLength = TGAData.Width*TGAData.Height*4; //4 = (24+8)/8; we need RGBA! 178 RGBAData=(GLubyte *)malloc(RGBADataLength); 179 //Check if malloc succeeded: 180 if (RGBAData==NULL) 181 { 182 LogStr = new char[2000]; 183 sprintf(LogStr,"Failed to load Texture (%s, %s). Reason: Out of memory."); 184 return false; 185 } 186 187 //Loop. Copy three bytes of the TGA, then one byte of the alpha map. 188 //We do not swap R and B here, this is done at the end. 189 for (GLuint i = 0; i < RGBADataLength/4; i++) 190 { 191 RGBAData[i*4+0] = TGAData.Data[i*3+0]; 192 RGBAData[i*4+1] = TGAData.Data[i*3+1]; 193 RGBAData[i*4+2] = TGAData.Data[i*3+2]; 194 RGBAData[i*4+3] = AlphaData.Data[i]; 195 } 196 } 197 else //if type == EIGHT_BIT_FORMAT 198 { 199 RGBADataLength = AlphaData.Width*AlphaData.Height; 200 RGBAData=(GLubyte *)malloc(RGBADataLength); 201 for (GLuint i = 0; i < RGBADataLength; i++) 202 { 203 204 RGBAData[i] = AlphaData.Data[i]; 205 206 } 207 type = GL_ALPHA; 208 Width = AlphaData.Width; 209 Height = AlphaData.Height; 210 } 211 212 } 213 else //No Alphamap specified 214 { 215 //Store the TGAData in the local variables. This is RGB Data! 216 RGBAData = TGAData.Data; 217 RGBADataLength = TGAData.Height*TGAData.Height*TGAData.BitsPerPixel/8; 218 } 219 } 220 221 //Now swap the R and B values. Be careful. Do not forget to check if we have RGBA or RGB data! 222 GLuint SwapC; //Counter for swapping 223 int TempR; //To Swap we need a temporary variable. This var here will store the temp R value. 224 225 int BytesPerPixel = 3; 226 if (type == GL_RGBA) 227 BytesPerPixel = 4; 228 if (type == EIGHT_BIT_FORMAT) 229 BytesPerPixel = 1; 230 231 if (BytesPerPixel > 1) 232 for (SwapC = 0; SwapC < RGBADataLength/BytesPerPixel;SwapC++) 233 { 234 TempR = RGBAData[SwapC*BytesPerPixel+0]; 235 RGBAData[SwapC*BytesPerPixel+0] = RGBAData[SwapC*BytesPerPixel+2]; 236 RGBAData[SwapC*BytesPerPixel+2] = TempR; 237 } 238 239 240 241 if (bMipMaps) 242 { 243 glGenTextures(1,&ID); 244 glBindTexture( GL_TEXTURE_2D, ID); 245 GLuint res = gluBuild2DMipmaps( GL_TEXTURE_2D, 246 BytesPerPixel, //computed earlier, 247 Width, 248 Height, 249 type, 250 GL_UNSIGNED_BYTE, 251 RGBAData); 252 if (res != 0) 253 { 254 return false; 255 256 } 257 } 258 else 259 { 260 glGenTextures(1, &ID); // Generate OpenGL texture IDs 261 glBindTexture(GL_TEXTURE_2D, ID); // Bind Our Texture 262 glTexImage2D(GL_TEXTURE_2D, 0, BytesPerPixel, Width,Height, 0, type, GL_UNSIGNED_BYTE, RGBAData); 263 } 264 265 //Store the filenames: 266 if (filename == NULL) 267 m_TexFilename = NULL; 268 else 269 { 270 m_TexFilename = new char[strlen(filename)+2]; 271 strcpy(m_TexFilename,filename); 272 } 273 if (AlphaMap == NULL) 274 m_AlphaFilename = NULL; 275 else 276 { 277 m_AlphaFilename = new char[strlen(AlphaMap)+2]; 278 strcpy(m_AlphaFilename,AlphaMap); 279 } 280 281 282 return true; 283 } 284 285 286 void COGLTexture::SetActive() 287 { 288 glBindTexture( GL_TEXTURE_2D, ID); 289 } 290 291 unsigned int COGLTexture::GetID() 292 { 293 return ID; 294 } 295 296 GLuint COGLTexture::GetWidth() 297 { 298 return Width; 299 } 300 GLuint COGLTexture::GetHeight() 301 { 302 return Height; 303 }