diff options
author | Ian C <ianc@noddybox.co.uk> | 2006-05-02 19:12:46 +0000 |
---|---|---|
committer | Ian C <ianc@noddybox.co.uk> | 2006-05-02 19:12:46 +0000 |
commit | 99778e9b85bd4a16a9055587a273446068577100 (patch) | |
tree | 5bd5c5a0fb48f52f306a2a8b19de200800ada7df /glgrav.cpp | |
parent | f77e2736cea27ddbcaa44ffb28b326846891029e (diff) |
This commit was generated by cvs2svn to compensate for changes in r2,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'glgrav.cpp')
-rw-r--r-- | glgrav.cpp | 955 |
1 files changed, 955 insertions, 0 deletions
diff --git a/glgrav.cpp b/glgrav.cpp new file mode 100644 index 0000000..3586e7d --- /dev/null +++ b/glgrav.cpp @@ -0,0 +1,955 @@ +// +// glgrav - OpenGL N-Body gravity simulator +// +// Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// ------------------------------------------------------------------------- +// +// Main +// +static const char id[]="$Id$"; + +#include "global.h" +#include "config.h" +#include "mass.h" +#include "particles.h" +#include "sparks.h" + +#include <cstdarg> +#include <ctime> + +static Config config; +static vector<Mass> mass; +static Particles *particles=0; +static Sparks *sparks=0; + +static int win; +static int width=100; +static int height=100; +static GLfloat particleSize=1.0f; + +#define MENU_SOLID 1 +#define MENU_LIGHTING 2 +#define MENU_TEXTURE 3 +#define MENU_PARTICLES 4 +#define MENU_SPARKS 5 +#define MENU_FOG 6 +#define MENU_RESETPOS 7 +#define MENU_QUIT 8 +#define LOOK_NONE -1 + +#define MENU_TRAVEL 1000 +#define MENU_LOOK 2000 +#define MENU_FRAME_SKIP 3000 + +static int menu; +static int travel_menu; +static int look_menu; +static int frame_skip_menu; + +#ifdef DEBUG + +#define DBG_DUMPOBJ 1 +static int debug_menu; +static void DebugMenu(int item); +#endif + +static bool solid; +static bool light; +static bool texture; +static bool render_particles; +static bool render_sparks; +static vector<string> look; +static int travel_as=LOOK_NONE; +static int look_at=LOOK_NONE; +static int frame_skip=0; +static int frame=0; +static bool fog=false; +static bool fog_light=false; +static GLfloat fog_col[4]={0.0f,0.0f,0.0f,1.0f}; + +static struct + { + GLfloat x,y,z; + GLfloat ang; + GLfloat speed; + } camera={0.0f,0.0f,0.0f,0.0f,0.0f}; + +static struct + { + int mx,my; + bool lmb; + bool shift; + bool ctrl; + bool pgup; + bool pgdn; + } control; + +static void Reshape(int w,int h); +static void Mouse(int b,int s, int x, int y); +static void Move(int x, int y); +static void Display(void); +static void Update(void); +static void Menu(int item); +static void TravelMenu(int item); +static void LookMenu(int item); +static void FrameSkipMenu(int item); +static void Key(int key, int mx, int my); + +static void HandleCollision(Config::Collide collide, + vector<bool>& del,vector<Mass>& mv, + Mass& m1, Mass& m2, int idx1, int idx2); +static void SetOption(int opt, string text, bool flag); +static void GLPrint(char *fmt,...); + + +int main(int argc, char *argv[]) +{ + int f; + + srand(time(0)); + + // Init GLUT display. Note window is created here to be reshaped later + // as it appears necessary for textures to work! + // + glutInit(&argc,argv); + glutInitWindowSize(width,height); + glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH); + + win=glutCreateWindow(argv[0]); + + + // Program initialisation + // + mass.clear(); + + if (!config.read(argc == 2 ? argv[1] : "dat",mass)) + { + cerr << "Config file reading failed : \n" << config.error() << endl; + exit(1); + } + + config.getCamera(camera.x,camera.y,camera.z,camera.ang); + + solid=config.enabled(Config::solid); + light=config.enabled(Config::lighting); + texture=config.enabled(Config::texture); + config.look(look); + config.getLookAndTravel(look_at,travel_as); + fog=config.enabled(Config::fog); + + if (config.particlesDefined()) + { + GLfloat adec,amin; + + config.getParticles(adec,amin,particleSize); + particles=new Particles(adec,amin); + render_particles=true; + } + else + render_particles=false; + + if (config.sparksDefined()) + { + int num,len; + GLfloat adec,amin,delta; + + config.getSparks(num,adec,amin,len,delta); + sparks=new Sparks(num,adec,amin,len,delta); + render_sparks=true; + } + else + render_sparks=false; + + config.windowSize(width,height); + + width=max(width,100); + height=max(height,100); + +# ifdef DEBUG + { + vector<Mass>::size_type f; + + for(f=0;f<mass.size();f++) + cout << "Initial : " << mass[f] << endl; + } +# endif + + glutDisplayFunc(Display); + glutMouseFunc(Mouse); + glutMotionFunc(Move); + glutPassiveMotionFunc(Move); + glutReshapeFunc(Reshape); + glutSpecialFunc(Key); + glutIdleFunc(Update); + + // Menu initialisation + // + menu=glutCreateMenu(Menu); + glutAddMenuEntry("X",MENU_SOLID); + glutAddMenuEntry("X",MENU_LIGHTING); + glutAddMenuEntry("X",MENU_TEXTURE); + glutAddMenuEntry("X",MENU_PARTICLES); + glutAddMenuEntry("X",MENU_SPARKS); + glutAddMenuEntry("X",MENU_FOG); + glutAddMenuEntry("Reset Position",MENU_RESETPOS); + + SetOption(MENU_SOLID,"Solid",solid); + SetOption(MENU_LIGHTING,"Lighting",light); + SetOption(MENU_TEXTURE,"Textures",texture); + SetOption(MENU_PARTICLES,"Particles",render_particles); + SetOption(MENU_SPARKS,"Sparks",render_sparks); + SetOption(MENU_FOG,"Fog",fog); + + // Create look and travel menus + // + vector<string>::size_type li; + + travel_menu=glutCreateMenu(TravelMenu); + glutAddMenuEntry("None",MENU_TRAVEL+LOOK_NONE); + + look_menu=glutCreateMenu(LookMenu); + glutAddMenuEntry("None",MENU_LOOK+LOOK_NONE); + + for(li=0;li<look.size();li++) + { + glutSetMenu(travel_menu); + glutAddMenuEntry(look[li].c_str(),MENU_TRAVEL+li); + glutSetMenu(look_menu); + glutAddMenuEntry(look[li].c_str(),MENU_LOOK+li); + } + + // Create frame skip menu + // + frame_skip_menu=glutCreateMenu(FrameSkipMenu); + + for(f=0;f<20;f++) + { + char s[64]; + int skip; + + if (f) + { + skip=f+1; + sprintf(s,"Draw every %d frames",skip); + } + else + { + skip=f; + strcpy(s,"No frame skip"); + } + + glutAddMenuEntry(s,MENU_FRAME_SKIP+skip); + } + + glutSetMenu(menu); + glutAddSubMenu("Travel as",travel_menu); + glutAddSubMenu("Look at",look_menu); + glutAddSubMenu("Frame skip",frame_skip_menu); + glutAddMenuEntry("Quit",MENU_QUIT); + glutAttachMenu(GLUT_RIGHT_BUTTON); + + // Create optional debug menu + // +# ifdef DEBUG + { + debug_menu=glutCreateMenu(DebugMenu); + glutAddMenuEntry("Dump Objects",DBG_DUMPOBJ); + glutSetMenu(menu); + glutAddSubMenu("DEBUG",debug_menu); + } +# endif + + // Open GL initialisation + // + glShadeModel(GL_SMOOTH); + + if (!light) + glDisable(GL_LIGHTING); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_COLOR_MATERIAL); + glEnable(GL_CULL_FACE); + glEnable(GL_POINT_SMOOTH); + + glClearColor(0.0f,0.0f,0.0f,1.0); + + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + if (fog) + { + GLfloat dist; + + config.getFog(dist,fog_col[0],fog_col[1],fog_col[2],fog_light); + + glFogfv(GL_FOG_COLOR,fog_col); + glFogf(GL_FOG_START,0.0f); + glFogf(GL_FOG_END,dist); + glFogi(GL_FOG_MODE,GL_LINEAR); + + glClearColor(fog_col[0],fog_col[1],fog_col[2],1.0); + } + + // Enter the main loop + // + glutReshapeWindow(width,height); + glutMainLoop(); + + return EXIT_SUCCESS; +} + + +static void Reshape(int w,int h) +{ + width=w; + height=h; + + glViewport(0,0,w,h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,1.0f,100000.0f); + glMatrixMode(GL_MODELVIEW); +} + + +static void Mouse(int b,int s, int x, int y) +{ + int mod=glutGetModifiers(); + + if (b==GLUT_LEFT_BUTTON) + { + control.lmb=(s==GLUT_DOWN); + + control.shift=mod&GLUT_ACTIVE_SHIFT; + control.ctrl=mod&GLUT_ACTIVE_CTRL; + } +} + + +static void Move(int x,int y) +{ + control.mx=x; + control.my=y; +} + + +static void Menu(int item) +{ +#ifdef DEBUG + cout << "Menu(" << item << ")\n"; +#endif + + switch (item) + { + case MENU_SOLID: + solid=!solid; + SetOption(MENU_SOLID,"Solid",solid); + break; + + case MENU_LIGHTING: + light=!light; + SetOption(MENU_LIGHTING,"Lighting",light); + + if (!light) + glDisable(GL_LIGHTING); + break; + + case MENU_TEXTURE: + texture=!texture; + SetOption(MENU_TEXTURE,"Texture",texture); + break; + + case MENU_RESETPOS: + config.getCamera(camera.x,camera.y,camera.z,camera.ang); + break; + + case MENU_PARTICLES: + render_particles=!render_particles; + SetOption(MENU_PARTICLES,"Particles",render_particles); + break; + + case MENU_SPARKS: + render_sparks=!render_sparks; + SetOption(MENU_SPARKS,"Sparks",render_sparks); + break; + + case MENU_FOG: + if (config.enabled(Config::fog)) + { + fog=!fog; + SetOption(MENU_FOG,"Fog",fog); + + if (fog) + glClearColor(fog_col[0],fog_col[1],fog_col[2],1.0); + else + glClearColor(0.0f,0.0f,0.0f,1.0); + } + break; + + case MENU_QUIT: + exit(EXIT_SUCCESS); + break; + } +} + + +static void TravelMenu(int item) +{ +#ifdef DEBUG + cout << "TravelMenu(" << item << ")\n"; +#endif + + int old=travel_as; + + travel_as=item-MENU_TRAVEL; + + if (travel_as!=LOOK_NONE and look_at==travel_as) + travel_as=old; +} + + +static void LookMenu(int item) +{ +#ifdef DEBUG + cout << "LookMenu(" << item << ")\n"; +#endif + + int old=look_at; + + look_at=item-MENU_LOOK; + + if (look_at!=LOOK_NONE and look_at==travel_as) + look_at=old; +} + + +static void FrameSkipMenu(int item) +{ +#ifdef DEBUG + cout << "FrameSkipMenu(" << item << ")\n"; +#endif + + frame_skip=item-MENU_FRAME_SKIP; +} + + +#ifdef DEBUG +static void DebugMenu(int item) +{ + vector<Mass>::size_type f; + + switch (item) + { + case DBG_DUMPOBJ: + for(f=0;f<mass.size();f++) + cout << mass[f] << endl; + break; + } +} +#endif + + +static void SetOption(int opt, string text, bool flag) +{ + if (flag) + text+=" Off"; + else + text+=" On"; + + glutChangeToMenuEntry(opt,text.c_str(),opt); +} + + +static void Key(int key, int mx, int my) +{ + switch(key) + { + case GLUT_KEY_PAGE_DOWN: + control.pgdn=true; + break; + + case GLUT_KEY_PAGE_UP: + control.pgup=true; + break; + + default: + break; + } +} + + +static void SetView() +{ + Mass lm; + + glLoadIdentity(); + + if ((look_at!=LOOK_NONE)&&(findMass(mass,look[look_at],lm))) + { + double x,y,z; + + lm.getPosition(x,y,z); + + // TODO: The last parameters (0,1,0) are the UP vector, and need + // some calculating to prevent awkward looking 'flips' + // + gluLookAt(static_cast<GLdouble>(camera.x), + static_cast<GLdouble>(camera.y), + static_cast<GLdouble>(camera.z), + x,y,z, + 0.0,1.0,0.0); + } + else + { + glRotatef(360.0-camera.ang,0.0f,1.0f,0.0f); + glTranslatef(-camera.x,-camera.y,-camera.z); + } +} + + +static void DrawMasses(Mass::DrawItem item) +{ + vector<Mass>::const_iterator i; + Mass lm; + + for(i=mass.begin();i!=mass.end();i++) + { + SetView(); + + if (light) + { + GLfloat light[4]; + GLfloat pos[4]; + string name; + + name=config.light(light); + + if (name!=i->getName() && findMass(mass,name,lm)) + { + double x,y,z; + + lm.getPosition(x,y,z); + + pos[0]=static_cast<GLfloat>(x); + pos[1]=static_cast<GLfloat>(y); + pos[2]=static_cast<GLfloat>(z); + pos[3]=1.0f; + + glLightfv(GL_LIGHT1,GL_DIFFUSE,light); + glLightfv(GL_LIGHT1,GL_POSITION,pos); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT1); + + if (fog) + glEnable(GL_FOG); + } + else + { + if (!fog_light) + glDisable(GL_FOG); + glDisable(GL_LIGHTING); + } + } + + i->draw(solid,texture,item); + } +} + + +static void Display(void) +{ + Mass lm; + + /* Looking up/down doesn't work yet... + */ + if ((travel_as!=LOOK_NONE)&&(findMass(mass,look[travel_as],lm))) + { + double x,y,z; + + lm.getPosition(x,y,z); + + camera.x=static_cast<GLfloat>(x); + camera.y=static_cast<GLfloat>(y); + camera.z=static_cast<GLfloat>(z); + } + else + { + GLPrint("Pos: %d,%d,%d",(int)camera.x,(int)camera.y,(int)camera.z); + GLPrint("Angle: %d",(int)camera.ang); + } + + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + + if (fog) + glEnable(GL_FOG); + else + glDisable(GL_FOG); + + DrawMasses(Mass::eMass); + + glEnable(GL_BLEND); + + DrawMasses(Mass::eRing); + + glDisable(GL_LIGHT1); + glDisable(GL_LIGHTING); + glDisable(GL_TEXTURE_2D); + + if (fog) + glEnable(GL_FOG); + + if (particles && render_particles) + { + glPointSize(particleSize); + particles->draw(); + } + + if (sparks && render_sparks) + { + glPointSize(1); + sparks->draw(); + } + + glDisable(GL_BLEND); + + glFlush(); + glutSwapBuffers(); +} + + +static void Shatter(vector<Mass>& mv, Mass& m,int no,double delta,int shield) +{ + double px,py,pz; + double npx,npy,npz; + double dx,dy,dz; + double ndx,ndy,ndz; + GLfloat r,g,b; + int f; + string name; + bool texture; + GLuint id; + double nm; + int size; + + nm=m.getMass()/no; + m.getDelta(dx,dy,dz); + m.getPosition(px,py,pz); + size=static_cast<int>(m.getSize()); + m.getColour(r,g,b); + name=m.getName(); + texture=m.getTexture(id); + + for(f=0;f<no;f++) + if (mv.size()<config.maxMass()) + { + npx=px+RND(size*2)-size; + npy=py+RND(size*2)-size; + npz=pz+RND(size*2)-size; + + if (npx<px) + ndx=dx-DRand()*delta; + else + ndx=dx+DRand()*delta; + + if (npy<py) + ndy=dy-DRand()*delta; + else + ndy=dy+DRand()*delta; + + if (npz<pz) + ndz=dz-DRand()*delta; + else + ndz=dz+DRand()*delta; + + Mass m(name,nm,config.scale(), + npx,npy,npz,ndx,ndy,ndz,r,g,b,0.5,shield); + + if (texture) + m.setTexture(id); + + mv.push_back(m); + } + +} + + +static void HandleCollision(Config::Collide collide, + vector<bool>& del,vector<Mass>& mv, + Mass& m1, Mass& m2, int idx1, int idx2) +{ + Mass *win; + Mass *lose; + double merge_mass; + double dx,dy,dz; + double odx,ody,odz; + int no; + double delta,min,max; + int shield; + + switch(collide) + { + case Config::merge: + if (m1.getMass()>=m2.getMass()) + { + win=&m1; + lose=&m2; + del[idx2]=true; + } + else + { + win=&m2; + lose=&m1; + del[idx1]=true; + } + + merge_mass=win->getMass()+lose->getMass(); + + win->reset(merge_mass); + + if (sparks) + { + double x1,y1,z1; + double x2,y2,z2; + + m1.getPosition(x1,y1,z1); + m2.getPosition(x2,y2,z2); + + sparks->add(x1+(x2-x1)/2, + y1+(y2-y1)/2, + z1+(z2-z1)/2); + } + + break; + + case Config::delta_merge: + if (m1.getMass()>=m2.getMass()) + { + win=&m1; + lose=&m2; + del[idx2]=true; + } + else + { + win=&m2; + lose=&m1; + del[idx1]=true; + } + + win->getDelta(odx,ody,odz); + lose->getDelta(dx,dy,dz); + + odx+=dx*(lose->getMass()/win->getMass()); + ody+=dy*(lose->getMass()/win->getMass()); + odz+=dz*(lose->getMass()/win->getMass()); + + merge_mass=win->getMass()+lose->getMass(); + + win->reset(merge_mass,odx,ody,odz); + + if (sparks) + { + double x1,y1,z1; + double x2,y2,z2; + + m1.getPosition(x1,y1,z1); + m2.getPosition(x2,y2,z2); + + sparks->add(x1+(x2-x1)/2, + y1+(y2-y1)/2, + z1+(z2-z1)/2); + } + + break; + + case Config::shatter: + config.getShatter(no,delta,min,max,shield); + + if (m1.getMass()<min || m2.getMass()<min) + { + HandleCollision(Config::merge,del,mv,m1,m2,idx1,idx2); + return; + } + + if ((m1.getMass()<max && m2.getMass()>=max) || + (m2.getMass()<max && m1.getMass()>=max)) + { + HandleCollision(Config::merge,del,mv,m1,m2,idx1,idx2); + return; + } + + Shatter(mv,m1,no,delta,shield); + Shatter(mv,m2,no,delta,shield); + + if (sparks) + { + double x1,y1,z1; + double x2,y2,z2; + + m1.getPosition(x1,y1,z1); + m2.getPosition(x2,y2,z2); + + sparks->add(x1+(x2-x1)/2, + y1+(y2-y1)/2, + z1+(z2-z1)/2); + } + + del[idx1]=true; + del[idx2]=true; + + break; + + case Config::none: + break; + + default: + break; + } +} + + +static void Update(void) +{ + vector<Mass> new_mass; + vector<bool> del_mass; + vector<Mass>::size_type f,r; + GLfloat mva; + + new_mass=mass; + + for(f=0;f<mass.size();f++) + del_mass.push_back(false); + + for(f=0;f<mass.size();f++) + for(r=0;r<mass.size();r++) + if (f!=r && !del_mass[f] && !del_mass[r]) + if (new_mass[f].calcAttraction(mass[r],config.gravConst())) + HandleCollision + (config.collide(), + del_mass,new_mass,new_mass[f],mass[r],f,r); + + mass.clear(); + + for(f=0;f<new_mass.size();f++) + if (f>mass.size() || !del_mass[f]) + mass.push_back(new_mass[f]); + + for(f=0;f<mass.size();f++) + { + GLfloat r,g,b; + double x,y,z; + double px,py,pz; + + mass[f].move(); + + mass[f].getColour(r,g,b); + mass[f].getPosition(x,y,z); + mass[f].getPreviousPosition(px,py,pz); + + if (particles && !mass[f].isMassless()) + particles->add(static_cast<GLfloat>(x), + static_cast<GLfloat>(y), + static_cast<GLfloat>(z), + static_cast<GLfloat>(px), + static_cast<GLfloat>(py), + static_cast<GLfloat>(pz), + r,g,b); + } + + mva=(control.mx-(width/2))/(100.0f*width/800.0); + + if (mva<-0.5 || mva>0.5) + { + camera.ang-=mva; + + if (camera.ang<0.0) + camera.ang+=360.0; + else if (camera.ang>=360.0) + camera.ang-=360.0; + } + + if (control.pgup) + camera.y+=10; + + if (control.pgdn) + camera.y-=10; + + control.pgup=false; + control.pgdn=false; + + if (control.lmb) + { + if (camera.speed<20.0) + camera.speed+=0.5; + + if (control.ctrl) + camera.speed*=10; + + if (control.shift) + { + camera.x+=(GLfloat)(sin(camera.ang*M_PI/180.0)*camera.speed); + camera.z+=(GLfloat)(cos(camera.ang*M_PI/180.0)*camera.speed); + } + else + { + camera.x-=(GLfloat)(sin(camera.ang*M_PI/180.0)*camera.speed); + camera.z-=(GLfloat)(cos(camera.ang*M_PI/180.0)*camera.speed); + } + + if (control.ctrl) + camera.speed/=10; + } + else + { + if (camera.speed>0.0) + camera.speed-=0.5; + + if (camera.speed<0.0) + camera.speed+=0.5; + } + + frame++; + + if (sparks) + sparks->update(); + + if (particles) + particles->update(); + + if (!frame_skip || (frame%frame_skip)==0) + glutPostWindowRedisplay(win); +} + + +static void GLPrint(char *fmt,...) +{ + char s[256]; + va_list va; + char *p; + + va_start(va,fmt); + vsprintf(s,fmt,va); + + p=s; + + /* + while(*p) + glutBitmapCharacter(GLUT_BITMAP_8_BY_13,(int)*p++); + */ +} + + +// END OF FILE // |