// // 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 #include static Config config; static vector 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 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& del,vector& 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::size_type f; for(f=0;f::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::size_type f; switch (item) { case DBG_DUMPOBJ: for(f=0;f(camera.x), static_cast(camera.y), static_cast(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::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(x); pos[1]=static_cast(y); pos[2]=static_cast(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(x); camera.y=static_cast(y); camera.z=static_cast(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& 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(m.getSize()); m.getColour(r,g,b); name=m.getName(); texture=m.getTexture(id); for(f=0;f& del,vector& 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()=max) || (m2.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 new_mass; vector del_mass; vector::size_type f,r; GLfloat mva; new_mass=mass; for(f=0;fmass.size() || !del_mass[f]) mass.push_back(new_mass[f]); for(f=0;fadd(static_cast(x), static_cast(y), static_cast(z), static_cast(px), static_cast(py), static_cast(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 //