Last active
December 10, 2015 02:58
-
-
Save jl2/4371812 to your computer and use it in GitHub Desktop.
Create an animation of a 3D "growing" version of Conway's Game Of Life, using spheres and 3Delight.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "ri.h" | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <stdbool.h> | |
| #include <math.h> | |
| #define PI (3.141592654) | |
| size_t randUInt(size_t min, size_t max) { | |
| return ((rand()%(max-min)) + min); | |
| } | |
| typedef struct game_of_life_s { | |
| size_t width; | |
| size_t height; | |
| bool **board; | |
| } game_of_life_t; | |
| game_of_life_t *gol_create_board(size_t w, size_t h) { | |
| game_of_life_t *rval = malloc(sizeof(game_of_life_t)); | |
| rval->width = w; | |
| rval->height = h; | |
| rval->board = malloc(sizeof(bool*)*rval->width); | |
| for (size_t i=0; i<rval->width; ++i) { | |
| rval->board[i] = malloc(sizeof(bool)*rval->height); | |
| for (size_t j=0; j<rval->height; ++j) { | |
| rval->board[i][j] = false; | |
| } | |
| } | |
| return rval; | |
| } | |
| void gol_destroy_board(game_of_life_t **board) { | |
| for (size_t i=0; i<(*board)->width; ++i) { | |
| free((*board)->board[i]); | |
| } | |
| free((*board)->board); | |
| free(*board); | |
| *board = 0; | |
| } | |
| void gol_debug_show_life(game_of_life_t *board) { | |
| for (size_t j=0; j<board->height; ++j) { | |
| for (size_t i=0; i<board->width; ++i) { | |
| printf(board->board[i][j]?"X":" "); | |
| } | |
| printf("\n"); | |
| } | |
| } | |
| void gol_random_init(game_of_life_t *board, double prob) { | |
| size_t numFilled = prob*(board->width*board->height); | |
| for (int i=0;i<numFilled; ++i) { | |
| size_t ri = randUInt(0, board->height); | |
| size_t rj = randUInt(0, board->width); | |
| board->board[ri][rj] = true; | |
| } | |
| } | |
| size_t gol_count_neighbors(game_of_life_t *board, int i, int j) { | |
| int w = board->width; | |
| int h = board->height; | |
| int num = 0; | |
| int up = i-1>0 ? i-1 : h-1; | |
| int down = i+1 <h-1 ? i+1 : 0; | |
| int left = j-1>0 ? j-1 : w-1; | |
| int right = j+1 < w-1 ? j+1 : 0; | |
| num += board->board[up][j]; | |
| num += board->board[down][j]; | |
| num += board->board[i][left]; | |
| num += board->board[i][right]; | |
| num += board->board[up][left]; | |
| num += board->board[up][right]; | |
| num += board->board[down][left]; | |
| num += board->board[down][right]; | |
| return num; | |
| } | |
| game_of_life_t *gol_evolve(game_of_life_t *board) { | |
| int w = board->width; | |
| int h = board->height; | |
| game_of_life_t *goes_to = malloc(sizeof(game_of_life_t)); | |
| goes_to->width = w; | |
| goes_to->height = h; | |
| goes_to->board = malloc(sizeof(bool*)*goes_to->width); | |
| for (size_t i=0; i<goes_to->width; ++i) { | |
| goes_to->board[i] = malloc(sizeof(bool)*goes_to->height); | |
| for (size_t j=0; j<goes_to->height; ++j) { | |
| int num = gol_count_neighbors(board, i,j); | |
| if (board->board[i][j]) { | |
| if ((num < 2) || (num > 3)) { | |
| goes_to->board[i][j] = false; | |
| } else { | |
| goes_to->board[i][j] = true; | |
| } | |
| } else { | |
| if (num == 3) { | |
| goes_to->board[i][j] = true; | |
| } else { | |
| goes_to->board[i][j] = false; | |
| } | |
| } | |
| } | |
| } | |
| return goes_to; | |
| } | |
| void gol_show_renderman(game_of_life_t *board) { | |
| RiTransformBegin(); | |
| /* RiTranslate(-board->width/2.0, -board->height/2.0, 0.0); */ | |
| for (size_t j=0; j<board->height; ++j) { | |
| RiTransformBegin(); | |
| for (size_t i=0; i<board->width; ++i) { | |
| RiTranslate(1.0, 0.0, 0.0); | |
| if (board->board[i][j]) { | |
| RiSphere(0.5, -0.5,0.5, 360.0, RI_NULL); | |
| } | |
| } | |
| RiTransformEnd(); | |
| RiTranslate(0.0, 1.0, 0.0); | |
| } | |
| RiTransformEnd(); | |
| } | |
| /* #define DEBUG_LIFE 1 */ | |
| #ifdef DEBUG_LIFE | |
| int main(int argc, char *argv[]) { | |
| game_of_life_t *cur= gol_create_board(50,50); | |
| gol_random_init(cur, 0.25); | |
| for (int i=0;i<50; ++i) { | |
| gol_debug_show_life(cur); | |
| game_of_life_t *next = gol_evolve(cur); | |
| gol_destroy_board(&cur); | |
| cur = next; | |
| } | |
| } | |
| #else | |
| typedef struct camera_s { | |
| RtPoint location; | |
| RtPoint look_at; | |
| double roll; | |
| } camera_t; | |
| typedef struct scene_info_s { | |
| camera_t cam; | |
| char *fprefix; | |
| } scene_info_t; | |
| void AimZ(RtPoint direction); | |
| void PlaceCamera(camera_t *cam); | |
| void AimZ(RtPoint direction) | |
| { | |
| double xzlen, yzlen, yrot, xrot; | |
| if (direction[0]==0 && direction[1]==0 && direction[2]==0) | |
| return; | |
| /* | |
| * The initial rotation about the y axis is given by the projection of | |
| * the direction vector onto the x,z plane: the x and z components | |
| * of the direction. | |
| */ | |
| xzlen = sqrt(direction[0]*direction[0]+direction[2]*direction[2]); | |
| if (xzlen == 0) | |
| yrot = (direction[1] < 0) ? 180.0 : 0.0; | |
| else | |
| yrot = 180.0*acos(direction[2]/xzlen)/PI; | |
| /* | |
| * The second rotation, about the x axis, is given by the projection on | |
| * the y,z plane of the y-rotated direction vector: the original y | |
| * component, and the rotated x,z vector from above. | |
| */ | |
| yzlen = sqrt(direction[1]*direction[1]+xzlen*xzlen); | |
| xrot = 180*acos(xzlen/yzlen)/PI; /* yzlen should never be 0 */ | |
| if (direction[1] > 0) | |
| RiRotate(xrot, 1.0, 0.0, 0.0); | |
| else | |
| RiRotate(-xrot, 1.0, 0.0, 0.0); | |
| /* The last rotation declared gets performed first */ | |
| if (direction[0] > 0) | |
| RiRotate(-yrot, 0.0, 1.0, 0.0); | |
| else | |
| RiRotate(yrot, 0.0, 1.0, 0.0); | |
| } | |
| void PlaceCamera(camera_t *cam) | |
| { | |
| RtPoint direction; | |
| RiIdentity(); | |
| RiRotate(-cam->roll, 0.0, 0.0, 1.0); | |
| direction[0] = cam->look_at[0]-cam->location[0]; | |
| direction[1] = cam->look_at[1]-cam->location[1]; | |
| direction[2] = cam->look_at[2]-cam->location[2]; | |
| AimZ(direction); | |
| RiTranslate(-cam->location[0], -cam->location[1], -cam->location[2]); | |
| } | |
| int main(int argc, char *argv[]) { | |
| if (argc < 2) { | |
| printf("Not enough arguments given!\n"); | |
| return 1; | |
| } else if (argc > 2) { | |
| printf("Too many arguments given!\n"); | |
| return 1; | |
| } | |
| char *fprefix = argv[1]; | |
| const size_t NUM_FRAMES = 30; | |
| RtInt md = 4; | |
| scene_info_t scene; | |
| double rad = 60.0; | |
| double t = 0.0; | |
| double dt = 2.0*PI/(NUM_FRAMES-1); | |
| size_t fnum; | |
| RiBegin(RI_NULL); | |
| RiOption("trace", "maxdepth", &md, RI_NULL); | |
| RiSides(1); | |
| scene.cam.location[0] = 0; | |
| scene.cam.location[1] = rad; | |
| scene.cam.location[2] = rad; | |
| scene.cam.look_at[0]= 0.0; | |
| scene.cam.look_at[1]= 0.0; | |
| scene.cam.look_at[2]= 0.0; | |
| scene.cam.roll = 180.0; | |
| scene.fprefix = fprefix; | |
| game_of_life_t *boards[NUM_FRAMES+1]; | |
| size_t curBoard = 0; | |
| boards[curBoard] = gol_create_board(100,100); | |
| gol_random_init(boards[curBoard], 0.25); | |
| for (fnum = 0; fnum < NUM_FRAMES; ++fnum) { | |
| /* scene.cam.location[0] = rad * sin(t); */ | |
| /* scene.cam.location[2] = rad * cos(t); */ | |
| t += dt; | |
| printf("Rendering frame %lu\n", fnum); | |
| RtInt on = 1; | |
| char buffer[256]; | |
| RtString on_string = "on"; | |
| RtInt samples = 2; | |
| RtPoint lightPos = {80,80,80}; | |
| RiFrameBegin(fnum); | |
| sprintf(buffer, "images/%s%05zd.tif", scene.fprefix, fnum); | |
| RiDisplay(buffer,(char*)"file",(char*)"rgba",RI_NULL); | |
| RiFormat(800,800,1.0); | |
| RiProjection((char*)"perspective",RI_NULL); | |
| PlaceCamera(&scene.cam); | |
| RiAttribute("visibility", "int trace", &on, RI_NULL); | |
| RiAttribute( "visibility", | |
| "int camera", (RtPointer)&on, | |
| "int transmission", (RtPointer)&on, | |
| "int diffuse", (RtPointer)&on, | |
| "int specular", (RtPointer)&on, | |
| "int photon", (RtPointer)&on, | |
| RI_NULL ); | |
| RiAttribute( "light", (RtToken)"shadows", (RtPointer)&on_string, (RtToken)"samples", (RtPointer)&samples, RI_NULL ); | |
| RiAttribute((RtToken)"light", "string shadow", (RtPointer)&on_string, RI_NULL); | |
| RiLightSource("distantlight", "point from", (RtPointer)lightPos, RI_NULL); | |
| RiWorldBegin(); | |
| RiAttributeBegin(); | |
| RtColor col = {0.0,1.0,0.0}; | |
| RiSurface((char*)"matte", RI_NULL); | |
| RiColor(col); | |
| for (size_t i=0;i<(curBoard+1); ++i) { | |
| RiTransformBegin(); | |
| RiTranslate(-50.0, -50.0, i); | |
| gol_show_renderman(boards[i]); | |
| RiTransformEnd(); | |
| } | |
| RiAttributeEnd(); | |
| boards[curBoard+1] = gol_evolve(boards[curBoard]); | |
| curBoard+=1; | |
| RiWorldEnd(); | |
| RiFrameEnd(); | |
| } | |
| RiEnd(); | |
| for (size_t i=0; i<curBoard; ++i) { | |
| gol_destroy_board(&boards[i]); | |
| } | |
| return 0; | |
| } | |
| #endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| render: liferender.c Makefile | |
| clang -std=c99 -g -I"$(DELIGHT)/include" -o liferender liferender.c -L"$(DELIGHT)/lib" -l3delight |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment