save.pp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. {
  2. Ported to FPC by Nikolay Nikolov ([email protected])
  3. }
  4. {
  5. Save example for OpenPTC 1.0 C++ implementation
  6. Copyright (c) Glenn Fiedler ([email protected])
  7. This source code is in the public domain
  8. }
  9. program SaveExample;
  10. {$MODE objfpc}
  11. uses
  12. ptc, Math;
  13. procedure save(surface: TPTCSurface; filename: string);
  14. var
  15. F: File;
  16. width, height: Integer;
  17. size: Integer;
  18. y: Integer;
  19. pixels: PUint8 = nil;
  20. format: TPTCFormat = nil;
  21. palette: TPTCPalette = nil;
  22. { generate the header for a true color targa image }
  23. header: array [0..17] of Uint8 =
  24. (0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  25. begin
  26. { open image file for writing }
  27. AssignFile(F, filename);
  28. Rewrite(F, 1);
  29. try
  30. { get surface dimensions }
  31. width := surface.width;
  32. height := surface.height;
  33. { set targa image width }
  34. header[12] := width and $FF;
  35. header[13] := width shr 8;
  36. { set targa image height }
  37. header[14] := height and $FF;
  38. header[15] := height shr 8;
  39. { set bits per pixel }
  40. header[16] := 24;
  41. { write tga header }
  42. BlockWrite(F, header, 18);
  43. { calculate size of image pixels }
  44. size := width * height * 3;
  45. { allocate image pixels }
  46. pixels := GetMem(size);
  47. {$IFDEF FPC_LITTLE_ENDIAN}
  48. format := TPTCFormat.Create(24, $00FF0000, $0000FF00, $000000FF);
  49. {$ELSE FPC_LITTLE_ENDIAN}
  50. format := TPTCFormat.Create(24, $000000FF, $0000FF00, $00FF0000);
  51. {$ENDIF FPC_LITTLE_ENDIAN}
  52. palette := TPTCPalette.Create;
  53. { save surface to image pixels }
  54. surface.save(pixels, width, height, width * 3, format, palette);
  55. { write image pixels one line at a time }
  56. for y := height - 1 DownTo 0 do
  57. BlockWrite(F, pixels[width * y * 3], width * 3);
  58. finally
  59. { free image pixels }
  60. FreeMem(pixels);
  61. palette.Free;
  62. format.Free;
  63. CloseFile(F);
  64. end;
  65. end;
  66. function calculate(real, imaginary: Single; maximum: Integer): Integer;
  67. var
  68. c_r, c_i: Single;
  69. z_r, z_i: Single;
  70. z_r_squared, z_i_squared: Single;
  71. z_squared_magnitude: Single;
  72. count: Integer;
  73. begin
  74. { complex number 'c' }
  75. c_r := real;
  76. c_i := imaginary;
  77. { complex 'z' }
  78. z_r := 0;
  79. z_i := 0;
  80. { complex 'z' squares }
  81. z_r_squared := 0;
  82. z_i_squared := 0;
  83. { mandelbrot function iteration loop }
  84. for count := 0 to maximum - 1 do
  85. begin
  86. { square 'z' and add 'c' }
  87. z_i := 2 * z_r * z_i + c_i;
  88. z_r := z_r_squared - z_i_squared + c_r;
  89. { update 'z' squares }
  90. z_r_squared := z_r * z_r;
  91. z_i_squared := z_i * z_i;
  92. { calculate squared magnitude of complex 'z' }
  93. z_squared_magnitude := z_r_squared + z_i_squared;
  94. { stop iterating if the magnitude of 'z' is greater than two }
  95. if z_squared_magnitude > 4 then
  96. begin
  97. calculate := Count;
  98. exit;
  99. end;
  100. end;
  101. { maximum }
  102. calculate := 0;
  103. end;
  104. procedure mandelbrot(console: TPTCConsole; surface: TPTCSurface;
  105. x1, y1, x2, y2: Single);
  106. const
  107. { constant values }
  108. entries = 1024;
  109. maximum = 1024;
  110. var
  111. { fractal color table }
  112. table: array [0..entries - 1] of Uint32;
  113. i: Integer;
  114. f_index: Single;
  115. time: Single;
  116. intensity: Single;
  117. pixels, pixel: PUint32;
  118. width, height: Integer;
  119. dx, dy: Single;
  120. real, imaginary: Single;
  121. x, y: Integer;
  122. count: Integer;
  123. index: Integer;
  124. color: Uint32;
  125. area: TPTCArea;
  126. begin
  127. { generate fractal color table }
  128. for i := 0 to entries - 1 do
  129. begin
  130. { calculate normalized index }
  131. f_index := i / entries;
  132. { calculate sine curve time value }
  133. time := f_index * pi - pi / 2;
  134. { lookup sine curve intensity at time and scale to [0,1] }
  135. intensity := (sin(time) + 1) / 2;
  136. { raise the intensity to a power }
  137. intensity := power(intensity, 0.1);
  138. { store intensity as a shade of blue }
  139. table[i] := Trunc(255 * intensity);
  140. end;
  141. { lock surface pixels }
  142. pixels := surface.lock;
  143. try
  144. { get surface dimensions }
  145. width := surface.width;
  146. height := surface.height;
  147. { current pixel pointer }
  148. pixel := pixels;
  149. { calculate real x,y deltas }
  150. dx := (x2 - x1) / width;
  151. dy := (y2 - y1) / height;
  152. { imaginary axis }
  153. imaginary := y1;
  154. { iterate down surface y }
  155. for y := 0 to height - 1 do
  156. begin
  157. { real axis }
  158. real := x1;
  159. { iterate across surface x }
  160. for x := 0 to width - 1 do
  161. begin
  162. { calculate the mandelbrot interation count }
  163. count := calculate(real, imaginary, maximum);
  164. { calculate color table index }
  165. index := count mod entries;
  166. { lookup color from iteration }
  167. color := table[index];
  168. { store color }
  169. pixel^ := color;
  170. { next pixel }
  171. Inc(pixel);
  172. { update real }
  173. real := real + dx;
  174. end;
  175. { update imaginary }
  176. imaginary := imaginary + dy;
  177. { setup line area }
  178. area := TPTCArea.Create(0, y, width, y + 1);
  179. try
  180. { copy surface area to console }
  181. surface.copy(console, area, area);
  182. finally
  183. area.Free;
  184. end;
  185. { update console area }
  186. console.update;
  187. end;
  188. finally
  189. { unlock surface }
  190. surface.unlock;
  191. end;
  192. end;
  193. var
  194. console: TPTCConsole = nil;
  195. surface: TPTCSurface = nil;
  196. format: TPTCFormat = nil;
  197. x1, y1, x2, y2: Single;
  198. begin
  199. try
  200. try
  201. { create console }
  202. console := TPTCConsole.Create;
  203. { create format }
  204. format := TPTCFormat.Create(32, $00FF0000, $0000FF00, $000000FF);
  205. { open the console with a single page }
  206. console.open('Save example', format, 1);
  207. { create surface matching console dimensions }
  208. surface := TPTCSurface.Create(console.width, console.height, format);
  209. { setup viewing area }
  210. x1 := -2.00;
  211. y1 := -1.25;
  212. x2 := +1.00;
  213. y2 := +1.25;
  214. { render the mandelbrot fractal }
  215. mandelbrot(console, surface, x1, y1, x2, y2);
  216. { save mandelbrot image }
  217. save(surface, 'save.tga');
  218. { read key }
  219. console.ReadKey;
  220. finally
  221. console.close;
  222. console.Free;
  223. surface.Free;
  224. format.Free;
  225. end;
  226. except
  227. on error: TPTCError do
  228. { report error }
  229. error.report;
  230. end;
  231. end.