fractals_random.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /* fractals_random.c */
  2. /* This demo shows a single-buffering "freeglut" example. */
  3. /*
  4. * Program to draw a fractal by Michael Barnsley's stochastic algorithm.
  5. * Algorithm:
  6. * (1) Define the affine transformations (of the form r(i+1) = A r(i) + b )
  7. * (2) Find the stationary point for the first transformation
  8. * (3) To draw:
  9. * - Pick a random integer between 1 and the number of transformations (inclusive)
  10. * - Send the current point through the transformation to create the new current point
  11. * - Plot the new current point
  12. */
  13. /*
  14. * User Commands:
  15. * PgUp, PgDn - increase/decrease scaling
  16. * Arrow keys - translate viewing section
  17. * r - reset view
  18. * Escape - quit
  19. */
  20. #include <GL/freeglut.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <math.h>
  25. #define FGH_PI 3.14159265358979323846
  26. #ifdef _MSC_VER
  27. /* DUMP MEMORY LEAKS */
  28. #include <crtdbg.h>
  29. #endif
  30. typedef struct
  31. {
  32. double a00, a01, a10, a11 ; /* Transformation matrix */
  33. double b0, b1 ; /* Constant vector added on */
  34. double statx, staty ; /* Coordinates of the stationary point */
  35. }
  36. AffineTrans ;
  37. /* Number of levels to draw the fractal */
  38. static int num_levels = 0 ;
  39. /* The definition of the fractal */
  40. static int num_trans ;
  41. static AffineTrans *affine ;
  42. /* the window title */
  43. char window_title [ 80 ] ;
  44. /* The amount the view is translated */
  45. double xwin = 0.0, ywin = 0.0 ;
  46. double scale_factor = 1.0 ;
  47. /* The current point */
  48. double current_x = 0.0, current_y = 0.0 ;
  49. /* Signals when a glClear is needed */
  50. static GLboolean needClear = GL_TRUE;
  51. static void draw_level ( int num, double m00, double m01, double m10, double m11, double n0, double n1 )
  52. {
  53. /* Draw a fractal transformed by "M", "N" as passed in */
  54. int i ;
  55. for ( i = 0; i < 10; i++ )
  56. {
  57. int random = ( rand( ) >> 10 ) % num_trans;
  58. double new_x = affine[random].a00 * current_x + affine[random].a01 * current_y + affine[random].b0 ;
  59. double new_y = affine[random].a10 * current_x + affine[random].a11 * current_y + affine[random].b1 ;
  60. glVertex2d ( new_x, new_y ) ;
  61. current_x = new_x ;
  62. current_y = new_y ;
  63. }
  64. }
  65. static void
  66. Display(void)
  67. {
  68. if (needClear) {
  69. glClear(GL_COLOR_BUFFER_BIT);
  70. needClear = GL_FALSE;
  71. }
  72. /* the curve */
  73. glPushMatrix();
  74. glScaled(2.5, 2.5, 2.5);
  75. glColor4f(0.0, 0.0, 0.0, 1.0);
  76. glBegin ( GL_POINTS ) ;
  77. draw_level ( num_levels, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 );
  78. glEnd () ;
  79. glPopMatrix();
  80. glFlush();
  81. glutPostRedisplay(); /* Needed so that this function will be called again */
  82. }
  83. static void
  84. Reshape(int width, int height)
  85. {
  86. float ar;
  87. glViewport(0, 0, width, height);
  88. glMatrixMode(GL_PROJECTION);
  89. glLoadIdentity();
  90. ar = (float) width / (float) height;
  91. if( ar > 1 )
  92. glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
  93. else
  94. glFrustum(-1.0, 1.0, -1/ar, 1/ar, 2.0, 100.0);
  95. glMatrixMode(GL_MODELVIEW);
  96. glLoadIdentity();
  97. xwin = -1.0 ;
  98. ywin = 0.0 ;
  99. glTranslated(xwin, ywin, -5.0);
  100. needClear = GL_TRUE;
  101. }
  102. static void
  103. Key(unsigned char key, int x, int y)
  104. {
  105. int changed_settings = 1;
  106. switch (key) {
  107. case 27: /* Escape key */
  108. glutLeaveMainLoop ();
  109. break;
  110. case 'r' : case 'R' :
  111. glMatrixMode(GL_MODELVIEW);
  112. glLoadIdentity();
  113. xwin = -1.0 ;
  114. ywin = 0.0 ;
  115. glTranslated(xwin, ywin, -5.0);
  116. break ;
  117. default:
  118. changed_settings = 0;
  119. break;
  120. }
  121. if (changed_settings)
  122. needClear = GL_TRUE;
  123. glutPostRedisplay();
  124. }
  125. static void
  126. Special(int key, int x, int y)
  127. {
  128. int changed_settings = 1;
  129. switch (key) {
  130. case GLUT_KEY_UP :
  131. glMatrixMode(GL_MODELVIEW);
  132. ywin += 0.1 * scale_factor ;
  133. glTranslated(0.0, 0.1 * scale_factor, 0.0);
  134. break ;
  135. case GLUT_KEY_DOWN :
  136. glMatrixMode(GL_MODELVIEW);
  137. ywin -= 0.1 * scale_factor ;
  138. glTranslated(0.0, -0.1 * scale_factor, 0.0);
  139. break ;
  140. case GLUT_KEY_LEFT :
  141. glMatrixMode(GL_MODELVIEW);
  142. xwin -= 0.1 * scale_factor ;
  143. glTranslated(-0.1 * scale_factor, 0.0, 0.0);
  144. break ;
  145. case GLUT_KEY_RIGHT :
  146. glMatrixMode(GL_MODELVIEW);
  147. xwin += 0.1 * scale_factor ;
  148. glTranslated(0.1 * scale_factor, 0.0, 0.0);
  149. break ;
  150. case GLUT_KEY_PAGE_UP :
  151. glMatrixMode(GL_MODELVIEW);
  152. glTranslated ( -xwin, -ywin, 0.0 ) ;
  153. glScaled(1.25, 1.25, 1.25);
  154. glTranslated ( xwin, ywin, 0.0 ) ;
  155. scale_factor *= 0.8 ;
  156. break ;
  157. case GLUT_KEY_PAGE_DOWN :
  158. glMatrixMode(GL_MODELVIEW);
  159. glTranslated ( -xwin, -ywin, 0.0 ) ;
  160. glScaled(0.8, 0.8, 0.8);
  161. glTranslated ( xwin, ywin, 0.0 ) ;
  162. scale_factor *= 1.25 ;
  163. break ;
  164. default:
  165. changed_settings = 0;
  166. break;
  167. }
  168. if (changed_settings)
  169. needClear = GL_TRUE;
  170. glutPostRedisplay();
  171. }
  172. static int mouse_x = 0, mouse_y = 0 ;
  173. static int button_down = GLUT_DOWN ;
  174. static void
  175. Mouse ( int button, int updown, int x, int y )
  176. {
  177. button_down = updown ;
  178. if ( updown == GLUT_DOWN )
  179. {
  180. mouse_x = x ;
  181. mouse_y = y ;
  182. }
  183. }
  184. static void
  185. MouseMotion ( int x, int y )
  186. {
  187. int window_width = glutGet ( GLUT_WINDOW_WIDTH ) ;
  188. int window_height = glutGet ( GLUT_WINDOW_HEIGHT ) ;
  189. int window_size = ( window_width < window_height ) ? window_width : window_height ;
  190. double delta_x = 5.0 * (double)(x - mouse_x) / (double)(window_size) ;
  191. double delta_y = 5.0 * (double)(y - mouse_y) / (double)(window_size) ;
  192. xwin += delta_x * scale_factor ;
  193. ywin -= delta_y * scale_factor ;
  194. glMatrixMode ( GL_MODELVIEW ) ;
  195. glTranslated ( delta_x * scale_factor, -delta_y * scale_factor, 0.0 ) ;
  196. needClear = GL_TRUE;
  197. glutPostRedisplay();
  198. mouse_x = x ;
  199. mouse_y = y ;
  200. }
  201. static void
  202. MouseWheel ( int wheel_number, int direction, int x, int y )
  203. {
  204. double scale = ( direction > 0 ) ? 1.25 : 0.8 ;
  205. glMatrixMode ( GL_MODELVIEW ) ;
  206. glTranslated ( -xwin, -ywin, 0.0 ) ;
  207. glScaled ( scale, scale, scale ) ;
  208. glTranslated ( xwin, ywin, 0.0 ) ;
  209. scale_factor /= scale ;
  210. needClear = GL_TRUE;
  211. glutPostRedisplay();
  212. }
  213. static void
  214. checkedFGets ( char *s, int size, FILE *stream )
  215. {
  216. if ( fgets ( s, size, stream ) == NULL ) {
  217. fprintf ( stderr, "fgets failed\n");
  218. exit ( EXIT_FAILURE );
  219. }
  220. }
  221. void readConfigFile ( char *fnme )
  222. {
  223. FILE *fptr = fopen ( fnme, "rt" ) ;
  224. int i ;
  225. char inputline [ 256 ] ;
  226. if ( fptr )
  227. {
  228. /* Read a header line */
  229. checkedFGets ( inputline, sizeof ( inputline ), fptr ) ;
  230. /* Read a comment line */
  231. checkedFGets ( inputline, sizeof ( inputline ), fptr ) ;
  232. /* Read the window title */
  233. checkedFGets ( inputline, sizeof ( inputline ), fptr ) ;
  234. /* We assume here that this line will not exceed 79 characters plus a
  235. newline (window_title is 80 characters long). That'll cause a buffer
  236. overflow. For a simple program like this, though, we're letting it
  237. slide!
  238. */
  239. sscanf ( inputline, "%[a-zA-Z0-9!@#$%^&*()+=/\\_-\" ]", window_title ) ;
  240. /* Read a comment line */
  241. checkedFGets ( inputline, sizeof ( inputline ), fptr ) ;
  242. /* Read the number of affine transformations */
  243. checkedFGets ( inputline, sizeof ( inputline ), fptr ) ;
  244. sscanf ( inputline, "%d", &num_trans ) ;
  245. affine = (AffineTrans *)malloc ( num_trans * sizeof(AffineTrans) ) ;
  246. /* Read a comment line */
  247. checkedFGets ( inputline, sizeof ( inputline ), fptr ) ;
  248. for ( i = 0; i < num_trans; i++ )
  249. {
  250. /* Read an affine transformation definition */
  251. checkedFGets ( inputline, sizeof ( inputline ), fptr ) ;
  252. sscanf ( inputline, "%lf %lf %lf %lf %lf %lf", &affine[i].a00, &affine[i].a01,
  253. &affine[i].a10, &affine[i].a11, &affine[i].b0, &affine[i].b1 ) ;
  254. }
  255. }
  256. else /* No data file, set a default */
  257. {
  258. printf ( "ERROR opening file <%s>\n", fnme ) ;
  259. strcpy ( window_title, "Koch Snowflake" ) ;
  260. num_trans = 4 ;
  261. affine = (AffineTrans *)malloc ( num_trans * sizeof(AffineTrans) ) ;
  262. affine[0].a00 = 1/3. ; affine[0].a01 = 0.00 ; affine[0].a10 = 0.00 ; affine[0].a11 = 1/3. ;
  263. affine[0].b0 = 0.0 ; affine[0].b1 = 0.0 ;
  264. affine[1].a00 = 1/6. ; affine[1].a01 = -1/3.*sin(FGH_PI/3.) ; affine[1].a10 = 1/3.*sin(FGH_PI/3.) ; affine[1].a11 = 1/6. ;
  265. affine[1].b0 = 1/3. ; affine[1].b1 = 0.0 ;
  266. affine[2].a00 = 1/6. ; affine[2].a01 = -1/3.*sin(-FGH_PI/3.) ; affine[2].a10 = 1/3.*sin(-FGH_PI/3.) ; affine[2].a11 = 1/6. ;
  267. affine[2].b0 = 0.5 ; affine[2].b1 = sqrt(3)/6. ;
  268. affine[3].a00 = 1/3. ; affine[3].a01 = 0.00 ; affine[3].a10 = 0.00 ; affine[3].a11 = 1/3. ;
  269. affine[3].b0 = 2/3. ; affine[3].b1 = 0.0 ;
  270. }
  271. for ( i = 0; i < num_trans; i++ )
  272. {
  273. double m00, m01, m10, m11 ; /* Matrix "I" minus "A" */
  274. double determ ; /* Determinant of this matrix */
  275. /* Calculate the stationary point */
  276. m00 = 1.0 - affine[i].a00 ;
  277. m01 = - affine[i].a01 ;
  278. m10 = - affine[i].a10 ;
  279. m11 = 1.0 - affine[i].a11 ;
  280. determ = m00 * m11 - m01 * m10 ;
  281. if ( fabs ( determ ) > 1.e-6 )
  282. {
  283. affine[i].statx = ( m11 * affine[i].b0 - m01 * affine[i].b1 ) / determ ;
  284. affine[i].staty = ( -m10 * affine[i].b0 + m00 * affine[i].b1 ) / determ ;
  285. }
  286. else
  287. affine[i].statx = affine[i].staty = 0.0 ;
  288. }
  289. }
  290. int
  291. main(int argc, char *argv[])
  292. {
  293. glutInitDisplayMode( GLUT_RGB | GLUT_SINGLE );
  294. glutInitWindowSize(500, 250);
  295. glutInitWindowPosition ( 140, 140 ) ;
  296. glutInit(&argc, argv);
  297. if ( argc > 1 )
  298. readConfigFile ( argv[1] ) ;
  299. else
  300. readConfigFile ( "fractals.dat" ) ;
  301. glutCreateWindow( window_title );
  302. glClearColor(1.0, 1.0, 1.0, 1.0);
  303. glutReshapeFunc(Reshape);
  304. glutKeyboardFunc(Key);
  305. glutSpecialFunc(Special);
  306. glutDisplayFunc(Display);
  307. glutMouseFunc(Mouse);
  308. glutMotionFunc(MouseMotion);
  309. glutMouseWheelFunc(MouseWheel);
  310. glutMainLoop();
  311. printf ( "Back from the 'freeglut' main loop\n" ) ;
  312. free ( affine ) ;
  313. #ifdef _MSC_VER
  314. /* DUMP MEMORY LEAK INFORMATION */
  315. _CrtDumpMemoryLeaks () ;
  316. #endif
  317. return 0; /* ANSI C requires main to return int. */
  318. }