/* * A 5-Chemical Reaction-Diffusion simulator for PLY objects. (rdstripes) * * for usage info, run program without any parameters * */ #include #include #include #include "rply.h" /***** extra stuff for mouse picking */ /* size of mouse picking selection buffer */ #define SELECT_MAX 250 /* window size (its square) */ GLint winx = 250, winy = 250; /* the buffer itself */ GLuint selectBuf[SELECT_MAX]; /* viewport array */ GLint vp[4]; /* array of initiator cells */ long initiators[10]; /* index to that array and number of initiators */ int initiatorindex = 0, maxinitiators = 10; int runningRD = 0; /***** end of mouse picking stuff */ /* R-D parameters and arrays */ GLfloat p1 = 0.04; GLfloat p2 = 0.06; GLfloat p3 = 0.04; GLfloat Dg = 0.05; //0.1; //0.009; GLfloat Ds = 0.2; //0.2; GLfloat speed = 1.0; GLfloat kg,kr,ks; GLfloat g1rand = 0.02; GLfloat *BETA; GLfloat *g1; GLfloat *g2; GLfloat *r; GLfloat *s1; GLfloat *s2; GLfloat *dg1; GLfloat *dg2; GLfloat *dr; GLfloat *ds1; GLfloat *ds2; GLfloat *activator; /* 3d object data arrays */ GLfloat **vertices; GLfloat **normals; GLfloat **diffusion; long **faces; long **neighbours; /* just some vars for extracting data from PLY (could be done better) */ long vertex=0, axis=0, face=0, fvertex=0, home=0, neighb=0; GLfloat maxv = -100; GLfloat minv = 100; /* angles and stuff for rotating and zooming the object */ GLfloat xangle = 0.0; GLfloat yangle = 0.0; GLfloat zangle = 0.0; GLfloat zoom = 1.5; GLfloat atX = 0.0; GLfloat atY = 0.0; /* global for number of vertices and faces */ long nvertices,nfaces; e_ply_type vertex_t, face_length_t, face_value_t; /* GLUT window identifier and viewport size (so we see whole object)*/ static int win; GLfloat view; /* input PLY filename */ char *filename; char *nbsfile; /* just some global variables for stuff that should be implemented better */ int plyHasNeighbs=0, plyHasNormals=0, plyHasDiff=0; /* * * Display usage info * */ void printUsage() { printf("Reaction-Diffusion Simulator (Stripes)\n\nusage:\trdstripes [-p ]\n\n"); printf("\tOptions:\n\t-p\t\t- Use R-D parameters in \n\t\t\t [If not specified defaults are used]\n\n"); printf("\tControls:\n\t\tRotate on X axis: 'a' and 'd'\n\t\tRotate on Y axis: 's' and 'w'\n\t\tRotate on Z axis: 'z' and 'c'\n\t\tZoom in and out: '+', '-'\n\t\tMove object: Left, Right, Up and Down arrows\n\t\tReset view: 'r'\n\t\tExport concentration levels: 'e'\n\t\tSelect stripe initiator cells: Mouse\n\t\tPause/resume simulation: 'p'\n\t\tQuit: 'q'\n\n"); printf("\tParameter file format:\n\t\t\t\t- ~0.04\n\t\t\t\t- ~0.06\n\t\t\t\t- ~0.04\n\t\t\t\t- ~0.05\n\t\t\t\t- ~0.2\n\n"); printf("If the PLY input file does not contain additional data about vertex normals and neighbour cells, this will be generated before R-D simulation begins. In this case a PLY file with the extra data is stored at _nbs.ply, and this file should be used in future to save on computation time.\n\n"); } /* * * The Reaction-Diffusion Jazz * */ void updateConc() /* * updateConc(): calculate the new values for each of the chemicals involved using * Meinhardt's R-D equations. */ { long i; int j, frozen=0; GLfloat ddg1,ddg2,dds1,dds2; GLfloat temp1, temp2, c=0.01; /* run through each triangular face (cell) */ for (i=0;i= maxinitiators) { if (!runningRD) { runningRD = 1; printf("R-D simulation running...\n"); } else { runningRD = 0; printf("R-D simulation paused. Press 'p' to resume.\n"); } } break; case 'q': case 'Q': printf("Freeing memory\n"); for(i=0;i= maxinitiators) printf("Stripe initiators set. Press the spacebar to begin R-D simulation...\n"); } } } /* * * All the PLY model handling routines * */ static int vertex_cb(p_ply_argument argument) /* * vertex_cb(argument): RPly vertex callback. This is called everytime RPly encounters * a vertex as it parses the PLY file. We store the vertex coordinates and (rather crudely) * find the max and min coordinates, for use in setting the viewport correctly. */ { long eol; p_ply_property property; ply_get_argument_user_data(argument, NULL, &eol); ply_get_argument_property(argument, &property, NULL, NULL); ply_get_property_info(property, NULL, &vertex_t, NULL, NULL); vertices[vertex][axis] = (GLfloat)ply_get_argument_value(argument); if (vertices[vertex][axis] > maxv) maxv = vertices[vertex][axis]; if (vertices[vertex][axis] < minv) minv = vertices[vertex][axis]; axis++; if (eol) { vertex++; axis=0; } return 1; } static int normal_cb(p_ply_argument argument) /* * normal_cb(argument): RPly normal callback. Store the normal for each vertex. */ { long eol; ply_get_argument_user_data(argument, NULL, &eol); normals[vertex-1][axis] = (GLfloat)ply_get_argument_value(argument); axis++; if (eol) { //vertex++; axis=0; } return 1; } static int face_cb(p_ply_argument argument) /* * face_cb(argument): RPly face callback. Store vertex indices for each face. */ { long length, value_index; p_ply_property property; ply_get_argument_property(argument, &property, &length, &value_index); ply_get_property_info(property, NULL, NULL, &face_length_t, &face_value_t); switch (value_index) { case 0: case 1: faces[face][fvertex++] = (long)ply_get_argument_value(argument); break; case 2: faces[face][fvertex++] = (long)ply_get_argument_value(argument); face++; fvertex=0; break; default: break; } return 1; } static int neighbours_cb(p_ply_argument argument) /* * neighbours_cb(argument): RPly neighbour callback. Retrieves the neighbour indices. * home variable indexs current cell, neighb indexs its neighbours. Bit of a cludge to * cover the case where neighbours ar found but not diffusion weightings. */ { long value_index; ply_get_argument_property(argument, NULL, NULL, &value_index); switch (value_index) { case 0: case 1: neighbours[home][neighb++] = (long)ply_get_argument_value(argument); break; case 2: neighbours[home][neighb++] = (long)ply_get_argument_value(argument); if (plyHasDiff == 0) home++; neighb=0; break; default: break; } return 1; } static int diffusion_cb(p_ply_argument argument) /* * diffusion_cb(argument): RPly diffusion weightings callback. */ { long value_index; ply_get_argument_property(argument, NULL, NULL, &value_index); switch (value_index) { case 0: case 1: diffusion[home][neighb++] = (GLfloat)ply_get_argument_value(argument); break; case 2: diffusion[home][neighb++] = (GLfloat)ply_get_argument_value(argument); home++; neighb=0; break; default: break; } return 1; } int outputPLY(char *filename) /* * outputPLY(filename): calls all the RPly output functions in correct order to write * a PLY file with all additional data (neighbours, normals, diffusion weightings). */ { int i,j; p_ply ply; ply = ply_create(filename, PLY_ASCII, NULL); /* add vertex element header info */ if (!ply_add_element(ply, "vertex", nvertices)) printf("cant add vertex element\n"); ply_add_scalar_property(ply, "x", vertex_t); ply_add_scalar_property(ply, "y", vertex_t); ply_add_scalar_property(ply, "z", vertex_t); ply_add_scalar_property(ply, "xnorm", vertex_t); ply_add_scalar_property(ply, "ynorm", vertex_t); ply_add_scalar_property(ply, "znorm", vertex_t); /* add faces element info */ if (!ply_add_element(ply, "face", nfaces)) printf("cant add face element\n"); ply_add_list_property(ply, "vertex_indices", face_length_t, face_value_t); /* add neighbours element info */ if (!ply_add_element(ply, "neighbours", nfaces)) printf("cant add neighbours element\n"); ply_add_list_property(ply, "vertex_indices", face_length_t, face_value_t); ply_add_list_property(ply, "diffusion_weighting", face_length_t, vertex_t); /* add comment saying created by our prog and added neighbours */ ply_add_comment(ply, "Extra neighbour and vertex normal data generated for Reaction-Diffusion simulations"); /* write the header */ if (!ply_write_header(ply)) printf("cant write header\n"); /* write the properties one by one */ for (i=0;i 0) { printf("\nSelect %d stripe initator cells using the mouse pointer...\n\t[left-click to set white; right-click to set black]\n", maxinitiators); } else { printf("\nRandom stripes will be generated.\nR-D simulation running...\n"); runningRD = 1; } } int main(int argc, char** argv) { FILE *fp; /* print out usage information */ if ((argc == 1) || (argv[1][0] == '-')) { printUsage(); return 0; } /* get PLY filename from command-line */ filename = argv[1]; printf("%s\n",filename); /* test if a parameter file is given, otherwise use defaults */ if (argv[2] != NULL) { switch (argv[2][1]) { case 'p': if (fp = fopen(argv[3],"r")) { fscanf(fp, "%f\n%f\n%f\n%f\n%f", &p1, &p2, &p3, &Dg, &Ds); printf("Taking parameters from %s:\n", argv[3]); fclose(fp); break; } else printf("Parameter file %s not found. ",argv[3]); default: printf("Using default parameters:\n"); } } else { printf("Using default parameters:\n"); } printf("\tp1: %f\n\tp2: %f\n\tp3: %f\n\tDg: %f\n\tDs: %f\n",p1,p2,p3,Dg,Ds); /* intialise GLUT and register callbacks, then enter main loop */ glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB); glutInitWindowSize(winx, winy); glutInitWindowPosition(300,200); win = glutCreateWindow("Stripey R-D Objects"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutIdleFunc(update); glutKeyboardFunc(keyb); glutSpecialFunc(special); glutMouseFunc(mouse); glutMainLoop(); return 0; }