Simple Particle
Simple Particle
CHAPTER 1
INTRODUCTION
CHAPTER 2
REQUIREMENT SPECIFICATION
CHAPTER 3
DESIGN
3.1 Design Phase
In the design phase the software requirements are transformed into definitions of
software components and their interfaces, to establish the framework of the software. The
system design is about the system’s behavioral design affecting the design of system
components.
The essence of software design is making decisions about the logical organization of
the software. Sometimes we represent this logical organization as a model in a defined
modeling language. Sometimes we simply use informal notations and sketches to represent
the design.
The purpose of this phase is to develop the concept and basic framework for the
design of the project. This is the most existing and creative part of the project. This phase
starts with the requirement document delivered by the requirement phase and maps the
requirements into architecture.
The design which represents the working of the nuclear power plant is shown. The
complete overview of the project is shown in the block diagram; it shows how it will perform
the actions through user interaction.
User Interface
Key board
Mouse
‘t’
spray ‘s’
colli less sma larg tog togg toggl
more
pressed
type(wa pressed
sio n le e full
flow flow ll er er gle
ter fall/ sphe of Figureof3.1 Designpart
of the project
par poi fra scree
fountai m n
res ticl nts
parti ic
spray type(water fall/
less flow of
of particles. smaller
Right click
particles. larger
particles.
toggle points/line
toggle frame rate ON/OFF toggle
The Figure 3.1 shows the working of the project. The input is given with the help of
keyboard. By pressing various keys we come to know how the woman is crossing the river.
The design depicted above specifies the initial model of the project. It is well defined
and uses motion functions to provide movement. Also it is made interactive with the user
through the input device, i.e. keyboard and mouse. The various keys and menu provide
different options to the user. The other key functions are:
‘f’=fog on/off
‘t’=spray type(water fall/ fountain)
‘s’=collision spheres.
‘[-]’=less flow of particles.
‘[+]’=more flow of particles.
‘p’=smaller particles.
‘P’=larger particles.
‘l’=toggle points/line
‘#’=toggle framerate ON/OFF.
‘~’=toggle fullscreen ON/OFF.
‘[!]’=change active spheres.
[Esc]=quit.
Use these numeric keys to move the active sphere
‘1’=move the sphere back.
‘2’=move the sphere down.
‘3’=moves the sphere front.
‘4’=move the sphere right.
‘6’=move the sphere left.
‘7’=decreases the size of the active sphere.
‘8’=move the sphere up.
‘9’=increases the size of active sphere.
CHAPTER
4
IMPLEMENTATION
Implementation is third phase of the project. In this phase the project inception
review is done and the activity schedule is prepared. The pseudo code is a basic idea of a
program and the flowchart provides a pictorial representation of the program. The
pseudo code, flowchart and the functions that are used in the program are discussed
below:
4.1 Algorithm
Algorithm is a step by step procedure to solve the problem.
Step1: start ()
Step2: display();
Step3: Alphabetical functions
‘f’=fog on/off
‘t’=spray type(water fall/ fountain)
‘s’=collision spheres.
‘[-]’=less flow of particles.
‘[+]’=more flow of particles.
‘p’=smaller particles.
‘P’=larger particles.
‘l’=toggle points/line
‘#’=toggle framerate ON/OFF.
‘~’=toggle fullscreen ON/OFF.
‘[!]’=change active spheres.
[Esc]=quit.
Void main ()
{
The program execution begins from the first statement of this function.
It also calls various other functions defined in the program and do the
following: Initializes the argument counter argc and argument vector array argv.
Sets the parameter required for window.
Calls display function.
Calls init function.
Calls Keyboard function.
Calls Mouse function.
}
Void init ()
{
Performs init functions
}
Void display ()
{
Initially, the buffers are cleared using glClear ();
Displays rasterized text
}
Void mouse ()
{
When right mouse button is clicked, it gives the menu options
}
Void keys ()
{
If ‘1’ is pressed, it moves the sphere back.
If ‘2’ is pressed, it moves the sphere down.
If ‘3’ is pressed, it moves the sphere front.
If ‘4’ is pressed, it moves the sphere right.
If ‘6’ is pressed, it moves the sphere left.
If ‘7’ is pressed, it decreases the size of the active sphere.
If ‘8’ is pressed moves the sphere up.
If ‘9’ is pressed increases the size of active sphere.
}
4.3 FUNCTIONS
The implementation of the project requires the usage of different kinds of
functions. Functions can either be inbuilt or defined by the user. The functions that are
used in the program are discovered below. This section contains brief description of all
the headers and functions. These functions are as follows:
void glutInit ( )
All Initializes the GLUT. The arguments from main are passed in and can
be used by the application.
void glutCreateWindow( )
Creates a window on the display. The string title can be used to label the
window.
void glutInitDisplayMode()
timedelta(void);
This function returns the number of seconds that have elapsed since the
previous call to the function.
void text( );
This function draws a string of text with an 18 point Helvetica bitmap font at
position(x,y) in window space.
int fequal( );
Customized equals ("==") operation for floating point value.
void psTimestep( );
Updates velocity and position of particles by a small value delta.
void psNewparticle( );
Initializes the velocity, position,dampening and related information of
particles based on the particle type.
void psBounce( );
psBounce: the particle has gone past (or exactly hit) the ground
plane, so calculate the time at which the particle actually
intersected the ground plane (s). essentially, this just rolls
back time to when the particle hit the ground plane, then starts
time again from then.
- - o A (previous position)
| | \
| s \ o (position it _should_ be at) -
t | \/ |t-s
| - ------X-------- -
| \
- o B (new position)
A + V*s = 0 or s = -A/V
to calculate where the particle should be:
A + V*t + V*(t-s)*d
where d is a damping factor which accounts for the loss
of energy due to the bounce.
Void mydisplay();
This function displays the front screen.
void key(unsigned char key,int x,int y);
This function specifies various keys for different movements.
void display();
This function displays various objects on the screen.
Sta
Main
()
Init ()
Display ()
User Functions
Keyboard Functions
Fog ON/OF
Change Quit .
The active The active
active
sphere sphere
sphere.
moves back moves
down.
If ‘3’ is If ‘6’ is
If ‘4’ is If ‘7’ is
pressed pressed
If ‘f’ pressed pressed
If ‘8’ is
If ‘9’ is
pressed
pressed
The active sphere is moved up. the size of the active sphere.
Increases
CHAPTER 5
TESTING
5.1 Introduction to testing
Verification and validation is a generic name given to checking process which
ensures that the software confirms to its specifications and meets the demands of users.
Validation
Are we building the right product?
Validation involves checking the program that the program has implanted
meets the requirement of the users.
Verification
Are we building the right product?
Verification involves checking that program confirms to its specification.
Unit testing
Each individual unit is tested for correctness. These individual components will
be tested to ensure that they operate correctly.
System testing
The Sub-systems are integrated to make up the entire system. The errors that
result from unanticipated interaction between sub-systems and system components are
removed.
Integration testing
This phase in software testing in which individual software modules are
combined and tested as a group. It occurs after unit testing and before validation
testing. Integration testing takes as its input modules that have been unit tested,
groups them in larger aggregates, applies tests defined in an integration test plan to
those aggregates, and delivers as its output the integrated system ready for system
testing.
Test plan
Careful planning is needed to the most of testing and controlled testing cost.
Test Expected
case Test case description Input Actual output output Remark
Id
A simple particle system Press key Waterfall flow Waterfall
1 (with spray type ‘t’ of particles. flow of Pass
(waterfall)) [Figure 5.1(a)] particles has
to happen
A simple particle system Press key Fountain flow Fountain flow
2 (with spray ‘t’ of particles. of particles Pass
type(fountain) [Figure 5.1(b)] has to happen
Shows the “toggle Press key Particles will be Particles has
points or lines” ‘l’ in points or to be in points
3 lines. [Figure or lines Pass
5.2(a), 5.2(b)]
7 Enable full screen Press key Full screen will Full screen
ON/OFF ‘[~]’ be enabled. has to be Pass
[Figure 5.5] enabled
function)
CHAPTER 6
PROJECT CODE AND SNAPSHOT
Project Code:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <GL/glut.h>
#ifdef _WIN32
#define drand48() ((float)rand()/RAND_MAX)
#endif
/* #define SCREEN_SAVER_MODE */
typedef struct {
float x, y, z;
float radius;
} PSsphere;
typedef struct {
float position[3]; /* current position */
float previous[3]; /* previous position */
float velocity[3]; /* velocity (magnitude & direction) */
float dampening; /* % of energy lost on collision
*/ int alive; /* is this particle alive? */
} PSparticle;
float spin_x = 0;
float spin_y = 0;
int point_size = 4;
/* timedelta: returns the number of seconds that have elapsed since
the previous call to the function. */
#if defined(_WIN32)
#include <sys/timeb.h>
#else
#include <limits.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/times.h>
#endif
#ifndef CLK_TCK
#define CLK_TCK 1000
#endif
float
timedelta(void)
{
static long begin = 0;
static long finish, difference;
#if defined(_WIN32)
static struct timeb tb;
ftime(&tb);
finish = tb.time*1000+tb.millitm;
#else
static struct tms tb;
finish = times(&tb);
#endif
return (float)difference/(float)CLK_TCK;
}
/* text: draws a string of text with an 18 point helvetica bitmap font
at position (x,y) in window space (bottom left corner is (0,0). */
void
text(int x, int y, char* s)
{
int lines;
char* p;
glDisable(GL_DEPTH_TEST);
glDisable(GL_FOG);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, glutGet(GLUT_WINDOW_WIDTH),
0, glutGet(GLUT_WINDOW_HEIGHT), -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glColor3ub(0, 0, 0);
glRasterPos2i(x+1, y-1);
for(p = s, lines = 0; *p; p++) {
if (*p == '\n') {
lines++;
glRasterPos2i(x+1, y-1-(lines*18));
}
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *p);
}
glColor3ub(128, 0, 255);
glRasterPos2i(x, y);
for(p = s, lines = 0; *p; p++) {
if (*p == '\n') {
lines++;
glRasterPos2i(x, y-(lines*18));
}
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *p);
}
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glEnable(GL_FOG);
glEnable(GL_DEPTH_TEST);
}
int
fequal(float a, float b)
{
float epsilon = 0.1;
float f = a - b;
if (f < epsilon && f > -epsilon)
return 1;
else
return 0;
}
void
psTimeStep(PSparticle* p, float dt)
{
if (p->alive == 0)
return;
p->velocity[0] += 0;
p->velocity[1] += PS_GRAVITY*dt;
p->velocity[2] += 0;
p->previous[0] = p->position[0];
p->previous[1] = p->position[1];
p->previous[2] = p->position[2];
p->position[0] += p->velocity[0]*dt;
p->position[1] += p->velocity[1]*dt;
p->position[2] += p->velocity[2]*dt;
}
void
psNewParticle(PSparticle* p, float dt)
{
if (type == PS_WATERFALL) {
p->velocity[0] = -2*(drand48()-0.0);
p->velocity[1] = 0;
p->velocity[2] = 0.5*(drand48()-0.0);
p->position[0] = 0;
p->position[1] = 2;
p->position[2] = 0;
p->previous[0] = p->position[0];
p->previous[1] = p->position[1];
p->previous[2] = p->position[2];
p->dampening = 0.45*drand48();
p->alive = 1;
} else if (type == PS_FOUNTAIN) {
p->velocity[0] = 2*(drand48()-0.5);
p->velocity[1] = 5;
p->velocity[2] = 2*(drand48()-0.5);
p->position[0] = -0.1;
p->position[1] = 0.9;
p->position[2] = 0;
p->previous[0] = p->position[0];
p->previous[1] = p->position[1];
p->previous[2] = p->position[2];
p->dampening = 0.35*drand48();
p->alive = 1;
}
psTimeStep(p, 2*dt*drand48());
}
/* psBounce: the particle has gone past (or exactly hit) the ground
plane, so calculate the time at which the particle actually
intersected the ground plane (s). essentially, this just rolls
back time to when the particle hit the ground plane, then starts
time again from then.
- - o A (previous position)
| | \
| s \ o (position it _should_ be at) -
t | \/ |t-s
| - ------X-------- -
| \
- o B (new position)
A + V*s = 0 or s = -A/V
A + V*t + V*(t-s)*d
if (p->alive == 0)
return;
/* since we know it is the ground plane, we only need to
calculate s for a single dimension. */
s = -p->previous[1]/p->velocity[1];
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, (float)width/height, 0.1, 1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 1, 3, 0, 1, 0, 0, 1, 0);
glFogfv(GL_FOG_COLOR, black);
glFogf(GL_FOG_START, 2.5);
glFogf(GL_FOG_END, 4);
glEnable(GL_FOG);
glFogi(GL_FOG_MODE, GL_LINEAR);
glPointSize(point_size);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHT0);
timedelta();
}
void
display(void)
{
static int i;
static float c;
static int j = 0;
static char s[32];
static int frames = 0;
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(spin_y, 1, 0, 0);
glRotatef(spin_x, 0, 1, 0);
glEnable(GL_LIGHTING);
if (draw_spheres) {
for (i = 0; i < draw_spheres; i++) {
glPushMatrix();
glTranslatef(spheres[i].x, spheres[i].y, spheres[i].z);
glColor3ub(0, 255, 128);
if (points) {
glBegin(GL_POINTS);
for (i = 0; i < num_particles; i++) {
if (particles[i].alive == 0)
continue;
c = particles[i].position[1]/2.1*255;
glColor3ub(c, 128+c*0.5, 255);
glVertex3fv(particles[i].position);
}
glEnd();
} else {
glBegin(GL_LINES);
for (i = 0; i < num_particles; i++) {
if (particles[i].alive == 0)
continue;
c = particles[i].previous[1]/2.1*255;
glColor4ub(c, 128+c*0.5, 255, 32);
glVertex3fv(particles[i].previous);
c = particles[i].position[1]/2.1*255;
glColor4ub(c, 128+c*0.5, 255, 196);
glVertex3fv(particles[i].position);
}
glEnd();
}
/* spit out frame rate. */
if (frame_rate) {
frames++;
if (frames > 7) {
sprintf(s, "%g fps", (float)7/frame_time);
frame_time = 0;
frames = 0;
}
text(5, 5, s);
}
glPopMatrix();
glutSwapBuffers();
}
void
idle(void)
{
static int i, j;
static int living = 0; /* index to end of live particles
*/ static float dt;
static float last = 0;
dt = timedelta();
frame_time += dt;
#if 1
/* slow the simulation if we can't keep the frame rate up around
10 fps */
if (dt > 0.1) {
slow_down = 1.0/(100*dt);
} else if (dt < 0.1) {
slow_down = 1;
}
#endif
dt *= slow_down;
/* resurrect a few particles */
for (i = 0; i < flow*dt; i++) {
psNewParticle(&particles[living], dt);
living++;
if (living >= num_particles)
living = 0;
}
bail(0);
}
void
ss_mouse(int button, int state, int x, int y)
{
bail(0);
}
void
ss_passive(int x, int y)
{
static int been_here = 0;
/* for some reason, GLUT sends an initial passive motion callback
when a window is initialized, so this would immediately
terminate the program. to get around this, see if we've been
here before. (actually if we've been here twice.) */
if (been_here > 1)
bail(0);
been_here++;
}
#else
void
keyboard(unsigned char key, int x, int y)
{
static int fullscreen = 0;
static int old_x = 50;
static int old_y = 50;
static int old_width = 512;
static int old_height = 512;
static int s = 0;
switch (key) {
case 27:
bail(0);
break;
case 't':
if (type == PS_WATERFALL)
type = PS_FOUNTAIN;
else if (type == PS_FOUNTAIN)
type = PS_WATERFALL;
break;
case 's':
draw_spheres++;
if (draw_spheres > NUM_SPHERES)
draw_spheres = 0;
break;
case 'S':
printf("PSsphere spheres[NUM_SPHERES] = {/* position of spheres
*/\n");
for (s = 0; s < NUM_SPHERES; s++) {
printf(" { %g, %g, %g, %g },\n",
spheres[s].x, spheres[s].y,
spheres[s].z, spheres[s].radius);
}
printf("};\n");
break;
case 'l':
points = !points;
break;
case 'P':
point_size++;
glPointSize(point_size);
break;
case 'p':
point_size--;
if (point_size < 1)
point_size = 1;
glPointSize(point_size);
break;
case '+':
flow += 100;
if (flow > num_particles)
flow = num_particles;
printf("%g particles/second\n", flow);
break;
case '-':
flow -= 100;
if (flow < 0)
flow = 0;
printf("%g particles/second\n", flow);
break;
case '#':
frame_rate = !frame_rate;
break;
case '~':
fullscreen = !fullscreen;
if (fullscreen) {
old_x = glutGet(GLUT_WINDOW_X);
old_y = glutGet(GLUT_WINDOW_Y);
old_width = glutGet(GLUT_WINDOW_WIDTH);
old_height = glutGet(GLUT_WINDOW_HEIGHT);
glutFullScreen();
} else {
glutReshapeWindow(old_width, old_height);
glutPositionWindow(old_x, old_y);
}
break;
case '!':
s++;
if (s >= NUM_SPHERES)
s = 0;
break;
case '4':
spheres[s].x -= 0.05;
break;
case '6':
spheres[s].x += 0.05;
break;
case '2':
spheres[s].y -= 0.05;
break;
case '8':
spheres[s].y += 0.05;
break;
case '7':
spheres[s].z -= 0.05;
break;
case '3':
spheres[s].z += 0.05;
break;
case '9':
spheres[s].radius += 0.05;
break;
case '1':
spheres[s].radius -= 0.05;
break;
}
}
void
menu(int item)
{
keyboard((unsigned char)item, 0, 0);
}
void
menustate(int state)
{
/* hook up a fake time delta to avoid jumping when menu comes up */
if (state == GLUT_MENU_NOT_IN_USE)
timedelta();
}
#endif
int old_x, old_y;
void
mouse(int button, int state, int x, int y)
{
old_x = x;
old_y = y;
glutPostRedisplay();
}
void
motion(int x, int y)
{
spin_x = x - old_x;
spin_y = y - old_y;
glutPostRedisplay();
}
int
main(int argc, char** argv)
{
glutInitDisplayMode(GLUT_RGB|GLUT_DEPTH|GLUT_DOUBLE);
glutInitWindowPosition(0, 0);
glutInitWindowSize(640, 480);
glutInit(&argc, argv);
glutCreateWindow("Particles");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
#ifdef SCREEN_SAVER_MODE
glutPassiveMotionFunc(ss_passive);
glutKeyboardFunc(ss_keyboard);
glutMouseFunc(ss_mouse);
glutSetCursor(GLUT_CURSOR_NONE);
glutFullScreen();
#else
glutMotionFunc(motion);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
#endif
glutMenuStateFunc(menustate);
glutCreateMenu(menu);
glutAddMenuEntry("Particle", 0);
glutAddMenuEntry("", 0);
glutAddMenuEntry("[f] Fog on/off", 'f');
glutAddMenuEntry("[t] Spray type", 't');
glutAddMenuEntry("[s] Collision spheres", 's');
glutAddMenuEntry("[-] Less flow", '-');
glutAddMenuEntry("[+] More flow", '+');
glutAddMenuEntry("[p] Smaller points", 'p');
glutAddMenuEntry("[P] Larger points", 'P');
glutAddMenuEntry("[l] Toggle points/lines", 'l');
glutAddMenuEntry("[#] Toggle framerate on/off", '#');
glutAddMenuEntry("[~] Toggle fullscreen on/off", '~');
glutAddMenuEntry("", 0);
glutAddMenuEntry("Use the numeric keypad to move the spheres", 0);
glutAddMenuEntry("[!] Change active sphere", 0);
glutAddMenuEntry("", 0);
glutAddMenuEntry("[Esc] Quit", 27);
glutAttachMenu(GLUT_RIGHT_BUTTON);
if (argc > 1) {
if (strcmp(argv[1], "-h") == 0) {
fprintf(stderr, "%s [particles] [flow] [speed%]\n", argv[0]);
exit(0);
}
glutVisibilityFunc(visible);
glutMainLoop();
return 0;
}
SNAPSHOTS:
Figure 5.1(a) A simple particle system(with spray type (waterfall) on pressing ‘t’.
Figure 5.1(b) A simple particle system with spray type(fountain) on pressing ‘t’.
Figure 5.4 Shows the toggle frame rate OFF/ON on pressing [#].
Figure 5.6 Shows a simple particle system with a rotatable bottom,which helps us to view the
system from any direction (using mouse).
CHAPTER 7
CONCLUSION:
The project has involved the designing of “SIMPLE PARTICLE SYSTEM”. It is
implemented using some in-built functions which are provided in the standards graphics
package. It even has a number of user defines functions.
The graphics system allows the programmer to decline pictures that include variety of
transformations. The project shows three spheres and particles bouncing on it. The
movements are done by using various keyboard functions and mouse functions which have
been successfully implemented.
FUTURE ENHANCEMENTS:
Further development in the project can be done by illustrating graphically some other
conditions other than what we have illustrated and some more advanced techniques that are
recently used can be implemented. It can be made still more attractive using 3D
implementation. The project is widely open to anyone who wishes to improve it further on
graphical way. We can modify the project by adding some features in the future. The project
can further be implemented by changing the colors, by adding more operations and functions.
Many other keyboard and mouse functions could be given.
BIBLIOGRAPHY
BOOKS
Edward Angel, 2009, Interactive computer graphics A Top-Down approach with
OpenGL, 5TH EDITION, Addison-Wesley.
Blinn, J.F., and M.E. Newell, 1996, Texture and Reflection in Computer
Generated Images, CACM.
WEBSITES
https://www.opengl.org
http://www.glprogramming.com
http://bluelotusrajeev.hubpages.com/hub