Skip to content

Instantly share code, notes, and snippets.

@jl2
Last active December 10, 2015 02:58
Show Gist options
  • Select an option

  • Save jl2/4371812 to your computer and use it in GitHub Desktop.

Select an option

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.
#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
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