/******************************************************** Graphics functions and structures for the neutron model *********************************************************/ Uint32 color = 0x55ddff; Uint32 Red = 0xff0000, Blue = 0x0000ff; Uint32 Yellow = 0xffff00, Greenish = 0x00ffff; #define sign(a) (((a)<0) ? -1 : (a)>0 ? 1 : 0) #define PI 3.141592653589793238462643383279502884197169399375105 int minx = 0, miny = 0, maxx = 800, maxy = 600; void proton(double, double, double); void putpixel(unsigned int, unsigned int, unsigned int); void line(int, int, double, double, int); void linexy(int, int, int, int, int); struct control { int view; int trigger; int lines; int vec; void reset(){ view = 0; lines = 0; vec = 0; trigger = 0; } void setview(){ view = 1; } void setlines(){ lines = 1; } void setvec(){ vec = 1; } }; struct nprot { // Proton based upon polar coordinates double x; // x position double y; // y position double z; // z position as size double vx; // x component movement double vy; // y component movement double vz; // z component movement double vt; // Movement vector magnitude double rad; // Movement direction in radians double rs1; // Polarity direction of shell one double rs2; // Polarity direction of shell two double rs3; // and shell three double ms1; double ms2; double ms3; double ms4; double ms; // Total Mass double p; // Total Momemtum int half; // Time to live when it is a neutron int lines; // Special effects flag void makeneut(){ ms1 = 2.549920405; ms = ms1 + ms2 + ms3 + ms4; half = rand() % 6000; // About 6 minutes time to live p = vt * ms; } void setmass(){ // In units of electron masses ms1 = 2.549920405; ms2 = ms1 * ms1; ms3 = ms2 * ms2; ms4 = ms3 * ms3; int twopi = 2 * PI * 1000; vt = (float) (rand() % 1000) / 100; // Initual movement vector magnitude x = rand() % maxx; y = rand() % maxy; z = .15; rad = (float) (rand() % twopi) / 1000; rs1 = (float) (rand() % twopi) / 1000; rs2 = (float) (rand() % twopi) / 1000; rs3 = (float) (rand() % twopi) / 1000; lines = 0; makeneut(); } void makeprot(){ ms1 = 0; vt += 15; ms = ms2 + ms3 + ms4; } void rotate(){ // Rotate the amplitude around the shell rs1 += .310; // Speed of rotation not to scale rs2 -= .610; // Middle shell rotating counter clockwise rs3 += .810; // Direction of rotation is SWAG if(rs1 > 2 * PI) rs1 -= 2 * PI; // Keep it positive between if(rs2 < 0) rs2 += 2 * PI; // zero and 2 PI if(rs3 > 2 * PI) rs3 -= 2 * PI; } void ellipse(){ // Draw the proton double c = 0; // Shell sizes in units of shell 4 double sr4 = z; if(sr4 < 1) sr4 = 1; double sr3 = z * 42; if(sr3 < 1) sr3 = 1; double sr2 = z * 274; double sr1 = z * 701; double inc = 1 / sr2; // Dot density around circle double prot = ms2 + ms3 + ms4; int minamp, maxamp; double xx, yy, xrs, yrs; int ofst = 0; int pos = 0xff0000; // Red for positive field int neg = 0x0000ff; // Blue for negative field rotate(); while(c < 2 * PI){ c += inc; rs1 += inc; rs2 += inc; rs3 += inc; xx = x + cos(c) * sr4; yy = y + sin(c) * sr4; putpixel(xx, yy, pos); // One dot for shell four minamp = sin(rs3) * z * 20; maxamp = sin(rs3) * z * 20; if(minamp > 0) minamp *= -1.0; if(maxamp < 0) maxamp *= -1.0; for(ofst = minamp; ofst < maxamp; ofst ++){ if(ofst < 0){ // Shell three hash marks xx = x + cos(c) * (sr3 + ofst); yy = y + sin(c) * (sr3 + ofst); putpixel(xx, yy, pos); } else{ xx = x + cos(c) * (sr3 + ofst); yy = y + sin(c) * (sr3 + ofst); putpixel(xx, yy, neg); } } minamp = sin(rs2) * z * 60; maxamp = sin(rs2) * z * 60; if(minamp > 0) minamp *= -1.0; if(maxamp < 0) maxamp *= -1.0; for(ofst = minamp; ofst < maxamp; ofst ++){ if(ofst < 0){ // Shell two hash marks xx = x + cos(c) * (sr2 + ofst); yy = y + sin(c) * (sr2 + ofst); putpixel(xx, yy, neg); } else{ xx = x + cos(c) * (sr2 + ofst); yy = y + sin(c) * (sr2 + ofst); putpixel(xx, yy, pos); } } if(ms > prot){ // It is a neutron minamp = sin(rs1) * z * 200; // so draw shell one maxamp = sin(rs1) * z * 200; if(minamp > 0) minamp *= -1.0; if(maxamp < 0) maxamp *= -1.0; for(ofst = minamp; ofst < maxamp; ofst ++){ if(ofst < 0){ // Shell one hash marks xx = x + cos(c) * (sr1 + ofst); yy = y + sin(c) * (sr1 + ofst); putpixel(xx, yy, pos); } else{ xx = x + cos(c) * (sr1 + ofst); yy = y + sin(c) * (sr1 + ofst); putpixel(xx, yy, neg); } } } } } void bump(nprot & p1, control & c1){ if(z < p1.z || z > p1.z) return; // Same size only if(c1.lines == 1) linexy(x, y, p1.x, p1.y, 0x000000); double dx = (x + vx) - (p1.x + p1.vx); double dy = (y + vy) - (p1.y + p1.vy); // contact on next move double sr = z * 274 + p1.z * 274; sr *= sr; if(dx * dx + dy * dy > sr) return; // No collision double dc = sqrt(dx * dx + dy * dy); double nx = dx / dc; double a1 = vt * nx; double a2 = p1.vt * nx; double pc = (2.0 * (a1 - a2)) / (ms + p1.ms); // Momemtum change double v1 = vt - pc * p1.ms * nx; double v2 = p1.vt + pc * ms * nx; vt = v1; p1.vt = v2; a1 = nx + p1.rad; a2 = nx + rad; rad = a1; p1.rad = a2; line(x, y, a1, 150, 0x000000); line(p1.x, p1.y, a2, 150, 0xffffff); linexy(x, y, p1.x, p1.y, 0x002200); if(c1.view == 1) c1.trigger = 1; } void showvec(){ line(x, y, rad, vt * 5, 0xffff00); } void move(){ vx = cos(rad) * vt; vy = sin(rad) * vt; if(x + vx > maxx || x + vx < minx){ // Left or right wall bounce is rad = PI - rad; // new radian = PI - old radian vx = cos(rad) * vt; } if(y + vy > maxy || y + vy < miny){ // Up or down wall bounce is rad = 2 * PI - rad; // new radian = 2 * PI - old radian vy = sin(rad) * vt; } x += vx; y += vy; ellipse(); if(half > 0) half --; // time to live and make it if(half == 1) makeprot(); // a proton when it dies } // Only do it once }; SDL_Surface *screen; int init_screen(int srt, int sdn) { screen = SDL_SetVideoMode(srt, sdn, 32, SDL_SWSURFACE); if( screen == NULL ) { fprintf(stderr, "Couldn't set video mode: %s\n", SDL_GetError()); exit(1); } } void putpixel(unsigned int x, unsigned int y, unsigned int color) { if(x >= minx && x < maxx && y >= miny && y < maxy){ unsigned int *ptr = (unsigned int*)screen->pixels; int lineoffset = y * (screen->pitch / 4); ptr[lineoffset + x] = color; } } Uint32 getpixel(SDL_Surface *surface, int x, int y) { int bpp = surface->format->BytesPerPixel; // Here p is the address to the pixel we want to retrieve if(x >= minx && x < maxx && y >= miny && y < maxy){ Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; switch(bpp) { case 1: return *p; case 2: return *(Uint16 *)p; case 3: if(SDL_BYTEORDER == SDL_BIG_ENDIAN) return p[0] << 16 | p[1] << 8 | p[2]; else return p[0] | p[1] << 8 | p[2] << 16; case 4: return *(Uint32 *)p; default: return 0; /* shouldn't happen, but avoids warnings */ } } return 0; } int ColorFill(int color, int maxx, int maxy) { int x, y; for(y = 0; y < maxy; y++){ for(x = 0; x < maxx; x++){ putpixel(x, y, color); } } } void linexy(int x1, int y1, int x2, int y2, int hue) { // Draw a line using Cartesian coordinates double vx = x1 - x2; double vy = y1 - y2; double vt = sqrt(vx * vx + vy * vy); double nx = vx / vt; double ny = vy / vt; int x; vx = x2; // Reusing vx and vy vy = y2; for(x = 0; x < vt; x ++){ putpixel(x1, y1, hue); vx += nx; vy += ny; x1 = (int) vx; y1 = (int) vy; } } void line(int x, int y, double rad, double vt, int hue) { // Draw a line using polar coordinates double xx; double vx = cos(rad) * vt; double vy = sin(rad) * vt; double nx = vx / vt; double ny = vy / vt; vx = x; vy = y; for(xx = 0; xx < vt; xx ++){ putpixel(x, y, hue); vx += nx; vy += ny; x = (int) vx; y = (int) vy; } } void MakeCircle(float xx, float yy, float radius, Uint32 color) { // Larger circle gets more dots per degree double inc = 1 / (radius * 2); double circle = 0; while(circle < 2 * PI){ circle += inc; putpixel(xx + cos(circle) * radius, yy + sin(circle) * radius, color); } } char keystroke(void) { int count = 0; char keydat = 0; SDL_Event event; /* Poll for events. SDL_PollEvent() returns 0 when there are no */ /* more events on the event queue, our while loop will exit when */ /* that occurs. */ while( SDL_PollEvent( &event ) ){ switch( event.type ){ case SDL_KEYDOWN: keydat = event.key.keysym.sym; //printf( "Key press detected\n" ); count ++; break; case SDL_KEYUP: //printf( "Key release detected\n" ); count ++; break; case SDL_QUIT: keydat = 'q'; break; case SDLK_KP_ENTER: keydat = 0x0a; break; case SDLK_RETURN: keydat = 0x0a; break; case SDLK_KP0: keydat = '0'; break; case SDLK_KP1: keydat = '1'; break; case SDLK_KP2: keydat = '2'; break; case SDLK_KP3: keydat = '3'; break; default: break; } } return keydat; }