#include #ifdef __TURBOC__ // Turbo C++ stuff #include #include #include #include #include #include int maxx, maxy; void DrawCircle(int X, int Y, int Size, int Color) { setcolor(Color); circle(X, Y, Size); } void DrawPixel(int X, int Y, int Color) { putpixel(X, Y, Color); } #else // GLUT stuff #include #include #include "glut.h" const int maxx = 640; const int maxy = 480; const GLfloat YELLOW[3] = {1.0f, 1.0f, 0.0f}; const GLfloat BLACK[3] = {0.0f, 0.0f, 0.0f}; const GLfloat LIGHTGREEN[3] = {0.0f, 1.0f, 0.0f}; const GLfloat LIGHTGRAY[3] = {1.0f, 1.0f, 1.0f}; const GLfloat WHITE[3] = {1.0f, 1.0f, 1.0f}; void DrawCircle(int X, int Y, int Size, const GLfloat *Color) { glEnable(GL_POINT_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPointSize(Size); glBegin(GL_POINTS); glColor3fv(Color); glVertex2f(X, Y); glEnd(); } void DrawPixel(int X, int Y, const GLfloat *Color) { DrawCircle(X, Y, 1, Color); } #endif class Celestial { protected: double X, Y; int Size; virtual void Show(int) = 0; virtual void Recalc() { ; } public: Celestial(double px, double py, int psize); double getX() const { return X; } double getY() const { return Y; } int getSize() const { return Size; } void Update(); }; Celestial :: Celestial(double px, double py, int psize) : X(px), Y(py), Size(psize) { } void Celestial :: Update() { #ifdef __TURBOC__ Show(0); // в GLUT не нужно удалять старое изображение #endif Recalc(); Show(1); } double dist(Celestial &a, Celestial &b) { double dx = a.getX() - b.getX(); double dy = a.getY() - b.getY(); return sqrt(dx * dx + dy * dy); } class Star : public Celestial { int Shown; public: Star(int psize) : Celestial(maxx / 2, maxy / 2, psize), Shown(0) { } virtual void Show(int); }; void Star :: Show(int bShow) { DrawCircle((int)X, (int)Y, Size, YELLOW); } Star *sun; class Planet : public Celestial { private: int R; const char *name; double Angle, DeltaAngle; protected: virtual void Recalc() { Angle -= DeltaAngle; if(Angle < 0) Angle += 360; X = maxx/2 + R*cos(Angle*M_PI/180); Y = maxy/2 + R*sin(Angle*M_PI/180); } public: Planet(double px, double py, int psize, int pr, double pdeltaangle, const char *pname); virtual void Show(int); }; Planet :: Planet(double px,double py, int psize, int pr, double pdeltaangle, const char *pname) : Celestial(px, py, psize), R(pr), name(pname), Angle(360), DeltaAngle(pdeltaangle) { } void Planet :: Show(int bShow) { DrawCircle((int)X, (int)Y, Size, (bShow ? LIGHTGREEN : BLACK)); } class Particle : public Celestial { private: double Vx, Vy; public: Particle(double px, double py, double pvx, double pvy); ~Particle(); virtual void Show(int); virtual void Recalc(); }; Particle :: Particle(double px, double py, double pvx, double pvy) : Celestial(px, py, 1), Vx(pvx), Vy(pvy) { } Particle :: ~Particle() { Show(0); } void Particle :: Show(int bShow) { DrawPixel((int)X, (int)Y, (bShow ? LIGHTGRAY : BLACK)); } void Particle :: Recalc() { Vx += ((getX() - sun->getX()) / dist(*sun, *this)); Vy += ((getY() - sun->getY()) / dist(*sun, *this)); X += Vx; Y += Vy; } const int parrSize = 1500; const int stepParticles = 15; const int maxPartSpeed = 3; class Comet : public Celestial { private: double Ex, Ey; int Vx, Vy; Particle *trace[parrSize]; int maxParticles; int Cvt(int curr); protected: virtual void Recalc(); public: Comet(double px, double py, int psize, int pvx, int pvy); virtual void Show(int); int OutOfSystem() { return (X < -5 || X > maxx + 5 || Y < -5 || Y > maxy + 5) ? 1 : 0; } }; Planet *earth, *mars; Comet *c_01; int Comet :: Cvt(int curr) { int sign; if(!curr) sign = 0; else sign = curr / abs(curr); return sign * (maxPartSpeed - abs(curr)) ? (rand() % (maxPartSpeed - abs(curr))) : 0; } Comet :: Comet(double px, double py, int psize, int pvx, int pvy) : Celestial(px, py, psize), Vx(pvx), Vy(pvy), maxParticles(100) { Ex = (sun->getX() - sun->getSize()) / maxPartSpeed; Ey = (sun->getY() - sun->getSize()) / maxPartSpeed; for(int i = 0; i < maxParticles; i++) { double dx = (px - sun->getX()); double dy = (py - sun->getY()); trace[i] = new Particle(px - 1 + (rand() % 2), py - 1 + (rand() % 2), Vx + Cvt((int)(dx / Ex)) - 1 + (rand() % 2), Vy + Cvt((int)(dy / Ey)) - 1 + (rand() % 2)); } } void Comet :: Recalc() { X += Vx; Y += Vy; int count = 0; for(int i = 0; i < maxParticles; i++) { trace[i]->Recalc(); double d = dist(*trace[i], *this); if(d > 25 * Size) { delete trace[i]; count += 1; trace[i] = new Particle((int)(getX()) - 1 + (rand() % 2), (int)(getY()) - 1 + (rand() % 2), Vx + Cvt((int)((getX() - sun->getX()) / Ex)) - 1 + (rand() % 2), Vy + Cvt((int)((getY() - sun->getY()) / Ey)) - 1 + (rand() % 2)); } } for(int j = 0; j <= stepParticles - count; j++) { trace[maxParticles + j] = new Particle((int)(getX()) - 1 + (rand() % 2), (int)(getY()) - 1 + (rand() % 2), Vx + Cvt((int)((getX() - sun->getX()) / Ex)) - 1 + (rand() % 2), Vy + Cvt((int)((getY() - sun->getY()) / Ey)) - 1 + (rand() % 2)); } if(stepParticles - count > 0) maxParticles += (stepParticles - count); } void Comet :: Show(int bShow) { DrawCircle((int)X, (int)Y, Size, (bShow ? WHITE : BLACK)); for(int i = 0; i < maxParticles; i++) trace[i]->Show(bShow); } class Observer { public: Observer(); ~Observer(); void Run(); void Cycle(); }; Observer :: Observer() { sun = new Star(10); earth = new Planet(maxx / 2.+ 3 * 20, maxy / 2., 3, 60, 360./365., "earth"); mars = new Planet(maxx / 2.+ 4 * 20, maxy / 2., 3, 80, 360./687., "mars"); c_01 = new Comet(rand()%maxx, maxy, 2, 5, -5); } Observer :: ~Observer() { #ifdef __TURBOC__ closegraph(); #endif } void Observer::Cycle() { sun->Update(); earth->Update(); mars->Update(); c_01->Update(); if(c_01->OutOfSystem()) // Проверяем, если вышли за пределы - то пересоздаем комету... { delete c_01; c_01 = new Comet(rand()%maxx, maxy, 2, 5, -5); } } void Observer::Run() { #ifdef __TURBOC__ // Это не нужно делать в GLUT, это работа таймера while(1) { Cycle(); if(kbhit()) { if(getch() == 27) break; } delay(5); } #endif } Observer *engine; #ifdef __TURBOC__ #else void display() { glClear(GL_COLOR_BUFFER_BIT); // engine->Cycle(); glutSwapBuffers(); } void timer(int = 0) { glutPostRedisplay(); // glutTimerFunc(1, timer, 0); } #endif int main(int argc, char** argv) { #ifdef __TURBOC__ // Старая ламповая BGI-графика - под Турбо С++ int gdriver = DETECT, gmode, errorcode; initgraph(&gdriver, &gmode, "../BGI"); errorcode = graphresult(); if(errorcode != grOk) { cerr << "Graphics error: " << grapherrormsg(errorcode) << endl; exit(-1); } maxx = getmaxx(); maxy = getmaxy(); randomize(); #else // Это не для ДОС glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(maxx, maxy); glutInitWindowPosition(100, 100); glutCreateWindow("Solar System"); glClearColor(0, 0, 0, 1.0); glLoadIdentity(); glOrtho(0, maxx, maxy, 0, -1, 1); srand(time(0)); #endif // Инициализируем основной класс и запускаем главный цикл: engine = new Observer(); #ifdef __TURBOC__ engine->Run(); delete engine; #else glutDisplayFunc(display); timer(); glutMainLoop(); #endif return 0; }