/* ** PixelMachine ** v 0.1.20070220 ** ** A ray-traced 3D renderer by SuperJer ** ** Email = superjer@superjer.com ** Web = http://www.superjer.com/ ** ** You can do whatever you like with this code, I don't care, ** just please recognize me as the original author. :) ** */ #include #include #include #include #include #include #include "collision.h" #define TERDIV 8 // terrain divisions (powers of 2 ONLY!) #define TERSECS 8 // sections per division // this will work out to (TERDIV*TERSECS+1)^3 cubes!! #define BSIZE (TERDIV*TERSECS+1) #define SQSIZE (1000.0/(double)BSIZE) #define MULTIS 2 // level of multisampling (makes rendering n^2 times slower!!) #define W 200 // output image size #define H 150 #define FRAMES 1 // frames of animation #define XY 0 #define XZ 1 #define YZ 2 #define SCATTER 0.00003 #define SUNS 2 #define SPHERES 100 double terrain[BSIZE][BSIZE]; unsigned char *img = NULL; int w; int h; int multis; int frames; COLOR blocks[BSIZE][BSIZE][BSIZE] = {0}; double blocksize = 1000.0/((double)BSIZE); V cam; V tar; double tarw; double pixpitch; double subpitch; V sun[SUNS]; SPHERE sphere[SPHERES]; void savebmp( const char *filename, int w, int h ); void preview( int w, int h ); void render( int w, int h, bool quiet ); COLOR &raytrace( COLOR &color, const V &cam, const V &ray, bool lighttest ); int main(int argc,char **argv) { int i,j,k; int w,h; char str[80]; unsigned seed = (unsigned)-1; w = W; h = H; multis = MULTIS; frames = FRAMES; for(i=1; i1 ) { for(i=div/2;i(BSIZE*2)/5 && i<(BSIZE*3)/5 && j>(BSIZE*2)/5 && j<(BSIZE*3)/5 ) // shiny area! { if( k= k*(1000.0/(double)BSIZE ) ) { blocks[i][j][k] = blocks[i][j][k-1]; } else { blocks[i][j][k].r = 0.0; blocks[i][j][k].g = 0.0; blocks[i][j][k].b = 0.0; blocks[i][j][k].a = 0.0; } sun[0].x = (double)(rand()%1500) - 250.0; sun[0].y = (double)(rand()%1500) - 250.0; sun[0].z = (double)(rand()%700) + 100.0; for(i=0; i 1 ) sprintf(str,"./video/frame%.4d.bmp",i); else sprintf(str,"./img.bmp"); savebmp(str,w,h); /**/ subtract( cam, cam, lin ); tar.z -= 0.85; cam.z -= 0.9; for(j=0;j> 8); bmpfileheader[ 4] = (unsigned char)(filesize>>16); bmpfileheader[ 5] = (unsigned char)(filesize>>24); bmpinfoheader[ 4] = (unsigned char)( w ); bmpinfoheader[ 5] = (unsigned char)( w>> 8); bmpinfoheader[ 6] = (unsigned char)( w>>16); bmpinfoheader[ 7] = (unsigned char)( w>>24); bmpinfoheader[ 8] = (unsigned char)( h ); bmpinfoheader[ 9] = (unsigned char)( h>> 8); bmpinfoheader[10] = (unsigned char)( h>>16); bmpinfoheader[11] = (unsigned char)( h>>24); //f = fopen("img.raw","wb"); //fwrite(img,3,w*h,f); //fclose(f); f = fopen(filename,"wb"); fwrite(bmpfileheader,1,14,f); fwrite(bmpinfoheader,1,40,f); for(i=0; imax ) max = brightness; if( brightnessmin+step*10 ) printf("#"); else if( brightness>min+step*9 ) printf("@"); else if( brightness>min+step*8 ) printf("8"); else if( brightness>min+step*7 ) printf("$"); else if( brightness>min+step*6 ) printf("?"); else if( brightness>min+step*5 ) printf("%%"); else if( brightness>min+step*4 ) printf("*"); else if( brightness>min+step*3 ) printf(";"); else if( brightness>min+step*2 ) printf(","); else if( brightness>min+step*1 ) printf("`"); else printf(" "); } printf("\n"); } } void render( int w, int h, bool quiet ) { int i,j,k,m,n; COLOR *color; color = (COLOR*)malloc(sizeof(COLOR)*(multis*multis)); if( img ) free( img ); img = (unsigned char *)malloc(3*w*h); memset(img,0,sizeof(img)); subtract( tar, tar, cam ); normalize( tar, 1.0 ); add( tar, tar, cam ); tarw = 2.0; pixpitch = tarw/w; subpitch = pixpitch/((double)multis+1.0); V lin; lin.x = tar.x - cam.x; lin.y = tar.y - cam.y; lin.z = tar.z - cam.z; double di,dj; double r,g,b; int subgoal; subgoal = 0; for(i=0; i= subgoal ) { subgoal += 20; if( subgoal%100==0 ) printf("%d",subgoal/10); else printf("."); fflush(stdout); } } if( !quiet ) printf("\n"); } COLOR &raytrace( COLOR &color, const V &cam, const V &ray, bool lighttest ) { int i,k; double r,g,b,a; int blockx,blocky,blockz; V hit0,hit1,hit2; V hit; double p0,p1,p2; double p,potp; int side; int hitobject,pothitobject; side = XY; r = 0.0; g = 0.0; b = 0.0; a = 0.0; // spheres potp = 99999999.0; hitobject = -1; pothitobject = -1; for(i=0; iBSIZE-1 || blocky<1 || blocky>BSIZE-1 || blockz<0 || blockz>BSIZE-1 || k>1000 || (lighttest && p>=1.0) ) { if( !lighttest ) { double dot = (ray.x*ray.x + ray.y*ray.y); double ang = fabs(dot/( sqrt(dot) * sqrt(ray.x*ray.x + ray.y*ray.y + ray.z*ray.z) )); ang *= ang; r = r + 0.5*ang*(1.0-a); g = g + 0.6*ang*(1.0-a); b = b + 1.0*ang*(1.0-a); a = 1.0; } break; } k++; // pickup color from current space block COLOR *c; if( hitobject>=0 ) c = &sphere[hitobject].color; else c = &blocks[blockx][blocky][blockz]; if( k>0 && (c->a>0.0 || hitobject>=0 ) ) { if( lighttest ) { color.r = 0.0; color.g = 0.0; color.b = 0.0; color.a = 0.7; return color; } // get incoming light/shadow V beam; COLOR light; COLOR finallight; finallight.r = 0.0; finallight.g = 0.0; finallight.b = 0.0; for(int m=0;m=0 || blockx>(BSIZE*2)/5 && blockx<(BSIZE*3)/5 && blocky>(BSIZE*2)/5 && blocky<(BSIZE*3)/5 ) //reflect! { V ray2 = ray; if( hitobject>=0 ) { V rad; subtract( rad, hit, sphere[hitobject].center ); mirror( ray2, ray, rad ); ray2.x = -ray2.x; ray2.y = -ray2.y; ray2.z = -ray2.z; } else if( side==XY ) ray2.z = -ray.z; else if( side==XZ ) ray2.y = -ray.y; else ray2.x = -ray.x; //printf("%f",sin( (hit.z)*0.01 )*0.1 ); double scatter; if( hitobject>=0 ) scatter = 0.0; else scatter = SCATTER; ray2.x *= 1.0 + (double)(rand()%1000)*scatter; // + sin( (hit.z)*0.1 )*0.3; ray2.y *= 1.0 + (double)(rand()%1000)*scatter; // + cos( (hit.z)*0.1 )*0.3; ray2.z *= 1.0 + (double)(rand()%1000)*scatter; // + sin( (hit.x)*0.1 )*0.3; raytrace(color, hit, ray2, false); r = r + color.r*(1.0-a)*sidefactor*finallight.r; g = g + color.g*(1.0-a)*sidefactor*finallight.g; b = b + color.b*(1.0-a)*sidefactor*finallight.b; a = 1.0; break; } r = r + c->r*c->a*(1.0-a)*sidefactor*finallight.r; g = g + c->g*c->a*(1.0-a)*sidefactor*finallight.g; b = b + c->b*c->a*(1.0-a)*sidefactor*finallight.b; a += c->a*(1.0-a); if( a>=0.98 ) { a = 1.0; break; } } // move to next space block hit0.x = (double)blockx*blocksize + (ray.x>0.0?blocksize:0.0); hit1.y = (double)blocky*blocksize + (ray.y>0.0?blocksize:0.0); hit2.z = (double)blockz*blocksize + (ray.z>0.0?blocksize:0.0); p0 = (hit0.x-cam.x)/(ray.x) + 0.00001; p1 = (hit1.y-cam.y)/(ray.y) + 0.00001; p2 = (hit2.z-cam.z)/(ray.z) + 0.00001; if( (int)((cam.x+p0*ray.x)/blocksize)==blockx && (int)((cam.y+p0*ray.y)/blocksize)==blocky && (int)((cam.z+p0*ray.z)/blocksize)==blockz ) p0 = 99999.0; if( (int)((cam.x+p1*ray.x)/blocksize)==blockx && (int)((cam.y+p1*ray.y)/blocksize)==blocky && (int)((cam.z+p1*ray.z)/blocksize)==blockz ) p1 = 99999.0; if( (int)((cam.x+p2*ray.x)/blocksize)==blockx && (int)((cam.y+p2*ray.y)/blocksize)==blocky && (int)((cam.z+p2*ray.z)/blocksize)==blockz ) p2 = 99999.0; if( p0

potp ) { hitobject = pothitobject; side = XY; p = potp; } hit.x = (p-0.00002)*ray.x + cam.x; hit.y = (p-0.00002)*ray.y + cam.y; hit.z = (p-0.00002)*ray.z + cam.z; //printf( "%.4d %.4d %.4d\n", blockx, blocky, blockz ); } if( r>1.0 ) r = 1.0; if( g>1.0 ) g = 1.0; if( b>1.0 ) b = 1.0; if( r<0.0 ) r = 0.0; if( g<0.0 ) g = 0.0; if( b<0.0 ) b = 0.0; color.r = r; color.g = g; color.b = b; color.a = a; return color; }