using System;
using System.Collections.Generic;
using System.Text;
using ESRI.ArcGIS.Geometry;
using CsGL.Basecode;
using CsGL.OpenGL;
using System.Drawing.Imaging;
using CsGL;
using System.Drawing;
using ESRI.ArcGIS.Analyst3D;
namespace USTC
{
/// <summary>
/// 使用如下:
/// Particles pt = new Particles();
/// pt.initParticles(@"D:/rr.bmp",this.m_sceneViwer);
/// pt.DrawParticles(pp.glX,pp.glY,pp.glZ);
/// </summary>
class Particles
{
#region Private Fields
private const int MAX_PARTICLES = 300; // Number Of Particles To Create
private static bool rainbow = true; // Rainbow Mode?
private static bool sbp; // Space Bar Pressed?
private static bool rp; // R Pressed?
private static float slowdown = 2.0f; // Slow Down Particles
private static float xspeed = 0.0f; // Base X Speed (To Allow Keyboard Direction Of Tail)
private static float yspeed = 0.0f; // Base Y Speed (To Allow Keyboard Direction Of Tail)
private static float zoom = -40.0f; // Used To Zoom Out
private static uint loop; // Misc Loop Variable
private static uint col; // Current Color Selection
private static uint delay; // Rainbow Effect Delay
private static uint[] texture = new uint[1]; // Our Particle Texture
private struct Particle
{ // Create A Structure For Particle
public bool active; // Active True / False
public float life; // Particle Life
public float fade; // Fade Speed
public float r; // Red Value
public float g; // Green Value
public float b; // Blue Value
public float x; // X Position
public float y; // Y Position
public float z; // Z Position
public float xi; // X Direction
public float yi; // Y Direction
public float zi; // Z Direction
public float xg; // X Gravity
public float yg; // Y Gravity
public float zg; // Z Gravity
}
private static Particle[] particle = new Particle[MAX_PARTICLES]; // Particle Array
private static float[][] colors = new float[12][] { // Rainbow Of Colors
new float[] {1.0f, 0.5f, 0.5f},
new float[] {1.0f, 0.75f, 0.5f},
new float[] {1.0f, 1.0f, 0.5f},
new float[] {0.75f, 1.0f, 0.5f},
new float[] {0.5f, 1.0f, 0.5f},
new float[] {0.5f, 1.0f, 0.75f},
new float[] {0.5f, 1.0f, 1.0f},
new float[] {0.5f, 0.75f, 1.0f},
new float[] {0.5f, 0.5f, 1.0f},
new float[] {0.75f, 0.5f, 1.0f},
new float[] {1.0f, 0.5f, 1.0f},
new float[] {1.0f, 0.5f, 0.75f}
};
private static Random rand = new Random(); // Random Number Generator
#endregion Private Fields
private double[] m_modelViewMatrix = null;
private double[] m_billboardMatrix = null;
private ISceneViewer m_sceneViwer = null;
#region 粒子系统计算
public void initParticles(string filename, ISceneViewer sceneViwer)
{
this.m_sceneViwer = sceneViwer;
texture[0] = OpenGLTool.CreateTexture(filename);
// Jump To Texture Loading Routine
m_modelViewMatrix = new double[16];
m_billboardMatrix = new double[16];
for (loop = 0; loop < MAX_PARTICLES; loop++)
{ // Initialize All The Particles
particle[loop].active = true; // Make All The Particles Active
particle[loop].life = 1.0f; // Give All The Particles Full Life
particle[loop].fade = (rand.Next() % 100) / 1000.0f + 0.003f; // Random Fade Speed
particle[loop].r = colors[loop * (12 / MAX_PARTICLES)][0]; // Select Red Rainbow Color
particle[loop].g = colors[loop * (12 / MAX_PARTICLES)][1]; // Select Red Rainbow Color
particle[loop].b = colors[loop * (12 / MAX_PARTICLES)][2]; // Select Red Rainbow Color
particle[loop].xi = ((rand.Next() % 50) - 26.0f) * 10.0f; // Random Speed On X Axis
particle[loop].yi = ((rand.Next() % 50) - 25.0f) * 10.0f; // Random Speed On Y Axis
particle[loop].zi = ((rand.Next() % 50) - 25.0f) * 10.0f; // Random Speed On Z Axis
particle[loop].xg = 0.0f; // Set Horizontal Pull To Zero
particle[loop].yg = -0.8f; // Set Vertical Pull Downward
particle[loop].zg = 0.0f; // Set Pull On Z Axis To Zero
}
}
#endregion
public void DrawParticles(double dx,double dy,double dz)
{
GL.glGetDoublev(GL.GL_MODELVIEW_MATRIX, m_modelViewMatrix);
//populate the billboard matrix
m_billboardMatrix[0] = m_modelViewMatrix[0];
m_billboardMatrix[1] = m_modelViewMatrix[4];
m_billboardMatrix[2] = m_modelViewMatrix[8];
m_billboardMatrix[3] = 0;
m_billboardMatrix[4] = m_modelViewMatrix[1];
m_billboardMatrix[5] = m_modelViewMatrix[5];
m_billboardMatrix[6] = m_modelViewMatrix[9];
m_billboardMatrix[7] = 0;
m_billboardMatrix[8] = m_modelViewMatrix[2];
m_billboardMatrix[9] = m_modelViewMatrix[6];
m_billboardMatrix[10] = m_modelViewMatrix[10];
m_billboardMatrix[11] = 0;
m_billboardMatrix[12] = 0;
m_billboardMatrix[13] = 0;
m_billboardMatrix[14] = 0;
m_billboardMatrix[15] = 1;
GL.glEnable(GL.GL_TEXTURE_2D); // Enable Texture Mapping
//glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background
//GL.glDisable(GL.GL_DEPTH_TEST); // Disables Depth Testing
//GL.glEnable(GL.GL_BLEND); // Enable Blending
//GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); // Type Of Blending To Perform
//GL.glHint(GL.GL_POINT_SMOOTH_HINT, GL.GL_NICEST); // Really Nice Point Smoothing
GL.glBindTexture(GL.GL_TEXTURE_2D, texture[0]); // Select Our Texture
double dblObsX, dblObsY, dblObsZ, dMagnitude, scale;
ICamera camera = m_sceneViwer.Camera;
camera.Observer.QueryCoords(out dblObsX, out dblObsY);
dblObsZ = camera.Observer.Z;
for (loop = 0; loop < MAX_PARTICLES; loop++)
{ // Loop Through All The Particles
if (particle[loop].active)
{ // If The Particle Is Active
float x = particle[loop].x / 1000 + (float)dx; // Grab Our Particle X Position
float y = particle[loop].y / 1000 + (float)dy; // Grab Our Particle Y Position
float z = (particle[loop].z) / 1000 + (float)dz; // Particle Z Pos + Zoom
IVector3D m_vector3D = new Vector3DClass();
m_vector3D .SetComponents(dblObsX -dx, dblObsY - dy, dblObsZ - dz);
dMagnitude = m_vector3D.Magnitude;
scale = 0.01 * dMagnitude;
GL.glDisable(GL.GL_LIGHTING);
GL.glEnable(GL.GL_BLEND);
GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
GL.glDepthFunc(GL.GL_LEQUAL);
// GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
// GL.glLoadIdentity(); // Reset The Current Modelview Matrix
GL.glPushMatrix();
// GL.glAlphaFunc(GL.GL_GREATER, 0.5f);
//translate to the items location
GL.glTranslatef((float)x, (float)y, (float)z);
//orient the icon so that it'll face the camera
OrientBillboard();
//scale the item (original size is 1 ubit)
GL.glScaled(scale, scale, 1.0);
// Draw The Particle Using Our RGB Values, Fade The Particle Based On It's Life
// GL.glColor4f(particle[loop].r, particle[loop].g, particle[loop].b, particle[loop].life);
// GL.glBegin(GL.GL_TRIANGLE_STRIP); // Build Quad From A Triangle Strip
GL.glBegin(GL.GL_QUADS);
GL.glTexCoord2d(1, 1); GL.glVertex3f(0.5f, 0.5f, 0); // Top Right
GL.glTexCoord2d(0, 1); GL.glVertex3f(-0.5f, 0.5f, 0); // Top Left
GL.glTexCoord2d(1, 0); GL.glVertex3f(0.5f, -0.5f, 0); // Bottom Right
GL.glTexCoord2d(0, 0); GL.glVertex3f(-0.5f, -0.5f, 0); // Bottom Left
GL.glEnd();
GL.glPopMatrix();// Done Building Triangle Strip
// GL.glPolygonMode(GL.GL_FRONT, GL.GL_FILL);
particle[loop].x += particle[loop].xi / (slowdown * 1000); // Move On The X Axis By X Speed
particle[loop].y += particle[loop].yi / (slowdown * 1000); // Move On The Y Axis By Y Speed
particle[loop].z += particle[loop].zi / (slowdown * 1000); // Move On The Z Axis By Z Speed
particle[loop].xi += particle[loop].xg; // Take Pull On X Axis Into Account
particle[loop].yi += particle[loop].yg; // Take Pull On Y Axis Into Account
particle[loop].zi += particle[loop].zg; // Take Pull On Z Axis Into Account
particle[loop].life -= particle[loop].fade; // Reduce Particles Life By 'Fade'
if (particle[loop].life < 0.0f)
{ // If Particle Is Burned Out
particle[loop].life = 1.0f; // Give It New Life
particle[loop].fade = (rand.Next() % 100) / 1000.0f + 0.003f; // Random Fade Value
particle[loop].x = 0.0f; // Center On X Axis
particle[loop].y = 0.0f; // Center On Y Axis
particle[loop].z = 0.0f; // Center On Z Axis
particle[loop].xi = (xspeed + (rand.Next() % 60)) - 32.0f; // X Axis Speed And Direction
particle[loop].yi = (yspeed + (rand.Next() % 60)) - 30.0f; // Y Axis Speed And Direction
particle[loop].zi = (rand.Next() % 60) - 30.0f; // Z Axis Speed And Direction
particle[loop].r = colors[col][0]; // Select Red From Color Table
particle[loop].g = colors[col][1]; // Select Green From Color Table
particle[loop].b = colors[col][2]; // Select Blue From Color Table
}
}
}
delay++;
// Increase Rainbow Mode Color Cycling Delay Counter
if (rainbow && (delay > 25))
{ // If rainbow Is On And delay Is Too High
delay = 0; // Reset The Rainbow Color Cycling Delay
col++; // Change The Particle Color
if (col > 11)
{ // If col Is Too High
col = 0; // Reset It
}
}
GL.glDisable(GL.GL_BLEND);
}
private void LoadTextures(string filename)
{
//string filename = @"D:/OpenGL专题3D/CsGLExamples/data/NeHeLesson19/Particle.bmp"; // The File To Load
Bitmap bitmap = null; // The Bitmap Image For Our Texture
Rectangle rectangle; // The Rectangle For Locking The Bitmap In Memory
BitmapData bitmapData = null; // The Bitmap's Pixel Data
// Load The Bitmap
try
{
bitmap = new Bitmap(filename); // Load The File As A Bitmap
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); // Flip The Bitmap Along The Y-Axis
rectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height); // Select The Whole Bitmap
// Get The Pixel Data From The Locked Bitmap
bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
GL.glGenTextures(1, texture); // Create 1 Texture
// Create Linear Filtered Texture
GL.glBindTexture(GL.GL_TEXTURE_2D, texture[0]);
GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, (int)GL.GL_RGB8, bitmap.Width, bitmap.Height, 0, GL.GL_BGR_EXT, GL.GL_UNSIGNED_BYTE, bitmapData.Scan0);
}
catch (Exception e)
{
// Handle Any Exceptions While Loading Textures, Exit App
string errorMsg = "An Error Occurred While Loading Texture:/n/t" + filename + "/n" + "/n/nStack Trace:/n/t" + e.StackTrace + "/n";
//MessageBox.Show(errorMsg, "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
finally
{
if (bitmap != null)
{
bitmap.UnlockBits(bitmapData); // Unlock The Pixel Data From Memory
bitmap.Dispose(); // Clean Up The Bitmap
}
}
}
/// <summary>
/// orient the icons so that it'll face the camera
/// </summary>
private void OrientBillboard()
{
GL.glMultMatrixd(m_billboardMatrix);
}
}
}