Rob Younger
/
fire_demo
Embed:
(wiki syntax)
Show/hide line numbers
composite.cpp
00001 //////////////////////////////////////////////////////////// 00002 // Software generation of a grayscale composite TV signal // 00003 // Puts a 105x128 grayscale fractal zoom onscreen (slow!) // 00004 // // 00005 // Hacked together, (ab)uses the LPC1768 DAC output (p18) // 00006 // with some shifty looking timing sensitive code // 00007 // // 00008 // // 00009 // Rob Younger 26th Oct 2009, (tweaked 15th Nov 2009) // 00010 //////////////////////////////////////////////////////////// 00011 00012 //////////////////////////////////////////////////////////// 00013 // fire demo routine based on http://demo-effects.sourceforge.net/ 00014 // Copyright (C) 2003 W.P. van Paassen - peter@paassen.tmfweb.nl 00015 // which I guess means this version is GPL. 00016 // 00017 // note it uses a secondary buffer for the fire, which is 00018 // copied into the main buffer, innefficient but quick! 00019 // limits on available resolution due to inneficient mem use 00020 //////////////////////////////////////////////////////////// 00021 00022 // Generating video like it's 1982! 00023 00024 // Warning : this is *very* hacky code - just proof of concept! 00025 // This might blow up your mbed or your TV. 00026 // I claim no responsibility for anything :-) 00027 00028 // Start with a 180 Ohm resistor in series with the DAC output 00029 // before connecting to a composite AV input, 00030 // DAC is about 0-3.3v output, Composite in 1v p-p, with a 75 Ohm termination, so 180 Ohms is about right. 00031 00032 // but it also worked without any resistor for me! Start with a higher value if you aren't sure. 00033 // More likely to burn out your mbed or TV with low/no resistor - Use at your own risk! 00034 00035 00036 // HOW THIS WORKS: 00037 00038 // The DAC output is written as fast as possible to software generate a composite signal 00039 // dac.write_u16() seems to take about 0.5 us: I worked this timing out using a big loop of 00040 // dac.write_u16(0); 00041 // .... 00042 // dac.write_u16(0); 00043 // dac.write_u16(0xFFFF); 00044 // .... 00045 // dac.write_u16(0xFFFF); 00046 // Until I got a frequency I could measure on a multimeter. 00047 // 00048 // At full speed gives us about 1MHz max frequency - 00049 // I don't have an oscilloscope to see how well this actually works, probably totally out of spec! 00050 // 00051 // The software just runs loads of these to generate the composite signal as fast as possible! 00052 // 00053 // Since a TV output is generated continuously this would use 100% CPU time. 00054 // 00055 // Clever to-the-metal code would do things like use the horizontal and vertical blanking 00056 // intervals to do any required calculation. This isn't clever to-the-metal code! 00057 // Instead, I just don't draw the bottom few percent of the TV picture, and use this free time to run code. 00058 // This may well cause your TV to loose sync, but it works for me - I did say it was a hack! 00059 // 00060 // Driving the display takes 90%, main code gets 10% to play with at the end of each frame. 00061 // Tweak these percentages up and down, but loose too many lines and the tv is much more likely to 00062 // drop the signal, equally as you hit 100% CPU the frame calls might start to overlap and it all goes a bit wrong! 00063 // 00064 // This code actually starts with the end of previous frame signalling first, then all the setup, then the actual picture. 00065 // 00066 // It's coded up as a routine that draws a whole frame (field), which is called from main on a timer interrupt (at 50Hz for PAL) 00067 // This makes it easy to have a main routing that can operate normally, without you having to worry (too much) about the timing involved. 00068 // The picture elements of the signal are created by dumping a global frame buffer over to the DAC: 00069 // unsigned short int framebuffer[HEIGHT][WIDTH]; 00070 // The values in this framebuffer are the actual composite signal, NOT just shades of gray! 00071 // In other words, only write values between 0x56DB (black) and 0xFFFF (bright white). 00072 // For this reason, it's important to initialize the buffer to all 0x56DB or above 00073 00074 // Yes - there's probably a much better way to do this - but you don't want to slow down the DAC writes at all. 00075 // Adding checks or shifting the value from a normal range might be to slow - over to the real programmers to work out how to do this... 00076 00077 // The frame buffer is 105 pixels wide - this is just because 105 dac writes take up the time required for a horizontal tv line. 00078 // height is more arbitrary, as we draw every scan line - but I double or quadruple scan to get squarish pixels! 00079 // Use a modulo value in the picture write line to repeat the picture for small framebuffers. 00080 00081 // This program has a couple of demo routines. One draws a fractal, and the other just writes random values to the framebuffer 00082 00083 // A future enhancement could be to have two small framebuffers 105x64 and do double buffering? Needs to all be in fast memory though. 00084 // The code could definitely do with some tuning as the sync delays are all a bit off... 00085 00086 ////////////////////////////////////////////////////////////////////////////////////////////////////////// 00087 00088 00089 #include "mbed.h" 00090 00091 //Framebuffer size 00092 #define WIDTH 105 00093 #define HEIGHT 86 00094 00095 //TV signal generation controlling: 00096 #define LINES 256 //Visible lines drawn to screen 00097 #define SCAN 3 //Number of scanlines per pixel (vertical) 00098 #define DRAWWIDTH 105 //Pixels per line 00099 00100 // LINES: theoretically up to 286 for PAL, 241 for NTSC). 285 seems to be about 100% CPU on PAL. Smaller values means I stop drawing the signal early. 00101 // SCAN: controls double scan (e.g. 128 pixels to 256 lines) 00102 // DRAWWIDTH: number of pixels to attempt to draw in a line (should be =< framebuffer WIDTH). Very timing critical - expect different values to break 00103 00104 // Composite signal values for DAC output. These should really be scaled for 1v peak-to-peak 00105 #define IRE_m40 0x0000 //0volts 00106 #define IRE_0 0x4920 //Baseline 00107 #define IRE_7p5 0x56DB //Black 00108 #define IRE_100 0xFFFF //White 00109 // DAC is 10bit, but i'm using write_u16 to write to the DAC. 00110 // IRE is a definition: 00111 // the levels are -40 (0volts), 0 (baseline below black), 7.5 (Black), 100 (White). 00112 // IRE -40 is 0v, 100 is 1v, so scale accordingly! 00113 00114 AnalogOut dac(p18); // Video out pin 00115 Ticker timer; // Timer for calling the frame 00116 00117 DigitalOut led1(LED1);//Some status lights... 00118 DigitalOut led2(LED2); 00119 DigitalOut led3(LED3); 00120 DigitalOut led4(LED4); 00121 00122 // Framebuffer actually has video signal levels in it - not just grayscale data 00123 // This means it must be initialised to at least all black IRE_7p5 before it's used. 00124 // zero values will likely kill the output and TV will loose sync. 00125 unsigned short int framebuffer[HEIGHT][WIDTH]; 00126 00127 00128 00129 ///////////////////////////////////////////////////////////// 00130 //Software composite signal generation (very timing specific) 00131 ///////////////////////////////////////////////////////////// 00132 00133 void createframe() { 00134 00135 // Procedure to create a output frame to a tv - needs to run on a very regular sync (e.g. 50Hz or 60Hz) 00136 // Using the DAC to create this output, which seems to happily run at 2MHz update 00137 // dac.write_u16 seems to take almost spot on 0.5us, so I'm using multiples of this to create a signal. 00138 00139 // Could maybe be done with timing precision through multiple digital outputs and a resistor ladder to create an external DAC, but this didn't need any external components! 00140 00141 // Someone with an oscilloscope can tweak this to get the delays more up to standard! 00142 00143 // TV signal specs 00144 00145 // For 50Hz PAL, each line takes up 64us, and there are 625 lines, but split into two fields of about 312 lines. 00146 // I'm treating both fields exactly the same, so we have a 312(ish) lines at 50Hz. 00147 // NTSC is actually very similar but with slightly different timings/counts. (525 lines at 60Hz). 00148 00149 // Some info found through google: 00150 00151 //525line (NTSC) - required timing in us for a line 00152 //NAME LENGTH LEVEL 00153 //Front porch 1.5 IRE_0 00154 //Sync Tip 4.7 IRE_m40 00155 //Breezeway 0.6 IRE_0 00156 //Color Burst 2.5 IRE_0 00157 //Back Porch 1.6 IRE_0 00158 //Active Video 52.6 IRE_7p5 - IRE100 00159 00160 //Total line time = 63.5us ( * half of 525 lines * 60Hz) 00161 00162 //625line (PAL) - required timing in us for a line 00163 //NAME LENGTH LEVEL 00164 //Front porch 1.65 IRE_0 00165 //Sync Tip 4.7 IRE_m40 00166 //Breezeway 0.9 IRE_0 00167 //Color Burst 2.25 IRE_0 00168 //Back Porch 2.55 IRE_0 00169 //Active Video 51.95 IRE_7p5 - IRE100 00170 00171 //Total line time = 64us ( * half of 625 lines * 50Hz) 00172 00173 // There actually seem to be a lot of variations on this, but they all seem roughly the same. 00174 00175 // Colour needs a precision ~4MHz carrier signal applied over the 'color burst' and active video 00176 // with precise phase and amplitude control (sounds like a lot of work!) 00177 00178 // So for colour, Use svideo, VGA, or use 3 of these signals to generate an RGB scart signal? 00179 00180 //The basic frame format is 00181 //1) few lines of special start pulses, 00182 //2) some off screen lines, which had things like teletext/close captions 00183 //3) the tv picture bit you see, 00184 //4) some special pulses to say end of screen, go back to the top. 00185 // Then straight back to 1 for the next frame. 00186 00187 // To get the timing right - I do this: 00188 //4) some special pulses to say end of screen, go back to the top. 00189 //1) few lines of special start pulses, 00190 //2) some off screen lines, which had things like teletext/close captions 00191 //3) the tv picture bit you see, 00192 00193 // You can get away dropping the last few lines of 3) 00194 // I use this to drop back to the main program to run as normal. 00195 00196 // Ideally you'd use the few cycles between each line to do stuff, but that's going to be hard to get timing right. 00197 00198 00199 //////////////////////////////////////////////////////////// 00200 //Start of Frame 00201 //////////////////////////////////////////////////////////// 00202 00203 //Each dac.write is ~0.5us, so multiply up to create the timings. 00204 00205 // (This is a mix of PAL and NTSC - hack as appropriate) 00206 00207 // There are 21 lines per field in a vertical blanking period 00208 // the last 4 lines of a field indicate are just before flyback 00209 // then there are 5 blank lines for flyback itself... 00210 00211 //END OF A FRAME + FLYBACK + START OF NEW FRAME signalling (9 lines) 00212 for (int i = 0; i < 6; i++) { //6 equalizing pulses (time = 6 half lines) 00213 dac.write_u16(IRE_m40); //2.4us 00214 dac.write_u16(IRE_m40); 00215 dac.write_u16(IRE_m40); 00216 dac.write_u16(IRE_m40); 00217 // dac.write_u16(IRE_m40); 00218 dac.write_u16(IRE_0); //29.4us 00219 wait_us(28); 00220 } 00221 for (int i = 0; i < 6; i++) {// 6 serrated vertical pulses (time = 6 half lines) 00222 dac.write_u16(IRE_0); //2.4us 00223 dac.write_u16(IRE_0); 00224 dac.write_u16(IRE_0); 00225 dac.write_u16(IRE_0); 00226 // dac.write_u16(IRE_0); 00227 dac.write_u16(IRE_m40); //29.4us 00228 wait_us(28); 00229 } 00230 for (int i = 0; i < 6; i++) { // 6 equalizing pulses (time = 6 half lines) 00231 dac.write_u16(IRE_m40); //2.4us 00232 dac.write_u16(IRE_m40); 00233 dac.write_u16(IRE_m40); 00234 dac.write_u16(IRE_m40); 00235 // dac.write_u16(IRE_m40); 00236 dac.write_u16(IRE_0); //29.4us 00237 wait_us(28); 00238 } 00239 00240 00241 // The lines just above the top of the picture used for setup/teletext/closed captions etc. 00242 // about 17 lines for PAL, 12 for NTSC? 00243 for (int i = 0; i < 17; i++) { 00244 //10.9us (NTSC) or 12.5us (PAL) for horizontal blanking interval 00245 dac.write_u16(IRE_0); //Front porch 1.6us 00246 dac.write_u16(IRE_0); 00247 dac.write_u16(IRE_0); 00248 dac.write_u16(IRE_m40); //Sync Tip 4.7us 00249 dac.write_u16(IRE_m40); 00250 dac.write_u16(IRE_m40); 00251 dac.write_u16(IRE_m40); 00252 dac.write_u16(IRE_m40); 00253 dac.write_u16(IRE_m40); 00254 dac.write_u16(IRE_m40); 00255 dac.write_u16(IRE_m40); 00256 dac.write_u16(IRE_m40); 00257 // dac.write_u16(IRE_m40); //extra for PAL timing 00258 dac.write_u16(IRE_0); //Breezeway 0.5us 00259 dac.write_u16(IRE_0); //ColorBurst 2.5us 00260 dac.write_u16(IRE_0); 00261 dac.write_u16(IRE_0); 00262 dac.write_u16(IRE_0); 00263 dac.write_u16(IRE_0); 00264 dac.write_u16(IRE_m40); //Back Porch 1.6us (2.55us in PAL) 00265 dac.write_u16(IRE_m40); 00266 dac.write_u16(IRE_m40); 00267 dac.write_u16(IRE_m40); //extra for PAL timing 00268 dac.write_u16(IRE_m40); //extra for PAL timing 00269 00270 // for (int j = 0; j < DRAWWIDTH; j++) { 00271 // dac.write_u16(IRE_0); 00272 // } //next pixel 00273 00274 00275 //Then that video signal for 52.6us (52 for PAL) 00276 dac.write_u16(IRE_0); //Video signal for 52.6us 00277 wait_us(51); // replaces another 104 dac.write_u16(IRE_0) 00278 } 00279 00280 00281 //Draw the actual visible lines on screen: exactly same header as previous, but followed by real video data. 00282 // intentionally dropping the last few lines to throw some time to main() 00283 // otherwise this loop would use 100% of CPU. 00284 for (int i = 0; i < LINES; i++) { 00285 //10.9us (NTSC) or 12.5us (PAL) for horizontal blanking interval 00286 dac.write_u16(IRE_0); //Front porch 1.6us 00287 dac.write_u16(IRE_0); 00288 dac.write_u16(IRE_0); 00289 dac.write_u16(IRE_m40); //Sync Tip 4.7us 00290 dac.write_u16(IRE_m40); 00291 dac.write_u16(IRE_m40); 00292 dac.write_u16(IRE_m40); 00293 dac.write_u16(IRE_m40); 00294 dac.write_u16(IRE_m40); 00295 dac.write_u16(IRE_m40); 00296 dac.write_u16(IRE_m40); 00297 dac.write_u16(IRE_m40); 00298 // dac.write_u16(IRE_m40); //extra for PAL timing 00299 dac.write_u16(IRE_0); //Breezeway 0.5us 00300 dac.write_u16(IRE_0); //ColorBurst 2.5us 00301 dac.write_u16(IRE_0); 00302 dac.write_u16(IRE_0); 00303 dac.write_u16(IRE_0); 00304 dac.write_u16(IRE_0); 00305 dac.write_u16(IRE_m40); //Back Porch 1.6us (2.55us in PAL) 00306 dac.write_u16(IRE_m40); 00307 dac.write_u16(IRE_m40); 00308 dac.write_u16(IRE_m40); //extra for PAL timing 00309 dac.write_u16(IRE_m40); //extra for PAL timing 00310 00311 //Then that video signal for 52.6us (52 for PAL): 00312 00313 //////////////////////////////////////////////////////////// 00314 //Write out the video data 00315 //(very timing sensitive as must last ~53us, no more or less) 00316 //////////////////////////////////////////////////////////// 00317 00318 // Examples: 00319 00320 //1) draw random shade per line 00321 // dac.write_u16(rand() % 40000 + IRE_7p5); //Video signal for 52.6us 00322 // wait_us(52); 00323 00324 //2) draw black 00325 // dac.write_u16(IRE_7p5); 00326 // wait_us(51); 00327 00328 //3) draw white 00329 // dac.write_u16(IRE_100); 00330 // wait_us(51); 00331 00332 //4) draw framebuffer 00333 00334 // Code here is very timing critical. 00335 00336 // loop count is instruction dependent, if you add some code here, it will need be a different width 00337 // We have ~52.5us and a a dac write takes 0.5us so 104/105px seems correct. 00338 // Trial+error shows ~100-110 pixels to be OKish on a particular old TV. 00339 00340 int k =(i/ SCAN ); //double scan the framebuffer, particularly convenient for 128 vertical px but 256 line resolution.. 00341 00342 // The modulo is only needed if screen output size is bigger than framebuffer (wrapping occurs). 00343 // Stick to powers of 2 for modulo wrapping (or likely too slow). 00344 for (int j = 0; j < DRAWWIDTH; j++) { 00345 dac.write_u16( framebuffer[k%128][j%128] ); //modulo used to wrap framebuffer. Keep to power of 2 =< framebuffer sizes. 00346 } //next pixel 00347 00348 } //next line loop 00349 00350 //Default back to black when we don't bother drawing the last few lines of a frame! 00351 dac.write_u16(IRE_7p5); 00352 } //End of createframe routine 00353 00354 00355 00356 //////////////////////////////////////////////////////////// 00357 // randomfill the framebuffer // 00358 //////////////////////////////////////////////////////////// 00359 void randomfill () { 00360 for (int j = 0; j < HEIGHT; j++) { 00361 for (int i = 0; i < WIDTH; i++) { 00362 framebuffer[j][i] = rand(); 00363 if (framebuffer[j][i] < IRE_7p5 ) { 00364 framebuffer[j][i] = IRE_7p5; 00365 } 00366 } 00367 } 00368 } 00369 00370 //////////////////////////////////////////////////////////// 00371 // blank the framebuffer // 00372 //////////////////////////////////////////////////////////// 00373 void blankfill () { 00374 for (int j = 0; j < HEIGHT; j++) { 00375 for (int i = 0; i < WIDTH; i++) { 00376 framebuffer[j][i] = IRE_7p5; 00377 //framebuffer[j][i] = IRE_100; 00378 } 00379 } 00380 } 00381 00382 //////////////////////////////////////////////////////////// 00383 // zooming mandelbot fractal in the framebuffer // 00384 //////////////////////////////////////////////////////////// 00385 00386 void mandelbrot () { 00387 //Mandelbrot escape time algorithm (doubles+iteration=slow) 00388 //Taken from wikipedia pseudocode, 00389 //tweaked by using the speeded up version that google found on geocities 00390 //(oops - Geocities has shut down in the 3 weeks since I wrote this! first time I've used it in years!) 00391 //http://www.geocities.com/CapeCanaveral/5003/Mandel.txt 00392 //then put in a loop to zoom in on a intersting co-ords point i saw elsewhere... 00393 double zoom; 00394 for (int z = 0; z < 200; z++) {//2^50 is quite a lot of zoom - thats why you need precision! 00395 zoom= pow((double)1.2,z); 00396 00397 led1=0; 00398 led2=0; 00399 led3=0; 00400 led4=0; 00401 00402 double x,y; 00403 double x0,y0; 00404 // double xtemp; 00405 double xsq; 00406 double ysq; 00407 00408 unsigned short int iteration = 0; 00409 unsigned short int max_iteration = (z*2)+20; //arbitrary scaling so there are more interation allowed as you zoom 00410 for (int j = 0; j < HEIGHT; j++) { 00411 //little status hack as as drawing fractals (particularly with doubles on only 10% of a cpu is slow!) 00412 if (j== (( HEIGHT /4)-1)) { 00413 led1=1; 00414 } else if (j==(( HEIGHT /2)-1)) { 00415 led2=1; 00416 } else if (j==(3*( HEIGHT /4)-1)) { 00417 led3=1; 00418 } else if (j==( HEIGHT -1)) { 00419 led4=1; 00420 } 00421 //end of little status hack 00422 00423 00424 for (int i = 0; i < WIDTH; i++) { 00425 // x0=(((float) i) -32.0)/32.0;//redefine 0to63 as -1to+1 mandelbrot window 00426 // y0=(((float) j) -32.0)/32.0;//redefine 0to63 as -1to+1 mandelbrot window 00427 //-1.865725138512217656771 moves center point to something interesting 00428 x0=((((double) i) - ( WIDTH /2)) /zoom)-1.865725138512217656771;//redefine 0to63 as -1to+1 mandelbrot window 00429 y0=(((double) j) - ( HEIGHT /2)) /zoom;//redefine 0to63 as -1to+1 mandelbrot window 00430 iteration = 0; 00431 00432 //Standard version of mandelbrot loop based on wikipedia pseudocode 00433 // x=0; 00434 // y=0; 00435 // while ( ((x*x + y*y) <= (2*2)) && (iteration < max_iteration) ) { 00436 // xtemp = x*x - y*y + x0; 00437 // y = 2*x*y + y0; 00438 // x = xtemp; 00439 // iteration++; 00440 // } 00441 00442 //Speedy version of main mandelbrot loop (algorithm from geocities page) 00443 x=x0+x0*x0-y0*y0; 00444 y=y0+x0*y0+x0*y0; 00445 for (iteration=0;iteration<max_iteration && (ysq=y*y)+(xsq=x*x)<4;iteration++,y=y0+x*y+x*y,x=x0-ysq+xsq) ; 00446 00447 //Iteration count determines color (clamp max iteration to zero, and normalize for black to white) 00448 framebuffer[j][i] = (( iteration == max_iteration ) ? (IRE_7p5) : (IRE_7p5 + ((iteration%20)*2000)) ); 00449 } 00450 } 00451 }//zoom loop 00452 } 00453 00454 //////////////////////////////////////////////////////////// 00455 // fire the framebuffer // 00456 //////////////////////////////////////////////////////////// 00457 // based on demo at http://demo-effects.sourceforge.net/ 00458 // refer back to original code for how it should be done :-) 00459 void fire () { 00460 static unsigned char fire[WIDTH * HEIGHT]; 00461 int i,j,index,temp; 00462 00463 /* draw random bottom line in fire array*/ 00464 00465 j = WIDTH * (HEIGHT- 1); 00466 for (i = 0; i < WIDTH - 1; i++) { 00467 int random = 1 + (int)(16.0 * (rand()/(RAND_MAX+1.0))); 00468 if (random > 8) /* the lower the value, the intenser the fire, compensate a lower value with a higher decay value*/ 00469 fire[j + i] = 255; /*maximum heat*/ 00470 else 00471 fire[j + i] = 0; 00472 } 00473 00474 /* move fire upwards, start at bottom*/ 00475 00476 for (index = 0; index < HEIGHT-4 ; ++index) { 00477 for (i = 0; i < WIDTH - 1; ++i) { 00478 if (i == 0) { /* at the left border*/ 00479 temp = fire[j]; 00480 temp += fire[j + 1]; 00481 temp += fire[j - WIDTH]; 00482 temp /=3; 00483 } else if (i == WIDTH - 1) { /* at the right border*/ 00484 temp = fire[j + i]; 00485 temp += fire[j - WIDTH + i]; 00486 temp += fire[j + i - 1]; 00487 temp /= 3; 00488 } else { 00489 temp = fire[j + i]; 00490 temp += fire[j + i + 1]; 00491 temp += fire[j + i - 1]; 00492 temp += fire[j - WIDTH + i]; 00493 temp >>= 2; 00494 } 00495 if (temp > 1) 00496 temp -= 1; /* decay */ 00497 00498 fire[j - WIDTH + i] = temp; 00499 } 00500 j -= WIDTH; 00501 } 00502 00503 //dirty hack to convert the fire data to the framebuffer. better graduation of shades would look better! 00504 for (int j = HEIGHT-3 ; j >= 0; --j) { 00505 for (int i = WIDTH-1; i >= -1 ; --i) { 00506 framebuffer[j][i] = ((fire[j * WIDTH + i])*150)+IRE_7p5; 00507 } 00508 } 00509 00510 00511 } 00512 00513 00514 //////////////////////////////////////////////////////////// 00515 // main() showing use framebuffer // 00516 // Puts a grayscale pic in it // 00517 //////////////////////////////////////////////////////////// 00518 00519 int main() { 00520 00521 blankfill(); //set framebuffer to blank values 00522 00523 timer.attach_us(&createframe,20000);//attach the display (at 50Hz) 00524 00525 // int attached=0; //attach frame 00526 // //If you had a lot of setup in a main game loop, you could do something like this: 00527 // if (attached==0) { 00528 // timer.attach_us(&createframe,20000); 00529 // attached=1; 00530 // } 00531 00532 //Program loop 00533 while (1) { 00534 // Add you own demo code here. Expect it to get regularly interupted by the screen draw call! 00535 // very simple code can run at full fps. 00536 //Example - change HEIGHT to 64 and SCAN to 4 and use randomfill... 00537 //randomfill(); //random pixel fill 00538 00539 //Example - change HEIGHT to 86 and SCAN to 3 and use fire; 00540 fire(); 00541 00542 //Example - change HEIGHT to 128 and SCAN to 2 and use mandelbrot... 00543 //mandelbrot(); //mandelbrot procedure is a 200 loop zoom so takes ages - and each scene redraw takes a few seconds! 00544 } //while 00545 00546 } //main 00547 00548
Generated on Sun Jul 24 2022 14:44:43 by 1.7.2