From d3a98cf6cbc3bd0b9efc570f58e8812c03931c18 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 16 Oct 2018 10:08:48 +0200 Subject: Original 5.40 --- hacks/.gdbinit | 12 + hacks/Makefile.in | 3263 + hacks/README | 6 + hacks/abstractile.c | 1605 + hacks/abstractile.man | 52 + hacks/analogtv.c | 2431 + hacks/analogtv.h | 338 + hacks/anemone.c | 448 + hacks/anemone.man | 74 + hacks/anemotaxis.c | 755 + hacks/anemotaxis.man | 78 + hacks/ant.c | 1350 + hacks/ant.man | 96 + hacks/apollonian.c | 810 + hacks/apollonian.man | 70 + hacks/apple2-main.c | 1913 + hacks/apple2.c | 885 + hacks/apple2.h | 121 + hacks/apple2.man | 206 + hacks/asm6502.c | 2275 + hacks/asm6502.h | 181 + hacks/attraction.c | 1109 + hacks/attraction.man | 214 + hacks/automata.h | 64 + hacks/barcode.c | 1995 + hacks/barcode.man | 61 + hacks/binaryring.c | 587 + hacks/binaryring.man | 88 + hacks/blaster.c | 1191 + hacks/blaster.man | 65 + hacks/blitspin.c | 451 + hacks/blitspin.man | 96 + hacks/bouboule.c | 858 + hacks/bouboule.man | 80 + hacks/boxfit.c | 561 + hacks/boxfit.man | 102 + hacks/braid.c | 443 + hacks/braid.man | 69 + hacks/bsod.c | 6008 + hacks/bsod.man | 149 + hacks/bubbles-default.c | 154 + hacks/bubbles.c | 1437 + hacks/bubbles.h | 208 + hacks/bubbles.man | 140 + hacks/bumps.c | 700 + hacks/bumps.man | 80 + hacks/ccurve.c | 866 + hacks/ccurve.man | 60 + hacks/celtic.c | 1131 + hacks/celtic.man | 64 + hacks/check-configs.pl | 1243 + hacks/cloudlife.c | 428 + hacks/cloudlife.man | 87 + hacks/compass.c | 986 + hacks/compass.man | 57 + hacks/compile_axp.com | 156 + hacks/compile_decc.com | 156 + hacks/config/README | 262 + hacks/config/abstractile.xml | 36 + hacks/config/anemone.xml | 61 + hacks/config/anemotaxis.xml | 39 + hacks/config/ant.xml | 74 + hacks/config/antinspect.xml | 25 + hacks/config/antmaze.xml | 23 + hacks/config/antspotlight.xml | 25 + hacks/config/apollonian.xml | 42 + hacks/config/apple2.xml | 65 + hacks/config/atlantis.xml | 50 + hacks/config/attraction.xml | 87 + hacks/config/atunnel.xml | 26 + hacks/config/barcode.xml | 35 + hacks/config/binaryring.xml | 31 + hacks/config/blaster.xml | 63 + hacks/config/blinkbox.xml | 35 + hacks/config/blitspin.xml | 46 + hacks/config/blocktube.xml | 33 + hacks/config/boing.xml | 51 + hacks/config/bouboule.xml | 33 + hacks/config/bouncingcow.xml | 32 + hacks/config/boxed.xml | 58 + hacks/config/boxfit.xml | 65 + hacks/config/braid.xml | 39 + hacks/config/bsod.xml | 105 + hacks/config/bubble3d.xml | 30 + hacks/config/bubbles.xml | 42 + hacks/config/bumps.xml | 36 + hacks/config/cage.xml | 27 + hacks/config/carousel.xml | 57 + hacks/config/ccurve.xml | 32 + hacks/config/celtic.xml | 32 + hacks/config/circuit.xml | 37 + hacks/config/cityflow.xml | 55 + hacks/config/cloudlife.xml | 41 + hacks/config/companioncube.xml | 56 + hacks/config/compass.xml | 24 + hacks/config/coral.xml | 36 + hacks/config/crackberg.xml | 52 + hacks/config/critical.xml | 31 + hacks/config/crumbler.xml | 49 + hacks/config/crystal.xml | 48 + hacks/config/cube21.xml | 77 + hacks/config/cubenetic.xml | 67 + hacks/config/cubestack.xml | 44 + hacks/config/cubestorm.xml | 53 + hacks/config/cubetwist.xml | 46 + hacks/config/cubicgrid.xml | 31 + hacks/config/cwaves.xml | 31 + hacks/config/cynosure.xml | 32 + hacks/config/dangerball.xml | 37 + hacks/config/decayscreen.xml | 48 + hacks/config/deco.xml | 45 + hacks/config/deluxe.xml | 39 + hacks/config/demon.xml | 41 + hacks/config/discoball.xml | 37 + hacks/config/discrete.xml | 32 + hacks/config/distort.xml | 53 + hacks/config/dnalogo.xml | 50 + hacks/config/drift.xml | 31 + hacks/config/dymaxionmap.xml | 79 + hacks/config/endgame.xml | 29 + hacks/config/energystream.xml | 26 + hacks/config/engine.xml | 44 + hacks/config/epicycle.xml | 57 + hacks/config/eruption.xml | 53 + hacks/config/esper.xml | 46 + hacks/config/euler2d.xml | 53 + hacks/config/extrusion.xml | 44 + hacks/config/fadeplot.xml | 35 + hacks/config/fiberlamp.xml | 31 + hacks/config/filmleader.xml | 42 + hacks/config/fireworkx.xml | 30 + hacks/config/flag.xml | 41 + hacks/config/flame.xml | 39 + hacks/config/flipflop.xml | 52 + hacks/config/flipscreen3d.xml | 27 + hacks/config/fliptext.xml | 55 + hacks/config/flow.xml | 60 + hacks/config/fluidballs.xml | 55 + hacks/config/flurry.xml | 29 + hacks/config/flyingtoasters.xml | 42 + hacks/config/fontglide.xml | 54 + hacks/config/forest.xml | 30 + hacks/config/fuzzyflakes.xml | 66 + hacks/config/galaxy.xml | 36 + hacks/config/gears.xml | 39 + hacks/config/geodesic.xml | 61 + hacks/config/geodesicgears.xml | 41 + hacks/config/gflux.xml | 61 + hacks/config/glblur.xml | 46 + hacks/config/glcells.xml | 64 + hacks/config/gleidescope.xml | 41 + hacks/config/glforestfire.xml | 46 + hacks/config/glhanoi.xml | 54 + hacks/config/glitchpeg.xml | 38 + hacks/config/glknots.xml | 63 + hacks/config/glmatrix.xml | 53 + hacks/config/glplanet.xml | 43 + hacks/config/glschool.xml | 45 + hacks/config/glslideshow.xml | 55 + hacks/config/glsnake.xml | 56 + hacks/config/gltext.xml | 51 + hacks/config/goop.xml | 65 + hacks/config/grav.xml | 36 + hacks/config/greynetic.xml | 25 + hacks/config/halftone.xml | 61 + hacks/config/halo.xml | 42 + hacks/config/helix.xml | 27 + hacks/config/hexadrop.xml | 60 + hacks/config/hexstrut.xml | 48 + hacks/config/hilbert.xml | 77 + hacks/config/hopalong.xml | 64 + hacks/config/hydrostat.xml | 76 + hacks/config/hyperball.xml | 66 + hacks/config/hypercube.xml | 77 + hacks/config/hypertorus.xml | 116 + hacks/config/hypnowheel.xml | 54 + hacks/config/ifs.xml | 65 + hacks/config/imsmap.xml | 46 + hacks/config/interaggregate.xml | 33 + hacks/config/interference.xml | 57 + hacks/config/intermomentary.xml | 37 + hacks/config/jigglypuff.xml | 95 + hacks/config/jigsaw.xml | 51 + hacks/config/juggle.xml | 60 + hacks/config/juggler3d.xml | 55 + hacks/config/julia.xml | 39 + hacks/config/kaleidescope.xml | 42 + hacks/config/kaleidocycle.xml | 57 + hacks/config/klein.xml | 131 + hacks/config/kumppa.xml | 32 + hacks/config/lament.xml | 29 + hacks/config/laser.xml | 38 + hacks/config/lavalite.xml | 90 + hacks/config/lcdscrub.xml | 58 + hacks/config/lightning.xml | 30 + hacks/config/lisa.xml | 50 + hacks/config/lissie.xml | 52 + hacks/config/lmorph.xml | 51 + hacks/config/lockward.xml | 67 + hacks/config/loop.xml | 37 + hacks/config/m6502.xml | 55 + hacks/config/maze.xml | 71 + hacks/config/maze3d.xml | 122 + hacks/config/memscroller.xml | 35 + hacks/config/menger.xml | 51 + hacks/config/metaballs.xml | 53 + hacks/config/mirrorblob.xml | 75 + hacks/config/mismunch.xml | 44 + hacks/config/moebius.xml | 29 + hacks/config/moebiusgears.xml | 47 + hacks/config/moire.xml | 38 + hacks/config/moire2.xml | 34 + hacks/config/molecule.xml | 60 + hacks/config/morph3d.xml | 34 + hacks/config/mountain.xml | 31 + hacks/config/munch.xml | 63 + hacks/config/nerverot.xml | 62 + hacks/config/noof.xml | 23 + hacks/config/noseguy.xml | 19 + hacks/config/pacman.xml | 28 + hacks/config/pedal.xml | 33 + hacks/config/peepers.xml | 47 + hacks/config/penetrate.xml | 34 + hacks/config/penrose.xml | 55 + hacks/config/petri.xml | 83 + hacks/config/phosphor.xml | 49 + hacks/config/photopile.xml | 65 + hacks/config/piecewise.xml | 45 + hacks/config/pinion.xml | 49 + hacks/config/pipes.xml | 49 + hacks/config/polyhedra.xml | 201 + hacks/config/polyominoes.xml | 36 + hacks/config/polytopes.xml | 112 + hacks/config/pong.xml | 46 + hacks/config/popsquares.xml | 56 + hacks/config/projectiveplane.xml | 153 + hacks/config/providence.xml | 29 + hacks/config/pulsar.xml | 42 + hacks/config/pyro.xml | 37 + hacks/config/qix.xml | 74 + hacks/config/quasicrystal.xml | 56 + hacks/config/queens.xml | 31 + hacks/config/raverhoop.xml | 54 + hacks/config/razzledazzle.xml | 66 + hacks/config/rd-bomb.xml | 67 + hacks/config/rdbomb.xml | 1 + hacks/config/ripples.xml | 55 + hacks/config/rocks.xml | 45 + hacks/config/romanboy.xml | 128 + hacks/config/rorschach.xml | 36 + hacks/config/rotor.xml | 40 + hacks/config/rotzoomer.xml | 43 + hacks/config/rubik.xml | 39 + hacks/config/rubikblocks.xml | 67 + hacks/config/sballs.xml | 37 + hacks/config/shadebobs.xml | 38 + hacks/config/sierpinski.xml | 37 + hacks/config/sierpinski3d.xml | 34 + hacks/config/skytentacles.xml | 71 + hacks/config/slidescreen.xml | 54 + hacks/config/slip.xml | 43 + hacks/config/sonar.xml | 85 + hacks/config/speedmine.xml | 62 + hacks/config/sphere.xml | 30 + hacks/config/spheremonics.xml | 60 + hacks/config/spiral.xml | 38 + hacks/config/splitflap.xml | 72 + hacks/config/splodesic.xml | 32 + hacks/config/spotlight.xml | 34 + hacks/config/sproingies.xml | 36 + hacks/config/squiral.xml | 51 + hacks/config/stairs.xml | 25 + hacks/config/starfish.xml | 43 + hacks/config/starwars.xml | 63 + hacks/config/stonerview.xml | 27 + hacks/config/strange.xml | 58 + hacks/config/substrate.xml | 47 + hacks/config/superquadrics.xml | 36 + hacks/config/surfaces.xml | 75 + hacks/config/swirl.xml | 33 + hacks/config/t3d.xml | 60 + hacks/config/tangram.xml | 45 + hacks/config/tessellimage.xml | 66 + hacks/config/testx11.xml | 17 + hacks/config/thornbird.xml | 37 + hacks/config/timetunnel.xml | 42 + hacks/config/topblock.xml | 64 + hacks/config/triangle.xml | 28 + hacks/config/tronbit.xml | 41 + hacks/config/truchet.xml | 41 + hacks/config/twang.xml | 61 + hacks/config/unicrud.xml | 44 + hacks/config/unknownpleasures.xml | 57 + hacks/config/vermiculate.xml | 22 + hacks/config/vfeedback.xml | 39 + hacks/config/vidwhacker.xml | 32 + hacks/config/vigilance.xml | 30 + hacks/config/vines.xml | 30 + hacks/config/voronoi.xml | 63 + hacks/config/wander.xml | 55 + hacks/config/webcollage.xml | 56 + hacks/config/whirlwindwarp.xml | 28 + hacks/config/whirlygig.xml | 90 + hacks/config/winduprobot.xml | 62 + hacks/config/worm.xml | 39 + hacks/config/wormhole.xml | 31 + hacks/config/xanalogtv.xml | 48 + hacks/config/xflame.xml | 34 + hacks/config/xjack.xml | 25 + hacks/config/xlyap.xml | 52 + hacks/config/xmatrix.xml | 68 + hacks/config/xrayswarm.xml | 23 + hacks/config/xspirograph.xml | 32 + hacks/config/xss.dtd | 109 + hacks/config/xss.xsd | 375 + hacks/config/zoom.xml | 54 + hacks/coral.c | 314 + hacks/coral.man | 64 + hacks/critical.c | 454 + hacks/critical.man | 94 + hacks/crystal.c | 1284 + hacks/crystal.man | 81 + hacks/cwaves.c | 212 + hacks/cwaves.man | 76 + hacks/cynosure.c | 443 + hacks/cynosure.man | 64 + hacks/decayscreen.c | 397 + hacks/decayscreen.man | 92 + hacks/deco.c | 339 + hacks/deco.man | 105 + hacks/delaunay.c | 301 + hacks/delaunay.h | 52 + hacks/deluxe.c | 465 + hacks/deluxe.man | 72 + hacks/demon.c | 952 + hacks/demon.man | 69 + hacks/discrete.c | 440 + hacks/discrete.man | 61 + hacks/distort.c | 864 + hacks/distort.man | 137 + hacks/drift.c | 672 + hacks/drift.man | 79 + hacks/epicycle.c | 794 + hacks/epicycle.man | 204 + hacks/eruption.c | 526 + hacks/eruption.man | 77 + hacks/euler2d.c | 887 + hacks/euler2d.man | 69 + hacks/euler2d.tex | 337 + hacks/fadeplot.c | 233 + hacks/fadeplot.man | 65 + hacks/fiberlamp.c | 474 + hacks/fiberlamp.man | 65 + hacks/filmleader.c | 571 + hacks/filmleader.man | 69 + hacks/fireworkx.c | 868 + hacks/fireworkx.man | 88 + hacks/flag.c | 565 + hacks/flag.man | 92 + hacks/flame.c | 466 + hacks/flame.man | 74 + hacks/flow.c | 1211 + hacks/flow.man | 137 + hacks/fluidballs.c | 852 + hacks/fluidballs.man | 90 + hacks/fontglide.c | 2489 + hacks/fontglide.man | 124 + hacks/forest.c | 244 + hacks/forest.man | 62 + hacks/fps.c | 268 + hacks/fps.h | 35 + hacks/fpsI.h | 40 + hacks/fuzzyflakes.c | 646 + hacks/fuzzyflakes.man | 112 + hacks/galaxy.c | 451 + hacks/galaxy.man | 87 + hacks/glitchpeg.c | 440 + hacks/glitchpeg.man | 79 + hacks/glx/Makefile.in | 3473 + hacks/glx/README | 10 + hacks/glx/antinspect.c | 704 + hacks/glx/antinspect.man | 56 + hacks/glx/antmaze.c | 1613 + hacks/glx/antmaze.man | 52 + hacks/glx/ants.h | 45 + hacks/glx/antspotlight.c | 799 + hacks/glx/antspotlight.man | 56 + hacks/glx/atlantis.c | 577 + hacks/glx/atlantis.h | 133 + hacks/glx/atlantis.man | 78 + hacks/glx/atunnel.c | 317 + hacks/glx/atunnel.man | 83 + hacks/glx/b_draw.c | 239 + hacks/glx/b_lockglue.c | 240 + hacks/glx/b_sphere.c | 219 + hacks/glx/blinkbox.c | 608 + hacks/glx/blinkbox.man | 73 + hacks/glx/blocktube.c | 457 + hacks/glx/blocktube.man | 73 + hacks/glx/boing.c | 658 + hacks/glx/boing.man | 105 + hacks/glx/bouncingcow.c | 519 + hacks/glx/bouncingcow.man | 73 + hacks/glx/boxed.c | 1370 + hacks/glx/boxed.h | 4116 + hacks/glx/boxed.man | 56 + hacks/glx/bubble3d.c | 281 + hacks/glx/bubble3d.h | 100 + hacks/glx/bubble3d.man | 62 + hacks/glx/buildlwo.c | 96 + hacks/glx/buildlwo.h | 43 + hacks/glx/cage.c | 480 + hacks/glx/cage.man | 61 + hacks/glx/carousel.c | 941 + hacks/glx/carousel.man | 109 + hacks/glx/chessgames.h | 343 + hacks/glx/chessmodels.c | 1738 + hacks/glx/chessmodels.h | 44 + hacks/glx/circuit.c | 2094 + hacks/glx/circuit.man | 72 + hacks/glx/cityflow.c | 545 + hacks/glx/cityflow.man | 77 + hacks/glx/companion.c | 592 + hacks/glx/companion_disc.c | 9593 ++ hacks/glx/companion_heart.c | 653 + hacks/glx/companion_quad.c | 389 + hacks/glx/companioncube.man | 85 + hacks/glx/cow_face.c | 341 + hacks/glx/cow_hide.c | 13055 ++ hacks/glx/cow_hoofs.c | 1037 + hacks/glx/cow_horns.c | 1025 + hacks/glx/cow_tail.c | 464 + hacks/glx/cow_udder.c | 1520 + hacks/glx/crackberg.c | 1468 + hacks/glx/crackberg.man | 123 + hacks/glx/crumbler.c | 875 + hacks/glx/crumbler.man | 77 + hacks/glx/cube21.c | 941 + hacks/glx/cube21.man | 147 + hacks/glx/cubenetic.c | 598 + hacks/glx/cubenetic.man | 89 + hacks/glx/cubestack.c | 462 + hacks/glx/cubestack.man | 72 + hacks/glx/cubestorm.c | 469 + hacks/glx/cubestorm.man | 77 + hacks/glx/cubetwist.c | 595 + hacks/glx/cubetwist.man | 80 + hacks/glx/cubicgrid.c | 269 + hacks/glx/cubicgrid.man | 83 + hacks/glx/curlicue.h | 261 + hacks/glx/dangerball.c | 364 + hacks/glx/dangerball.man | 72 + hacks/glx/discoball.c | 707 + hacks/glx/discoball.man | 72 + hacks/glx/dnalogo.c | 3639 + hacks/glx/dnapizza.h | 122 + hacks/glx/dolphin.c | 2061 + hacks/glx/dropshadow.c | 181 + hacks/glx/dropshadow.h | 40 + hacks/glx/dxf2gl.pl | 729 + hacks/glx/dymaxionmap-coords.c | 685 + hacks/glx/dymaxionmap-coords.h | 6 + hacks/glx/dymaxionmap.c | 1654 + hacks/glx/dymaxionmap.man | 117 + hacks/glx/e_textures.h | 1478 + hacks/glx/endgame.c | 971 + hacks/glx/endgame.man | 72 + hacks/glx/energystream.c | 534 + hacks/glx/energystream.man | 56 + hacks/glx/engine.c | 1006 + hacks/glx/engine.man | 80 + hacks/glx/erase-gl.c | 38 + hacks/glx/esper.c | 2412 + hacks/glx/esper.man | 68 + hacks/glx/extrusion-helix2.c | 47 + hacks/glx/extrusion-helix3.c | 46 + hacks/glx/extrusion-helix4.c | 63 + hacks/glx/extrusion-joinoffset.c | 148 + hacks/glx/extrusion-screw.c | 114 + hacks/glx/extrusion-taper.c | 218 + hacks/glx/extrusion-twistoid.c | 215 + hacks/glx/extrusion.c | 556 + hacks/glx/extrusion.h | 55 + hacks/glx/extrusion.man | 71 + hacks/glx/flipflop.c | 859 + hacks/glx/flipflop.man | 95 + hacks/glx/flipscreen3d.c | 518 + hacks/glx/flipscreen3d.man | 61 + hacks/glx/fliptext.c | 1001 + hacks/glx/fliptext.man | 114 + hacks/glx/flurry-smoke.c | 1441 + hacks/glx/flurry-spark.c | 285 + hacks/glx/flurry-star.c | 106 + hacks/glx/flurry-texture.c | 224 + hacks/glx/flurry.c | 549 + hacks/glx/flurry.h | 299 + hacks/glx/flurry.man | 73 + hacks/glx/flyingtoasters.c | 868 + hacks/glx/flyingtoasters.man | 86 + hacks/glx/fps-gl.c | 98 + hacks/glx/gears.c | 938 + hacks/glx/gears.man | 79 + hacks/glx/geodesic.c | 816 + hacks/glx/geodesic.man | 79 + hacks/glx/geodesicgears.c | 1803 + hacks/glx/geodesicgears.man | 78 + hacks/glx/gflux.c | 803 + hacks/glx/gflux.man | 111 + hacks/glx/glblur.c | 610 + hacks/glx/glblur.man | 76 + hacks/glx/glcells.c | 1388 + hacks/glx/glcells.man | 97 + hacks/glx/gleidescope.c | 1624 + hacks/glx/gleidescope.man | 77 + hacks/glx/glforestfire.c | 1097 + hacks/glx/glforestfire.man | 130 + hacks/glx/glhanoi.c | 2086 + hacks/glx/glhanoi.man | 83 + hacks/glx/glknots.c | 445 + hacks/glx/glknots.man | 81 + hacks/glx/gllist.c | 127 + hacks/glx/gllist.h | 44 + hacks/glx/glmatrix.c | 1068 + hacks/glx/glmatrix.man | 116 + hacks/glx/glplanet.c | 847 + hacks/glx/glplanet.man | 75 + hacks/glx/glschool.c | 216 + hacks/glx/glschool.h | 17 + hacks/glx/glschool.man | 126 + hacks/glx/glschool_alg.c | 364 + hacks/glx/glschool_alg.h | 126 + hacks/glx/glschool_gl.c | 274 + hacks/glx/glschool_gl.h | 51 + hacks/glx/glslideshow.c | 1222 + hacks/glx/glslideshow.man | 131 + hacks/glx/glsnake.c | 2694 + hacks/glx/glsnake.man | 98 + hacks/glx/gltext.c | 660 + hacks/glx/gltext.man | 152 + hacks/glx/gltrackball.c | 337 + hacks/glx/gltrackball.h | 72 + hacks/glx/glut_mroman.h | 2456 + hacks/glx/glut_roman.h | 2455 + hacks/glx/glut_stroke.c | 66 + hacks/glx/glut_swidth.c | 77 + hacks/glx/glutstroke.h | 47 + hacks/glx/grab-ximage.c | 813 + hacks/glx/grab-ximage.h | 76 + hacks/glx/hexstrut.c | 509 + hacks/glx/hexstrut.man | 77 + hacks/glx/hilbert.c | 1144 + hacks/glx/hilbert.man | 103 + hacks/glx/hydrostat.c | 809 + hacks/glx/hydrostat.man | 103 + hacks/glx/hypertorus.c | 1016 + hacks/glx/hypertorus.man | 188 + hacks/glx/hypnowheel.c | 322 + hacks/glx/hypnowheel.man | 80 + hacks/glx/involute.c | 998 + hacks/glx/involute.h | 78 + hacks/glx/jigglypuff.c | 1076 + hacks/glx/jigglypuff.man | 121 + hacks/glx/jigsaw.c | 1509 + hacks/glx/jigsaw.man | 90 + hacks/glx/juggler3d.c | 3022 + hacks/glx/juggler3d.man | 183 + hacks/glx/kaleidocycle.c | 574 + hacks/glx/kaleidocycle.man | 96 + hacks/glx/klein.c | 2099 + hacks/glx/klein.man | 308 + hacks/glx/lament.c | 1786 + hacks/glx/lament.dxf | 163404 +++++++++++++++++++++++ hacks/glx/lament.man | 68 + hacks/glx/lament_model.c | 16258 +++ hacks/glx/lavalite.c | 1539 + hacks/glx/lavalite.man | 160 + hacks/glx/lockward.c | 970 + hacks/glx/lockward.man | 79 + hacks/glx/marching.c | 645 + hacks/glx/marching.h | 48 + hacks/glx/maze3d.c | 1955 + hacks/glx/maze3d.man | 116 + hacks/glx/menger.c | 562 + hacks/glx/menger.man | 78 + hacks/glx/mirrorblob.c | 1841 + hacks/glx/mirrorblob.man | 107 + hacks/glx/moebius.c | 788 + hacks/glx/moebius.man | 65 + hacks/glx/moebiusgears.c | 437 + hacks/glx/moebiusgears.man | 86 + hacks/glx/molecule.c | 1682 + hacks/glx/molecule.man | 160 + hacks/glx/molecules.sh | 23 + hacks/glx/morph3d.c | 837 + hacks/glx/morph3d.man | 57 + hacks/glx/noof.c | 519 + hacks/glx/noof.man | 52 + hacks/glx/normals.c | 52 + hacks/glx/normals.h | 48 + hacks/glx/peepers.c | 1455 + hacks/glx/peepers.man | 80 + hacks/glx/photopile.c | 833 + hacks/glx/photopile.man | 113 + hacks/glx/pinion.c | 1470 + hacks/glx/pinion.man | 82 + hacks/glx/pipeobjs.c | 3262 + hacks/glx/pipes.c | 1220 + hacks/glx/pipes.man | 85 + hacks/glx/polyhedra-gl.c | 683 + hacks/glx/polyhedra.c | 2457 + hacks/glx/polyhedra.h | 52 + hacks/glx/polyhedra.man | 124 + hacks/glx/polytopes.c | 3189 + hacks/glx/polytopes.man | 207 + hacks/glx/projectiveplane.c | 1550 + hacks/glx/projectiveplane.man | 400 + hacks/glx/providence.c | 799 + hacks/glx/providence.man | 66 + hacks/glx/pulsar.c | 515 + hacks/glx/pulsar.man | 102 + hacks/glx/quasicrystal.c | 478 + hacks/glx/quasicrystal.man | 83 + hacks/glx/queens.c | 610 + hacks/glx/queens.man | 66 + hacks/glx/quickhull.c | 1368 + hacks/glx/quickhull.h | 56 + hacks/glx/raverhoop.c | 767 + hacks/glx/raverhoop.man | 83 + hacks/glx/razzledazzle.c | 725 + hacks/glx/razzledazzle.man | 76 + hacks/glx/robot-wireframe.c | 154 + hacks/glx/robot-wireframe.dxf | 1160 + hacks/glx/robot.c | 18539 +++ hacks/glx/robot.dxf | 185616 ++++++++++++++++++++++++++ hacks/glx/romanboy.c | 1552 + hacks/glx/romanboy.man | 390 + hacks/glx/rotator.c | 274 + hacks/glx/rotator.h | 60 + hacks/glx/rubik.c | 2140 + hacks/glx/rubik.man | 69 + hacks/glx/rubikblocks.c | 633 + hacks/glx/rubikblocks.man | 117 + hacks/glx/s1_1.c | 1733 + hacks/glx/s1_2.c | 1733 + hacks/glx/s1_3.c | 1733 + hacks/glx/s1_4.c | 1733 + hacks/glx/s1_5.c | 1733 + hacks/glx/s1_6.c | 1733 + hacks/glx/s1_b.c | 505 + hacks/glx/sballs.c | 823 + hacks/glx/sballs.man | 125 + hacks/glx/seccam.c | 1388 + hacks/glx/seccam.dxf | 13606 ++ hacks/glx/shark.c | 1395 + hacks/glx/ships.c | 4976 + hacks/glx/ships.dxf | 49148 +++++++ hacks/glx/sierpinski3d.c | 581 + hacks/glx/sierpinski3d.man | 67 + hacks/glx/skytentacles.c | 1103 + hacks/glx/skytentacles.man | 102 + hacks/glx/sonar-icmp.c | 1703 + hacks/glx/sonar-sim.c | 112 + hacks/glx/sonar.c | 1258 + hacks/glx/sonar.h | 71 + hacks/glx/sonar.man | 169 + hacks/glx/sphere.c | 155 + hacks/glx/sphere.h | 24 + hacks/glx/spheremonics.c | 882 + hacks/glx/spheremonics.man | 92 + hacks/glx/splitflap.c | 1408 + hacks/glx/splitflap.dxf | 1658 + hacks/glx/splitflap.man | 98 + hacks/glx/splitflap_obj.c | 200 + hacks/glx/splodesic.c | 640 + hacks/glx/splodesic.man | 69 + hacks/glx/sproingies.c | 906 + hacks/glx/sproingies.h | 43 + hacks/glx/sproingies.man | 68 + hacks/glx/sproingiewrap.c | 231 + hacks/glx/stairs.c | 589 + hacks/glx/stairs.man | 56 + hacks/glx/starwars.c | 1075 + hacks/glx/starwars.h | 363 + hacks/glx/starwars.man | 181 + hacks/glx/starwars.txt | 415 + hacks/glx/stonerview-move.c | 147 + hacks/glx/stonerview-move.h | 32 + hacks/glx/stonerview-osc.c | 341 + hacks/glx/stonerview-osc.h | 175 + hacks/glx/stonerview-view.c | 134 + hacks/glx/stonerview.c | 154 + hacks/glx/stonerview.h | 59 + hacks/glx/stonerview.man | 53 + hacks/glx/superquadrics.c | 807 + hacks/glx/superquadrics.man | 70 + hacks/glx/surfaces.c | 648 + hacks/glx/surfaces.man | 127 + hacks/glx/swim.c | 232 + hacks/glx/tangram.c | 1067 + hacks/glx/tangram.man | 67 + hacks/glx/tangram_shapes.c | 240 + hacks/glx/tangram_shapes.h | 15 + hacks/glx/teapot.c | 285 + hacks/glx/teapot.h | 7 + hacks/glx/teapot2.h | 6330 + hacks/glx/texfont.c | 961 + hacks/glx/texfont.h | 72 + hacks/glx/timetunnel.c | 1240 + hacks/glx/timetunnel.man | 105 + hacks/glx/toast.c | 190 + hacks/glx/toast.dxf | 1814 + hacks/glx/toast2.c | 214 + hacks/glx/toast2.dxf | 2054 + hacks/glx/toaster.c | 376 + hacks/glx/toaster.dxf | 3674 + hacks/glx/toaster_base.c | 130 + hacks/glx/toaster_base.dxf | 1214 + hacks/glx/toaster_handle.c | 64 + hacks/glx/toaster_handle.dxf | 554 + hacks/glx/toaster_handle2.c | 40 + hacks/glx/toaster_handle2.dxf | 314 + hacks/glx/toaster_jet.c | 178 + hacks/glx/toaster_jet.dxf | 1694 + hacks/glx/toaster_knob.c | 76 + hacks/glx/toaster_knob.dxf | 674 + hacks/glx/toaster_slots.c | 106 + hacks/glx/toaster_slots.dxf | 974 + hacks/glx/toaster_wing.c | 43 + hacks/glx/toaster_wing.dxf | 344 + hacks/glx/topblock.c | 883 + hacks/glx/topblock.h | 45 + hacks/glx/topblock.man | 170 + hacks/glx/trackball.c | 331 + hacks/glx/trackball.h | 82 + hacks/glx/tronbit.c | 536 + hacks/glx/tronbit.man | 79 + hacks/glx/tronbit_idle1.c | 247 + hacks/glx/tronbit_idle2.c | 175 + hacks/glx/tronbit_no.c | 1087 + hacks/glx/tronbit_yes.c | 31 + hacks/glx/tube.c | 403 + hacks/glx/tube.h | 32 + hacks/glx/tunnel_draw.c | 512 + hacks/glx/tunnel_draw.h | 11 + hacks/glx/unicrud.c | 961 + hacks/glx/unicrud.man | 74 + hacks/glx/unknownpleasures.c | 486 + hacks/glx/unknownpleasures.man | 74 + hacks/glx/vigilance.c | 1150 + hacks/glx/vigilance.man | 57 + hacks/glx/voronoi.c | 543 + hacks/glx/voronoi.man | 88 + hacks/glx/vrml2gl.pl | 361 + hacks/glx/wfront2gl.pl | 361 + hacks/glx/whale.c | 1887 + hacks/glx/winduprobot.c | 2483 + hacks/glx/winduprobot.man | 85 + hacks/glx/xlock-gl-utils.c | 230 + hacks/glx/xscreensaver-gl-helper.c | 74 + hacks/glx/xscreensaver-gl-helper.man | 33 + hacks/glx/zalgo.txt | 30 + hacks/goop.c | 650 + hacks/goop.man | 84 + hacks/grav.c | 356 + hacks/grav.man | 78 + hacks/greynetic.c | 296 + hacks/greynetic.man | 56 + hacks/halftone.c | 397 + hacks/halftone.man | 83 + hacks/halo.c | 440 + hacks/halo.man | 75 + hacks/helix.c | 356 + hacks/helix.man | 62 + hacks/hexadrop.c | 414 + hacks/hexadrop.man | 74 + hacks/hopalong.c | 555 + hacks/hopalong.man | 82 + hacks/hyperball.c | 2458 + hacks/hyperball.man | 88 + hacks/hypercube.c | 569 + hacks/hypercube.man | 97 + hacks/ifs.c | 551 + hacks/ifs.man | 111 + hacks/images/6x10font.png | Bin 0 -> 1968 bytes hacks/images/Makefile | 54 + hacks/images/Makefile.in | 54 + hacks/images/amiga.png | Bin 0 -> 1136 bytes hacks/images/android.png | Bin 0 -> 1091 bytes hacks/images/apple.png | Bin 0 -> 1562 bytes hacks/images/apple2font.png | Bin 0 -> 651 bytes hacks/images/atari.png | Bin 0 -> 148 bytes hacks/images/atm.png | Bin 0 -> 982 bytes hacks/images/blocktube.png | Bin 0 -> 23571 bytes hacks/images/bob.png | Bin 0 -> 1491 bytes hacks/images/brick1.png | Bin 0 -> 8544 bytes hacks/images/brick2.png | Bin 0 -> 688 bytes hacks/images/bubbles/blood.pov | 24 + hacks/images/bubbles/blood1.png | Bin 0 -> 583 bytes hacks/images/bubbles/blood10.png | Bin 0 -> 8605 bytes hacks/images/bubbles/blood11.png | Bin 0 -> 11682 bytes hacks/images/bubbles/blood2.png | Bin 0 -> 781 bytes hacks/images/bubbles/blood3.png | Bin 0 -> 1020 bytes hacks/images/bubbles/blood4.png | Bin 0 -> 1276 bytes hacks/images/bubbles/blood5.png | Bin 0 -> 1768 bytes hacks/images/bubbles/blood6.png | Bin 0 -> 2612 bytes hacks/images/bubbles/blood7.png | Bin 0 -> 3571 bytes hacks/images/bubbles/blood8.png | Bin 0 -> 5076 bytes hacks/images/bubbles/blood9.png | Bin 0 -> 6324 bytes hacks/images/bubbles/blue.pov | 22 + hacks/images/bubbles/blue1.png | Bin 0 -> 583 bytes hacks/images/bubbles/blue10.png | Bin 0 -> 7064 bytes hacks/images/bubbles/blue11.png | Bin 0 -> 9455 bytes hacks/images/bubbles/blue2.png | Bin 0 -> 781 bytes hacks/images/bubbles/blue3.png | Bin 0 -> 1018 bytes hacks/images/bubbles/blue4.png | Bin 0 -> 1184 bytes hacks/images/bubbles/blue5.png | Bin 0 -> 1626 bytes hacks/images/bubbles/blue6.png | Bin 0 -> 2354 bytes hacks/images/bubbles/blue7.png | Bin 0 -> 3133 bytes hacks/images/bubbles/blue8.png | Bin 0 -> 4300 bytes hacks/images/bubbles/blue9.png | Bin 0 -> 5286 bytes hacks/images/bubbles/glass.pov | 27 + hacks/images/bubbles/glass1.png | Bin 0 -> 583 bytes hacks/images/bubbles/glass10.png | Bin 0 -> 6805 bytes hacks/images/bubbles/glass11.png | Bin 0 -> 9200 bytes hacks/images/bubbles/glass2.png | Bin 0 -> 781 bytes hacks/images/bubbles/glass3.png | Bin 0 -> 1018 bytes hacks/images/bubbles/glass4.png | Bin 0 -> 1045 bytes hacks/images/bubbles/glass5.png | Bin 0 -> 1425 bytes hacks/images/bubbles/glass6.png | Bin 0 -> 2110 bytes hacks/images/bubbles/glass7.png | Bin 0 -> 2856 bytes hacks/images/bubbles/glass8.png | Bin 0 -> 4014 bytes hacks/images/bubbles/glass9.png | Bin 0 -> 4996 bytes hacks/images/bubbles/jade.pov | 24 + hacks/images/bubbles/jade1.png | Bin 0 -> 583 bytes hacks/images/bubbles/jade10.png | Bin 0 -> 7853 bytes hacks/images/bubbles/jade11.png | Bin 0 -> 10816 bytes hacks/images/bubbles/jade2.png | Bin 0 -> 781 bytes hacks/images/bubbles/jade3.png | Bin 0 -> 1018 bytes hacks/images/bubbles/jade4.png | Bin 0 -> 1202 bytes hacks/images/bubbles/jade5.png | Bin 0 -> 1670 bytes hacks/images/bubbles/jade6.png | Bin 0 -> 2416 bytes hacks/images/bubbles/jade7.png | Bin 0 -> 3255 bytes hacks/images/bubbles/jade8.png | Bin 0 -> 4670 bytes hacks/images/bubbles/jade9.png | Bin 0 -> 5758 bytes hacks/images/chromesphere.png | Bin 0 -> 33091 bytes hacks/images/earth.png | Bin 0 -> 433159 bytes hacks/images/earth_flat.png | Bin 0 -> 16698 bytes hacks/images/earth_night.png | Bin 0 -> 390020 bytes hacks/images/ground.png | Bin 0 -> 13299 bytes hacks/images/hmac.png | Bin 0 -> 439 bytes hacks/images/iris.png | Bin 0 -> 143843 bytes hacks/images/jigglymap.png | Bin 0 -> 29863 bytes hacks/images/lament512.png | Bin 0 -> 566651 bytes hacks/images/logo-180.png | Bin 0 -> 8734 bytes hacks/images/logo-32.png | Bin 0 -> 1614 bytes hacks/images/logo-50.png | Bin 0 -> 2030 bytes hacks/images/m6502/amiga.asm | 120 + hacks/images/m6502/breakout.asm | 195 + hacks/images/m6502/byterun.asm | 100 + hacks/images/m6502/cellular-30.asm | 67 + hacks/images/m6502/cellular-600.asm | 209 + hacks/images/m6502/colors.asm | 46 + hacks/images/m6502/crunch6502.asm | 292 + hacks/images/m6502/demoscene.asm | 457 + hacks/images/m6502/disco.asm | 23 + hacks/images/m6502/dmsc.asm | 130 + hacks/images/m6502/dmsc.txt | 768 + hacks/images/m6502/dragon-fractal.asm | 49 + hacks/images/m6502/fullscreenlogo.asm | 107 + hacks/images/m6502/greynetic.asm | 96 + hacks/images/m6502/keftal.asm | 82 + hacks/images/m6502/life.asm | 127 + hacks/images/m6502/lines.asm | 313 + hacks/images/m6502/matrix.asm | 67 + hacks/images/m6502/noise.asm | 16 + hacks/images/m6502/random-walk.asm | 82 + hacks/images/m6502/random.asm | 11 + hacks/images/m6502/random2.asm | 11 + hacks/images/m6502/rorschach.asm | 124 + hacks/images/m6502/santa.asm | 142 + hacks/images/m6502/selfmodify.asm | 12 + hacks/images/m6502/sflake.asm | 320 + hacks/images/m6502/sierpinski.asm | 24 + hacks/images/m6502/sierpinsky.asm | 131 + hacks/images/m6502/softsprite.asm | 132 + hacks/images/m6502/spacer.asm | 235 + hacks/images/m6502/starfield2d.asm | 50 + hacks/images/m6502/texture.asm | 393 + hacks/images/m6502/wave6502.asm | 164 + hacks/images/m6502/zookeeper.asm | 109 + hacks/images/mac.png | Bin 0 -> 211 bytes hacks/images/macbomb.png | Bin 0 -> 697 bytes hacks/images/matrix1.png | Bin 0 -> 29412 bytes hacks/images/matrix1b.png | Bin 0 -> 11525 bytes hacks/images/matrix2.png | Bin 0 -> 27982 bytes hacks/images/matrix2b.png | Bin 0 -> 11468 bytes hacks/images/matrix3.png | Bin 0 -> 125539 bytes hacks/images/molecules/adenine.pdb | 37 + hacks/images/molecules/adrenochrome.pdb | 55 + hacks/images/molecules/bucky.pdb | 156 + hacks/images/molecules/caffeine.pdb | 54 + hacks/images/molecules/capsaicin.pdb | 49 + hacks/images/molecules/chlordecone.pdb | 49 + hacks/images/molecules/cocaine.pdb | 93 + hacks/images/molecules/codeine.pdb | 93 + hacks/images/molecules/cyclohexane.pdb | 151 + hacks/images/molecules/cytosine.pdb | 33 + hacks/images/molecules/dna.pdb | 972 + hacks/images/molecules/dodecahedrane.pdb | 87 + hacks/images/molecules/dthc.pdb | 107 + hacks/images/molecules/dynamite.pdb | 47 + hacks/images/molecules/glycol.pdb | 27 + hacks/images/molecules/guanine.pdb | 39 + hacks/images/molecules/heroin.pdb | 107 + hacks/images/molecules/hexahelicene.pdb | 90 + hacks/images/molecules/ibuprofen.pdb | 72 + hacks/images/molecules/lsd.pdb | 104 + hacks/images/molecules/menthol.pdb | 69 + hacks/images/molecules/mescaline.pdb | 71 + hacks/images/molecules/methamphetamine.pdb | 88 + hacks/images/molecules/morphine.pdb | 87 + hacks/images/molecules/nicotine.pdb | 59 + hacks/images/molecules/novocaine.pdb | 81 + hacks/images/molecules/olestra.pdb | 913 + hacks/images/molecules/penicillin.pdb | 89 + hacks/images/molecules/salvinorin.pdb | 92 + hacks/images/molecules/sarin.pdb | 43 + hacks/images/molecules/strychnine.pdb | 101 + hacks/images/molecules/sucrose.pdb | 97 + hacks/images/molecules/thalidomide.pdb | 65 + hacks/images/molecules/thymine.pdb | 37 + hacks/images/molecules/viagra.pdb | 133 + hacks/images/molecules/vitaminb6.pdb | 56 + hacks/images/molecules/vitaminc.pdb | 47 + hacks/images/molecules/vx.pdb | 92 + hacks/images/noseguy/nose-f1.png | Bin 0 -> 454 bytes hacks/images/noseguy/nose-f2.png | Bin 0 -> 397 bytes hacks/images/noseguy/nose-f3.png | Bin 0 -> 396 bytes hacks/images/noseguy/nose-f4.png | Bin 0 -> 448 bytes hacks/images/noseguy/nose-l1.png | Bin 0 -> 388 bytes hacks/images/noseguy/nose-l2.png | Bin 0 -> 470 bytes hacks/images/noseguy/nose-r1.png | Bin 0 -> 386 bytes hacks/images/noseguy/nose-r2.png | Bin 0 -> 467 bytes hacks/images/osx_10_2.png | Bin 0 -> 53621 bytes hacks/images/osx_10_3.png | Bin 0 -> 28292 bytes hacks/images/pacman.png | Bin 0 -> 2695 bytes hacks/images/ransomware.png | Bin 0 -> 976 bytes hacks/images/sball-bg.png | Bin 0 -> 31249 bytes hacks/images/sball.png | Bin 0 -> 2334 bytes hacks/images/scales.png | Bin 0 -> 8573 bytes hacks/images/sclera.png | Bin 0 -> 230321 bytes hacks/images/sea-texture.png | Bin 0 -> 6933 bytes hacks/images/som.png | Bin 0 -> 7593 bytes hacks/images/start.png | Bin 0 -> 1153 bytes hacks/images/testcard_bbcf.png | Bin 0 -> 67094 bytes hacks/images/testcard_pm5544.png | Bin 0 -> 20774 bytes hacks/images/testcard_rca.png | Bin 0 -> 96263 bytes hacks/images/timetunnel0.png | Bin 0 -> 35798 bytes hacks/images/timetunnel1.png | Bin 0 -> 131957 bytes hacks/images/timetunnel2.png | Bin 0 -> 50547 bytes hacks/images/toast.png | Bin 0 -> 11667 bytes hacks/images/tree.png | Bin 0 -> 5944 bytes hacks/images/tunnel0.png | Bin 0 -> 6996 bytes hacks/images/tunnel1.png | Bin 0 -> 3449 bytes hacks/images/tunnel2.png | Bin 0 -> 11424 bytes hacks/images/tunnel3.png | Bin 0 -> 6725 bytes hacks/images/tunnel4.png | Bin 0 -> 3297 bytes hacks/images/tunnel5.png | Bin 0 -> 3340 bytes hacks/images/tunnelstar.png | Bin 0 -> 23414 bytes hacks/images/win10_spinner.gif | Bin 0 -> 64501 bytes hacks/images/wood.png | Bin 0 -> 2130 bytes hacks/images/wood2.png | Bin 0 -> 3274 bytes hacks/imsmap.c | 420 + hacks/imsmap.man | 64 + hacks/interaggregate.c | 981 + hacks/interaggregate.man | 72 + hacks/interference.c | 1001 + hacks/interference.man | 86 + hacks/intermomentary.c | 577 + hacks/intermomentary.man | 82 + hacks/juggle.c | 2796 + hacks/juggle.man | 181 + hacks/julia.c | 442 + hacks/julia.man | 81 + hacks/kaleidescope.c | 490 + hacks/kaleidescope.man | 89 + hacks/kumppa.c | 537 + hacks/kumppa.man | 65 + hacks/laser.c | 355 + hacks/laser.man | 68 + hacks/lcdscrub.c | 401 + hacks/lcdscrub.man | 73 + hacks/lightning.c | 601 + hacks/lightning.man | 62 + hacks/link_axp.com | 107 + hacks/link_decc.com | 107 + hacks/lisa.c | 739 + hacks/lisa.man | 71 + hacks/lissie.c | 322 + hacks/lissie.man | 69 + hacks/ljlatest | 1 + hacks/ljlatest.man | 61 + hacks/lmorph.c | 568 + hacks/lmorph.man | 65 + hacks/loop.c | 1694 + hacks/loop.man | 65 + hacks/m6502.c | 307 + hacks/m6502.sh | 26 + hacks/maze.c | 1661 + hacks/maze.man | 148 + hacks/memscroller.c | 636 + hacks/memscroller.man | 78 + hacks/metaballs.c | 436 + hacks/metaballs.man | 73 + hacks/moire.c | 245 + hacks/moire.man | 68 + hacks/moire2.c | 356 + hacks/moire2.man | 63 + hacks/mountain.c | 282 + hacks/mountain.man | 60 + hacks/munch.c | 476 + hacks/munch.man | 153 + hacks/munge-ad.pl | 237 + hacks/nerverot.c | 1354 + hacks/nerverot.man | 132 + hacks/noseguy.c | 689 + hacks/noseguy.man | 84 + hacks/pacman.c | 1467 + hacks/pacman.h | 220 + hacks/pacman.man | 67 + hacks/pacman_ai.c | 876 + hacks/pacman_ai.h | 32 + hacks/pacman_level.c | 772 + hacks/pacman_level.h | 33 + hacks/pedal.c | 335 + hacks/pedal.man | 60 + hacks/penetrate.c | 977 + hacks/penetrate.man | 98 + hacks/penrose.c | 1352 + hacks/penrose.man | 106 + hacks/petri.c | 761 + hacks/petri.man | 129 + hacks/phosphor.c | 1451 + hacks/phosphor.man | 173 + hacks/piecewise.c | 1006 + hacks/piecewise.man | 77 + hacks/polyominoes.c | 2368 + hacks/polyominoes.man | 65 + hacks/pong.c | 1118 + hacks/pong.man | 86 + hacks/popsquares.c | 306 + hacks/pyro.c | 368 + hacks/pyro.man | 64 + hacks/qix.c | 624 + hacks/qix.man | 132 + hacks/rd-bomb.c | 549 + hacks/rd-bomb.man | 100 + hacks/recanim.c | 413 + hacks/recanim.h | 36 + hacks/ripples.c | 1118 + hacks/ripples.man | 96 + hacks/rocks.c | 550 + hacks/rocks.man | 90 + hacks/rorschach.c | 214 + hacks/rorschach.man | 75 + hacks/rotor.c | 389 + hacks/rotor.man | 68 + hacks/rotzoomer.c | 585 + hacks/rotzoomer.man | 88 + hacks/screenhack.c | 984 + hacks/screenhack.h | 67 + hacks/screenhackI.h | 162 + hacks/shadebobs.c | 471 + hacks/shadebobs.man | 65 + hacks/sierpinski.c | 213 + hacks/sierpinski.man | 69 + hacks/slidescreen.c | 510 + hacks/slidescreen.man | 97 + hacks/slip.c | 375 + hacks/slip.man | 86 + hacks/speedmine.c | 1647 + hacks/speedmine.man | 246 + hacks/sphere.c | 303 + hacks/sphere.man | 62 + hacks/spiral.c | 330 + hacks/spiral.man | 71 + hacks/spotlight.c | 353 + hacks/spotlight.man | 80 + hacks/squiral.c | 290 + hacks/squiral.man | 80 + hacks/starfish.c | 559 + hacks/starfish.man | 84 + hacks/strange.c | 1341 + hacks/strange.man | 79 + hacks/substrate.c | 773 + hacks/substrate.man | 73 + hacks/swirl.c | 1445 + hacks/swirl.man | 70 + hacks/t3d.c | 980 + hacks/t3d.man | 131 + hacks/tessellimage.c | 1013 + hacks/tessellimage.man | 86 + hacks/testx11.c | 968 + hacks/thornbird.c | 264 + hacks/thornbird.man | 64 + hacks/triangle.c | 354 + hacks/triangle.man | 56 + hacks/truchet.c | 536 + hacks/truchet.man | 139 + hacks/twang.c | 775 + hacks/twang.man | 132 + hacks/vermiculate.c | 1221 + hacks/vermiculate.man | 48 + hacks/vfeedback.c | 628 + hacks/vfeedback.man | 71 + hacks/vidwhacker | 506 + hacks/vidwhacker.man | 89 + hacks/vines.c | 179 + hacks/vines.man | 66 + hacks/vms_axp.opt | 4 + hacks/vms_axp_12.opt | 4 + hacks/vms_decc.opt | 4 + hacks/vms_decc_12.opt | 4 + hacks/wander.c | 280 + hacks/wander.man | 76 + hacks/webcollage | 4048 + hacks/webcollage-cocoa.m | 428 + hacks/webcollage-helper-cocoa.m | 510 + hacks/webcollage-helper.c | 592 + hacks/webcollage.man | 247 + hacks/whirlwindwarp.c | 506 + hacks/whirlwindwarp.man | 64 + hacks/whirlygig.c | 733 + hacks/whirlygig.man | 137 + hacks/worm.c | 433 + hacks/worm.man | 65 + hacks/wormhole.c | 725 + hacks/wormhole.man | 69 + hacks/xanalogtv.c | 654 + hacks/xanalogtv.man | 84 + hacks/xflame.c | 819 + hacks/xflame.man | 72 + hacks/ximage-loader.c | 686 + hacks/ximage-loader.h | 37 + hacks/xjack.c | 487 + hacks/xjack.man | 52 + hacks/xlockmore.c | 773 + hacks/xlockmore.h | 255 + hacks/xlockmoreI.h | 177 + hacks/xlyap.c | 1932 + hacks/xlyap.man | 223 + hacks/xmatrix.c | 1856 + hacks/xmatrix.man | 146 + hacks/xml2man.pl | 266 + hacks/xrayswarm.c | 1224 + hacks/xrayswarm.man | 50 + hacks/xscreensaver-sgigl.c | 266 + hacks/xspirograph.c | 333 + hacks/xspirograph.man | 71 + hacks/xsublim.c | 799 + hacks/xsublim.man | 91 + hacks/zoom.c | 291 + hacks/zoom.man | 111 + 1163 files changed, 866018 insertions(+) create mode 100644 hacks/.gdbinit create mode 100644 hacks/Makefile.in create mode 100644 hacks/README create mode 100644 hacks/abstractile.c create mode 100644 hacks/abstractile.man create mode 100644 hacks/analogtv.c create mode 100644 hacks/analogtv.h create mode 100644 hacks/anemone.c create mode 100644 hacks/anemone.man create mode 100644 hacks/anemotaxis.c create mode 100644 hacks/anemotaxis.man create mode 100644 hacks/ant.c create mode 100644 hacks/ant.man create mode 100644 hacks/apollonian.c create mode 100644 hacks/apollonian.man create mode 100644 hacks/apple2-main.c create mode 100644 hacks/apple2.c create mode 100644 hacks/apple2.h create mode 100644 hacks/apple2.man create mode 100644 hacks/asm6502.c create mode 100644 hacks/asm6502.h create mode 100644 hacks/attraction.c create mode 100644 hacks/attraction.man create mode 100644 hacks/automata.h create mode 100644 hacks/barcode.c create mode 100644 hacks/barcode.man create mode 100644 hacks/binaryring.c create mode 100644 hacks/binaryring.man create mode 100644 hacks/blaster.c create mode 100644 hacks/blaster.man create mode 100644 hacks/blitspin.c create mode 100644 hacks/blitspin.man create mode 100644 hacks/bouboule.c create mode 100644 hacks/bouboule.man create mode 100644 hacks/boxfit.c create mode 100644 hacks/boxfit.man create mode 100644 hacks/braid.c create mode 100644 hacks/braid.man create mode 100644 hacks/bsod.c create mode 100644 hacks/bsod.man create mode 100644 hacks/bubbles-default.c create mode 100644 hacks/bubbles.c create mode 100644 hacks/bubbles.h create mode 100644 hacks/bubbles.man create mode 100644 hacks/bumps.c create mode 100644 hacks/bumps.man create mode 100644 hacks/ccurve.c create mode 100644 hacks/ccurve.man create mode 100644 hacks/celtic.c create mode 100644 hacks/celtic.man create mode 100755 hacks/check-configs.pl create mode 100644 hacks/cloudlife.c create mode 100644 hacks/cloudlife.man create mode 100644 hacks/compass.c create mode 100644 hacks/compass.man create mode 100644 hacks/compile_axp.com create mode 100644 hacks/compile_decc.com create mode 100644 hacks/config/README create mode 100644 hacks/config/abstractile.xml create mode 100644 hacks/config/anemone.xml create mode 100644 hacks/config/anemotaxis.xml create mode 100644 hacks/config/ant.xml create mode 100644 hacks/config/antinspect.xml create mode 100644 hacks/config/antmaze.xml create mode 100644 hacks/config/antspotlight.xml create mode 100644 hacks/config/apollonian.xml create mode 100644 hacks/config/apple2.xml create mode 100644 hacks/config/atlantis.xml create mode 100644 hacks/config/attraction.xml create mode 100644 hacks/config/atunnel.xml create mode 100644 hacks/config/barcode.xml create mode 100644 hacks/config/binaryring.xml create mode 100644 hacks/config/blaster.xml create mode 100644 hacks/config/blinkbox.xml create mode 100644 hacks/config/blitspin.xml create mode 100644 hacks/config/blocktube.xml create mode 100644 hacks/config/boing.xml create mode 100644 hacks/config/bouboule.xml create mode 100644 hacks/config/bouncingcow.xml create mode 100644 hacks/config/boxed.xml create mode 100644 hacks/config/boxfit.xml create mode 100644 hacks/config/braid.xml create mode 100644 hacks/config/bsod.xml create mode 100644 hacks/config/bubble3d.xml create mode 100644 hacks/config/bubbles.xml create mode 100644 hacks/config/bumps.xml create mode 100644 hacks/config/cage.xml create mode 100644 hacks/config/carousel.xml create mode 100644 hacks/config/ccurve.xml create mode 100644 hacks/config/celtic.xml create mode 100644 hacks/config/circuit.xml create mode 100644 hacks/config/cityflow.xml create mode 100644 hacks/config/cloudlife.xml create mode 100644 hacks/config/companioncube.xml create mode 100644 hacks/config/compass.xml create mode 100644 hacks/config/coral.xml create mode 100644 hacks/config/crackberg.xml create mode 100644 hacks/config/critical.xml create mode 100644 hacks/config/crumbler.xml create mode 100644 hacks/config/crystal.xml create mode 100644 hacks/config/cube21.xml create mode 100644 hacks/config/cubenetic.xml create mode 100644 hacks/config/cubestack.xml create mode 100644 hacks/config/cubestorm.xml create mode 100644 hacks/config/cubetwist.xml create mode 100644 hacks/config/cubicgrid.xml create mode 100644 hacks/config/cwaves.xml create mode 100644 hacks/config/cynosure.xml create mode 100644 hacks/config/dangerball.xml create mode 100644 hacks/config/decayscreen.xml create mode 100644 hacks/config/deco.xml create mode 100644 hacks/config/deluxe.xml create mode 100644 hacks/config/demon.xml create mode 100644 hacks/config/discoball.xml create mode 100644 hacks/config/discrete.xml create mode 100644 hacks/config/distort.xml create mode 100644 hacks/config/dnalogo.xml create mode 100644 hacks/config/drift.xml create mode 100644 hacks/config/dymaxionmap.xml create mode 100644 hacks/config/endgame.xml create mode 100644 hacks/config/energystream.xml create mode 100644 hacks/config/engine.xml create mode 100644 hacks/config/epicycle.xml create mode 100644 hacks/config/eruption.xml create mode 100644 hacks/config/esper.xml create mode 100644 hacks/config/euler2d.xml create mode 100644 hacks/config/extrusion.xml create mode 100644 hacks/config/fadeplot.xml create mode 100644 hacks/config/fiberlamp.xml create mode 100644 hacks/config/filmleader.xml create mode 100644 hacks/config/fireworkx.xml create mode 100644 hacks/config/flag.xml create mode 100644 hacks/config/flame.xml create mode 100644 hacks/config/flipflop.xml create mode 100644 hacks/config/flipscreen3d.xml create mode 100644 hacks/config/fliptext.xml create mode 100644 hacks/config/flow.xml create mode 100644 hacks/config/fluidballs.xml create mode 100644 hacks/config/flurry.xml create mode 100644 hacks/config/flyingtoasters.xml create mode 100644 hacks/config/fontglide.xml create mode 100644 hacks/config/forest.xml create mode 100644 hacks/config/fuzzyflakes.xml create mode 100644 hacks/config/galaxy.xml create mode 100644 hacks/config/gears.xml create mode 100644 hacks/config/geodesic.xml create mode 100644 hacks/config/geodesicgears.xml create mode 100644 hacks/config/gflux.xml create mode 100644 hacks/config/glblur.xml create mode 100644 hacks/config/glcells.xml create mode 100644 hacks/config/gleidescope.xml create mode 100644 hacks/config/glforestfire.xml create mode 100644 hacks/config/glhanoi.xml create mode 100644 hacks/config/glitchpeg.xml create mode 100644 hacks/config/glknots.xml create mode 100644 hacks/config/glmatrix.xml create mode 100644 hacks/config/glplanet.xml create mode 100644 hacks/config/glschool.xml create mode 100644 hacks/config/glslideshow.xml create mode 100644 hacks/config/glsnake.xml create mode 100644 hacks/config/gltext.xml create mode 100644 hacks/config/goop.xml create mode 100644 hacks/config/grav.xml create mode 100644 hacks/config/greynetic.xml create mode 100644 hacks/config/halftone.xml create mode 100644 hacks/config/halo.xml create mode 100644 hacks/config/helix.xml create mode 100644 hacks/config/hexadrop.xml create mode 100644 hacks/config/hexstrut.xml create mode 100644 hacks/config/hilbert.xml create mode 100644 hacks/config/hopalong.xml create mode 100644 hacks/config/hydrostat.xml create mode 100644 hacks/config/hyperball.xml create mode 100644 hacks/config/hypercube.xml create mode 100644 hacks/config/hypertorus.xml create mode 100644 hacks/config/hypnowheel.xml create mode 100644 hacks/config/ifs.xml create mode 100644 hacks/config/imsmap.xml create mode 100644 hacks/config/interaggregate.xml create mode 100644 hacks/config/interference.xml create mode 100644 hacks/config/intermomentary.xml create mode 100644 hacks/config/jigglypuff.xml create mode 100644 hacks/config/jigsaw.xml create mode 100644 hacks/config/juggle.xml create mode 100644 hacks/config/juggler3d.xml create mode 100644 hacks/config/julia.xml create mode 100644 hacks/config/kaleidescope.xml create mode 100644 hacks/config/kaleidocycle.xml create mode 100644 hacks/config/klein.xml create mode 100644 hacks/config/kumppa.xml create mode 100644 hacks/config/lament.xml create mode 100644 hacks/config/laser.xml create mode 100644 hacks/config/lavalite.xml create mode 100644 hacks/config/lcdscrub.xml create mode 100644 hacks/config/lightning.xml create mode 100644 hacks/config/lisa.xml create mode 100644 hacks/config/lissie.xml create mode 100644 hacks/config/lmorph.xml create mode 100644 hacks/config/lockward.xml create mode 100644 hacks/config/loop.xml create mode 100644 hacks/config/m6502.xml create mode 100644 hacks/config/maze.xml create mode 100755 hacks/config/maze3d.xml create mode 100644 hacks/config/memscroller.xml create mode 100644 hacks/config/menger.xml create mode 100644 hacks/config/metaballs.xml create mode 100644 hacks/config/mirrorblob.xml create mode 100644 hacks/config/mismunch.xml create mode 100644 hacks/config/moebius.xml create mode 100644 hacks/config/moebiusgears.xml create mode 100644 hacks/config/moire.xml create mode 100644 hacks/config/moire2.xml create mode 100644 hacks/config/molecule.xml create mode 100644 hacks/config/morph3d.xml create mode 100644 hacks/config/mountain.xml create mode 100644 hacks/config/munch.xml create mode 100644 hacks/config/nerverot.xml create mode 100644 hacks/config/noof.xml create mode 100644 hacks/config/noseguy.xml create mode 100644 hacks/config/pacman.xml create mode 100644 hacks/config/pedal.xml create mode 100644 hacks/config/peepers.xml create mode 100644 hacks/config/penetrate.xml create mode 100644 hacks/config/penrose.xml create mode 100644 hacks/config/petri.xml create mode 100644 hacks/config/phosphor.xml create mode 100644 hacks/config/photopile.xml create mode 100644 hacks/config/piecewise.xml create mode 100644 hacks/config/pinion.xml create mode 100644 hacks/config/pipes.xml create mode 100644 hacks/config/polyhedra.xml create mode 100644 hacks/config/polyominoes.xml create mode 100644 hacks/config/polytopes.xml create mode 100644 hacks/config/pong.xml create mode 100644 hacks/config/popsquares.xml create mode 100644 hacks/config/projectiveplane.xml create mode 100644 hacks/config/providence.xml create mode 100644 hacks/config/pulsar.xml create mode 100644 hacks/config/pyro.xml create mode 100644 hacks/config/qix.xml create mode 100644 hacks/config/quasicrystal.xml create mode 100644 hacks/config/queens.xml create mode 100644 hacks/config/raverhoop.xml create mode 100644 hacks/config/razzledazzle.xml create mode 100644 hacks/config/rd-bomb.xml create mode 120000 hacks/config/rdbomb.xml create mode 100644 hacks/config/ripples.xml create mode 100644 hacks/config/rocks.xml create mode 100644 hacks/config/romanboy.xml create mode 100644 hacks/config/rorschach.xml create mode 100644 hacks/config/rotor.xml create mode 100644 hacks/config/rotzoomer.xml create mode 100644 hacks/config/rubik.xml create mode 100644 hacks/config/rubikblocks.xml create mode 100644 hacks/config/sballs.xml create mode 100644 hacks/config/shadebobs.xml create mode 100644 hacks/config/sierpinski.xml create mode 100644 hacks/config/sierpinski3d.xml create mode 100644 hacks/config/skytentacles.xml create mode 100644 hacks/config/slidescreen.xml create mode 100644 hacks/config/slip.xml create mode 100644 hacks/config/sonar.xml create mode 100644 hacks/config/speedmine.xml create mode 100644 hacks/config/sphere.xml create mode 100644 hacks/config/spheremonics.xml create mode 100644 hacks/config/spiral.xml create mode 100644 hacks/config/splitflap.xml create mode 100644 hacks/config/splodesic.xml create mode 100644 hacks/config/spotlight.xml create mode 100644 hacks/config/sproingies.xml create mode 100644 hacks/config/squiral.xml create mode 100644 hacks/config/stairs.xml create mode 100644 hacks/config/starfish.xml create mode 100644 hacks/config/starwars.xml create mode 100644 hacks/config/stonerview.xml create mode 100644 hacks/config/strange.xml create mode 100644 hacks/config/substrate.xml create mode 100644 hacks/config/superquadrics.xml create mode 100644 hacks/config/surfaces.xml create mode 100644 hacks/config/swirl.xml create mode 100644 hacks/config/t3d.xml create mode 100644 hacks/config/tangram.xml create mode 100644 hacks/config/tessellimage.xml create mode 100644 hacks/config/testx11.xml create mode 100644 hacks/config/thornbird.xml create mode 100644 hacks/config/timetunnel.xml create mode 100644 hacks/config/topblock.xml create mode 100644 hacks/config/triangle.xml create mode 100644 hacks/config/tronbit.xml create mode 100644 hacks/config/truchet.xml create mode 100644 hacks/config/twang.xml create mode 100644 hacks/config/unicrud.xml create mode 100644 hacks/config/unknownpleasures.xml create mode 100644 hacks/config/vermiculate.xml create mode 100644 hacks/config/vfeedback.xml create mode 100644 hacks/config/vidwhacker.xml create mode 100644 hacks/config/vigilance.xml create mode 100644 hacks/config/vines.xml create mode 100644 hacks/config/voronoi.xml create mode 100644 hacks/config/wander.xml create mode 100644 hacks/config/webcollage.xml create mode 100644 hacks/config/whirlwindwarp.xml create mode 100644 hacks/config/whirlygig.xml create mode 100644 hacks/config/winduprobot.xml create mode 100644 hacks/config/worm.xml create mode 100644 hacks/config/wormhole.xml create mode 100644 hacks/config/xanalogtv.xml create mode 100644 hacks/config/xflame.xml create mode 100644 hacks/config/xjack.xml create mode 100644 hacks/config/xlyap.xml create mode 100644 hacks/config/xmatrix.xml create mode 100644 hacks/config/xrayswarm.xml create mode 100644 hacks/config/xspirograph.xml create mode 100644 hacks/config/xss.dtd create mode 100644 hacks/config/xss.xsd create mode 100644 hacks/config/zoom.xml create mode 100644 hacks/coral.c create mode 100644 hacks/coral.man create mode 100644 hacks/critical.c create mode 100644 hacks/critical.man create mode 100644 hacks/crystal.c create mode 100644 hacks/crystal.man create mode 100644 hacks/cwaves.c create mode 100644 hacks/cwaves.man create mode 100644 hacks/cynosure.c create mode 100644 hacks/cynosure.man create mode 100644 hacks/decayscreen.c create mode 100644 hacks/decayscreen.man create mode 100644 hacks/deco.c create mode 100644 hacks/deco.man create mode 100644 hacks/delaunay.c create mode 100644 hacks/delaunay.h create mode 100644 hacks/deluxe.c create mode 100644 hacks/deluxe.man create mode 100644 hacks/demon.c create mode 100644 hacks/demon.man create mode 100644 hacks/discrete.c create mode 100644 hacks/discrete.man create mode 100644 hacks/distort.c create mode 100644 hacks/distort.man create mode 100644 hacks/drift.c create mode 100644 hacks/drift.man create mode 100644 hacks/epicycle.c create mode 100644 hacks/epicycle.man create mode 100644 hacks/eruption.c create mode 100644 hacks/eruption.man create mode 100644 hacks/euler2d.c create mode 100644 hacks/euler2d.man create mode 100644 hacks/euler2d.tex create mode 100644 hacks/fadeplot.c create mode 100644 hacks/fadeplot.man create mode 100644 hacks/fiberlamp.c create mode 100644 hacks/fiberlamp.man create mode 100644 hacks/filmleader.c create mode 100644 hacks/filmleader.man create mode 100644 hacks/fireworkx.c create mode 100644 hacks/fireworkx.man create mode 100644 hacks/flag.c create mode 100644 hacks/flag.man create mode 100644 hacks/flame.c create mode 100644 hacks/flame.man create mode 100644 hacks/flow.c create mode 100644 hacks/flow.man create mode 100644 hacks/fluidballs.c create mode 100644 hacks/fluidballs.man create mode 100644 hacks/fontglide.c create mode 100644 hacks/fontglide.man create mode 100644 hacks/forest.c create mode 100644 hacks/forest.man create mode 100644 hacks/fps.c create mode 100644 hacks/fps.h create mode 100644 hacks/fpsI.h create mode 100644 hacks/fuzzyflakes.c create mode 100644 hacks/fuzzyflakes.man create mode 100644 hacks/galaxy.c create mode 100644 hacks/galaxy.man create mode 100644 hacks/glitchpeg.c create mode 100644 hacks/glitchpeg.man create mode 100644 hacks/glx/Makefile.in create mode 100644 hacks/glx/README create mode 100644 hacks/glx/antinspect.c create mode 100644 hacks/glx/antinspect.man create mode 100644 hacks/glx/antmaze.c create mode 100644 hacks/glx/antmaze.man create mode 100644 hacks/glx/ants.h create mode 100644 hacks/glx/antspotlight.c create mode 100644 hacks/glx/antspotlight.man create mode 100644 hacks/glx/atlantis.c create mode 100644 hacks/glx/atlantis.h create mode 100644 hacks/glx/atlantis.man create mode 100644 hacks/glx/atunnel.c create mode 100644 hacks/glx/atunnel.man create mode 100644 hacks/glx/b_draw.c create mode 100644 hacks/glx/b_lockglue.c create mode 100644 hacks/glx/b_sphere.c create mode 100644 hacks/glx/blinkbox.c create mode 100644 hacks/glx/blinkbox.man create mode 100644 hacks/glx/blocktube.c create mode 100644 hacks/glx/blocktube.man create mode 100644 hacks/glx/boing.c create mode 100644 hacks/glx/boing.man create mode 100644 hacks/glx/bouncingcow.c create mode 100644 hacks/glx/bouncingcow.man create mode 100644 hacks/glx/boxed.c create mode 100644 hacks/glx/boxed.h create mode 100644 hacks/glx/boxed.man create mode 100644 hacks/glx/bubble3d.c create mode 100644 hacks/glx/bubble3d.h create mode 100644 hacks/glx/bubble3d.man create mode 100644 hacks/glx/buildlwo.c create mode 100644 hacks/glx/buildlwo.h create mode 100644 hacks/glx/cage.c create mode 100644 hacks/glx/cage.man create mode 100644 hacks/glx/carousel.c create mode 100644 hacks/glx/carousel.man create mode 100644 hacks/glx/chessgames.h create mode 100644 hacks/glx/chessmodels.c create mode 100644 hacks/glx/chessmodels.h create mode 100644 hacks/glx/circuit.c create mode 100644 hacks/glx/circuit.man create mode 100644 hacks/glx/cityflow.c create mode 100644 hacks/glx/cityflow.man create mode 100644 hacks/glx/companion.c create mode 100644 hacks/glx/companion_disc.c create mode 100644 hacks/glx/companion_heart.c create mode 100644 hacks/glx/companion_quad.c create mode 100644 hacks/glx/companioncube.man create mode 100644 hacks/glx/cow_face.c create mode 100644 hacks/glx/cow_hide.c create mode 100644 hacks/glx/cow_hoofs.c create mode 100644 hacks/glx/cow_horns.c create mode 100644 hacks/glx/cow_tail.c create mode 100644 hacks/glx/cow_udder.c create mode 100644 hacks/glx/crackberg.c create mode 100644 hacks/glx/crackberg.man create mode 100644 hacks/glx/crumbler.c create mode 100644 hacks/glx/crumbler.man create mode 100644 hacks/glx/cube21.c create mode 100644 hacks/glx/cube21.man create mode 100644 hacks/glx/cubenetic.c create mode 100644 hacks/glx/cubenetic.man create mode 100644 hacks/glx/cubestack.c create mode 100644 hacks/glx/cubestack.man create mode 100644 hacks/glx/cubestorm.c create mode 100644 hacks/glx/cubestorm.man create mode 100644 hacks/glx/cubetwist.c create mode 100644 hacks/glx/cubetwist.man create mode 100644 hacks/glx/cubicgrid.c create mode 100644 hacks/glx/cubicgrid.man create mode 100644 hacks/glx/curlicue.h create mode 100644 hacks/glx/dangerball.c create mode 100644 hacks/glx/dangerball.man create mode 100644 hacks/glx/discoball.c create mode 100644 hacks/glx/discoball.man create mode 100644 hacks/glx/dnalogo.c create mode 100644 hacks/glx/dnapizza.h create mode 100644 hacks/glx/dolphin.c create mode 100644 hacks/glx/dropshadow.c create mode 100644 hacks/glx/dropshadow.h create mode 100755 hacks/glx/dxf2gl.pl create mode 100644 hacks/glx/dymaxionmap-coords.c create mode 100644 hacks/glx/dymaxionmap-coords.h create mode 100644 hacks/glx/dymaxionmap.c create mode 100644 hacks/glx/dymaxionmap.man create mode 100644 hacks/glx/e_textures.h create mode 100644 hacks/glx/endgame.c create mode 100644 hacks/glx/endgame.man create mode 100644 hacks/glx/energystream.c create mode 100644 hacks/glx/energystream.man create mode 100644 hacks/glx/engine.c create mode 100644 hacks/glx/engine.man create mode 100644 hacks/glx/erase-gl.c create mode 100644 hacks/glx/esper.c create mode 100644 hacks/glx/esper.man create mode 100644 hacks/glx/extrusion-helix2.c create mode 100644 hacks/glx/extrusion-helix3.c create mode 100644 hacks/glx/extrusion-helix4.c create mode 100644 hacks/glx/extrusion-joinoffset.c create mode 100644 hacks/glx/extrusion-screw.c create mode 100644 hacks/glx/extrusion-taper.c create mode 100644 hacks/glx/extrusion-twistoid.c create mode 100644 hacks/glx/extrusion.c create mode 100644 hacks/glx/extrusion.h create mode 100644 hacks/glx/extrusion.man create mode 100644 hacks/glx/flipflop.c create mode 100644 hacks/glx/flipflop.man create mode 100644 hacks/glx/flipscreen3d.c create mode 100644 hacks/glx/flipscreen3d.man create mode 100644 hacks/glx/fliptext.c create mode 100644 hacks/glx/fliptext.man create mode 100644 hacks/glx/flurry-smoke.c create mode 100644 hacks/glx/flurry-spark.c create mode 100644 hacks/glx/flurry-star.c create mode 100644 hacks/glx/flurry-texture.c create mode 100644 hacks/glx/flurry.c create mode 100644 hacks/glx/flurry.h create mode 100644 hacks/glx/flurry.man create mode 100644 hacks/glx/flyingtoasters.c create mode 100644 hacks/glx/flyingtoasters.man create mode 100644 hacks/glx/fps-gl.c create mode 100644 hacks/glx/gears.c create mode 100644 hacks/glx/gears.man create mode 100644 hacks/glx/geodesic.c create mode 100644 hacks/glx/geodesic.man create mode 100644 hacks/glx/geodesicgears.c create mode 100644 hacks/glx/geodesicgears.man create mode 100644 hacks/glx/gflux.c create mode 100644 hacks/glx/gflux.man create mode 100644 hacks/glx/glblur.c create mode 100644 hacks/glx/glblur.man create mode 100644 hacks/glx/glcells.c create mode 100644 hacks/glx/glcells.man create mode 100644 hacks/glx/gleidescope.c create mode 100644 hacks/glx/gleidescope.man create mode 100644 hacks/glx/glforestfire.c create mode 100644 hacks/glx/glforestfire.man create mode 100644 hacks/glx/glhanoi.c create mode 100644 hacks/glx/glhanoi.man create mode 100644 hacks/glx/glknots.c create mode 100644 hacks/glx/glknots.man create mode 100644 hacks/glx/gllist.c create mode 100644 hacks/glx/gllist.h create mode 100644 hacks/glx/glmatrix.c create mode 100644 hacks/glx/glmatrix.man create mode 100644 hacks/glx/glplanet.c create mode 100644 hacks/glx/glplanet.man create mode 100644 hacks/glx/glschool.c create mode 100644 hacks/glx/glschool.h create mode 100644 hacks/glx/glschool.man create mode 100644 hacks/glx/glschool_alg.c create mode 100644 hacks/glx/glschool_alg.h create mode 100644 hacks/glx/glschool_gl.c create mode 100644 hacks/glx/glschool_gl.h create mode 100644 hacks/glx/glslideshow.c create mode 100644 hacks/glx/glslideshow.man create mode 100644 hacks/glx/glsnake.c create mode 100644 hacks/glx/glsnake.man create mode 100644 hacks/glx/gltext.c create mode 100644 hacks/glx/gltext.man create mode 100644 hacks/glx/gltrackball.c create mode 100644 hacks/glx/gltrackball.h create mode 100644 hacks/glx/glut_mroman.h create mode 100644 hacks/glx/glut_roman.h create mode 100644 hacks/glx/glut_stroke.c create mode 100644 hacks/glx/glut_swidth.c create mode 100644 hacks/glx/glutstroke.h create mode 100644 hacks/glx/grab-ximage.c create mode 100644 hacks/glx/grab-ximage.h create mode 100644 hacks/glx/hexstrut.c create mode 100644 hacks/glx/hexstrut.man create mode 100644 hacks/glx/hilbert.c create mode 100644 hacks/glx/hilbert.man create mode 100644 hacks/glx/hydrostat.c create mode 100644 hacks/glx/hydrostat.man create mode 100644 hacks/glx/hypertorus.c create mode 100644 hacks/glx/hypertorus.man create mode 100644 hacks/glx/hypnowheel.c create mode 100644 hacks/glx/hypnowheel.man create mode 100644 hacks/glx/involute.c create mode 100644 hacks/glx/involute.h create mode 100644 hacks/glx/jigglypuff.c create mode 100644 hacks/glx/jigglypuff.man create mode 100644 hacks/glx/jigsaw.c create mode 100644 hacks/glx/jigsaw.man create mode 100644 hacks/glx/juggler3d.c create mode 100644 hacks/glx/juggler3d.man create mode 100644 hacks/glx/kaleidocycle.c create mode 100644 hacks/glx/kaleidocycle.man create mode 100644 hacks/glx/klein.c create mode 100644 hacks/glx/klein.man create mode 100644 hacks/glx/lament.c create mode 100644 hacks/glx/lament.dxf create mode 100644 hacks/glx/lament.man create mode 100644 hacks/glx/lament_model.c create mode 100644 hacks/glx/lavalite.c create mode 100644 hacks/glx/lavalite.man create mode 100644 hacks/glx/lockward.c create mode 100644 hacks/glx/lockward.man create mode 100644 hacks/glx/marching.c create mode 100644 hacks/glx/marching.h create mode 100755 hacks/glx/maze3d.c create mode 100755 hacks/glx/maze3d.man create mode 100644 hacks/glx/menger.c create mode 100644 hacks/glx/menger.man create mode 100644 hacks/glx/mirrorblob.c create mode 100644 hacks/glx/mirrorblob.man create mode 100644 hacks/glx/moebius.c create mode 100644 hacks/glx/moebius.man create mode 100644 hacks/glx/moebiusgears.c create mode 100644 hacks/glx/moebiusgears.man create mode 100644 hacks/glx/molecule.c create mode 100644 hacks/glx/molecule.man create mode 100755 hacks/glx/molecules.sh create mode 100644 hacks/glx/morph3d.c create mode 100644 hacks/glx/morph3d.man create mode 100644 hacks/glx/noof.c create mode 100644 hacks/glx/noof.man create mode 100644 hacks/glx/normals.c create mode 100644 hacks/glx/normals.h create mode 100644 hacks/glx/peepers.c create mode 100644 hacks/glx/peepers.man create mode 100644 hacks/glx/photopile.c create mode 100644 hacks/glx/photopile.man create mode 100644 hacks/glx/pinion.c create mode 100644 hacks/glx/pinion.man create mode 100644 hacks/glx/pipeobjs.c create mode 100644 hacks/glx/pipes.c create mode 100644 hacks/glx/pipes.man create mode 100644 hacks/glx/polyhedra-gl.c create mode 100644 hacks/glx/polyhedra.c create mode 100644 hacks/glx/polyhedra.h create mode 100644 hacks/glx/polyhedra.man create mode 100644 hacks/glx/polytopes.c create mode 100644 hacks/glx/polytopes.man create mode 100644 hacks/glx/projectiveplane.c create mode 100644 hacks/glx/projectiveplane.man create mode 100644 hacks/glx/providence.c create mode 100644 hacks/glx/providence.man create mode 100644 hacks/glx/pulsar.c create mode 100644 hacks/glx/pulsar.man create mode 100644 hacks/glx/quasicrystal.c create mode 100644 hacks/glx/quasicrystal.man create mode 100644 hacks/glx/queens.c create mode 100644 hacks/glx/queens.man create mode 100644 hacks/glx/quickhull.c create mode 100644 hacks/glx/quickhull.h create mode 100644 hacks/glx/raverhoop.c create mode 100644 hacks/glx/raverhoop.man create mode 100644 hacks/glx/razzledazzle.c create mode 100644 hacks/glx/razzledazzle.man create mode 100644 hacks/glx/robot-wireframe.c create mode 100644 hacks/glx/robot-wireframe.dxf create mode 100644 hacks/glx/robot.c create mode 100644 hacks/glx/robot.dxf create mode 100644 hacks/glx/romanboy.c create mode 100644 hacks/glx/romanboy.man create mode 100644 hacks/glx/rotator.c create mode 100644 hacks/glx/rotator.h create mode 100644 hacks/glx/rubik.c create mode 100644 hacks/glx/rubik.man create mode 100644 hacks/glx/rubikblocks.c create mode 100644 hacks/glx/rubikblocks.man create mode 100644 hacks/glx/s1_1.c create mode 100644 hacks/glx/s1_2.c create mode 100644 hacks/glx/s1_3.c create mode 100644 hacks/glx/s1_4.c create mode 100644 hacks/glx/s1_5.c create mode 100644 hacks/glx/s1_6.c create mode 100644 hacks/glx/s1_b.c create mode 100644 hacks/glx/sballs.c create mode 100644 hacks/glx/sballs.man create mode 100644 hacks/glx/seccam.c create mode 100644 hacks/glx/seccam.dxf create mode 100644 hacks/glx/shark.c create mode 100644 hacks/glx/ships.c create mode 100644 hacks/glx/ships.dxf create mode 100644 hacks/glx/sierpinski3d.c create mode 100644 hacks/glx/sierpinski3d.man create mode 100644 hacks/glx/skytentacles.c create mode 100644 hacks/glx/skytentacles.man create mode 100644 hacks/glx/sonar-icmp.c create mode 100644 hacks/glx/sonar-sim.c create mode 100644 hacks/glx/sonar.c create mode 100644 hacks/glx/sonar.h create mode 100644 hacks/glx/sonar.man create mode 100644 hacks/glx/sphere.c create mode 100644 hacks/glx/sphere.h create mode 100644 hacks/glx/spheremonics.c create mode 100644 hacks/glx/spheremonics.man create mode 100644 hacks/glx/splitflap.c create mode 100644 hacks/glx/splitflap.dxf create mode 100644 hacks/glx/splitflap.man create mode 100644 hacks/glx/splitflap_obj.c create mode 100644 hacks/glx/splodesic.c create mode 100644 hacks/glx/splodesic.man create mode 100644 hacks/glx/sproingies.c create mode 100644 hacks/glx/sproingies.h create mode 100644 hacks/glx/sproingies.man create mode 100644 hacks/glx/sproingiewrap.c create mode 100644 hacks/glx/stairs.c create mode 100644 hacks/glx/stairs.man create mode 100644 hacks/glx/starwars.c create mode 100644 hacks/glx/starwars.h create mode 100644 hacks/glx/starwars.man create mode 100644 hacks/glx/starwars.txt create mode 100644 hacks/glx/stonerview-move.c create mode 100644 hacks/glx/stonerview-move.h create mode 100644 hacks/glx/stonerview-osc.c create mode 100644 hacks/glx/stonerview-osc.h create mode 100644 hacks/glx/stonerview-view.c create mode 100644 hacks/glx/stonerview.c create mode 100644 hacks/glx/stonerview.h create mode 100644 hacks/glx/stonerview.man create mode 100644 hacks/glx/superquadrics.c create mode 100644 hacks/glx/superquadrics.man create mode 100644 hacks/glx/surfaces.c create mode 100644 hacks/glx/surfaces.man create mode 100644 hacks/glx/swim.c create mode 100644 hacks/glx/tangram.c create mode 100644 hacks/glx/tangram.man create mode 100644 hacks/glx/tangram_shapes.c create mode 100644 hacks/glx/tangram_shapes.h create mode 100644 hacks/glx/teapot.c create mode 100644 hacks/glx/teapot.h create mode 100644 hacks/glx/teapot2.h create mode 100644 hacks/glx/texfont.c create mode 100644 hacks/glx/texfont.h create mode 100644 hacks/glx/timetunnel.c create mode 100644 hacks/glx/timetunnel.man create mode 100644 hacks/glx/toast.c create mode 100644 hacks/glx/toast.dxf create mode 100644 hacks/glx/toast2.c create mode 100644 hacks/glx/toast2.dxf create mode 100644 hacks/glx/toaster.c create mode 100644 hacks/glx/toaster.dxf create mode 100644 hacks/glx/toaster_base.c create mode 100644 hacks/glx/toaster_base.dxf create mode 100644 hacks/glx/toaster_handle.c create mode 100644 hacks/glx/toaster_handle.dxf create mode 100644 hacks/glx/toaster_handle2.c create mode 100644 hacks/glx/toaster_handle2.dxf create mode 100644 hacks/glx/toaster_jet.c create mode 100644 hacks/glx/toaster_jet.dxf create mode 100644 hacks/glx/toaster_knob.c create mode 100644 hacks/glx/toaster_knob.dxf create mode 100644 hacks/glx/toaster_slots.c create mode 100644 hacks/glx/toaster_slots.dxf create mode 100644 hacks/glx/toaster_wing.c create mode 100644 hacks/glx/toaster_wing.dxf create mode 100644 hacks/glx/topblock.c create mode 100644 hacks/glx/topblock.h create mode 100644 hacks/glx/topblock.man create mode 100644 hacks/glx/trackball.c create mode 100644 hacks/glx/trackball.h create mode 100644 hacks/glx/tronbit.c create mode 100644 hacks/glx/tronbit.man create mode 100644 hacks/glx/tronbit_idle1.c create mode 100644 hacks/glx/tronbit_idle2.c create mode 100644 hacks/glx/tronbit_no.c create mode 100644 hacks/glx/tronbit_yes.c create mode 100644 hacks/glx/tube.c create mode 100644 hacks/glx/tube.h create mode 100644 hacks/glx/tunnel_draw.c create mode 100644 hacks/glx/tunnel_draw.h create mode 100644 hacks/glx/unicrud.c create mode 100644 hacks/glx/unicrud.man create mode 100644 hacks/glx/unknownpleasures.c create mode 100644 hacks/glx/unknownpleasures.man create mode 100644 hacks/glx/vigilance.c create mode 100644 hacks/glx/vigilance.man create mode 100644 hacks/glx/voronoi.c create mode 100644 hacks/glx/voronoi.man create mode 100755 hacks/glx/vrml2gl.pl create mode 100755 hacks/glx/wfront2gl.pl create mode 100644 hacks/glx/whale.c create mode 100644 hacks/glx/winduprobot.c create mode 100644 hacks/glx/winduprobot.man create mode 100644 hacks/glx/xlock-gl-utils.c create mode 100644 hacks/glx/xscreensaver-gl-helper.c create mode 100644 hacks/glx/xscreensaver-gl-helper.man create mode 100644 hacks/glx/zalgo.txt create mode 100644 hacks/goop.c create mode 100644 hacks/goop.man create mode 100644 hacks/grav.c create mode 100644 hacks/grav.man create mode 100644 hacks/greynetic.c create mode 100644 hacks/greynetic.man create mode 100644 hacks/halftone.c create mode 100644 hacks/halftone.man create mode 100644 hacks/halo.c create mode 100644 hacks/halo.man create mode 100644 hacks/helix.c create mode 100644 hacks/helix.man create mode 100644 hacks/hexadrop.c create mode 100644 hacks/hexadrop.man create mode 100644 hacks/hopalong.c create mode 100644 hacks/hopalong.man create mode 100644 hacks/hyperball.c create mode 100644 hacks/hyperball.man create mode 100644 hacks/hypercube.c create mode 100644 hacks/hypercube.man create mode 100644 hacks/ifs.c create mode 100644 hacks/ifs.man create mode 100644 hacks/images/6x10font.png create mode 100644 hacks/images/Makefile create mode 100644 hacks/images/Makefile.in create mode 100644 hacks/images/amiga.png create mode 100644 hacks/images/android.png create mode 100644 hacks/images/apple.png create mode 100644 hacks/images/apple2font.png create mode 100644 hacks/images/atari.png create mode 100644 hacks/images/atm.png create mode 100644 hacks/images/blocktube.png create mode 100644 hacks/images/bob.png create mode 100644 hacks/images/brick1.png create mode 100644 hacks/images/brick2.png create mode 100644 hacks/images/bubbles/blood.pov create mode 100644 hacks/images/bubbles/blood1.png create mode 100644 hacks/images/bubbles/blood10.png create mode 100644 hacks/images/bubbles/blood11.png create mode 100644 hacks/images/bubbles/blood2.png create mode 100644 hacks/images/bubbles/blood3.png create mode 100644 hacks/images/bubbles/blood4.png create mode 100644 hacks/images/bubbles/blood5.png create mode 100644 hacks/images/bubbles/blood6.png create mode 100644 hacks/images/bubbles/blood7.png create mode 100644 hacks/images/bubbles/blood8.png create mode 100644 hacks/images/bubbles/blood9.png create mode 100644 hacks/images/bubbles/blue.pov create mode 100644 hacks/images/bubbles/blue1.png create mode 100644 hacks/images/bubbles/blue10.png create mode 100644 hacks/images/bubbles/blue11.png create mode 100644 hacks/images/bubbles/blue2.png create mode 100644 hacks/images/bubbles/blue3.png create mode 100644 hacks/images/bubbles/blue4.png create mode 100644 hacks/images/bubbles/blue5.png create mode 100644 hacks/images/bubbles/blue6.png create mode 100644 hacks/images/bubbles/blue7.png create mode 100644 hacks/images/bubbles/blue8.png create mode 100644 hacks/images/bubbles/blue9.png create mode 100644 hacks/images/bubbles/glass.pov create mode 100644 hacks/images/bubbles/glass1.png create mode 100644 hacks/images/bubbles/glass10.png create mode 100644 hacks/images/bubbles/glass11.png create mode 100644 hacks/images/bubbles/glass2.png create mode 100644 hacks/images/bubbles/glass3.png create mode 100644 hacks/images/bubbles/glass4.png create mode 100644 hacks/images/bubbles/glass5.png create mode 100644 hacks/images/bubbles/glass6.png create mode 100644 hacks/images/bubbles/glass7.png create mode 100644 hacks/images/bubbles/glass8.png create mode 100644 hacks/images/bubbles/glass9.png create mode 100644 hacks/images/bubbles/jade.pov create mode 100644 hacks/images/bubbles/jade1.png create mode 100644 hacks/images/bubbles/jade10.png create mode 100644 hacks/images/bubbles/jade11.png create mode 100644 hacks/images/bubbles/jade2.png create mode 100644 hacks/images/bubbles/jade3.png create mode 100644 hacks/images/bubbles/jade4.png create mode 100644 hacks/images/bubbles/jade5.png create mode 100644 hacks/images/bubbles/jade6.png create mode 100644 hacks/images/bubbles/jade7.png create mode 100644 hacks/images/bubbles/jade8.png create mode 100644 hacks/images/bubbles/jade9.png create mode 100644 hacks/images/chromesphere.png create mode 100644 hacks/images/earth.png create mode 100644 hacks/images/earth_flat.png create mode 100644 hacks/images/earth_night.png create mode 100644 hacks/images/ground.png create mode 100644 hacks/images/hmac.png create mode 100644 hacks/images/iris.png create mode 100644 hacks/images/jigglymap.png create mode 100644 hacks/images/lament512.png create mode 100644 hacks/images/logo-180.png create mode 100644 hacks/images/logo-32.png create mode 100644 hacks/images/logo-50.png create mode 100644 hacks/images/m6502/amiga.asm create mode 100644 hacks/images/m6502/breakout.asm create mode 100644 hacks/images/m6502/byterun.asm create mode 100644 hacks/images/m6502/cellular-30.asm create mode 100644 hacks/images/m6502/cellular-600.asm create mode 100644 hacks/images/m6502/colors.asm create mode 100644 hacks/images/m6502/crunch6502.asm create mode 100644 hacks/images/m6502/demoscene.asm create mode 100644 hacks/images/m6502/disco.asm create mode 100644 hacks/images/m6502/dmsc.asm create mode 100644 hacks/images/m6502/dmsc.txt create mode 100644 hacks/images/m6502/dragon-fractal.asm create mode 100644 hacks/images/m6502/fullscreenlogo.asm create mode 100644 hacks/images/m6502/greynetic.asm create mode 100644 hacks/images/m6502/keftal.asm create mode 100644 hacks/images/m6502/life.asm create mode 100644 hacks/images/m6502/lines.asm create mode 100644 hacks/images/m6502/matrix.asm create mode 100644 hacks/images/m6502/noise.asm create mode 100644 hacks/images/m6502/random-walk.asm create mode 100644 hacks/images/m6502/random.asm create mode 100644 hacks/images/m6502/random2.asm create mode 100644 hacks/images/m6502/rorschach.asm create mode 100644 hacks/images/m6502/santa.asm create mode 100644 hacks/images/m6502/selfmodify.asm create mode 100644 hacks/images/m6502/sflake.asm create mode 100644 hacks/images/m6502/sierpinski.asm create mode 100644 hacks/images/m6502/sierpinsky.asm create mode 100644 hacks/images/m6502/softsprite.asm create mode 100644 hacks/images/m6502/spacer.asm create mode 100644 hacks/images/m6502/starfield2d.asm create mode 100644 hacks/images/m6502/texture.asm create mode 100644 hacks/images/m6502/wave6502.asm create mode 100644 hacks/images/m6502/zookeeper.asm create mode 100644 hacks/images/mac.png create mode 100644 hacks/images/macbomb.png create mode 100644 hacks/images/matrix1.png create mode 100644 hacks/images/matrix1b.png create mode 100644 hacks/images/matrix2.png create mode 100644 hacks/images/matrix2b.png create mode 100644 hacks/images/matrix3.png create mode 100644 hacks/images/molecules/adenine.pdb create mode 100644 hacks/images/molecules/adrenochrome.pdb create mode 100644 hacks/images/molecules/bucky.pdb create mode 100644 hacks/images/molecules/caffeine.pdb create mode 100644 hacks/images/molecules/capsaicin.pdb create mode 100644 hacks/images/molecules/chlordecone.pdb create mode 100644 hacks/images/molecules/cocaine.pdb create mode 100644 hacks/images/molecules/codeine.pdb create mode 100644 hacks/images/molecules/cyclohexane.pdb create mode 100644 hacks/images/molecules/cytosine.pdb create mode 100644 hacks/images/molecules/dna.pdb create mode 100644 hacks/images/molecules/dodecahedrane.pdb create mode 100644 hacks/images/molecules/dthc.pdb create mode 100644 hacks/images/molecules/dynamite.pdb create mode 100644 hacks/images/molecules/glycol.pdb create mode 100644 hacks/images/molecules/guanine.pdb create mode 100644 hacks/images/molecules/heroin.pdb create mode 100644 hacks/images/molecules/hexahelicene.pdb create mode 100644 hacks/images/molecules/ibuprofen.pdb create mode 100644 hacks/images/molecules/lsd.pdb create mode 100644 hacks/images/molecules/menthol.pdb create mode 100644 hacks/images/molecules/mescaline.pdb create mode 100644 hacks/images/molecules/methamphetamine.pdb create mode 100644 hacks/images/molecules/morphine.pdb create mode 100644 hacks/images/molecules/nicotine.pdb create mode 100644 hacks/images/molecules/novocaine.pdb create mode 100644 hacks/images/molecules/olestra.pdb create mode 100644 hacks/images/molecules/penicillin.pdb create mode 100644 hacks/images/molecules/salvinorin.pdb create mode 100644 hacks/images/molecules/sarin.pdb create mode 100644 hacks/images/molecules/strychnine.pdb create mode 100644 hacks/images/molecules/sucrose.pdb create mode 100644 hacks/images/molecules/thalidomide.pdb create mode 100644 hacks/images/molecules/thymine.pdb create mode 100644 hacks/images/molecules/viagra.pdb create mode 100644 hacks/images/molecules/vitaminb6.pdb create mode 100644 hacks/images/molecules/vitaminc.pdb create mode 100644 hacks/images/molecules/vx.pdb create mode 100644 hacks/images/noseguy/nose-f1.png create mode 100644 hacks/images/noseguy/nose-f2.png create mode 100644 hacks/images/noseguy/nose-f3.png create mode 100644 hacks/images/noseguy/nose-f4.png create mode 100644 hacks/images/noseguy/nose-l1.png create mode 100644 hacks/images/noseguy/nose-l2.png create mode 100644 hacks/images/noseguy/nose-r1.png create mode 100644 hacks/images/noseguy/nose-r2.png create mode 100644 hacks/images/osx_10_2.png create mode 100644 hacks/images/osx_10_3.png create mode 100644 hacks/images/pacman.png create mode 100644 hacks/images/ransomware.png create mode 100644 hacks/images/sball-bg.png create mode 100644 hacks/images/sball.png create mode 100644 hacks/images/scales.png create mode 100644 hacks/images/sclera.png create mode 100644 hacks/images/sea-texture.png create mode 100644 hacks/images/som.png create mode 100644 hacks/images/start.png create mode 100644 hacks/images/testcard_bbcf.png create mode 100644 hacks/images/testcard_pm5544.png create mode 100644 hacks/images/testcard_rca.png create mode 100644 hacks/images/timetunnel0.png create mode 100644 hacks/images/timetunnel1.png create mode 100644 hacks/images/timetunnel2.png create mode 100644 hacks/images/toast.png create mode 100644 hacks/images/tree.png create mode 100644 hacks/images/tunnel0.png create mode 100644 hacks/images/tunnel1.png create mode 100644 hacks/images/tunnel2.png create mode 100644 hacks/images/tunnel3.png create mode 100644 hacks/images/tunnel4.png create mode 100644 hacks/images/tunnel5.png create mode 100644 hacks/images/tunnelstar.png create mode 100644 hacks/images/win10_spinner.gif create mode 100644 hacks/images/wood.png create mode 100644 hacks/images/wood2.png create mode 100644 hacks/imsmap.c create mode 100644 hacks/imsmap.man create mode 100644 hacks/interaggregate.c create mode 100644 hacks/interaggregate.man create mode 100644 hacks/interference.c create mode 100644 hacks/interference.man create mode 100644 hacks/intermomentary.c create mode 100644 hacks/intermomentary.man create mode 100644 hacks/juggle.c create mode 100644 hacks/juggle.man create mode 100644 hacks/julia.c create mode 100644 hacks/julia.man create mode 100644 hacks/kaleidescope.c create mode 100644 hacks/kaleidescope.man create mode 100644 hacks/kumppa.c create mode 100644 hacks/kumppa.man create mode 100644 hacks/laser.c create mode 100644 hacks/laser.man create mode 100644 hacks/lcdscrub.c create mode 100644 hacks/lcdscrub.man create mode 100644 hacks/lightning.c create mode 100644 hacks/lightning.man create mode 100644 hacks/link_axp.com create mode 100644 hacks/link_decc.com create mode 100644 hacks/lisa.c create mode 100644 hacks/lisa.man create mode 100644 hacks/lissie.c create mode 100644 hacks/lissie.man create mode 100755 hacks/ljlatest create mode 100644 hacks/ljlatest.man create mode 100644 hacks/lmorph.c create mode 100644 hacks/lmorph.man create mode 100644 hacks/loop.c create mode 100644 hacks/loop.man create mode 100644 hacks/m6502.c create mode 100755 hacks/m6502.sh create mode 100644 hacks/maze.c create mode 100644 hacks/maze.man create mode 100644 hacks/memscroller.c create mode 100644 hacks/memscroller.man create mode 100644 hacks/metaballs.c create mode 100644 hacks/metaballs.man create mode 100644 hacks/moire.c create mode 100644 hacks/moire.man create mode 100644 hacks/moire2.c create mode 100644 hacks/moire2.man create mode 100644 hacks/mountain.c create mode 100644 hacks/mountain.man create mode 100644 hacks/munch.c create mode 100644 hacks/munch.man create mode 100755 hacks/munge-ad.pl create mode 100644 hacks/nerverot.c create mode 100644 hacks/nerverot.man create mode 100644 hacks/noseguy.c create mode 100644 hacks/noseguy.man create mode 100644 hacks/pacman.c create mode 100644 hacks/pacman.h create mode 100644 hacks/pacman.man create mode 100644 hacks/pacman_ai.c create mode 100644 hacks/pacman_ai.h create mode 100644 hacks/pacman_level.c create mode 100644 hacks/pacman_level.h create mode 100644 hacks/pedal.c create mode 100644 hacks/pedal.man create mode 100644 hacks/penetrate.c create mode 100644 hacks/penetrate.man create mode 100644 hacks/penrose.c create mode 100644 hacks/penrose.man create mode 100644 hacks/petri.c create mode 100644 hacks/petri.man create mode 100644 hacks/phosphor.c create mode 100644 hacks/phosphor.man create mode 100644 hacks/piecewise.c create mode 100644 hacks/piecewise.man create mode 100644 hacks/polyominoes.c create mode 100644 hacks/polyominoes.man create mode 100644 hacks/pong.c create mode 100644 hacks/pong.man create mode 100644 hacks/popsquares.c create mode 100644 hacks/pyro.c create mode 100644 hacks/pyro.man create mode 100644 hacks/qix.c create mode 100644 hacks/qix.man create mode 100644 hacks/rd-bomb.c create mode 100644 hacks/rd-bomb.man create mode 100644 hacks/recanim.c create mode 100644 hacks/recanim.h create mode 100644 hacks/ripples.c create mode 100644 hacks/ripples.man create mode 100644 hacks/rocks.c create mode 100644 hacks/rocks.man create mode 100644 hacks/rorschach.c create mode 100644 hacks/rorschach.man create mode 100644 hacks/rotor.c create mode 100644 hacks/rotor.man create mode 100644 hacks/rotzoomer.c create mode 100644 hacks/rotzoomer.man create mode 100644 hacks/screenhack.c create mode 100644 hacks/screenhack.h create mode 100644 hacks/screenhackI.h create mode 100644 hacks/shadebobs.c create mode 100644 hacks/shadebobs.man create mode 100644 hacks/sierpinski.c create mode 100644 hacks/sierpinski.man create mode 100644 hacks/slidescreen.c create mode 100644 hacks/slidescreen.man create mode 100644 hacks/slip.c create mode 100644 hacks/slip.man create mode 100644 hacks/speedmine.c create mode 100644 hacks/speedmine.man create mode 100644 hacks/sphere.c create mode 100644 hacks/sphere.man create mode 100644 hacks/spiral.c create mode 100644 hacks/spiral.man create mode 100644 hacks/spotlight.c create mode 100644 hacks/spotlight.man create mode 100644 hacks/squiral.c create mode 100644 hacks/squiral.man create mode 100644 hacks/starfish.c create mode 100644 hacks/starfish.man create mode 100644 hacks/strange.c create mode 100644 hacks/strange.man create mode 100644 hacks/substrate.c create mode 100644 hacks/substrate.man create mode 100644 hacks/swirl.c create mode 100644 hacks/swirl.man create mode 100644 hacks/t3d.c create mode 100644 hacks/t3d.man create mode 100644 hacks/tessellimage.c create mode 100644 hacks/tessellimage.man create mode 100644 hacks/testx11.c create mode 100644 hacks/thornbird.c create mode 100644 hacks/thornbird.man create mode 100644 hacks/triangle.c create mode 100644 hacks/triangle.man create mode 100644 hacks/truchet.c create mode 100644 hacks/truchet.man create mode 100644 hacks/twang.c create mode 100644 hacks/twang.man create mode 100644 hacks/vermiculate.c create mode 100644 hacks/vermiculate.man create mode 100644 hacks/vfeedback.c create mode 100644 hacks/vfeedback.man create mode 100755 hacks/vidwhacker create mode 100644 hacks/vidwhacker.man create mode 100644 hacks/vines.c create mode 100644 hacks/vines.man create mode 100644 hacks/vms_axp.opt create mode 100644 hacks/vms_axp_12.opt create mode 100644 hacks/vms_decc.opt create mode 100644 hacks/vms_decc_12.opt create mode 100644 hacks/wander.c create mode 100644 hacks/wander.man create mode 100755 hacks/webcollage create mode 100644 hacks/webcollage-cocoa.m create mode 100644 hacks/webcollage-helper-cocoa.m create mode 100644 hacks/webcollage-helper.c create mode 100644 hacks/webcollage.man create mode 100644 hacks/whirlwindwarp.c create mode 100644 hacks/whirlwindwarp.man create mode 100644 hacks/whirlygig.c create mode 100644 hacks/whirlygig.man create mode 100644 hacks/worm.c create mode 100644 hacks/worm.man create mode 100644 hacks/wormhole.c create mode 100644 hacks/wormhole.man create mode 100644 hacks/xanalogtv.c create mode 100644 hacks/xanalogtv.man create mode 100644 hacks/xflame.c create mode 100644 hacks/xflame.man create mode 100644 hacks/ximage-loader.c create mode 100644 hacks/ximage-loader.h create mode 100644 hacks/xjack.c create mode 100644 hacks/xjack.man create mode 100644 hacks/xlockmore.c create mode 100644 hacks/xlockmore.h create mode 100644 hacks/xlockmoreI.h create mode 100644 hacks/xlyap.c create mode 100644 hacks/xlyap.man create mode 100644 hacks/xmatrix.c create mode 100644 hacks/xmatrix.man create mode 100755 hacks/xml2man.pl create mode 100644 hacks/xrayswarm.c create mode 100644 hacks/xrayswarm.man create mode 100644 hacks/xscreensaver-sgigl.c create mode 100644 hacks/xspirograph.c create mode 100644 hacks/xspirograph.man create mode 100644 hacks/xsublim.c create mode 100644 hacks/xsublim.man create mode 100644 hacks/zoom.c create mode 100644 hacks/zoom.man (limited to 'hacks') diff --git a/hacks/.gdbinit b/hacks/.gdbinit new file mode 100644 index 0000000..5649178 --- /dev/null +++ b/hacks/.gdbinit @@ -0,0 +1,12 @@ +set args -geom =800x600+0+0 -sync +set env MallocScribble 1 +set env MallocPreScribble 1 +set env MallocErrorAbort 1 +set env MallocCheckHeapAbort 1 +set env MallocGuardEdges 1 +#set env MallocCheckHeapStart 130000 +#set env MallocCheckHeapEach 1 +b screenhack_ehandler +b malloc_error_break +b exit +b abort diff --git a/hacks/Makefile.in b/hacks/Makefile.in new file mode 100644 index 0000000..4556872 --- /dev/null +++ b/hacks/Makefile.in @@ -0,0 +1,3263 @@ +# hacks/Makefile.in --- xscreensaver, Copyright (c) 1997-2015 Jamie Zawinski. +# the `../configure' script generates `hacks/Makefile' from this file. + +@SET_MAKE@ +.SUFFIXES: +.SUFFIXES: .c .o + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = .. + +install_prefix = +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +datarootdir = @datarootdir@ +datadir = @datadir@ +mandir = @mandir@ +libexecdir = @libexecdir@ +mansuffix = 6 +manNdir = $(mandir)/man$(mansuffix) + +HACKDIR = @HACKDIR@ +HACK_CONF_DIR = @HACK_CONF_DIR@ + +CC = @CC@ +CFLAGS = @CFLAGS@ +LDFLAGS = @LDFLAGS@ +DEFS = -DSTANDALONE @DEFS@ +LIBS = @LIBS@ +PERL = @PERL@ + +THREAD_LIBS = @PTHREAD_LIBS@ +THREAD_CFLAGS = @PTHREAD_CFLAGS@ + +DEPEND = @DEPEND@ +DEPEND_FLAGS = @DEPEND_FLAGS@ +DEPEND_DEFINES = @DEPEND_DEFINES@ + +SHELL = /bin/sh +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_DIRS = @INSTALL_DIRS@ + +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +XMU_LIBS = @XMU_LIBS@ +XFT_LIBS = @XFT_LIBS@ + +# Note: see comment in ../driver/Makefile.in for explanation of X_LIBS, etc. +# +HACK_PRE = $(LIBS) $(X_LIBS) +HACK_POST = $(X_PRE_LIBS) $(XFT_LIBS) -lXt -lX11 $(XMU_LIBS) -lXext $(X_EXTRA_LIBS) -lm +HACK_LIBS = $(HACK_PRE) @ANIM_LIBS@ @HACK_LIBS@ $(HACK_POST) +PNG_LIBS = $(HACK_PRE) @PNG_LIBS@ @HACK_LIBS@ $(HACK_POST) +JPEG_LIBS = @JPEG_LIBS@ +XLOCK_LIBS = $(HACK_LIBS) +TEXT_LIBS = @PTY_LIBS@ + +UTILS_SRC = $(srcdir)/../utils +UTILS_BIN = ../utils +HACK_BIN = . + +INCLUDES_1 = -I. -I$(srcdir) -I$(UTILS_SRC) -I.. +INCLUDES = $(INCLUDES_1) @INCLUDES@ + +UTIL_SRCS = $(UTILS_SRC)/alpha.c $(UTILS_SRC)/colors.c \ + $(UTILS_SRC)/grabclient.c \ + $(UTILS_SRC)/hsv.c $(UTILS_SRC)/resources.c \ + $(UTILS_SRC)/spline.c $(UTILS_SRC)/usleep.c \ + $(UTILS_SRC)/visual.c \ + $(UTILS_SRC)/yarandom.c $(UTILS_SRC)/erase.c \ + $(UTILS_SRC)/xshm.c $(UTILS_SRC)/xdbe.c \ + $(UTILS_SRC)/textclient.c $(UTILS_SRC)/aligned_malloc.c \ + $(UTILS_SRC)/thread_util.c $(UTILS_SRC)/pow2.c \ + $(UTILS_SRC)/font-retry.c +UTIL_OBJS = $(UTILS_BIN)/alpha.o $(UTILS_BIN)/colors.o \ + $(UTILS_BIN)/grabclient.o \ + $(UTILS_BIN)/hsv.o $(UTILS_BIN)/resources.o \ + $(UTILS_BIN)/spline.o $(UTILS_BIN)/usleep.o \ + $(UTILS_BIN)/visual.o \ + $(UTILS_BIN)/yarandom.o $(UTILS_BIN)/erase.o \ + $(UTILS_BIN)/xshm.o $(UTILS_BIN)/xdbe.o \ + $(UTILS_BIN)/colorbars.o \ + $(UTILS_BIN)/textclient.o $(UTILS_BIN)/aligned_malloc.o \ + $(UTILS_BIN)/thread_util.o $(UTILS_BIN)/pow2.o \ + $(UTILS_BIN)/xft.o $(UTILS_BIN)/utf8wc.o \ + $(UTILS_BIN)/font-retry-xft.o + +SRCS = attraction.c blitspin.c bouboule.c braid.c bubbles.c \ + bubbles-default.c decayscreen.c deco.c drift.c flag.c \ + flame.c forest.c vines.c galaxy.c grav.c greynetic.c \ + halo.c helix.c hopalong.c hypercube.c ifs.c imsmap.c \ + julia.c kaleidescope.c laser.c lightning.c lisa.c lmorph.c \ + maze.c moire.c noseguy.c pedal.c penrose.c pyro.c qix.c \ + rocks.c rorschach.c screenhack.c sierpinski.c slidescreen.c \ + slip.c sphere.c spiral.c strange.c swirl.c xlockmore.c \ + fps.c goop.c starfish.c munch.c fadeplot.c \ + rd-bomb.c coral.c mountain.c triangle.c lissie.c worm.c \ + rotor.c ant.c xjack.c xlyap.c xscreensaver-sgigl.c \ + cynosure.c moire2.c flow.c epicycle.c interference.c \ + truchet.c bsod.c crystal.c discrete.c distort.c kumppa.c \ + demon.c loop.c t3d.c penetrate.c deluxe.c compass.c \ + squiral.c xflame.c wander.c spotlight.c critical.c \ + phosphor.c xmatrix.c petri.c shadebobs.c xsublim.c ccurve.c \ + blaster.c bumps.c ripples.c xspirograph.c \ + nerverot.c xrayswarm.c hyperball.c zoom.c whirlwindwarp.c \ + rotzoomer.c whirlygig.c speedmine.c vermiculate.c \ + ximage-loader.c webcollage-helper.c twang.c apollonian.c \ + euler2d.c juggle.c polyominoes.c thornbird.c fluidballs.c \ + anemone.c halftone.c metaballs.c eruption.c popsquares.c \ + barcode.c piecewise.c cloudlife.c fontglide.c apple2.c \ + apple2-main.c analogtv.c xanalogtv.c pong.c filmleader.c \ + wormhole.c pacman.c pacman_ai.c pacman_level.c \ + fuzzyflakes.c anemotaxis.c memscroller.c substrate.c \ + intermomentary.c fireworkx.c fiberlamp.c \ + boxfit.c interaggregate.c celtic.c cwaves.c m6502.c \ + asm6502.c abstractile.c lcdscrub.c hexadrop.c \ + tessellimage.c delaunay.c recanim.c binaryring.c \ + glitchpeg.c vfeedback.c \ + webcollage-cocoa.m webcollage-helper-cocoa.m testx11.c +SCRIPTS = vidwhacker webcollage ljlatest + +# Programs that are mentioned in XScreenSaver.ad, and that have XML files, +# but that are not shipped with xscreensaver itself. +# +EXTERNALS = cosmos electricsheep fireflies goban \ + sphereeversion ssystem xaos xdaliclock xearth xfishtank \ + xmountains xplanet xsnow + +OBJS = attraction.o blitspin.o bouboule.o braid.o bubbles.o \ + bubbles-default.o decayscreen.o deco.o drift.o flag.o \ + flame.o forest.o vines.o galaxy.o grav.o greynetic.o \ + halo.o helix.o hopalong.o hypercube.o ifs.o imsmap.o \ + julia.o kaleidescope.o laser.o lightning.o lisa.o lmorph.o \ + maze.o moire.o noseguy.o pedal.o penrose.o pyro.o qix.o \ + rocks.o rorschach.o screenhack.o sierpinski.o slidescreen.o \ + slip.o sphere.o spiral.o strange.o swirl.o xlockmore.o \ + fps.o goop.o starfish.o munch.o fadeplot.o \ + rd-bomb.o coral.o mountain.o triangle.o lissie.o worm.o \ + rotor.o ant.o xjack.o xlyap.o xscreensaver-sgigl.o \ + cynosure.o moire2.o flow.o epicycle.o interference.o \ + truchet.o bsod.o crystal.o discrete.o distort.o kumppa.o \ + demon.o loop.o t3d.o penetrate.o deluxe.o compass.o \ + squiral.o xflame.o wander.o spotlight.o critical.o \ + phosphor.o xmatrix.o petri.o shadebobs.o xsublim.o ccurve.o \ + blaster.o bumps.o ripples.o xspirograph.o \ + nerverot.o xrayswarm.o hyperball.o zoom.o whirlwindwarp.o \ + rotzoomer.o whirlygig.o speedmine.o vermiculate.o \ + ximage-loader.o webcollage-helper.o twang.o apollonian.o \ + euler2d.o juggle.o polyominoes.o thornbird.o fluidballs.o \ + anemone.o halftone.o metaballs.o eruption.o popsquares.o \ + barcode.o piecewise.o cloudlife.o fontglide.o apple2.o \ + apple2-main.o analogtv.o xanalogtv.o pong.o filmleader.o \ + wormhole.o pacman.o pacman_ai.o pacman_level.o \ + fuzzyflakes.o anemotaxis.o memscroller.o substrate.o \ + intermomentary.o fireworkx.o fiberlamp.o boxfit.o \ + interaggregate.o celtic.o cwaves.o webcollage-cocoa.o \ + webcollage-helper-cocoa.o m6502.o asm6502.o abstractile.o \ + lcdscrub.o hexadrop.o tessellimage.o delaunay.o recanim.o \ + binaryring.o glitchpeg.o vfeedback.o testx11.o + +EXES = attraction blitspin bouboule braid decayscreen deco \ + drift flame galaxy grav greynetic halo \ + helix hopalong ifs imsmap julia kaleidescope \ + maze moire noseguy pedal \ + penrose pyro qix rocks rorschach sierpinski slidescreen \ + slip strange swirl goop starfish munch \ + fadeplot rd-bomb coral mountain triangle \ + xjack xlyap cynosure moire2 flow epicycle \ + interference truchet bsod crystal discrete distort kumppa \ + demon loop penetrate deluxe compass squiral xflame \ + wander spotlight phosphor xmatrix petri shadebobs \ + ccurve blaster bumps ripples xspirograph \ + nerverot xrayswarm zoom whirlwindwarp rotzoomer \ + speedmine vermiculate twang apollonian euler2d \ + polyominoes thornbird fluidballs anemone halftone \ + metaballs eruption popsquares barcode piecewise cloudlife \ + fontglide apple2 xanalogtv pong filmleader wormhole \ + pacman fuzzyflakes anemotaxis memscroller substrate \ + intermomentary fireworkx fiberlamp boxfit interaggregate \ + celtic cwaves m6502 abstractile lcdscrub hexadrop \ + tessellimage binaryring glitchpeg vfeedback \ + @JPEG_EXES@ +JPEG_EXES = webcollage-helper + +RETIRED_EXES = ant bubbles critical flag forest hyperball hypercube laser \ + lightning lisa lissie lmorph rotor sphere spiral t3d vines \ + whirlygig worm xsublim juggle testx11 + +HACK_OBJS_1 = fps.o $(UTILS_BIN)/resources.o $(UTILS_BIN)/visual.o \ + $(UTILS_BIN)/usleep.o $(UTILS_BIN)/yarandom.o \ + $(UTILS_BIN)/utf8wc.o $(UTILS_BIN)/font-retry-xft.o \ + @XMU_OBJS@ @XFT_OBJS@ @ANIM_OBJS@ +HACK_OBJS = screenhack.o $(HACK_OBJS_1) +XLOCK_OBJS = screenhack.o xlockmore.o $(COLOR_OBJS) $(HACK_OBJS_1) \ + $(ERASE) +COLOR_OBJS = $(UTILS_BIN)/hsv.o $(UTILS_BIN)/colors.o +GRAB_OBJS = $(UTILS_BIN)/grabclient.o +XSHM_OBJS = $(UTILS_BIN)/xshm.o +XDBE_OBJS = $(UTILS_BIN)/xdbe.o +ANIM_OBJS = recanim.o +ANIM_LIBS = @PNG_LIBS@ +THREAD_OBJS = $(UTILS_BIN)/aligned_malloc.o $(UTILS_BIN)/thread_util.o + +HDRS = screenhack.h screenhackI.h fps.h fpsI.h xlockmore.h \ + xlockmoreI.h automata.h bubbles.h ximage-loader.h \ + apple2.h analogtv.h pacman.h pacman_ai.h pacman_level.h \ + asm6502.h delaunay.h recanim.h +MEN = anemone.man apollonian.man attraction.man \ + blaster.man blitspin.man bouboule.man braid.man bsod.man \ + bumps.man ccurve.man compass.man coral.man \ + crystal.man cynosure.man decayscreen.man \ + deco.man deluxe.man demon.man discrete.man distort.man \ + drift.man epicycle.man euler2d.man fadeplot.man \ + flame.man flow.man fluidballs.man galaxy.man \ + goop.man grav.man greynetic.man halo.man helix.man \ + hopalong.man ifs.man imsmap.man \ + interference.man julia.man \ + kaleidescope.man kumppa.man \ + loop.man maze.man moire.man \ + moire2.man mountain.man munch.man nerverot.man noseguy.man \ + pedal.man penetrate.man penrose.man petri.man phosphor.man \ + polyominoes.man pyro.man qix.man rd-bomb.man ripples.man \ + rocks.man rorschach.man rotzoomer.man \ + shadebobs.man sierpinski.man slidescreen.man slip.man \ + speedmine.man \ + spotlight.man squiral.man starfish.man strange.man \ + swirl.man thornbird.man triangle.man truchet.man \ + twang.man vermiculate.man vidwhacker.man \ + wander.man webcollage.man whirlwindwarp.man \ + xflame.man xjack.man xlyap.man xmatrix.man \ + xrayswarm.man xspirograph.man \ + zoom.man halftone.man eruption.man metaballs.man \ + barcode.man piecewise.man cloudlife.man ljlatest.man \ + fontglide.man apple2.man xanalogtv.man filmleader.man \ + pong.man wormhole.man pacman.man fuzzyflakes.man \ + anemotaxis.man memscroller.man substrate.man \ + intermomentary.man fireworkx.man fiberlamp.man boxfit.man \ + interaggregate.man celtic.man cwaves.man abstractile.man \ + lcdscrub.man hexadrop.man tessellimage.man binaryring.man \ + glitchpeg.man vfeedback.man + +RETIRED_MEN = ant.man bubbles.man critical.man flag.man forest.man \ + laser.man lightning.man lisa.man lissie.man lmorph.man \ + rotor.man sphere.man spiral.man t3d.man vines.man \ + whirlygig.man worm.man xsublim.man juggle.man \ + hypercube.man hyperball.man + +STAR = * +EXTRAS = README Makefile.in xml2man.pl m6502.sh .gdbinit \ + euler2d.tex check-configs.pl munge-ad.pl \ + config/README \ + config/$(STAR).xml \ + config/$(STAR).dtd \ + config/$(STAR).xsd \ + +VMSFILES = compile_axp.com compile_decc.com link_axp.com link_decc.com \ + vms_axp.opt vms_axp_12.opt vms_decc.opt vms_decc_12.opt + +TARFILES = $(SRCS) $(HDRS) $(SCRIPTS) $(MEN) $(RETIRED_MEN) \ + $(EXTRAS) $(VMSFILES) + + +default: all +all: $(EXES) $(RETIRED_EXES) + +install: install-program install-scripts install-xml install-man +uninstall: uninstall-program uninstall-xml uninstall-man + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' \ + install + +# the hacks, in $HACKDIR +install-program:: $(EXES) + @if [ ! -d $(install_prefix)$(HACKDIR) ]; then \ + $(INSTALL_DIRS) $(install_prefix)$(HACKDIR) ; \ + fi ; \ + for program in $(EXES); do \ + echo $(INSTALL_PROGRAM) $$program \ + $(install_prefix)$(HACKDIR)/$$program ; \ + $(INSTALL_PROGRAM) $$program \ + $(install_prefix)$(HACKDIR)/$$program ; \ + done + +install-scripts: $(SCRIPTS) munge-scripts + @for program in $(SCRIPTS); do \ + if [ -r $$program ] ; then \ + p=$$program ; \ + else \ + p=$(srcdir)/$$program ; \ + fi ; \ + echo $(INSTALL_SCRIPT) $$p \ + $(install_prefix)$(HACKDIR)/$$program ; \ + $(INSTALL_SCRIPT) $$p \ + $(install_prefix)$(HACKDIR)/$$program ; \ + done + +munge-scripts: $(SCRIPTS) + @tmp=/tmp/mf.$$$$ ; \ + perl="${PERL}" ; \ + rm -f $$tmp ; \ + for program in $(SCRIPTS); do \ + sed "s@^\(#!\)\(/[^ ]*/perl[^ ]*\)\(.*\)\$$@\1$$perl\3@" \ + < $(srcdir)/$$program > $$tmp ; \ + if ! cmp -s $(srcdir)/$$program $$tmp ; then \ + echo "$$program: setting interpreter to $$perl" >&2 ; \ + cat $$tmp > ./$$program ; \ + fi ; \ + done ; \ + rm -f $$tmp + +# When installing man pages, we install "foo.man" as "foo.N" and update +# the .TH line in the installed file with one like +# +# .TH XScreenSaver N "V.VV (DD-MMM-YYYY)" "X Version 11" +# +# where N is the manual section suffix. +# +install-man: $(MEN) + @men="$(MEN)" ; \ + U=$(UTILS_SRC)/version.h ; \ + V=`sed -n 's/.*xscreensaver \([0-9]\.[^)]*)\).*/\1/p' < $$U` ; \ + T=/tmp/xs$$$$.$(mansuffix) ; \ + TH=".TH XScreenSaver $(mansuffix) \"$$V\" \"X Version 11\"" ; \ + echo "installing man pages: $$TH" ; \ + \ + if [ ! -d $(install_prefix)$(manNdir) ]; then \ + $(INSTALL_DIRS) $(install_prefix)$(manNdir) ; \ + fi ; \ + \ + for man in $$men; do \ + instname=`echo $$man | sed 's/\.man$$/\.$(mansuffix)/'` ; \ + manbase=`echo $$man | sed 's/\.man$$//'` ; \ + TH=".TH $$manbase $(mansuffix) \"$$V\" \"X Version 11\" \"XScreenSaver manual\"" ; \ + sed -e "s/^\.TH.*/$$TH/" \ + -e 's@(MANSUFFIX)@($(mansuffix))@g' \ + < $(srcdir)/$$man > $$T ; \ + echo $(INSTALL_DATA) $(srcdir)/$$man \ + $(install_prefix)$(manNdir)/$$instname ; \ + $(INSTALL_DATA) $$T \ + $(install_prefix)$(manNdir)/$$instname ; \ + done ; \ + rm -f $$T + +install-xml: + @dest=$(install_prefix)$(HACK_CONF_DIR) ; \ + if [ ! -d $$dest ]; then \ + $(INSTALL_DIRS) $$dest ; \ + fi ; \ + src=$(srcdir)/config ; \ + for file in $(EXES) $(SCRIPTS) $(EXTERNALS) ; do \ + if [ -f $$src/$$file.xml ]; then \ + echo $(INSTALL_DATA) $$src/$$file.xml $$dest/$$file.xml ; \ + $(INSTALL_DATA) $$src/$$file.xml $$dest/$$file.xml ; \ + fi ; \ + done + +uninstall-program: + @for program in $(EXES) $(RETIRED_EXES) $(SCRIPTS); do \ + echo rm -f $(install_prefix)$(HACKDIR)/$$program ; \ + rm -f $(install_prefix)$(HACKDIR)/$$program ; \ + done + +uninstall-man: + @men="$(MEN) $(RETIRED_MEN)" ; \ + for man in $$men; do \ + instname=`echo $$man | sed 's/\.man$$/\.$(mansuffix)/'` ; \ + echo rm -f $(install_prefix)$(manNdir)/$$instname* ; \ + rm -f $(install_prefix)$(manNdir)/$$instname* ; \ + done + +uninstall-xml: + @dest=$(install_prefix)$(HACK_CONF_DIR) ; \ + for file in $(EXES) $(RETIRED_EXES) $(SCRIPTS) $(EXTERNALS) ; do \ + echo rm -f $$dest/$$file.xml ; \ + rm -f $$dest/$$file.xml ; \ + done + +clean:: + -rm -f *.o a.out core $(EXES) $(RETIRED_EXES) m6502.h + +distclean: clean + -rm -f Makefile TAGS *~ "#"* + +# Adds all current dependencies to Makefile +depend: + $(DEPEND) -s '# DO NOT DELETE: updated by make depend' \ + $(DEPEND_FLAGS) -- \ + $(INCLUDES) $(DEFS) $(DEPEND_DEFINES) $(CFLAGS) $(X_CFLAGS) -- \ + $(SRCS) + +# Adds some dependencies to Makefile.in -- not totally accurate, but pretty +# close. This excludes dependencies on files in /usr/include, etc. It tries +# to include only dependencies on files which are themselves a part of this +# package. +distdepend:: m6502.h + @echo updating dependencies in `pwd`/Makefile.in... ; \ + $(DEPEND) -w 0 -f - \ + -s '# DO NOT DELETE: updated by make distdepend' $(DEPEND_FLAGS) -- \ + $(INCLUDES_1) $(DEFS) $(DEPEND_DEFINES) $(CFLAGS) $(X_CFLAGS) -- \ + $(SRCS) 2>/dev/null | \ + sort -d | \ + ( \ + awk '/^# .*Makefile.in ---/,/^# DO .*distdepend/' < Makefile.in ; \ + sed -e '/^#.*/d' \ + -e 's@ \./@ @g;s@ /[^ ]*@@g;/^.*:$$/d' \ + -e 's@\.\./utils@$$(UTILS_SRC)@g' \ + -e 's@ \([^$$]\)@ $$(srcdir)/\1@g' \ + -e 's@ $$(srcdir)/\(.*config.h\)@ \1@g' \ + -e 's@ $$(srcdir)/\(m6502.h\)@ \1@g' ; \ + echo '' \ + ) > /tmp/distdepend.$$$$ && \ + mv /tmp/distdepend.$$$$ Makefile.in + +TAGS: tags +tags: + find $(srcdir) -name '*.[chly]' -print | xargs etags -a + +echo_tarfiles: + @echo $(TARFILES) + +check_men: + @badmen="" ; \ + for exe in $(EXES) $(SCRIPTS); do \ + if ! [ -f $(srcdir)/$$exe.man \ + -o "$$exe" = webcollage-helper ]; then \ + badmen="$$badmen $$exe" ; \ + fi ; \ + done ; \ + if [ -n "$$badmen" ]; then \ + echo "" ; \ + echo "Warning: The following programs have no manuals:" ; \ + echo "" ; \ + for m in $$badmen ; do \ + echo " $$m" ; \ + done ; \ + fi + +validate_xml: + @echo "Validating XML..." ; \ + cd $(srcdir) ; ./check-configs.pl $(EXES) + +munge_ad_file: + @echo "Updating hack list in XScreenSaver.ad.in..." ; \ + cd $(srcdir) ; ./munge-ad.pl ../driver/XScreenSaver.ad.in + + +# Rules for generating the VMS makefiles on Unix, so that it doesn't have to +# be done by hand... +# +VMS_AXP_COMPILE_1=$$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE +VMS_AXP_COMPILE_2=)/INCL=([],[-],[-.UTILS]) + +compile_axp.com: Makefile.in + @echo generating $@ from $<... ; \ + ( for c in $(SRCS) ; do \ + c=`echo $$c | tr a-z A-Z` ; \ + echo "$(VMS_AXP_COMPILE_1)$(VMS_AXP_COMPILE_2) $$c" ; \ + done ; \ + ) | sort -d > $@ + +compile_decc.com: compile_axp.com + @echo generating $@ from $<... ; \ + sed 's/axp/decc/g' < $< > $@ + +#### TODO: generating link_axp.com is kinda tricky... + +link_decc.com: link_axp.com + @echo generating $@ from $<... ; \ + sed 's/axp/decc/g' < $< > $@ + +$(srcdir)/../setup.com: Makefile.in + @echo generating $@ from $<... ; \ + ( echo '$$! Xscreensaver - definition of various DCL symbols' ; \ + echo '$$ set NOON' ; \ + echo '$$ set def [.HACKS]' ; \ + echo '$$ mydisk = f$$trnlmn("SYS$$DISK")' ; \ + echo '$$ mydir = mydisk+f$$directory()' ; \ + ( for c in $(EXES) ; do \ + c2="$${c} " ; \ + c2=`echo "$${c2}" | sed 's/^\(........*\) $$/\1/'` ; \ + echo '$$' "$${c2}:== $$'mydir'$${c}" ; \ + done ; \ + ) | sort -d ; \ + echo '$$ set def [-.DRIVER]' ; \ + echo '$$ mydir = mydisk+f$$directory()' ; \ + echo "$$ xscreensaver :== $$'mydir'xscreensaver" ; \ + echo "$$ xscreen*command :== $$'mydir'xscreensaver-command" ; \ + echo '$$ set def [-]' ; \ + echo '$$ exit' ; \ + ) > $@ + +distdepend:: compile_axp.com compile_decc.com +distdepend:: link_axp.com link_decc.com +distdepend:: $(srcdir)/../setup.com +distdepend:: check_men validate_xml munge_ad_file + + +# Rules for noticing when the objects from the utils directory are out of +# date with respect to their sources, and going and building them according +# to the rules in their own Makefile... +# +$(UTILS_BIN)/alpha.o: $(UTILS_SRC)/alpha.c +$(UTILS_BIN)/colors.o: $(UTILS_SRC)/colors.c +$(UTILS_BIN)/grabclient.o: $(UTILS_SRC)/grabclient.c +$(UTILS_BIN)/hsv.o: $(UTILS_SRC)/hsv.c +$(UTILS_BIN)/resources.o: $(UTILS_SRC)/resources.c +$(UTILS_BIN)/spline.o: $(UTILS_SRC)/spline.c +$(UTILS_BIN)/usleep.o: $(UTILS_SRC)/usleep.c +$(UTILS_BIN)/visual.o: $(UTILS_SRC)/visual.c +$(UTILS_BIN)/xmu.o: $(UTILS_SRC)/xmu.c +$(UTILS_BIN)/xft.o: $(UTILS_SRC)/xft.c +$(UTILS_BIN)/utf8wc.o: $(UTILS_SRC)/utf8wc.c +$(UTILS_BIN)/yarandom.o: $(UTILS_SRC)/yarandom.c +$(UTILS_BIN)/erase.o: $(UTILS_SRC)/erase.c +$(UTILS_BIN)/xshm.o: $(UTILS_SRC)/xshm.c +$(UTILS_BIN)/xdbe.o: $(UTILS_SRC)/xdbe.c +$(UTILS_BIN)/textclient.o: $(UTILS_SRC)/textclient.c +$(UTILS_BIN)/aligned_malloc.o: $(UTILS_SRC)/aligned_malloc.c +$(UTILS_BIN)/thread_util.o: $(UTILS_SRC)/thread_util.c +$(UTILS_BIN)/pow2.o: $(UTILS_SRC)/pow2.c +$(UTILS_BIN)/font-retry-xft.o: $(UTILS_SRC)/font-retry.c + +$(UTIL_OBJS): + cd $(UTILS_BIN) ; \ + $(MAKE) $(@F) CC="$(CC)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" + +# How we build object files in this directory. +.c.o: + $(CC) -c $(INCLUDES) $(DEFS) $(CPPFLAGS) $(CFLAGS) $(X_CFLAGS) $< + + +# Make sure these are regenerated when the version number ticks. +screenhack.o: $(UTILS_SRC)/version.h + +# Some abbreviations to keep the lines short... +PNG = ximage-loader.o +ALP = $(UTILS_BIN)/alpha.o +HSV = $(UTILS_BIN)/hsv.o +SPL = $(UTILS_BIN)/spline.o +GRAB = $(GRAB_OBJS) +ERASE = $(UTILS_BIN)/erase.o +COL = $(COLOR_OBJS) +SHM = $(XSHM_OBJS) $(THREAD_OBJS) +DBE = $(XDBE_OBJS) +BARS = $(UTILS_BIN)/colorbars.o +THRO = $(THREAD_OBJS) +THRL = $(THREAD_CFLAGS) $(THREAD_LIBS) +ATV = analogtv.o $(SHM) +APPLE2 = apple2.o $(ATV) +TEXT = $(UTILS_BIN)/textclient.o + +CC_HACK = $(CC) $(LDFLAGS) + +xscreensaver-sgigl: xscreensaver-sgigl.c + $(CC) $(LDFLAGS) -o $@ $< -I$(UTILS_SRC) $(HACK_PRE) \ + $(XMU_LIBS) -lX11 -lXext $(X_EXTRA_LIBS) -lm + +test-utf8wc: $(UTILS_SRC)/utf8wc.c + $(CC) $(INCLUDES) $(DEFS) $(CPPFLAGS) $(CFLAGS) $(X_CFLAGS) $(LDFLAGS)\ + -o $@ -DSELFTEST $< + +# Make sure the images have been packaged. This is the first one hit: +$(HACK_BIN)/images/gen/nose-f1_png.h: + cd $(srcdir)/images && $(MAKE) + +# The rules for those hacks which follow the `screenhack.c' API. +# If make wasn't such an utter abomination, these could all be combined +# into one rule, but we don't live in such a perfect world. The $< rule +# is pretty much useless in the face of more than one dependency, as far +# as I can tell. +# +attraction: attraction.o $(HACK_OBJS) $(COL) $(SPL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(SPL) $(HACK_LIBS) + +binaryring: binaryring.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +blitspin: blitspin.o $(HACK_OBJS) $(GRAB) $(PNG) $(UTILS_BIN)/pow2.o + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(GRAB) $(PNG) $(UTILS_BIN)/pow2.o $(PNG_LIBS) + +bubbles: bubbles.o $(HACK_OBJS) bubbles-default.o $(PNG) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) bubbles-default.o $(PNG) $(PNG_LIBS) + +decayscreen: decayscreen.o $(HACK_OBJS) $(GRAB) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(GRAB) $(HACK_LIBS) + +deco: deco.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +flame: flame.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +greynetic: greynetic.o $(HACK_OBJS) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HACK_LIBS) + +halo: halo.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +helix: helix.o $(HACK_OBJS) $(HSV) $(ERASE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HSV) $(ERASE) $(HACK_LIBS) + +hypercube: hypercube.o $(HACK_OBJS) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HACK_LIBS) + +imsmap: imsmap.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +kaleidescope: kaleidescope.o $(HACK_OBJS) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HACK_LIBS) + +lmorph: lmorph.o $(HACK_OBJS) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HACK_LIBS) + +maze: maze.o $(HACK_OBJS) $(ERASE) $(PNG) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(ERASE) $(PNG) $(PNG_LIBS) + +moire: moire.o $(HACK_OBJS) $(COL) $(SHM) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(SHM) $(HACK_LIBS) $(THRL) + +moire2: moire2.o $(HACK_OBJS) $(COL) $(DBE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(DBE) $(HACK_LIBS) + +noseguy: noseguy.o $(HACK_OBJS) $(PNG) $(TEXT) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(PNG) $(TEXT) $(PNG_LIBS) $(TEXT_LIBS) + +pedal: pedal.o $(HACK_OBJS) $(HSV) $(ERASE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HSV) $(ERASE) $(HACK_LIBS) + +pyro: pyro.o $(HACK_OBJS) $(HSV) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HSV) $(HACK_LIBS) + +qix: qix.o $(HACK_OBJS) $(HSV) $(ALP) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HSV) $(ALP) $(HACK_LIBS) + +rocks: rocks.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +rorschach: rorschach.o $(HACK_OBJS) $(HSV) $(ERASE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HSV) $(ERASE) $(HACK_LIBS) + +slidescreen: slidescreen.o $(HACK_OBJS) $(GRAB) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(GRAB) $(HACK_LIBS) + +goop: goop.o $(HACK_OBJS) $(HSV) $(ALP) $(SPL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HSV) $(ALP) $(SPL) $(HACK_LIBS) + +starfish: starfish.o $(HACK_OBJS) $(COL) $(SPL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(SPL) $(HACK_LIBS) + +munch: munch.o $(HACK_OBJS) $(COL) $(SPL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(SPL) $(HACK_LIBS) + +rd-bomb: rd-bomb.o $(HACK_OBJS) $(COL) $(SHM) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(SHM) $(HACK_LIBS) $(THRL) + +coral: coral.o $(HACK_OBJS) $(COL) $(ERASE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(ERASE) $(HACK_LIBS) + +xjack: xjack.o $(HACK_OBJS) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HACK_LIBS) + +xlyap: xlyap.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +cynosure: cynosure.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +epicycle: epicycle.o $(HACK_OBJS) $(COL) $(ERASE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(ERASE) $(HACK_LIBS) + +interference: interference.o $(HACK_OBJS) $(COL) $(SHM) $(DBE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(SHM) $(DBE) $(HACK_LIBS) $(THRL) + +truchet: truchet.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +bsod: bsod.o $(HACK_OBJS) $(GRAB) $(APPLE2) $(PNG) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(GRAB) $(APPLE2) $(PNG) $(PNG_LIBS) $(THRL) + +apple2: apple2.o apple2-main.o $(HACK_OBJS) $(ATV) $(GRAB) $(TEXT) $(PNG) + $(CC_HACK) -o $@ $@.o apple2-main.o $(HACK_OBJS) $(ATV) $(GRAB) $(TEXT) $(PNG) $(PNG_LIBS) $(TEXT_LIBS) $(THRL) + +xanalogtv: xanalogtv.o $(HACK_OBJS) $(ATV) $(GRAB) $(PNG) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(ATV) $(GRAB) $(PNG) $(PNG_LIBS) $(HACK_LIBS) $(THRL) + +distort: distort.o $(HACK_OBJS) $(GRAB) $(SHM) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(GRAB) $(SHM) $(HACK_LIBS) $(THRL) + +kumppa: kumppa.o $(HACK_OBJS) $(DBE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(DBE) $(HACK_LIBS) + +t3d: t3d.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +penetrate: penetrate.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +deluxe: deluxe.o $(HACK_OBJS) $(ALP) $(COL) $(DBE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(ALP) $(COL) $(DBE) $(HACK_LIBS) + +compass: compass.o $(HACK_OBJS) $(DBE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(DBE) $(HACK_LIBS) + +squiral: squiral.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +xflame: xflame.o $(HACK_OBJS) $(SHM) $(PNG) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(SHM) $(PNG) $(PNG_LIBS) $(THRL) + +wander: wander.o $(HACK_OBJS) $(COL) $(ERASE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(ERASE) $(HACK_LIBS) + +spotlight: spotlight.o $(HACK_OBJS) $(GRAB) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(GRAB) $(HACK_LIBS) + +critical: critical.o $(HACK_OBJS) $(COL) $(ERASE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(ERASE) $(HACK_LIBS) + +phosphor: phosphor.o $(HACK_OBJS) $(TEXT) $(COL) $(PNG) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(TEXT) $(COL) $(PNG) $(PNG_LIBS) $(TEXT_LIBS) + +xmatrix: xmatrix.o $(HACK_OBJS) $(TEXT) $(PNG) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(TEXT) $(PNG) $(PNG_LIBS) $(TEXT_LIBS) + +petri: petri.o $(HACK_OBJS) $(COL) $(SPL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(SPL) $(HACK_LIBS) + +shadebobs: shadebobs.o $(HACK_OBJS) $(COL) $(SPL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(SPL) $(HACK_LIBS) + +ccurve: ccurve.o $(HACK_OBJS) $(COL) $(SPL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(ERASE) $(HACK_LIBS) + +blaster: blaster.o $(HACK_OBJS) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HACK_LIBS) + +bumps: bumps.o $(HACK_OBJS) $(GRAB) $(SHM) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(GRAB) $(SHM) $(HACK_LIBS) $(THRL) + +ripples: ripples.o $(HACK_OBJS) $(SHM) $(COL) $(GRAB) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(SHM) $(COL) $(GRAB) $(HACK_LIBS) $(THRL) + +xspirograph: xspirograph.o $(HACK_OBJS) $(COL) $(ERASE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(ERASE) $(HACK_LIBS) + +nerverot: nerverot.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +xrayswarm: xrayswarm.o $(HACK_OBJS) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HACK_LIBS) + +hyperball: hyperball.o $(HACK_OBJS) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HACK_LIBS) + +zoom: zoom.o $(HACK_OBJS) $(GRAB) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(GRAB) $(HACK_LIBS) + +whirlwindwarp: whirlwindwarp.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +rotzoomer: rotzoomer.o $(HACK_OBJS) $(GRAB) $(SHM) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(GRAB) $(SHM) $(HACK_LIBS) $(THRL) + +whirlygig: whirlygig.o $(HACK_OBJS) $(DBE) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(DBE) $(COL) $(HACK_LIBS) + +speedmine: speedmine.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +vermiculate: vermiculate.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +twang: twang.o $(HACK_OBJS) $(GRAB) $(SHM) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(GRAB) $(SHM) $(HACK_LIBS) $(THRL) + +fluidballs: fluidballs.o $(HACK_OBJS) $(DBE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(DBE) $(HACK_LIBS) + +anemone: anemone.o $(HACK_OBJS) $(COL) $(DBE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(DBE) $(HACK_LIBS) + +halftone: halftone.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +metaballs: metaballs.o $(HACK_OBJS) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HACK_LIBS) + +eruption: eruption.o $(HACK_OBJS) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HACK_LIBS) + +popsquares: popsquares.o $(HACK_OBJS) $(DBE) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(DBE) $(COL) $(HACK_LIBS) + +barcode: barcode.o $(HACK_OBJS) $(HSV) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HSV) $(HACK_LIBS) + +piecewise: piecewise.o $(HACK_OBJS) $(COL) $(DBE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(DBE) $(HACK_LIBS) + +cloudlife: cloudlife.o $(HACK_OBJS) $(COL) $(DBE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(DBE) $(HACK_LIBS) + +fontglide: fontglide.o $(HACK_OBJS) $(DBE) $(TEXT) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(DBE) $(TEXT) $(HACK_LIBS) $(TEXT_LIBS) + +pong: pong.o $(HACK_OBJS) $(ATV) $(GRAB) $(PNG) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(ATV) $(GRAB) $(PNG) $(PNG_LIBS) $(HACK_LIBS) $(THRL) + +wormhole: wormhole.o $(HACK_OBJS) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HACK_LIBS) + +fuzzyflakes: fuzzyflakes.o $(HACK_OBJS) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HACK_LIBS) + +anemotaxis: anemotaxis.o $(HACK_OBJS) $(COL) $(DBE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(DBE) $(HACK_LIBS) + +memscroller: memscroller.o $(HACK_OBJS) $(SHM) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(SHM) $(COL) $(HACK_LIBS) $(THRL) + +substrate: substrate.o $(HACK_OBJS) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HACK_LIBS) + +intermomentary: intermomentary.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +interaggregate: interaggregate.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +fireworkx: fireworkx.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +boxfit: boxfit.o $(HACK_OBJS) $(COL) $(GRAB) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(GRAB) $(HACK_LIBS) + +ifs: ifs.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +celtic: celtic.o $(HACK_OBJS) $(COL) $(ERASE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(ERASE) $(HACK_LIBS) + +cwaves: cwaves.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +m6502.h: + @echo "building m6502.h from $(srcdir)/images/m6502/*.asm"; \ + UTILS_SRC="$(UTILS_SRC)" \ + $(srcdir)/m6502.sh m6502.h $(srcdir)/images/m6502/*.asm + +m6502.o: m6502.h +m6502: m6502.o asm6502.o $(HACK_OBJS) $(ATV) $(PNG) + $(CC_HACK) -o $@ $@.o asm6502.o $(HACK_OBJS) $(ATV) $(PNG) $(PNG_LIBS) $(THRL) + +abstractile: abstractile.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +lcdscrub: lcdscrub.o $(HACK_OBJS) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(HACK_LIBS) + +hexadrop: hexadrop.o $(HACK_OBJS) $(COL) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) + +tessellimage: tessellimage.o delaunay.o $(HACK_OBJS) $(GRAB) + $(CC_HACK) -o $@ $@.o delaunay.o $(HACK_OBJS) $(GRAB) $(HACK_LIBS) + +glitchpeg: glitchpeg.o $(HACK_OBJS) $(PNG) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(PNG) $(PNG_LIBS) + +filmleader: filmleader.o $(HACK_OBJS) $(ATV) $(GRAB) $(PNG) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(ATV) $(GRAB) $(PNG) $(PNG_LIBS) $(HACK_LIBS) $(THRL) + +vfeedback: vfeedback.o $(HACK_OBJS) $(ATV) $(GRAB) $(PNG) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(ATV) $(GRAB) $(PNG) $(PNG_LIBS) $(HACK_LIBS) $(THRL) + + +testx11: testx11.o glx/rotator.o $(HACK_OBJS) $(COL) $(PNG) $(BARS) $(ERASE) + $(CC_HACK) -o $@ $@.o glx/rotator.o $(HACK_OBJS) $(COL) $(PNG) $(BARS) $(ERASE) $(PNG_LIBS) + +glx/rotator.o: glx/rotator.c + cd glx ; \ + $(MAKE) $(@F) CC="$(CC)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" + +# The rules for those hacks which follow the `xlockmore' API. +# + +bouboule: bouboule.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +braid: braid.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +drift: drift.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +flag: flag.o $(XLOCK_OBJS) $(PNG) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(PNG) $(PNG_LIBS) + +forest: forest.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +vines: vines.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +galaxy: galaxy.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +grav: grav.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +hopalong: hopalong.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +julia: julia.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +laser: laser.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +lightning: lightning.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +lisa: lisa.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +lissie: lissie.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +penrose: penrose.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +sierpinski: sierpinski.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +slip: slip.o $(XLOCK_OBJS) $(GRAB) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(GRAB) $(HACK_LIBS) + +sphere: sphere.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +spiral: spiral.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +strange: strange.o $(XLOCK_OBJS) $(SHM) $(UTILS_BIN)/pow2.o + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(SHM) $(UTILS_BIN)/pow2.o $(HACK_LIBS) $(THRL) + +swirl: swirl.o $(XLOCK_OBJS) $(SHM) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(SHM) $(HACK_LIBS) $(THRL) + +fadeplot: fadeplot.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +mountain: mountain.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +triangle: triangle.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +worm: worm.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +rotor: rotor.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +ant: ant.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +demon: demon.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +loop: loop.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +flow: flow.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +discrete: discrete.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +crystal: crystal.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +apollonian: apollonian.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +euler2d: euler2d.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +juggle: juggle.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +polyominoes: polyominoes.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +thornbird: thornbird.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +PACOBJS=pacman_ai.o pacman_level.o +pacman: pacman.o $(PACOBJS) $(XLOCK_OBJS) $(PNG) + $(CC_HACK) -o $@ $@.o $(PACOBJS) $(XLOCK_OBJS) $(PNG) $(PNG_LIBS) + +fiberlamp: fiberlamp.o $(XLOCK_OBJS) + $(CC_HACK) -o $@ $@.o $(XLOCK_OBJS) $(HACK_LIBS) + +# These are not like the others. +# +xsublim: xsublim.o $(HACK_OBJS_1) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS_1) $(HACK_LIBS) + +webcollage-helper: webcollage-helper.o + $(CC_HACK) -o $@ $@.o $(PNG_LIBS) $(JPEG_LIBS) + + +############################################################################## +# +# DO NOT DELETE: updated by make distdepend + +abstractile.o: ../config.h +abstractile.o: $(srcdir)/fps.h +abstractile.o: $(srcdir)/recanim.h +abstractile.o: $(srcdir)/screenhackI.h +abstractile.o: $(srcdir)/screenhack.h +abstractile.o: $(UTILS_SRC)/colors.h +abstractile.o: $(UTILS_SRC)/font-retry.h +abstractile.o: $(UTILS_SRC)/grabscreen.h +abstractile.o: $(UTILS_SRC)/hsv.h +abstractile.o: $(UTILS_SRC)/resources.h +abstractile.o: $(UTILS_SRC)/usleep.h +abstractile.o: $(UTILS_SRC)/visual.h +abstractile.o: $(UTILS_SRC)/yarandom.h +analogtv.o: $(srcdir)/analogtv.h +analogtv.o: ../config.h +analogtv.o: $(srcdir)/images/gen/6x10font_png.h +analogtv.o: $(UTILS_SRC)/aligned_malloc.h +analogtv.o: $(UTILS_SRC)/font-retry.h +analogtv.o: $(UTILS_SRC)/grabscreen.h +analogtv.o: $(UTILS_SRC)/resources.h +analogtv.o: $(UTILS_SRC)/thread_util.h +analogtv.o: $(UTILS_SRC)/utils.h +analogtv.o: $(UTILS_SRC)/visual.h +analogtv.o: $(UTILS_SRC)/xshm.h +analogtv.o: $(UTILS_SRC)/yarandom.h +analogtv.o: $(srcdir)/ximage-loader.h +anemone.o: ../config.h +anemone.o: $(srcdir)/fps.h +anemone.o: $(srcdir)/recanim.h +anemone.o: $(srcdir)/screenhackI.h +anemone.o: $(srcdir)/screenhack.h +anemone.o: $(UTILS_SRC)/colors.h +anemone.o: $(UTILS_SRC)/font-retry.h +anemone.o: $(UTILS_SRC)/grabscreen.h +anemone.o: $(UTILS_SRC)/hsv.h +anemone.o: $(UTILS_SRC)/resources.h +anemone.o: $(UTILS_SRC)/usleep.h +anemone.o: $(UTILS_SRC)/visual.h +anemone.o: $(UTILS_SRC)/xdbe.h +anemone.o: $(UTILS_SRC)/yarandom.h +anemotaxis.o: ../config.h +anemotaxis.o: $(srcdir)/fps.h +anemotaxis.o: $(srcdir)/recanim.h +anemotaxis.o: $(srcdir)/screenhackI.h +anemotaxis.o: $(srcdir)/screenhack.h +anemotaxis.o: $(UTILS_SRC)/colors.h +anemotaxis.o: $(UTILS_SRC)/font-retry.h +anemotaxis.o: $(UTILS_SRC)/grabscreen.h +anemotaxis.o: $(UTILS_SRC)/hsv.h +anemotaxis.o: $(UTILS_SRC)/resources.h +anemotaxis.o: $(UTILS_SRC)/usleep.h +anemotaxis.o: $(UTILS_SRC)/visual.h +anemotaxis.o: $(UTILS_SRC)/xdbe.h +anemotaxis.o: $(UTILS_SRC)/yarandom.h +ant.o: $(srcdir)/automata.h +ant.o: ../config.h +ant.o: $(srcdir)/fps.h +ant.o: $(srcdir)/recanim.h +ant.o: $(srcdir)/screenhackI.h +ant.o: $(UTILS_SRC)/colors.h +ant.o: $(UTILS_SRC)/erase.h +ant.o: $(UTILS_SRC)/font-retry.h +ant.o: $(UTILS_SRC)/grabscreen.h +ant.o: $(UTILS_SRC)/hsv.h +ant.o: $(UTILS_SRC)/resources.h +ant.o: $(UTILS_SRC)/usleep.h +ant.o: $(UTILS_SRC)/visual.h +ant.o: $(UTILS_SRC)/yarandom.h +ant.o: $(srcdir)/xlockmoreI.h +ant.o: $(srcdir)/xlockmore.h +apollonian.o: ../config.h +apollonian.o: $(srcdir)/fps.h +apollonian.o: $(srcdir)/recanim.h +apollonian.o: $(srcdir)/screenhackI.h +apollonian.o: $(UTILS_SRC)/colors.h +apollonian.o: $(UTILS_SRC)/erase.h +apollonian.o: $(UTILS_SRC)/font-retry.h +apollonian.o: $(UTILS_SRC)/grabscreen.h +apollonian.o: $(UTILS_SRC)/hsv.h +apollonian.o: $(UTILS_SRC)/resources.h +apollonian.o: $(UTILS_SRC)/usleep.h +apollonian.o: $(UTILS_SRC)/visual.h +apollonian.o: $(UTILS_SRC)/yarandom.h +apollonian.o: $(srcdir)/xlockmoreI.h +apollonian.o: $(srcdir)/xlockmore.h +apple2-main.o: $(srcdir)/analogtv.h +apple2-main.o: $(srcdir)/apple2.h +apple2-main.o: ../config.h +apple2-main.o: $(srcdir)/fps.h +apple2-main.o: $(srcdir)/recanim.h +apple2-main.o: $(srcdir)/screenhackI.h +apple2-main.o: $(srcdir)/screenhack.h +apple2-main.o: $(UTILS_SRC)/aligned_malloc.h +apple2-main.o: $(UTILS_SRC)/colors.h +apple2-main.o: $(UTILS_SRC)/font-retry.h +apple2-main.o: $(UTILS_SRC)/grabscreen.h +apple2-main.o: $(UTILS_SRC)/hsv.h +apple2-main.o: $(UTILS_SRC)/resources.h +apple2-main.o: $(UTILS_SRC)/textclient.h +apple2-main.o: $(UTILS_SRC)/thread_util.h +apple2-main.o: $(UTILS_SRC)/usleep.h +apple2-main.o: $(UTILS_SRC)/utf8wc.h +apple2-main.o: $(UTILS_SRC)/visual.h +apple2-main.o: $(UTILS_SRC)/xshm.h +apple2-main.o: $(UTILS_SRC)/yarandom.h +apple2.o: $(srcdir)/analogtv.h +apple2.o: $(srcdir)/apple2.h +apple2.o: ../config.h +apple2.o: $(srcdir)/fps.h +apple2.o: $(srcdir)/images/gen/apple2font_png.h +apple2.o: $(srcdir)/recanim.h +apple2.o: $(srcdir)/screenhackI.h +apple2.o: $(UTILS_SRC)/aligned_malloc.h +apple2.o: $(UTILS_SRC)/colors.h +apple2.o: $(UTILS_SRC)/font-retry.h +apple2.o: $(UTILS_SRC)/grabscreen.h +apple2.o: $(UTILS_SRC)/hsv.h +apple2.o: $(UTILS_SRC)/resources.h +apple2.o: $(UTILS_SRC)/thread_util.h +apple2.o: $(UTILS_SRC)/usleep.h +apple2.o: $(UTILS_SRC)/visual.h +apple2.o: $(UTILS_SRC)/xshm.h +apple2.o: $(UTILS_SRC)/yarandom.h +apple2.o: $(srcdir)/ximage-loader.h +asm6502.o: $(srcdir)/asm6502.h +asm6502.o: ../config.h +asm6502.o: $(UTILS_SRC)/yarandom.h +attraction.o: ../config.h +attraction.o: $(srcdir)/fps.h +attraction.o: $(srcdir)/recanim.h +attraction.o: $(srcdir)/screenhackI.h +attraction.o: $(srcdir)/screenhack.h +attraction.o: $(UTILS_SRC)/colors.h +attraction.o: $(UTILS_SRC)/font-retry.h +attraction.o: $(UTILS_SRC)/grabscreen.h +attraction.o: $(UTILS_SRC)/hsv.h +attraction.o: $(UTILS_SRC)/resources.h +attraction.o: $(UTILS_SRC)/spline.h +attraction.o: $(UTILS_SRC)/usleep.h +attraction.o: $(UTILS_SRC)/visual.h +attraction.o: $(UTILS_SRC)/yarandom.h +barcode.o: ../config.h +barcode.o: $(srcdir)/fps.h +barcode.o: $(srcdir)/recanim.h +barcode.o: $(srcdir)/screenhackI.h +barcode.o: $(srcdir)/screenhack.h +barcode.o: $(UTILS_SRC)/colors.h +barcode.o: $(UTILS_SRC)/font-retry.h +barcode.o: $(UTILS_SRC)/grabscreen.h +barcode.o: $(UTILS_SRC)/hsv.h +barcode.o: $(UTILS_SRC)/resources.h +barcode.o: $(UTILS_SRC)/usleep.h +barcode.o: $(UTILS_SRC)/visual.h +barcode.o: $(UTILS_SRC)/yarandom.h +binaryring.o: ../config.h +binaryring.o: $(srcdir)/fps.h +binaryring.o: $(srcdir)/recanim.h +binaryring.o: $(srcdir)/screenhackI.h +binaryring.o: $(srcdir)/screenhack.h +binaryring.o: $(UTILS_SRC)/colors.h +binaryring.o: $(UTILS_SRC)/font-retry.h +binaryring.o: $(UTILS_SRC)/grabscreen.h +binaryring.o: $(UTILS_SRC)/hsv.h +binaryring.o: $(UTILS_SRC)/resources.h +binaryring.o: $(UTILS_SRC)/usleep.h +binaryring.o: $(UTILS_SRC)/visual.h +binaryring.o: $(UTILS_SRC)/yarandom.h +blaster.o: ../config.h +blaster.o: $(srcdir)/fps.h +blaster.o: $(srcdir)/recanim.h +blaster.o: $(srcdir)/screenhackI.h +blaster.o: $(srcdir)/screenhack.h +blaster.o: $(UTILS_SRC)/colors.h +blaster.o: $(UTILS_SRC)/font-retry.h +blaster.o: $(UTILS_SRC)/grabscreen.h +blaster.o: $(UTILS_SRC)/hsv.h +blaster.o: $(UTILS_SRC)/resources.h +blaster.o: $(UTILS_SRC)/usleep.h +blaster.o: $(UTILS_SRC)/visual.h +blaster.o: $(UTILS_SRC)/yarandom.h +blitspin.o: ../config.h +blitspin.o: $(srcdir)/fps.h +blitspin.o: $(srcdir)/images/gen/som_png.h +blitspin.o: $(srcdir)/recanim.h +blitspin.o: $(srcdir)/screenhackI.h +blitspin.o: $(srcdir)/screenhack.h +blitspin.o: $(UTILS_SRC)/colors.h +blitspin.o: $(UTILS_SRC)/font-retry.h +blitspin.o: $(UTILS_SRC)/grabscreen.h +blitspin.o: $(UTILS_SRC)/hsv.h +blitspin.o: $(UTILS_SRC)/pow2.h +blitspin.o: $(UTILS_SRC)/resources.h +blitspin.o: $(UTILS_SRC)/usleep.h +blitspin.o: $(UTILS_SRC)/visual.h +blitspin.o: $(UTILS_SRC)/yarandom.h +blitspin.o: $(srcdir)/ximage-loader.h +bouboule.o: ../config.h +bouboule.o: $(srcdir)/fps.h +bouboule.o: $(srcdir)/recanim.h +bouboule.o: $(srcdir)/screenhackI.h +bouboule.o: $(UTILS_SRC)/colors.h +bouboule.o: $(UTILS_SRC)/erase.h +bouboule.o: $(UTILS_SRC)/font-retry.h +bouboule.o: $(UTILS_SRC)/grabscreen.h +bouboule.o: $(UTILS_SRC)/hsv.h +bouboule.o: $(UTILS_SRC)/resources.h +bouboule.o: $(UTILS_SRC)/usleep.h +bouboule.o: $(UTILS_SRC)/visual.h +bouboule.o: $(UTILS_SRC)/yarandom.h +bouboule.o: $(srcdir)/xlockmoreI.h +bouboule.o: $(srcdir)/xlockmore.h +boxfit.o: ../config.h +boxfit.o: $(srcdir)/fps.h +boxfit.o: $(srcdir)/recanim.h +boxfit.o: $(srcdir)/screenhackI.h +boxfit.o: $(srcdir)/screenhack.h +boxfit.o: $(UTILS_SRC)/colors.h +boxfit.o: $(UTILS_SRC)/font-retry.h +boxfit.o: $(UTILS_SRC)/grabscreen.h +boxfit.o: $(UTILS_SRC)/hsv.h +boxfit.o: $(UTILS_SRC)/resources.h +boxfit.o: $(UTILS_SRC)/usleep.h +boxfit.o: $(UTILS_SRC)/visual.h +boxfit.o: $(UTILS_SRC)/yarandom.h +boxfit.o: $(srcdir)/ximage-loader.h +braid.o: ../config.h +braid.o: $(srcdir)/fps.h +braid.o: $(srcdir)/recanim.h +braid.o: $(srcdir)/screenhackI.h +braid.o: $(UTILS_SRC)/colors.h +braid.o: $(UTILS_SRC)/erase.h +braid.o: $(UTILS_SRC)/font-retry.h +braid.o: $(UTILS_SRC)/grabscreen.h +braid.o: $(UTILS_SRC)/hsv.h +braid.o: $(UTILS_SRC)/resources.h +braid.o: $(UTILS_SRC)/usleep.h +braid.o: $(UTILS_SRC)/visual.h +braid.o: $(UTILS_SRC)/yarandom.h +braid.o: $(srcdir)/xlockmoreI.h +braid.o: $(srcdir)/xlockmore.h +bsod.o: $(srcdir)/analogtv.h +bsod.o: $(srcdir)/apple2.h +bsod.o: ../config.h +bsod.o: $(srcdir)/fps.h +bsod.o: $(srcdir)/images/gen/amiga_png.h +bsod.o: $(srcdir)/images/gen/android_png.h +bsod.o: $(srcdir)/images/gen/apple_png.h +bsod.o: $(srcdir)/images/gen/atari_png.h +bsod.o: $(srcdir)/images/gen/atm_png.h +bsod.o: $(srcdir)/images/gen/hmac_png.h +bsod.o: $(srcdir)/images/gen/macbomb_png.h +bsod.o: $(srcdir)/images/gen/mac_png.h +bsod.o: $(srcdir)/images/gen/osx_10_2_png.h +bsod.o: $(srcdir)/images/gen/osx_10_3_png.h +bsod.o: $(srcdir)/images/gen/ransomware_png.h +bsod.o: $(srcdir)/recanim.h +bsod.o: $(srcdir)/screenhackI.h +bsod.o: $(srcdir)/screenhack.h +bsod.o: $(UTILS_SRC)/aligned_malloc.h +bsod.o: $(UTILS_SRC)/colors.h +bsod.o: $(UTILS_SRC)/font-retry.h +bsod.o: $(UTILS_SRC)/grabscreen.h +bsod.o: $(UTILS_SRC)/hsv.h +bsod.o: $(UTILS_SRC)/resources.h +bsod.o: $(UTILS_SRC)/thread_util.h +bsod.o: $(UTILS_SRC)/usleep.h +bsod.o: $(UTILS_SRC)/visual.h +bsod.o: $(UTILS_SRC)/xshm.h +bsod.o: $(UTILS_SRC)/yarandom.h +bsod.o: $(srcdir)/ximage-loader.h +bubbles-default.o: $(srcdir)/bubbles.h +bubbles-default.o: ../config.h +bubbles-default.o: $(srcdir)/images/gen/blood10_png.h +bubbles-default.o: $(srcdir)/images/gen/blood11_png.h +bubbles-default.o: $(srcdir)/images/gen/blood1_png.h +bubbles-default.o: $(srcdir)/images/gen/blood2_png.h +bubbles-default.o: $(srcdir)/images/gen/blood3_png.h +bubbles-default.o: $(srcdir)/images/gen/blood4_png.h +bubbles-default.o: $(srcdir)/images/gen/blood5_png.h +bubbles-default.o: $(srcdir)/images/gen/blood6_png.h +bubbles-default.o: $(srcdir)/images/gen/blood7_png.h +bubbles-default.o: $(srcdir)/images/gen/blood8_png.h +bubbles-default.o: $(srcdir)/images/gen/blood9_png.h +bubbles-default.o: $(srcdir)/images/gen/blue10_png.h +bubbles-default.o: $(srcdir)/images/gen/blue11_png.h +bubbles-default.o: $(srcdir)/images/gen/blue1_png.h +bubbles-default.o: $(srcdir)/images/gen/blue2_png.h +bubbles-default.o: $(srcdir)/images/gen/blue3_png.h +bubbles-default.o: $(srcdir)/images/gen/blue4_png.h +bubbles-default.o: $(srcdir)/images/gen/blue5_png.h +bubbles-default.o: $(srcdir)/images/gen/blue6_png.h +bubbles-default.o: $(srcdir)/images/gen/blue7_png.h +bubbles-default.o: $(srcdir)/images/gen/blue8_png.h +bubbles-default.o: $(srcdir)/images/gen/blue9_png.h +bubbles-default.o: $(srcdir)/images/gen/glass10_png.h +bubbles-default.o: $(srcdir)/images/gen/glass11_png.h +bubbles-default.o: $(srcdir)/images/gen/glass1_png.h +bubbles-default.o: $(srcdir)/images/gen/glass2_png.h +bubbles-default.o: $(srcdir)/images/gen/glass3_png.h +bubbles-default.o: $(srcdir)/images/gen/glass4_png.h +bubbles-default.o: $(srcdir)/images/gen/glass5_png.h +bubbles-default.o: $(srcdir)/images/gen/glass6_png.h +bubbles-default.o: $(srcdir)/images/gen/glass7_png.h +bubbles-default.o: $(srcdir)/images/gen/glass8_png.h +bubbles-default.o: $(srcdir)/images/gen/glass9_png.h +bubbles-default.o: $(srcdir)/images/gen/jade10_png.h +bubbles-default.o: $(srcdir)/images/gen/jade11_png.h +bubbles-default.o: $(srcdir)/images/gen/jade1_png.h +bubbles-default.o: $(srcdir)/images/gen/jade2_png.h +bubbles-default.o: $(srcdir)/images/gen/jade3_png.h +bubbles-default.o: $(srcdir)/images/gen/jade4_png.h +bubbles-default.o: $(srcdir)/images/gen/jade5_png.h +bubbles-default.o: $(srcdir)/images/gen/jade6_png.h +bubbles-default.o: $(srcdir)/images/gen/jade7_png.h +bubbles-default.o: $(srcdir)/images/gen/jade8_png.h +bubbles-default.o: $(srcdir)/images/gen/jade9_png.h +bubbles-default.o: $(UTILS_SRC)/yarandom.h +bubbles.o: $(srcdir)/bubbles.h +bubbles.o: ../config.h +bubbles.o: $(srcdir)/fps.h +bubbles.o: $(srcdir)/recanim.h +bubbles.o: $(srcdir)/screenhackI.h +bubbles.o: $(srcdir)/screenhack.h +bubbles.o: $(UTILS_SRC)/colors.h +bubbles.o: $(UTILS_SRC)/font-retry.h +bubbles.o: $(UTILS_SRC)/grabscreen.h +bubbles.o: $(UTILS_SRC)/hsv.h +bubbles.o: $(UTILS_SRC)/resources.h +bubbles.o: $(UTILS_SRC)/usleep.h +bubbles.o: $(UTILS_SRC)/visual.h +bubbles.o: $(UTILS_SRC)/yarandom.h +bubbles.o: $(srcdir)/ximage-loader.h +bumps.o: ../config.h +bumps.o: $(srcdir)/fps.h +bumps.o: $(srcdir)/recanim.h +bumps.o: $(srcdir)/screenhackI.h +bumps.o: $(srcdir)/screenhack.h +bumps.o: $(UTILS_SRC)/colors.h +bumps.o: $(UTILS_SRC)/font-retry.h +bumps.o: $(UTILS_SRC)/grabscreen.h +bumps.o: $(UTILS_SRC)/hsv.h +bumps.o: $(UTILS_SRC)/resources.h +bumps.o: $(UTILS_SRC)/usleep.h +bumps.o: $(UTILS_SRC)/visual.h +bumps.o: $(UTILS_SRC)/xshm.h +bumps.o: $(UTILS_SRC)/yarandom.h +ccurve.o: ../config.h +ccurve.o: $(srcdir)/fps.h +ccurve.o: $(srcdir)/recanim.h +ccurve.o: $(srcdir)/screenhackI.h +ccurve.o: $(srcdir)/screenhack.h +ccurve.o: $(UTILS_SRC)/colors.h +ccurve.o: $(UTILS_SRC)/erase.h +ccurve.o: $(UTILS_SRC)/font-retry.h +ccurve.o: $(UTILS_SRC)/grabscreen.h +ccurve.o: $(UTILS_SRC)/hsv.h +ccurve.o: $(UTILS_SRC)/resources.h +ccurve.o: $(UTILS_SRC)/usleep.h +ccurve.o: $(UTILS_SRC)/visual.h +ccurve.o: $(UTILS_SRC)/yarandom.h +celtic.o: ../config.h +celtic.o: $(srcdir)/fps.h +celtic.o: $(srcdir)/recanim.h +celtic.o: $(srcdir)/screenhackI.h +celtic.o: $(srcdir)/screenhack.h +celtic.o: $(UTILS_SRC)/colors.h +celtic.o: $(UTILS_SRC)/erase.h +celtic.o: $(UTILS_SRC)/font-retry.h +celtic.o: $(UTILS_SRC)/grabscreen.h +celtic.o: $(UTILS_SRC)/hsv.h +celtic.o: $(UTILS_SRC)/resources.h +celtic.o: $(UTILS_SRC)/usleep.h +celtic.o: $(UTILS_SRC)/visual.h +celtic.o: $(UTILS_SRC)/yarandom.h +cloudlife.o: ../config.h +cloudlife.o: $(srcdir)/fps.h +cloudlife.o: $(srcdir)/recanim.h +cloudlife.o: $(srcdir)/screenhackI.h +cloudlife.o: $(srcdir)/screenhack.h +cloudlife.o: $(UTILS_SRC)/colors.h +cloudlife.o: $(UTILS_SRC)/font-retry.h +cloudlife.o: $(UTILS_SRC)/grabscreen.h +cloudlife.o: $(UTILS_SRC)/hsv.h +cloudlife.o: $(UTILS_SRC)/resources.h +cloudlife.o: $(UTILS_SRC)/usleep.h +cloudlife.o: $(UTILS_SRC)/visual.h +cloudlife.o: $(UTILS_SRC)/yarandom.h +compass.o: ../config.h +compass.o: $(srcdir)/fps.h +compass.o: $(srcdir)/recanim.h +compass.o: $(srcdir)/screenhackI.h +compass.o: $(srcdir)/screenhack.h +compass.o: $(UTILS_SRC)/colors.h +compass.o: $(UTILS_SRC)/font-retry.h +compass.o: $(UTILS_SRC)/grabscreen.h +compass.o: $(UTILS_SRC)/hsv.h +compass.o: $(UTILS_SRC)/resources.h +compass.o: $(UTILS_SRC)/usleep.h +compass.o: $(UTILS_SRC)/visual.h +compass.o: $(UTILS_SRC)/xdbe.h +compass.o: $(UTILS_SRC)/yarandom.h +coral.o: ../config.h +coral.o: $(srcdir)/fps.h +coral.o: $(srcdir)/recanim.h +coral.o: $(srcdir)/screenhackI.h +coral.o: $(srcdir)/screenhack.h +coral.o: $(UTILS_SRC)/colors.h +coral.o: $(UTILS_SRC)/erase.h +coral.o: $(UTILS_SRC)/font-retry.h +coral.o: $(UTILS_SRC)/grabscreen.h +coral.o: $(UTILS_SRC)/hsv.h +coral.o: $(UTILS_SRC)/resources.h +coral.o: $(UTILS_SRC)/usleep.h +coral.o: $(UTILS_SRC)/visual.h +coral.o: $(UTILS_SRC)/yarandom.h +critical.o: ../config.h +critical.o: $(srcdir)/fps.h +critical.o: $(srcdir)/recanim.h +critical.o: $(srcdir)/screenhackI.h +critical.o: $(srcdir)/screenhack.h +critical.o: $(UTILS_SRC)/colors.h +critical.o: $(UTILS_SRC)/erase.h +critical.o: $(UTILS_SRC)/font-retry.h +critical.o: $(UTILS_SRC)/grabscreen.h +critical.o: $(UTILS_SRC)/hsv.h +critical.o: $(UTILS_SRC)/resources.h +critical.o: $(UTILS_SRC)/usleep.h +critical.o: $(UTILS_SRC)/visual.h +critical.o: $(UTILS_SRC)/yarandom.h +crystal.o: ../config.h +crystal.o: $(srcdir)/fps.h +crystal.o: $(srcdir)/recanim.h +crystal.o: $(srcdir)/screenhackI.h +crystal.o: $(UTILS_SRC)/colors.h +crystal.o: $(UTILS_SRC)/erase.h +crystal.o: $(UTILS_SRC)/font-retry.h +crystal.o: $(UTILS_SRC)/grabscreen.h +crystal.o: $(UTILS_SRC)/hsv.h +crystal.o: $(UTILS_SRC)/resources.h +crystal.o: $(UTILS_SRC)/usleep.h +crystal.o: $(UTILS_SRC)/visual.h +crystal.o: $(UTILS_SRC)/yarandom.h +crystal.o: $(srcdir)/xlockmoreI.h +crystal.o: $(srcdir)/xlockmore.h +cwaves.o: ../config.h +cwaves.o: $(srcdir)/fps.h +cwaves.o: $(srcdir)/recanim.h +cwaves.o: $(srcdir)/screenhackI.h +cwaves.o: $(srcdir)/screenhack.h +cwaves.o: $(UTILS_SRC)/colors.h +cwaves.o: $(UTILS_SRC)/font-retry.h +cwaves.o: $(UTILS_SRC)/grabscreen.h +cwaves.o: $(UTILS_SRC)/hsv.h +cwaves.o: $(UTILS_SRC)/resources.h +cwaves.o: $(UTILS_SRC)/usleep.h +cwaves.o: $(UTILS_SRC)/visual.h +cwaves.o: $(UTILS_SRC)/yarandom.h +cwaves.o: $(srcdir)/ximage-loader.h +cynosure.o: ../config.h +cynosure.o: $(srcdir)/fps.h +cynosure.o: $(srcdir)/recanim.h +cynosure.o: $(srcdir)/screenhackI.h +cynosure.o: $(srcdir)/screenhack.h +cynosure.o: $(UTILS_SRC)/colors.h +cynosure.o: $(UTILS_SRC)/font-retry.h +cynosure.o: $(UTILS_SRC)/grabscreen.h +cynosure.o: $(UTILS_SRC)/hsv.h +cynosure.o: $(UTILS_SRC)/resources.h +cynosure.o: $(UTILS_SRC)/usleep.h +cynosure.o: $(UTILS_SRC)/visual.h +cynosure.o: $(UTILS_SRC)/yarandom.h +decayscreen.o: ../config.h +decayscreen.o: $(srcdir)/fps.h +decayscreen.o: $(srcdir)/recanim.h +decayscreen.o: $(srcdir)/screenhackI.h +decayscreen.o: $(srcdir)/screenhack.h +decayscreen.o: $(UTILS_SRC)/colors.h +decayscreen.o: $(UTILS_SRC)/font-retry.h +decayscreen.o: $(UTILS_SRC)/grabscreen.h +decayscreen.o: $(UTILS_SRC)/hsv.h +decayscreen.o: $(UTILS_SRC)/resources.h +decayscreen.o: $(UTILS_SRC)/usleep.h +decayscreen.o: $(UTILS_SRC)/visual.h +decayscreen.o: $(UTILS_SRC)/yarandom.h +deco.o: ../config.h +deco.o: $(srcdir)/fps.h +deco.o: $(srcdir)/recanim.h +deco.o: $(srcdir)/screenhackI.h +deco.o: $(srcdir)/screenhack.h +deco.o: $(UTILS_SRC)/colors.h +deco.o: $(UTILS_SRC)/font-retry.h +deco.o: $(UTILS_SRC)/grabscreen.h +deco.o: $(UTILS_SRC)/hsv.h +deco.o: $(UTILS_SRC)/resources.h +deco.o: $(UTILS_SRC)/usleep.h +deco.o: $(UTILS_SRC)/visual.h +deco.o: $(UTILS_SRC)/yarandom.h +delaunay.o: ../config.h +delaunay.o: $(srcdir)/delaunay.h +deluxe.o: ../config.h +deluxe.o: $(srcdir)/fps.h +deluxe.o: $(srcdir)/recanim.h +deluxe.o: $(srcdir)/screenhackI.h +deluxe.o: $(srcdir)/screenhack.h +deluxe.o: $(UTILS_SRC)/alpha.h +deluxe.o: $(UTILS_SRC)/colors.h +deluxe.o: $(UTILS_SRC)/font-retry.h +deluxe.o: $(UTILS_SRC)/grabscreen.h +deluxe.o: $(UTILS_SRC)/hsv.h +deluxe.o: $(UTILS_SRC)/resources.h +deluxe.o: $(UTILS_SRC)/usleep.h +deluxe.o: $(UTILS_SRC)/visual.h +deluxe.o: $(UTILS_SRC)/xdbe.h +deluxe.o: $(UTILS_SRC)/yarandom.h +demon.o: $(srcdir)/automata.h +demon.o: ../config.h +demon.o: $(srcdir)/fps.h +demon.o: $(srcdir)/recanim.h +demon.o: $(srcdir)/screenhackI.h +demon.o: $(UTILS_SRC)/colors.h +demon.o: $(UTILS_SRC)/erase.h +demon.o: $(UTILS_SRC)/font-retry.h +demon.o: $(UTILS_SRC)/grabscreen.h +demon.o: $(UTILS_SRC)/hsv.h +demon.o: $(UTILS_SRC)/resources.h +demon.o: $(UTILS_SRC)/usleep.h +demon.o: $(UTILS_SRC)/visual.h +demon.o: $(UTILS_SRC)/yarandom.h +demon.o: $(srcdir)/xlockmoreI.h +demon.o: $(srcdir)/xlockmore.h +discrete.o: ../config.h +discrete.o: $(srcdir)/fps.h +discrete.o: $(srcdir)/recanim.h +discrete.o: $(srcdir)/screenhackI.h +discrete.o: $(UTILS_SRC)/colors.h +discrete.o: $(UTILS_SRC)/erase.h +discrete.o: $(UTILS_SRC)/font-retry.h +discrete.o: $(UTILS_SRC)/grabscreen.h +discrete.o: $(UTILS_SRC)/hsv.h +discrete.o: $(UTILS_SRC)/resources.h +discrete.o: $(UTILS_SRC)/usleep.h +discrete.o: $(UTILS_SRC)/visual.h +discrete.o: $(UTILS_SRC)/yarandom.h +discrete.o: $(srcdir)/xlockmoreI.h +discrete.o: $(srcdir)/xlockmore.h +distort.o: ../config.h +distort.o: $(srcdir)/fps.h +distort.o: $(srcdir)/recanim.h +distort.o: $(srcdir)/screenhackI.h +distort.o: $(srcdir)/screenhack.h +distort.o: $(UTILS_SRC)/colors.h +distort.o: $(UTILS_SRC)/font-retry.h +distort.o: $(UTILS_SRC)/grabscreen.h +distort.o: $(UTILS_SRC)/hsv.h +distort.o: $(UTILS_SRC)/resources.h +distort.o: $(UTILS_SRC)/usleep.h +distort.o: $(UTILS_SRC)/visual.h +distort.o: $(UTILS_SRC)/xshm.h +distort.o: $(UTILS_SRC)/yarandom.h +drift.o: ../config.h +drift.o: $(srcdir)/fps.h +drift.o: $(srcdir)/recanim.h +drift.o: $(srcdir)/screenhackI.h +drift.o: $(UTILS_SRC)/colors.h +drift.o: $(UTILS_SRC)/erase.h +drift.o: $(UTILS_SRC)/font-retry.h +drift.o: $(UTILS_SRC)/grabscreen.h +drift.o: $(UTILS_SRC)/hsv.h +drift.o: $(UTILS_SRC)/resources.h +drift.o: $(UTILS_SRC)/usleep.h +drift.o: $(UTILS_SRC)/visual.h +drift.o: $(UTILS_SRC)/yarandom.h +drift.o: $(srcdir)/xlockmoreI.h +drift.o: $(srcdir)/xlockmore.h +epicycle.o: ../config.h +epicycle.o: $(srcdir)/fps.h +epicycle.o: $(srcdir)/recanim.h +epicycle.o: $(srcdir)/screenhackI.h +epicycle.o: $(srcdir)/screenhack.h +epicycle.o: $(UTILS_SRC)/colors.h +epicycle.o: $(UTILS_SRC)/erase.h +epicycle.o: $(UTILS_SRC)/font-retry.h +epicycle.o: $(UTILS_SRC)/grabscreen.h +epicycle.o: $(UTILS_SRC)/hsv.h +epicycle.o: $(UTILS_SRC)/resources.h +epicycle.o: $(UTILS_SRC)/usleep.h +epicycle.o: $(UTILS_SRC)/visual.h +epicycle.o: $(UTILS_SRC)/yarandom.h +eruption.o: ../config.h +eruption.o: $(srcdir)/fps.h +eruption.o: $(srcdir)/recanim.h +eruption.o: $(srcdir)/screenhackI.h +eruption.o: $(srcdir)/screenhack.h +eruption.o: $(UTILS_SRC)/colors.h +eruption.o: $(UTILS_SRC)/font-retry.h +eruption.o: $(UTILS_SRC)/grabscreen.h +eruption.o: $(UTILS_SRC)/hsv.h +eruption.o: $(UTILS_SRC)/resources.h +eruption.o: $(UTILS_SRC)/usleep.h +eruption.o: $(UTILS_SRC)/visual.h +eruption.o: $(UTILS_SRC)/yarandom.h +euler2d.o: ../config.h +euler2d.o: $(srcdir)/fps.h +euler2d.o: $(srcdir)/recanim.h +euler2d.o: $(srcdir)/screenhackI.h +euler2d.o: $(UTILS_SRC)/colors.h +euler2d.o: $(UTILS_SRC)/erase.h +euler2d.o: $(UTILS_SRC)/font-retry.h +euler2d.o: $(UTILS_SRC)/grabscreen.h +euler2d.o: $(UTILS_SRC)/hsv.h +euler2d.o: $(UTILS_SRC)/resources.h +euler2d.o: $(UTILS_SRC)/usleep.h +euler2d.o: $(UTILS_SRC)/visual.h +euler2d.o: $(UTILS_SRC)/yarandom.h +euler2d.o: $(srcdir)/xlockmoreI.h +euler2d.o: $(srcdir)/xlockmore.h +fadeplot.o: ../config.h +fadeplot.o: $(srcdir)/fps.h +fadeplot.o: $(srcdir)/recanim.h +fadeplot.o: $(srcdir)/screenhackI.h +fadeplot.o: $(UTILS_SRC)/colors.h +fadeplot.o: $(UTILS_SRC)/erase.h +fadeplot.o: $(UTILS_SRC)/font-retry.h +fadeplot.o: $(UTILS_SRC)/grabscreen.h +fadeplot.o: $(UTILS_SRC)/hsv.h +fadeplot.o: $(UTILS_SRC)/resources.h +fadeplot.o: $(UTILS_SRC)/usleep.h +fadeplot.o: $(UTILS_SRC)/visual.h +fadeplot.o: $(UTILS_SRC)/yarandom.h +fadeplot.o: $(srcdir)/xlockmoreI.h +fadeplot.o: $(srcdir)/xlockmore.h +fiberlamp.o: ../config.h +fiberlamp.o: $(srcdir)/fps.h +fiberlamp.o: $(srcdir)/recanim.h +fiberlamp.o: $(srcdir)/screenhackI.h +fiberlamp.o: $(UTILS_SRC)/colors.h +fiberlamp.o: $(UTILS_SRC)/erase.h +fiberlamp.o: $(UTILS_SRC)/font-retry.h +fiberlamp.o: $(UTILS_SRC)/grabscreen.h +fiberlamp.o: $(UTILS_SRC)/hsv.h +fiberlamp.o: $(UTILS_SRC)/resources.h +fiberlamp.o: $(UTILS_SRC)/usleep.h +fiberlamp.o: $(UTILS_SRC)/visual.h +fiberlamp.o: $(UTILS_SRC)/yarandom.h +fiberlamp.o: $(srcdir)/xlockmoreI.h +fiberlamp.o: $(srcdir)/xlockmore.h +filmleader.o: $(srcdir)/analogtv.h +filmleader.o: ../config.h +filmleader.o: $(srcdir)/fps.h +filmleader.o: $(srcdir)/recanim.h +filmleader.o: $(srcdir)/screenhackI.h +filmleader.o: $(srcdir)/screenhack.h +filmleader.o: $(UTILS_SRC)/aligned_malloc.h +filmleader.o: $(UTILS_SRC)/colors.h +filmleader.o: $(UTILS_SRC)/font-retry.h +filmleader.o: $(UTILS_SRC)/grabscreen.h +filmleader.o: $(UTILS_SRC)/hsv.h +filmleader.o: $(UTILS_SRC)/resources.h +filmleader.o: $(UTILS_SRC)/thread_util.h +filmleader.o: $(UTILS_SRC)/usleep.h +filmleader.o: $(UTILS_SRC)/visual.h +filmleader.o: $(UTILS_SRC)/xft.h +filmleader.o: $(UTILS_SRC)/xshm.h +filmleader.o: $(UTILS_SRC)/yarandom.h +fireworkx.o: ../config.h +fireworkx.o: $(srcdir)/fps.h +fireworkx.o: $(srcdir)/recanim.h +fireworkx.o: $(srcdir)/screenhackI.h +fireworkx.o: $(srcdir)/screenhack.h +fireworkx.o: $(UTILS_SRC)/colors.h +fireworkx.o: $(UTILS_SRC)/font-retry.h +fireworkx.o: $(UTILS_SRC)/grabscreen.h +fireworkx.o: $(UTILS_SRC)/hsv.h +fireworkx.o: $(UTILS_SRC)/resources.h +fireworkx.o: $(UTILS_SRC)/usleep.h +fireworkx.o: $(UTILS_SRC)/visual.h +fireworkx.o: $(UTILS_SRC)/yarandom.h +flag.o: ../config.h +flag.o: $(srcdir)/fps.h +flag.o: $(srcdir)/images/gen/bob_png.h +flag.o: $(srcdir)/recanim.h +flag.o: $(srcdir)/screenhackI.h +flag.o: $(UTILS_SRC)/colors.h +flag.o: $(UTILS_SRC)/erase.h +flag.o: $(UTILS_SRC)/font-retry.h +flag.o: $(UTILS_SRC)/grabscreen.h +flag.o: $(UTILS_SRC)/hsv.h +flag.o: $(UTILS_SRC)/resources.h +flag.o: $(UTILS_SRC)/usleep.h +flag.o: $(UTILS_SRC)/visual.h +flag.o: $(UTILS_SRC)/yarandom.h +flag.o: $(srcdir)/ximage-loader.h +flag.o: $(srcdir)/xlockmoreI.h +flag.o: $(srcdir)/xlockmore.h +flame.o: ../config.h +flame.o: $(srcdir)/fps.h +flame.o: $(srcdir)/recanim.h +flame.o: $(srcdir)/screenhackI.h +flame.o: $(srcdir)/screenhack.h +flame.o: $(UTILS_SRC)/colors.h +flame.o: $(UTILS_SRC)/font-retry.h +flame.o: $(UTILS_SRC)/grabscreen.h +flame.o: $(UTILS_SRC)/hsv.h +flame.o: $(UTILS_SRC)/resources.h +flame.o: $(UTILS_SRC)/usleep.h +flame.o: $(UTILS_SRC)/visual.h +flame.o: $(UTILS_SRC)/yarandom.h +flow.o: ../config.h +flow.o: $(srcdir)/fps.h +flow.o: $(srcdir)/recanim.h +flow.o: $(srcdir)/screenhackI.h +flow.o: $(UTILS_SRC)/colors.h +flow.o: $(UTILS_SRC)/erase.h +flow.o: $(UTILS_SRC)/font-retry.h +flow.o: $(UTILS_SRC)/grabscreen.h +flow.o: $(UTILS_SRC)/hsv.h +flow.o: $(UTILS_SRC)/resources.h +flow.o: $(UTILS_SRC)/usleep.h +flow.o: $(UTILS_SRC)/visual.h +flow.o: $(UTILS_SRC)/yarandom.h +flow.o: $(srcdir)/xlockmoreI.h +flow.o: $(srcdir)/xlockmore.h +fluidballs.o: ../config.h +fluidballs.o: $(srcdir)/fps.h +fluidballs.o: $(srcdir)/recanim.h +fluidballs.o: $(srcdir)/screenhackI.h +fluidballs.o: $(srcdir)/screenhack.h +fluidballs.o: $(UTILS_SRC)/colors.h +fluidballs.o: $(UTILS_SRC)/font-retry.h +fluidballs.o: $(UTILS_SRC)/grabscreen.h +fluidballs.o: $(UTILS_SRC)/hsv.h +fluidballs.o: $(UTILS_SRC)/resources.h +fluidballs.o: $(UTILS_SRC)/usleep.h +fluidballs.o: $(UTILS_SRC)/visual.h +fluidballs.o: $(UTILS_SRC)/xdbe.h +fluidballs.o: $(UTILS_SRC)/yarandom.h +fontglide.o: ../config.h +fontglide.o: $(srcdir)/fps.h +fontglide.o: $(srcdir)/recanim.h +fontglide.o: $(srcdir)/screenhackI.h +fontglide.o: $(srcdir)/screenhack.h +fontglide.o: $(UTILS_SRC)/colors.h +fontglide.o: $(UTILS_SRC)/font-retry.h +fontglide.o: $(UTILS_SRC)/grabscreen.h +fontglide.o: $(UTILS_SRC)/hsv.h +fontglide.o: $(UTILS_SRC)/resources.h +fontglide.o: $(UTILS_SRC)/textclient.h +fontglide.o: $(UTILS_SRC)/usleep.h +fontglide.o: $(UTILS_SRC)/utf8wc.h +fontglide.o: $(UTILS_SRC)/visual.h +fontglide.o: $(UTILS_SRC)/xdbe.h +fontglide.o: $(UTILS_SRC)/xft.h +fontglide.o: $(UTILS_SRC)/yarandom.h +forest.o: ../config.h +forest.o: $(srcdir)/fps.h +forest.o: $(srcdir)/recanim.h +forest.o: $(srcdir)/screenhackI.h +forest.o: $(UTILS_SRC)/colors.h +forest.o: $(UTILS_SRC)/erase.h +forest.o: $(UTILS_SRC)/font-retry.h +forest.o: $(UTILS_SRC)/grabscreen.h +forest.o: $(UTILS_SRC)/hsv.h +forest.o: $(UTILS_SRC)/resources.h +forest.o: $(UTILS_SRC)/usleep.h +forest.o: $(UTILS_SRC)/visual.h +forest.o: $(UTILS_SRC)/yarandom.h +forest.o: $(srcdir)/xlockmoreI.h +forest.o: $(srcdir)/xlockmore.h +fps.o: ../config.h +fps.o: $(srcdir)/fpsI.h +fps.o: $(srcdir)/fps.h +fps.o: $(srcdir)/recanim.h +fps.o: $(srcdir)/screenhackI.h +fps.o: $(UTILS_SRC)/colors.h +fps.o: $(UTILS_SRC)/font-retry.h +fps.o: $(UTILS_SRC)/grabscreen.h +fps.o: $(UTILS_SRC)/hsv.h +fps.o: $(UTILS_SRC)/resources.h +fps.o: $(UTILS_SRC)/usleep.h +fps.o: $(UTILS_SRC)/visual.h +fps.o: $(UTILS_SRC)/yarandom.h +fuzzyflakes.o: ../config.h +fuzzyflakes.o: $(srcdir)/fps.h +fuzzyflakes.o: $(srcdir)/recanim.h +fuzzyflakes.o: $(srcdir)/screenhackI.h +fuzzyflakes.o: $(srcdir)/screenhack.h +fuzzyflakes.o: $(UTILS_SRC)/colors.h +fuzzyflakes.o: $(UTILS_SRC)/font-retry.h +fuzzyflakes.o: $(UTILS_SRC)/grabscreen.h +fuzzyflakes.o: $(UTILS_SRC)/hsv.h +fuzzyflakes.o: $(UTILS_SRC)/resources.h +fuzzyflakes.o: $(UTILS_SRC)/usleep.h +fuzzyflakes.o: $(UTILS_SRC)/visual.h +fuzzyflakes.o: $(UTILS_SRC)/yarandom.h +galaxy.o: ../config.h +galaxy.o: $(srcdir)/fps.h +galaxy.o: $(srcdir)/recanim.h +galaxy.o: $(srcdir)/screenhackI.h +galaxy.o: $(UTILS_SRC)/colors.h +galaxy.o: $(UTILS_SRC)/erase.h +galaxy.o: $(UTILS_SRC)/font-retry.h +galaxy.o: $(UTILS_SRC)/grabscreen.h +galaxy.o: $(UTILS_SRC)/hsv.h +galaxy.o: $(UTILS_SRC)/resources.h +galaxy.o: $(UTILS_SRC)/usleep.h +galaxy.o: $(UTILS_SRC)/visual.h +galaxy.o: $(UTILS_SRC)/yarandom.h +galaxy.o: $(srcdir)/xlockmoreI.h +galaxy.o: $(srcdir)/xlockmore.h +glitchpeg.o: ../config.h +glitchpeg.o: $(srcdir)/fps.h +glitchpeg.o: $(srcdir)/recanim.h +glitchpeg.o: $(srcdir)/screenhackI.h +glitchpeg.o: $(srcdir)/screenhack.h +glitchpeg.o: $(UTILS_SRC)/colors.h +glitchpeg.o: $(UTILS_SRC)/font-retry.h +glitchpeg.o: $(UTILS_SRC)/grabscreen.h +glitchpeg.o: $(UTILS_SRC)/hsv.h +glitchpeg.o: $(UTILS_SRC)/resources.h +glitchpeg.o: $(UTILS_SRC)/usleep.h +glitchpeg.o: $(UTILS_SRC)/visual.h +glitchpeg.o: $(UTILS_SRC)/yarandom.h +glitchpeg.o: $(srcdir)/ximage-loader.h +goop.o: ../config.h +goop.o: $(srcdir)/fps.h +goop.o: $(srcdir)/recanim.h +goop.o: $(srcdir)/screenhackI.h +goop.o: $(srcdir)/screenhack.h +goop.o: $(UTILS_SRC)/alpha.h +goop.o: $(UTILS_SRC)/colors.h +goop.o: $(UTILS_SRC)/font-retry.h +goop.o: $(UTILS_SRC)/grabscreen.h +goop.o: $(UTILS_SRC)/hsv.h +goop.o: $(UTILS_SRC)/resources.h +goop.o: $(UTILS_SRC)/spline.h +goop.o: $(UTILS_SRC)/usleep.h +goop.o: $(UTILS_SRC)/visual.h +goop.o: $(UTILS_SRC)/yarandom.h +grav.o: ../config.h +grav.o: $(srcdir)/fps.h +grav.o: $(srcdir)/recanim.h +grav.o: $(srcdir)/screenhackI.h +grav.o: $(UTILS_SRC)/colors.h +grav.o: $(UTILS_SRC)/erase.h +grav.o: $(UTILS_SRC)/font-retry.h +grav.o: $(UTILS_SRC)/grabscreen.h +grav.o: $(UTILS_SRC)/hsv.h +grav.o: $(UTILS_SRC)/resources.h +grav.o: $(UTILS_SRC)/usleep.h +grav.o: $(UTILS_SRC)/visual.h +grav.o: $(UTILS_SRC)/yarandom.h +grav.o: $(srcdir)/xlockmoreI.h +grav.o: $(srcdir)/xlockmore.h +greynetic.o: ../config.h +greynetic.o: $(srcdir)/fps.h +greynetic.o: $(srcdir)/recanim.h +greynetic.o: $(srcdir)/screenhackI.h +greynetic.o: $(srcdir)/screenhack.h +greynetic.o: $(UTILS_SRC)/colors.h +greynetic.o: $(UTILS_SRC)/font-retry.h +greynetic.o: $(UTILS_SRC)/grabscreen.h +greynetic.o: $(UTILS_SRC)/hsv.h +greynetic.o: $(UTILS_SRC)/resources.h +greynetic.o: $(UTILS_SRC)/usleep.h +greynetic.o: $(UTILS_SRC)/visual.h +greynetic.o: $(UTILS_SRC)/yarandom.h +halftone.o: ../config.h +halftone.o: $(srcdir)/fps.h +halftone.o: $(srcdir)/recanim.h +halftone.o: $(srcdir)/screenhackI.h +halftone.o: $(srcdir)/screenhack.h +halftone.o: $(UTILS_SRC)/colors.h +halftone.o: $(UTILS_SRC)/font-retry.h +halftone.o: $(UTILS_SRC)/grabscreen.h +halftone.o: $(UTILS_SRC)/hsv.h +halftone.o: $(UTILS_SRC)/resources.h +halftone.o: $(UTILS_SRC)/usleep.h +halftone.o: $(UTILS_SRC)/visual.h +halftone.o: $(UTILS_SRC)/yarandom.h +halo.o: ../config.h +halo.o: $(srcdir)/fps.h +halo.o: $(srcdir)/recanim.h +halo.o: $(srcdir)/screenhackI.h +halo.o: $(srcdir)/screenhack.h +halo.o: $(UTILS_SRC)/colors.h +halo.o: $(UTILS_SRC)/font-retry.h +halo.o: $(UTILS_SRC)/grabscreen.h +halo.o: $(UTILS_SRC)/hsv.h +halo.o: $(UTILS_SRC)/resources.h +halo.o: $(UTILS_SRC)/usleep.h +halo.o: $(UTILS_SRC)/visual.h +halo.o: $(UTILS_SRC)/yarandom.h +helix.o: ../config.h +helix.o: $(srcdir)/fps.h +helix.o: $(srcdir)/recanim.h +helix.o: $(srcdir)/screenhackI.h +helix.o: $(srcdir)/screenhack.h +helix.o: $(UTILS_SRC)/colors.h +helix.o: $(UTILS_SRC)/erase.h +helix.o: $(UTILS_SRC)/font-retry.h +helix.o: $(UTILS_SRC)/grabscreen.h +helix.o: $(UTILS_SRC)/hsv.h +helix.o: $(UTILS_SRC)/resources.h +helix.o: $(UTILS_SRC)/usleep.h +helix.o: $(UTILS_SRC)/visual.h +helix.o: $(UTILS_SRC)/yarandom.h +hexadrop.o: ../config.h +hexadrop.o: $(srcdir)/fps.h +hexadrop.o: $(srcdir)/recanim.h +hexadrop.o: $(srcdir)/screenhackI.h +hexadrop.o: $(srcdir)/screenhack.h +hexadrop.o: $(UTILS_SRC)/colors.h +hexadrop.o: $(UTILS_SRC)/font-retry.h +hexadrop.o: $(UTILS_SRC)/grabscreen.h +hexadrop.o: $(UTILS_SRC)/hsv.h +hexadrop.o: $(UTILS_SRC)/resources.h +hexadrop.o: $(UTILS_SRC)/usleep.h +hexadrop.o: $(UTILS_SRC)/visual.h +hexadrop.o: $(UTILS_SRC)/yarandom.h +hopalong.o: ../config.h +hopalong.o: $(srcdir)/fps.h +hopalong.o: $(srcdir)/recanim.h +hopalong.o: $(srcdir)/screenhackI.h +hopalong.o: $(UTILS_SRC)/colors.h +hopalong.o: $(UTILS_SRC)/erase.h +hopalong.o: $(UTILS_SRC)/font-retry.h +hopalong.o: $(UTILS_SRC)/grabscreen.h +hopalong.o: $(UTILS_SRC)/hsv.h +hopalong.o: $(UTILS_SRC)/resources.h +hopalong.o: $(UTILS_SRC)/usleep.h +hopalong.o: $(UTILS_SRC)/visual.h +hopalong.o: $(UTILS_SRC)/yarandom.h +hopalong.o: $(srcdir)/xlockmoreI.h +hopalong.o: $(srcdir)/xlockmore.h +hyperball.o: ../config.h +hyperball.o: $(srcdir)/fps.h +hyperball.o: $(srcdir)/recanim.h +hyperball.o: $(srcdir)/screenhackI.h +hyperball.o: $(srcdir)/screenhack.h +hyperball.o: $(UTILS_SRC)/colors.h +hyperball.o: $(UTILS_SRC)/font-retry.h +hyperball.o: $(UTILS_SRC)/grabscreen.h +hyperball.o: $(UTILS_SRC)/hsv.h +hyperball.o: $(UTILS_SRC)/resources.h +hyperball.o: $(UTILS_SRC)/usleep.h +hyperball.o: $(UTILS_SRC)/visual.h +hyperball.o: $(UTILS_SRC)/yarandom.h +hypercube.o: ../config.h +hypercube.o: $(srcdir)/fps.h +hypercube.o: $(srcdir)/recanim.h +hypercube.o: $(srcdir)/screenhackI.h +hypercube.o: $(srcdir)/screenhack.h +hypercube.o: $(UTILS_SRC)/colors.h +hypercube.o: $(UTILS_SRC)/font-retry.h +hypercube.o: $(UTILS_SRC)/grabscreen.h +hypercube.o: $(UTILS_SRC)/hsv.h +hypercube.o: $(UTILS_SRC)/resources.h +hypercube.o: $(UTILS_SRC)/usleep.h +hypercube.o: $(UTILS_SRC)/visual.h +hypercube.o: $(UTILS_SRC)/yarandom.h +ifs.o: ../config.h +ifs.o: $(srcdir)/fps.h +ifs.o: $(srcdir)/recanim.h +ifs.o: $(srcdir)/screenhackI.h +ifs.o: $(srcdir)/screenhack.h +ifs.o: $(UTILS_SRC)/colors.h +ifs.o: $(UTILS_SRC)/font-retry.h +ifs.o: $(UTILS_SRC)/grabscreen.h +ifs.o: $(UTILS_SRC)/hsv.h +ifs.o: $(UTILS_SRC)/resources.h +ifs.o: $(UTILS_SRC)/usleep.h +ifs.o: $(UTILS_SRC)/visual.h +ifs.o: $(UTILS_SRC)/yarandom.h +imsmap.o: ../config.h +imsmap.o: $(srcdir)/fps.h +imsmap.o: $(srcdir)/recanim.h +imsmap.o: $(srcdir)/screenhackI.h +imsmap.o: $(srcdir)/screenhack.h +imsmap.o: $(UTILS_SRC)/colors.h +imsmap.o: $(UTILS_SRC)/font-retry.h +imsmap.o: $(UTILS_SRC)/grabscreen.h +imsmap.o: $(UTILS_SRC)/hsv.h +imsmap.o: $(UTILS_SRC)/resources.h +imsmap.o: $(UTILS_SRC)/usleep.h +imsmap.o: $(UTILS_SRC)/visual.h +imsmap.o: $(UTILS_SRC)/yarandom.h +interaggregate.o: ../config.h +interaggregate.o: $(srcdir)/fps.h +interaggregate.o: $(srcdir)/recanim.h +interaggregate.o: $(srcdir)/screenhackI.h +interaggregate.o: $(srcdir)/screenhack.h +interaggregate.o: $(UTILS_SRC)/colors.h +interaggregate.o: $(UTILS_SRC)/font-retry.h +interaggregate.o: $(UTILS_SRC)/grabscreen.h +interaggregate.o: $(UTILS_SRC)/hsv.h +interaggregate.o: $(UTILS_SRC)/resources.h +interaggregate.o: $(UTILS_SRC)/usleep.h +interaggregate.o: $(UTILS_SRC)/visual.h +interaggregate.o: $(UTILS_SRC)/yarandom.h +interference.o: ../config.h +interference.o: $(srcdir)/fps.h +interference.o: $(srcdir)/recanim.h +interference.o: $(srcdir)/screenhackI.h +interference.o: $(srcdir)/screenhack.h +interference.o: $(UTILS_SRC)/aligned_malloc.h +interference.o: $(UTILS_SRC)/colors.h +interference.o: $(UTILS_SRC)/font-retry.h +interference.o: $(UTILS_SRC)/grabscreen.h +interference.o: $(UTILS_SRC)/hsv.h +interference.o: $(UTILS_SRC)/resources.h +interference.o: $(UTILS_SRC)/thread_util.h +interference.o: $(UTILS_SRC)/usleep.h +interference.o: $(UTILS_SRC)/visual.h +interference.o: $(UTILS_SRC)/xdbe.h +interference.o: $(UTILS_SRC)/xshm.h +interference.o: $(UTILS_SRC)/yarandom.h +intermomentary.o: ../config.h +intermomentary.o: $(srcdir)/fps.h +intermomentary.o: $(srcdir)/recanim.h +intermomentary.o: $(srcdir)/screenhackI.h +intermomentary.o: $(srcdir)/screenhack.h +intermomentary.o: $(UTILS_SRC)/colors.h +intermomentary.o: $(UTILS_SRC)/font-retry.h +intermomentary.o: $(UTILS_SRC)/grabscreen.h +intermomentary.o: $(UTILS_SRC)/hsv.h +intermomentary.o: $(UTILS_SRC)/resources.h +intermomentary.o: $(UTILS_SRC)/usleep.h +intermomentary.o: $(UTILS_SRC)/visual.h +intermomentary.o: $(UTILS_SRC)/yarandom.h +juggle.o: ../config.h +juggle.o: $(srcdir)/fps.h +juggle.o: $(srcdir)/recanim.h +juggle.o: $(srcdir)/screenhackI.h +juggle.o: $(UTILS_SRC)/colors.h +juggle.o: $(UTILS_SRC)/erase.h +juggle.o: $(UTILS_SRC)/font-retry.h +juggle.o: $(UTILS_SRC)/grabscreen.h +juggle.o: $(UTILS_SRC)/hsv.h +juggle.o: $(UTILS_SRC)/resources.h +juggle.o: $(UTILS_SRC)/usleep.h +juggle.o: $(UTILS_SRC)/visual.h +juggle.o: $(UTILS_SRC)/yarandom.h +juggle.o: $(srcdir)/xlockmoreI.h +juggle.o: $(srcdir)/xlockmore.h +julia.o: ../config.h +julia.o: $(srcdir)/fps.h +julia.o: $(srcdir)/recanim.h +julia.o: $(srcdir)/screenhackI.h +julia.o: $(UTILS_SRC)/colors.h +julia.o: $(UTILS_SRC)/erase.h +julia.o: $(UTILS_SRC)/font-retry.h +julia.o: $(UTILS_SRC)/grabscreen.h +julia.o: $(UTILS_SRC)/hsv.h +julia.o: $(UTILS_SRC)/resources.h +julia.o: $(UTILS_SRC)/usleep.h +julia.o: $(UTILS_SRC)/visual.h +julia.o: $(UTILS_SRC)/yarandom.h +julia.o: $(srcdir)/xlockmoreI.h +julia.o: $(srcdir)/xlockmore.h +kaleidescope.o: ../config.h +kaleidescope.o: $(srcdir)/fps.h +kaleidescope.o: $(srcdir)/recanim.h +kaleidescope.o: $(srcdir)/screenhackI.h +kaleidescope.o: $(srcdir)/screenhack.h +kaleidescope.o: $(UTILS_SRC)/colors.h +kaleidescope.o: $(UTILS_SRC)/font-retry.h +kaleidescope.o: $(UTILS_SRC)/grabscreen.h +kaleidescope.o: $(UTILS_SRC)/hsv.h +kaleidescope.o: $(UTILS_SRC)/resources.h +kaleidescope.o: $(UTILS_SRC)/spline.h +kaleidescope.o: $(UTILS_SRC)/usleep.h +kaleidescope.o: $(UTILS_SRC)/visual.h +kaleidescope.o: $(UTILS_SRC)/yarandom.h +kumppa.o: ../config.h +kumppa.o: $(srcdir)/fps.h +kumppa.o: $(srcdir)/recanim.h +kumppa.o: $(srcdir)/screenhackI.h +kumppa.o: $(srcdir)/screenhack.h +kumppa.o: $(UTILS_SRC)/colors.h +kumppa.o: $(UTILS_SRC)/font-retry.h +kumppa.o: $(UTILS_SRC)/grabscreen.h +kumppa.o: $(UTILS_SRC)/hsv.h +kumppa.o: $(UTILS_SRC)/resources.h +kumppa.o: $(UTILS_SRC)/usleep.h +kumppa.o: $(UTILS_SRC)/visual.h +kumppa.o: $(UTILS_SRC)/xdbe.h +kumppa.o: $(UTILS_SRC)/yarandom.h +laser.o: ../config.h +laser.o: $(srcdir)/fps.h +laser.o: $(srcdir)/recanim.h +laser.o: $(srcdir)/screenhackI.h +laser.o: $(UTILS_SRC)/colors.h +laser.o: $(UTILS_SRC)/erase.h +laser.o: $(UTILS_SRC)/font-retry.h +laser.o: $(UTILS_SRC)/grabscreen.h +laser.o: $(UTILS_SRC)/hsv.h +laser.o: $(UTILS_SRC)/resources.h +laser.o: $(UTILS_SRC)/usleep.h +laser.o: $(UTILS_SRC)/visual.h +laser.o: $(UTILS_SRC)/yarandom.h +laser.o: $(srcdir)/xlockmoreI.h +laser.o: $(srcdir)/xlockmore.h +lcdscrub.o: ../config.h +lcdscrub.o: $(srcdir)/fps.h +lcdscrub.o: $(srcdir)/recanim.h +lcdscrub.o: $(srcdir)/screenhackI.h +lcdscrub.o: $(srcdir)/screenhack.h +lcdscrub.o: $(UTILS_SRC)/colors.h +lcdscrub.o: $(UTILS_SRC)/font-retry.h +lcdscrub.o: $(UTILS_SRC)/grabscreen.h +lcdscrub.o: $(UTILS_SRC)/hsv.h +lcdscrub.o: $(UTILS_SRC)/resources.h +lcdscrub.o: $(UTILS_SRC)/usleep.h +lcdscrub.o: $(UTILS_SRC)/visual.h +lcdscrub.o: $(UTILS_SRC)/yarandom.h +lightning.o: ../config.h +lightning.o: $(srcdir)/fps.h +lightning.o: $(srcdir)/recanim.h +lightning.o: $(srcdir)/screenhackI.h +lightning.o: $(UTILS_SRC)/colors.h +lightning.o: $(UTILS_SRC)/erase.h +lightning.o: $(UTILS_SRC)/font-retry.h +lightning.o: $(UTILS_SRC)/grabscreen.h +lightning.o: $(UTILS_SRC)/hsv.h +lightning.o: $(UTILS_SRC)/resources.h +lightning.o: $(UTILS_SRC)/usleep.h +lightning.o: $(UTILS_SRC)/visual.h +lightning.o: $(UTILS_SRC)/yarandom.h +lightning.o: $(srcdir)/xlockmoreI.h +lightning.o: $(srcdir)/xlockmore.h +lisa.o: ../config.h +lisa.o: $(srcdir)/fps.h +lisa.o: $(srcdir)/recanim.h +lisa.o: $(srcdir)/screenhackI.h +lisa.o: $(UTILS_SRC)/colors.h +lisa.o: $(UTILS_SRC)/erase.h +lisa.o: $(UTILS_SRC)/font-retry.h +lisa.o: $(UTILS_SRC)/grabscreen.h +lisa.o: $(UTILS_SRC)/hsv.h +lisa.o: $(UTILS_SRC)/resources.h +lisa.o: $(UTILS_SRC)/usleep.h +lisa.o: $(UTILS_SRC)/visual.h +lisa.o: $(UTILS_SRC)/yarandom.h +lisa.o: $(srcdir)/xlockmoreI.h +lisa.o: $(srcdir)/xlockmore.h +lissie.o: ../config.h +lissie.o: $(srcdir)/fps.h +lissie.o: $(srcdir)/recanim.h +lissie.o: $(srcdir)/screenhackI.h +lissie.o: $(UTILS_SRC)/colors.h +lissie.o: $(UTILS_SRC)/erase.h +lissie.o: $(UTILS_SRC)/font-retry.h +lissie.o: $(UTILS_SRC)/grabscreen.h +lissie.o: $(UTILS_SRC)/hsv.h +lissie.o: $(UTILS_SRC)/resources.h +lissie.o: $(UTILS_SRC)/usleep.h +lissie.o: $(UTILS_SRC)/visual.h +lissie.o: $(UTILS_SRC)/yarandom.h +lissie.o: $(srcdir)/xlockmoreI.h +lissie.o: $(srcdir)/xlockmore.h +lmorph.o: ../config.h +lmorph.o: $(srcdir)/fps.h +lmorph.o: $(srcdir)/recanim.h +lmorph.o: $(srcdir)/screenhackI.h +lmorph.o: $(srcdir)/screenhack.h +lmorph.o: $(UTILS_SRC)/colors.h +lmorph.o: $(UTILS_SRC)/font-retry.h +lmorph.o: $(UTILS_SRC)/grabscreen.h +lmorph.o: $(UTILS_SRC)/hsv.h +lmorph.o: $(UTILS_SRC)/resources.h +lmorph.o: $(UTILS_SRC)/usleep.h +lmorph.o: $(UTILS_SRC)/visual.h +lmorph.o: $(UTILS_SRC)/yarandom.h +loop.o: $(srcdir)/automata.h +loop.o: ../config.h +loop.o: $(srcdir)/fps.h +loop.o: $(srcdir)/recanim.h +loop.o: $(srcdir)/screenhackI.h +loop.o: $(UTILS_SRC)/colors.h +loop.o: $(UTILS_SRC)/erase.h +loop.o: $(UTILS_SRC)/font-retry.h +loop.o: $(UTILS_SRC)/grabscreen.h +loop.o: $(UTILS_SRC)/hsv.h +loop.o: $(UTILS_SRC)/resources.h +loop.o: $(UTILS_SRC)/usleep.h +loop.o: $(UTILS_SRC)/visual.h +loop.o: $(UTILS_SRC)/yarandom.h +loop.o: $(srcdir)/xlockmoreI.h +loop.o: $(srcdir)/xlockmore.h +m6502.o: $(srcdir)/analogtv.h +m6502.o: $(srcdir)/asm6502.h +m6502.o: ../config.h +m6502.o: $(srcdir)/fps.h +m6502.o: m6502.h +m6502.o: $(srcdir)/recanim.h +m6502.o: $(srcdir)/screenhackI.h +m6502.o: $(srcdir)/screenhack.h +m6502.o: $(UTILS_SRC)/aligned_malloc.h +m6502.o: $(UTILS_SRC)/colors.h +m6502.o: $(UTILS_SRC)/font-retry.h +m6502.o: $(UTILS_SRC)/grabscreen.h +m6502.o: $(UTILS_SRC)/hsv.h +m6502.o: $(UTILS_SRC)/resources.h +m6502.o: $(UTILS_SRC)/thread_util.h +m6502.o: $(UTILS_SRC)/usleep.h +m6502.o: $(UTILS_SRC)/visual.h +m6502.o: $(UTILS_SRC)/xshm.h +m6502.o: $(UTILS_SRC)/yarandom.h +maze.o: ../config.h +maze.o: $(srcdir)/fps.h +maze.o: $(srcdir)/images/gen/logo-180_png.h +maze.o: $(srcdir)/images/gen/logo-50_png.h +maze.o: $(srcdir)/recanim.h +maze.o: $(srcdir)/screenhackI.h +maze.o: $(srcdir)/screenhack.h +maze.o: $(UTILS_SRC)/colors.h +maze.o: $(UTILS_SRC)/erase.h +maze.o: $(UTILS_SRC)/font-retry.h +maze.o: $(UTILS_SRC)/grabscreen.h +maze.o: $(UTILS_SRC)/hsv.h +maze.o: $(UTILS_SRC)/resources.h +maze.o: $(UTILS_SRC)/usleep.h +maze.o: $(UTILS_SRC)/visual.h +maze.o: $(UTILS_SRC)/yarandom.h +maze.o: $(srcdir)/ximage-loader.h +memscroller.o: ../config.h +memscroller.o: $(srcdir)/fps.h +memscroller.o: $(srcdir)/recanim.h +memscroller.o: $(srcdir)/screenhackI.h +memscroller.o: $(srcdir)/screenhack.h +memscroller.o: $(UTILS_SRC)/colors.h +memscroller.o: $(UTILS_SRC)/font-retry.h +memscroller.o: $(UTILS_SRC)/grabscreen.h +memscroller.o: $(UTILS_SRC)/hsv.h +memscroller.o: $(UTILS_SRC)/resources.h +memscroller.o: $(UTILS_SRC)/usleep.h +memscroller.o: $(UTILS_SRC)/visual.h +memscroller.o: $(UTILS_SRC)/xshm.h +memscroller.o: $(UTILS_SRC)/yarandom.h +metaballs.o: ../config.h +metaballs.o: $(srcdir)/fps.h +metaballs.o: $(srcdir)/recanim.h +metaballs.o: $(srcdir)/screenhackI.h +metaballs.o: $(srcdir)/screenhack.h +metaballs.o: $(UTILS_SRC)/colors.h +metaballs.o: $(UTILS_SRC)/font-retry.h +metaballs.o: $(UTILS_SRC)/grabscreen.h +metaballs.o: $(UTILS_SRC)/hsv.h +metaballs.o: $(UTILS_SRC)/resources.h +metaballs.o: $(UTILS_SRC)/usleep.h +metaballs.o: $(UTILS_SRC)/visual.h +metaballs.o: $(UTILS_SRC)/yarandom.h +moire2.o: ../config.h +moire2.o: $(srcdir)/fps.h +moire2.o: $(srcdir)/recanim.h +moire2.o: $(srcdir)/screenhackI.h +moire2.o: $(srcdir)/screenhack.h +moire2.o: $(UTILS_SRC)/colors.h +moire2.o: $(UTILS_SRC)/font-retry.h +moire2.o: $(UTILS_SRC)/grabscreen.h +moire2.o: $(UTILS_SRC)/hsv.h +moire2.o: $(UTILS_SRC)/resources.h +moire2.o: $(UTILS_SRC)/usleep.h +moire2.o: $(UTILS_SRC)/visual.h +moire2.o: $(UTILS_SRC)/xdbe.h +moire2.o: $(UTILS_SRC)/yarandom.h +moire.o: ../config.h +moire.o: $(srcdir)/fps.h +moire.o: $(srcdir)/recanim.h +moire.o: $(srcdir)/screenhackI.h +moire.o: $(srcdir)/screenhack.h +moire.o: $(UTILS_SRC)/colors.h +moire.o: $(UTILS_SRC)/font-retry.h +moire.o: $(UTILS_SRC)/grabscreen.h +moire.o: $(UTILS_SRC)/hsv.h +moire.o: $(UTILS_SRC)/resources.h +moire.o: $(UTILS_SRC)/usleep.h +moire.o: $(UTILS_SRC)/visual.h +moire.o: $(UTILS_SRC)/xshm.h +moire.o: $(UTILS_SRC)/yarandom.h +mountain.o: ../config.h +mountain.o: $(srcdir)/fps.h +mountain.o: $(srcdir)/recanim.h +mountain.o: $(srcdir)/screenhackI.h +mountain.o: $(UTILS_SRC)/colors.h +mountain.o: $(UTILS_SRC)/erase.h +mountain.o: $(UTILS_SRC)/font-retry.h +mountain.o: $(UTILS_SRC)/grabscreen.h +mountain.o: $(UTILS_SRC)/hsv.h +mountain.o: $(UTILS_SRC)/resources.h +mountain.o: $(UTILS_SRC)/usleep.h +mountain.o: $(UTILS_SRC)/visual.h +mountain.o: $(UTILS_SRC)/yarandom.h +mountain.o: $(srcdir)/xlockmoreI.h +mountain.o: $(srcdir)/xlockmore.h +munch.o: ../config.h +munch.o: $(srcdir)/fps.h +munch.o: $(srcdir)/recanim.h +munch.o: $(srcdir)/screenhackI.h +munch.o: $(srcdir)/screenhack.h +munch.o: $(UTILS_SRC)/colors.h +munch.o: $(UTILS_SRC)/font-retry.h +munch.o: $(UTILS_SRC)/grabscreen.h +munch.o: $(UTILS_SRC)/hsv.h +munch.o: $(UTILS_SRC)/resources.h +munch.o: $(UTILS_SRC)/usleep.h +munch.o: $(UTILS_SRC)/visual.h +munch.o: $(UTILS_SRC)/yarandom.h +nerverot.o: ../config.h +nerverot.o: $(srcdir)/fps.h +nerverot.o: $(srcdir)/recanim.h +nerverot.o: $(srcdir)/screenhackI.h +nerverot.o: $(srcdir)/screenhack.h +nerverot.o: $(UTILS_SRC)/colors.h +nerverot.o: $(UTILS_SRC)/font-retry.h +nerverot.o: $(UTILS_SRC)/grabscreen.h +nerverot.o: $(UTILS_SRC)/hsv.h +nerverot.o: $(UTILS_SRC)/resources.h +nerverot.o: $(UTILS_SRC)/usleep.h +nerverot.o: $(UTILS_SRC)/visual.h +nerverot.o: $(UTILS_SRC)/yarandom.h +noseguy.o: ../config.h +noseguy.o: $(srcdir)/fps.h +noseguy.o: $(srcdir)/images/gen/nose-f1_png.h +noseguy.o: $(srcdir)/images/gen/nose-f2_png.h +noseguy.o: $(srcdir)/images/gen/nose-f3_png.h +noseguy.o: $(srcdir)/images/gen/nose-f4_png.h +noseguy.o: $(srcdir)/images/gen/nose-l1_png.h +noseguy.o: $(srcdir)/images/gen/nose-l2_png.h +noseguy.o: $(srcdir)/images/gen/nose-r1_png.h +noseguy.o: $(srcdir)/images/gen/nose-r2_png.h +noseguy.o: $(srcdir)/recanim.h +noseguy.o: $(srcdir)/screenhackI.h +noseguy.o: $(srcdir)/screenhack.h +noseguy.o: $(UTILS_SRC)/colors.h +noseguy.o: $(UTILS_SRC)/font-retry.h +noseguy.o: $(UTILS_SRC)/grabscreen.h +noseguy.o: $(UTILS_SRC)/hsv.h +noseguy.o: $(UTILS_SRC)/resources.h +noseguy.o: $(UTILS_SRC)/textclient.h +noseguy.o: $(UTILS_SRC)/usleep.h +noseguy.o: $(UTILS_SRC)/visual.h +noseguy.o: $(UTILS_SRC)/xft.h +noseguy.o: $(UTILS_SRC)/yarandom.h +noseguy.o: $(srcdir)/ximage-loader.h +pacman_ai.o: ../config.h +pacman_ai.o: $(srcdir)/fps.h +pacman_ai.o: $(srcdir)/pacman_ai.h +pacman_ai.o: $(srcdir)/pacman.h +pacman_ai.o: $(srcdir)/pacman_level.h +pacman_ai.o: $(srcdir)/recanim.h +pacman_ai.o: $(srcdir)/screenhackI.h +pacman_ai.o: $(UTILS_SRC)/colors.h +pacman_ai.o: $(UTILS_SRC)/erase.h +pacman_ai.o: $(UTILS_SRC)/font-retry.h +pacman_ai.o: $(UTILS_SRC)/grabscreen.h +pacman_ai.o: $(UTILS_SRC)/hsv.h +pacman_ai.o: $(UTILS_SRC)/resources.h +pacman_ai.o: $(UTILS_SRC)/usleep.h +pacman_ai.o: $(UTILS_SRC)/visual.h +pacman_ai.o: $(UTILS_SRC)/yarandom.h +pacman_ai.o: $(srcdir)/ximage-loader.h +pacman_ai.o: $(srcdir)/xlockmoreI.h +pacman_level.o: ../config.h +pacman_level.o: $(srcdir)/fps.h +pacman_level.o: $(srcdir)/pacman.h +pacman_level.o: $(srcdir)/pacman_level.h +pacman_level.o: $(srcdir)/recanim.h +pacman_level.o: $(srcdir)/screenhackI.h +pacman_level.o: $(UTILS_SRC)/colors.h +pacman_level.o: $(UTILS_SRC)/erase.h +pacman_level.o: $(UTILS_SRC)/font-retry.h +pacman_level.o: $(UTILS_SRC)/grabscreen.h +pacman_level.o: $(UTILS_SRC)/hsv.h +pacman_level.o: $(UTILS_SRC)/resources.h +pacman_level.o: $(UTILS_SRC)/usleep.h +pacman_level.o: $(UTILS_SRC)/visual.h +pacman_level.o: $(UTILS_SRC)/yarandom.h +pacman_level.o: $(srcdir)/ximage-loader.h +pacman_level.o: $(srcdir)/xlockmoreI.h +pacman.o: ../config.h +pacman.o: $(srcdir)/fps.h +pacman.o: $(srcdir)/images/gen/pacman_png.h +pacman.o: $(srcdir)/pacman_ai.h +pacman.o: $(srcdir)/pacman.h +pacman.o: $(srcdir)/pacman_level.h +pacman.o: $(srcdir)/recanim.h +pacman.o: $(srcdir)/screenhackI.h +pacman.o: $(UTILS_SRC)/colors.h +pacman.o: $(UTILS_SRC)/erase.h +pacman.o: $(UTILS_SRC)/font-retry.h +pacman.o: $(UTILS_SRC)/grabscreen.h +pacman.o: $(UTILS_SRC)/hsv.h +pacman.o: $(UTILS_SRC)/resources.h +pacman.o: $(UTILS_SRC)/usleep.h +pacman.o: $(UTILS_SRC)/visual.h +pacman.o: $(UTILS_SRC)/yarandom.h +pacman.o: $(srcdir)/ximage-loader.h +pacman.o: $(srcdir)/xlockmoreI.h +pacman.o: $(srcdir)/xlockmore.h +pedal.o: ../config.h +pedal.o: $(srcdir)/fps.h +pedal.o: $(srcdir)/recanim.h +pedal.o: $(srcdir)/screenhackI.h +pedal.o: $(srcdir)/screenhack.h +pedal.o: $(UTILS_SRC)/colors.h +pedal.o: $(UTILS_SRC)/erase.h +pedal.o: $(UTILS_SRC)/font-retry.h +pedal.o: $(UTILS_SRC)/grabscreen.h +pedal.o: $(UTILS_SRC)/hsv.h +pedal.o: $(UTILS_SRC)/resources.h +pedal.o: $(UTILS_SRC)/usleep.h +pedal.o: $(UTILS_SRC)/visual.h +pedal.o: $(UTILS_SRC)/yarandom.h +penetrate.o: ../config.h +penetrate.o: $(srcdir)/fps.h +penetrate.o: $(srcdir)/recanim.h +penetrate.o: $(srcdir)/screenhackI.h +penetrate.o: $(srcdir)/screenhack.h +penetrate.o: $(UTILS_SRC)/colors.h +penetrate.o: $(UTILS_SRC)/font-retry.h +penetrate.o: $(UTILS_SRC)/grabscreen.h +penetrate.o: $(UTILS_SRC)/hsv.h +penetrate.o: $(UTILS_SRC)/resources.h +penetrate.o: $(UTILS_SRC)/usleep.h +penetrate.o: $(UTILS_SRC)/visual.h +penetrate.o: $(UTILS_SRC)/yarandom.h +penrose.o: ../config.h +penrose.o: $(srcdir)/fps.h +penrose.o: $(srcdir)/recanim.h +penrose.o: $(srcdir)/screenhackI.h +penrose.o: $(UTILS_SRC)/colors.h +penrose.o: $(UTILS_SRC)/erase.h +penrose.o: $(UTILS_SRC)/font-retry.h +penrose.o: $(UTILS_SRC)/grabscreen.h +penrose.o: $(UTILS_SRC)/hsv.h +penrose.o: $(UTILS_SRC)/resources.h +penrose.o: $(UTILS_SRC)/usleep.h +penrose.o: $(UTILS_SRC)/visual.h +penrose.o: $(UTILS_SRC)/yarandom.h +penrose.o: $(srcdir)/xlockmoreI.h +penrose.o: $(srcdir)/xlockmore.h +petri.o: ../config.h +petri.o: $(srcdir)/fps.h +petri.o: $(srcdir)/recanim.h +petri.o: $(srcdir)/screenhackI.h +petri.o: $(srcdir)/screenhack.h +petri.o: $(UTILS_SRC)/colors.h +petri.o: $(UTILS_SRC)/font-retry.h +petri.o: $(UTILS_SRC)/grabscreen.h +petri.o: $(UTILS_SRC)/hsv.h +petri.o: $(UTILS_SRC)/resources.h +petri.o: $(UTILS_SRC)/spline.h +petri.o: $(UTILS_SRC)/usleep.h +petri.o: $(UTILS_SRC)/visual.h +petri.o: $(UTILS_SRC)/yarandom.h +phosphor.o: ../config.h +phosphor.o: $(srcdir)/fps.h +phosphor.o: $(srcdir)/images/gen/6x10font_png.h +phosphor.o: $(srcdir)/recanim.h +phosphor.o: $(srcdir)/screenhackI.h +phosphor.o: $(srcdir)/screenhack.h +phosphor.o: $(UTILS_SRC)/colors.h +phosphor.o: $(UTILS_SRC)/font-retry.h +phosphor.o: $(UTILS_SRC)/grabscreen.h +phosphor.o: $(UTILS_SRC)/hsv.h +phosphor.o: $(UTILS_SRC)/resources.h +phosphor.o: $(UTILS_SRC)/textclient.h +phosphor.o: $(UTILS_SRC)/usleep.h +phosphor.o: $(UTILS_SRC)/utf8wc.h +phosphor.o: $(UTILS_SRC)/visual.h +phosphor.o: $(UTILS_SRC)/yarandom.h +phosphor.o: $(srcdir)/ximage-loader.h +piecewise.o: ../config.h +piecewise.o: $(srcdir)/fps.h +piecewise.o: $(srcdir)/recanim.h +piecewise.o: $(srcdir)/screenhackI.h +piecewise.o: $(srcdir)/screenhack.h +piecewise.o: $(UTILS_SRC)/colors.h +piecewise.o: $(UTILS_SRC)/font-retry.h +piecewise.o: $(UTILS_SRC)/grabscreen.h +piecewise.o: $(UTILS_SRC)/hsv.h +piecewise.o: $(UTILS_SRC)/resources.h +piecewise.o: $(UTILS_SRC)/usleep.h +piecewise.o: $(UTILS_SRC)/visual.h +piecewise.o: $(UTILS_SRC)/xdbe.h +piecewise.o: $(UTILS_SRC)/yarandom.h +polyominoes.o: ../config.h +polyominoes.o: $(srcdir)/fps.h +polyominoes.o: $(srcdir)/recanim.h +polyominoes.o: $(srcdir)/screenhackI.h +polyominoes.o: $(UTILS_SRC)/colors.h +polyominoes.o: $(UTILS_SRC)/erase.h +polyominoes.o: $(UTILS_SRC)/font-retry.h +polyominoes.o: $(UTILS_SRC)/grabscreen.h +polyominoes.o: $(UTILS_SRC)/hsv.h +polyominoes.o: $(UTILS_SRC)/resources.h +polyominoes.o: $(UTILS_SRC)/usleep.h +polyominoes.o: $(UTILS_SRC)/visual.h +polyominoes.o: $(UTILS_SRC)/yarandom.h +polyominoes.o: $(srcdir)/xlockmoreI.h +polyominoes.o: $(srcdir)/xlockmore.h +pong.o: $(srcdir)/analogtv.h +pong.o: ../config.h +pong.o: $(srcdir)/fps.h +pong.o: $(srcdir)/recanim.h +pong.o: $(srcdir)/screenhackI.h +pong.o: $(srcdir)/screenhack.h +pong.o: $(UTILS_SRC)/aligned_malloc.h +pong.o: $(UTILS_SRC)/colors.h +pong.o: $(UTILS_SRC)/font-retry.h +pong.o: $(UTILS_SRC)/grabscreen.h +pong.o: $(UTILS_SRC)/hsv.h +pong.o: $(UTILS_SRC)/resources.h +pong.o: $(UTILS_SRC)/thread_util.h +pong.o: $(UTILS_SRC)/usleep.h +pong.o: $(UTILS_SRC)/visual.h +pong.o: $(UTILS_SRC)/xshm.h +pong.o: $(UTILS_SRC)/yarandom.h +popsquares.o: ../config.h +popsquares.o: $(srcdir)/fps.h +popsquares.o: $(srcdir)/recanim.h +popsquares.o: $(srcdir)/screenhackI.h +popsquares.o: $(srcdir)/screenhack.h +popsquares.o: $(UTILS_SRC)/colors.h +popsquares.o: $(UTILS_SRC)/font-retry.h +popsquares.o: $(UTILS_SRC)/grabscreen.h +popsquares.o: $(UTILS_SRC)/hsv.h +popsquares.o: $(UTILS_SRC)/resources.h +popsquares.o: $(UTILS_SRC)/usleep.h +popsquares.o: $(UTILS_SRC)/visual.h +popsquares.o: $(UTILS_SRC)/xdbe.h +popsquares.o: $(UTILS_SRC)/yarandom.h +pyro.o: ../config.h +pyro.o: $(srcdir)/fps.h +pyro.o: $(srcdir)/recanim.h +pyro.o: $(srcdir)/screenhackI.h +pyro.o: $(srcdir)/screenhack.h +pyro.o: $(UTILS_SRC)/colors.h +pyro.o: $(UTILS_SRC)/font-retry.h +pyro.o: $(UTILS_SRC)/grabscreen.h +pyro.o: $(UTILS_SRC)/hsv.h +pyro.o: $(UTILS_SRC)/resources.h +pyro.o: $(UTILS_SRC)/usleep.h +pyro.o: $(UTILS_SRC)/visual.h +pyro.o: $(UTILS_SRC)/yarandom.h +qix.o: ../config.h +qix.o: $(srcdir)/fps.h +qix.o: $(srcdir)/recanim.h +qix.o: $(srcdir)/screenhackI.h +qix.o: $(srcdir)/screenhack.h +qix.o: $(UTILS_SRC)/alpha.h +qix.o: $(UTILS_SRC)/colors.h +qix.o: $(UTILS_SRC)/font-retry.h +qix.o: $(UTILS_SRC)/grabscreen.h +qix.o: $(UTILS_SRC)/hsv.h +qix.o: $(UTILS_SRC)/resources.h +qix.o: $(UTILS_SRC)/usleep.h +qix.o: $(UTILS_SRC)/visual.h +qix.o: $(UTILS_SRC)/yarandom.h +rd-bomb.o: ../config.h +rd-bomb.o: $(srcdir)/fps.h +rd-bomb.o: $(srcdir)/recanim.h +rd-bomb.o: $(srcdir)/screenhackI.h +rd-bomb.o: $(srcdir)/screenhack.h +rd-bomb.o: $(UTILS_SRC)/colors.h +rd-bomb.o: $(UTILS_SRC)/font-retry.h +rd-bomb.o: $(UTILS_SRC)/grabscreen.h +rd-bomb.o: $(UTILS_SRC)/hsv.h +rd-bomb.o: $(UTILS_SRC)/resources.h +rd-bomb.o: $(UTILS_SRC)/usleep.h +rd-bomb.o: $(UTILS_SRC)/visual.h +rd-bomb.o: $(UTILS_SRC)/xshm.h +rd-bomb.o: $(UTILS_SRC)/yarandom.h +recanim.o: ../config.h +recanim.o: $(srcdir)/fps.h +recanim.o: $(srcdir)/recanim.h +recanim.o: $(srcdir)/screenhackI.h +recanim.o: $(UTILS_SRC)/colors.h +recanim.o: $(UTILS_SRC)/font-retry.h +recanim.o: $(UTILS_SRC)/grabscreen.h +recanim.o: $(UTILS_SRC)/hsv.h +recanim.o: $(UTILS_SRC)/resources.h +recanim.o: $(UTILS_SRC)/usleep.h +recanim.o: $(UTILS_SRC)/visual.h +recanim.o: $(UTILS_SRC)/yarandom.h +ripples.o: ../config.h +ripples.o: $(srcdir)/fps.h +ripples.o: $(srcdir)/recanim.h +ripples.o: $(srcdir)/screenhackI.h +ripples.o: $(srcdir)/screenhack.h +ripples.o: $(UTILS_SRC)/colors.h +ripples.o: $(UTILS_SRC)/font-retry.h +ripples.o: $(UTILS_SRC)/grabscreen.h +ripples.o: $(UTILS_SRC)/hsv.h +ripples.o: $(UTILS_SRC)/resources.h +ripples.o: $(UTILS_SRC)/usleep.h +ripples.o: $(UTILS_SRC)/visual.h +ripples.o: $(UTILS_SRC)/xshm.h +ripples.o: $(UTILS_SRC)/yarandom.h +rocks.o: ../config.h +rocks.o: $(srcdir)/fps.h +rocks.o: $(srcdir)/recanim.h +rocks.o: $(srcdir)/screenhackI.h +rocks.o: $(srcdir)/screenhack.h +rocks.o: $(UTILS_SRC)/colors.h +rocks.o: $(UTILS_SRC)/font-retry.h +rocks.o: $(UTILS_SRC)/grabscreen.h +rocks.o: $(UTILS_SRC)/hsv.h +rocks.o: $(UTILS_SRC)/resources.h +rocks.o: $(UTILS_SRC)/usleep.h +rocks.o: $(UTILS_SRC)/visual.h +rocks.o: $(UTILS_SRC)/yarandom.h +rorschach.o: ../config.h +rorschach.o: $(srcdir)/fps.h +rorschach.o: $(srcdir)/recanim.h +rorschach.o: $(srcdir)/screenhackI.h +rorschach.o: $(srcdir)/screenhack.h +rorschach.o: $(UTILS_SRC)/colors.h +rorschach.o: $(UTILS_SRC)/erase.h +rorschach.o: $(UTILS_SRC)/font-retry.h +rorschach.o: $(UTILS_SRC)/grabscreen.h +rorschach.o: $(UTILS_SRC)/hsv.h +rorschach.o: $(UTILS_SRC)/resources.h +rorschach.o: $(UTILS_SRC)/usleep.h +rorschach.o: $(UTILS_SRC)/visual.h +rorschach.o: $(UTILS_SRC)/yarandom.h +rotor.o: ../config.h +rotor.o: $(srcdir)/fps.h +rotor.o: $(srcdir)/recanim.h +rotor.o: $(srcdir)/screenhackI.h +rotor.o: $(UTILS_SRC)/colors.h +rotor.o: $(UTILS_SRC)/erase.h +rotor.o: $(UTILS_SRC)/font-retry.h +rotor.o: $(UTILS_SRC)/grabscreen.h +rotor.o: $(UTILS_SRC)/hsv.h +rotor.o: $(UTILS_SRC)/resources.h +rotor.o: $(UTILS_SRC)/usleep.h +rotor.o: $(UTILS_SRC)/visual.h +rotor.o: $(UTILS_SRC)/yarandom.h +rotor.o: $(srcdir)/xlockmoreI.h +rotor.o: $(srcdir)/xlockmore.h +rotzoomer.o: ../config.h +rotzoomer.o: $(srcdir)/fps.h +rotzoomer.o: $(srcdir)/recanim.h +rotzoomer.o: $(srcdir)/screenhackI.h +rotzoomer.o: $(srcdir)/screenhack.h +rotzoomer.o: $(UTILS_SRC)/colors.h +rotzoomer.o: $(UTILS_SRC)/font-retry.h +rotzoomer.o: $(UTILS_SRC)/grabscreen.h +rotzoomer.o: $(UTILS_SRC)/hsv.h +rotzoomer.o: $(UTILS_SRC)/resources.h +rotzoomer.o: $(UTILS_SRC)/usleep.h +rotzoomer.o: $(UTILS_SRC)/visual.h +rotzoomer.o: $(UTILS_SRC)/xshm.h +rotzoomer.o: $(UTILS_SRC)/yarandom.h +screenhack.o: ../config.h +screenhack.o: $(srcdir)/fps.h +screenhack.o: $(srcdir)/recanim.h +screenhack.o: $(srcdir)/screenhackI.h +screenhack.o: $(UTILS_SRC)/colors.h +screenhack.o: $(UTILS_SRC)/font-retry.h +screenhack.o: $(UTILS_SRC)/grabscreen.h +screenhack.o: $(UTILS_SRC)/hsv.h +screenhack.o: $(UTILS_SRC)/resources.h +screenhack.o: $(UTILS_SRC)/usleep.h +screenhack.o: $(UTILS_SRC)/version.h +screenhack.o: $(UTILS_SRC)/visual.h +screenhack.o: $(UTILS_SRC)/vroot.h +screenhack.o: $(UTILS_SRC)/xmu.h +screenhack.o: $(UTILS_SRC)/yarandom.h +shadebobs.o: ../config.h +shadebobs.o: $(srcdir)/fps.h +shadebobs.o: $(srcdir)/recanim.h +shadebobs.o: $(srcdir)/screenhackI.h +shadebobs.o: $(srcdir)/screenhack.h +shadebobs.o: $(UTILS_SRC)/colors.h +shadebobs.o: $(UTILS_SRC)/font-retry.h +shadebobs.o: $(UTILS_SRC)/grabscreen.h +shadebobs.o: $(UTILS_SRC)/hsv.h +shadebobs.o: $(UTILS_SRC)/resources.h +shadebobs.o: $(UTILS_SRC)/usleep.h +shadebobs.o: $(UTILS_SRC)/visual.h +shadebobs.o: $(UTILS_SRC)/yarandom.h +sierpinski.o: ../config.h +sierpinski.o: $(srcdir)/fps.h +sierpinski.o: $(srcdir)/recanim.h +sierpinski.o: $(srcdir)/screenhackI.h +sierpinski.o: $(UTILS_SRC)/colors.h +sierpinski.o: $(UTILS_SRC)/erase.h +sierpinski.o: $(UTILS_SRC)/font-retry.h +sierpinski.o: $(UTILS_SRC)/grabscreen.h +sierpinski.o: $(UTILS_SRC)/hsv.h +sierpinski.o: $(UTILS_SRC)/resources.h +sierpinski.o: $(UTILS_SRC)/usleep.h +sierpinski.o: $(UTILS_SRC)/visual.h +sierpinski.o: $(UTILS_SRC)/yarandom.h +sierpinski.o: $(srcdir)/xlockmoreI.h +sierpinski.o: $(srcdir)/xlockmore.h +slidescreen.o: ../config.h +slidescreen.o: $(srcdir)/fps.h +slidescreen.o: $(srcdir)/recanim.h +slidescreen.o: $(srcdir)/screenhackI.h +slidescreen.o: $(srcdir)/screenhack.h +slidescreen.o: $(UTILS_SRC)/colors.h +slidescreen.o: $(UTILS_SRC)/font-retry.h +slidescreen.o: $(UTILS_SRC)/grabscreen.h +slidescreen.o: $(UTILS_SRC)/hsv.h +slidescreen.o: $(UTILS_SRC)/resources.h +slidescreen.o: $(UTILS_SRC)/usleep.h +slidescreen.o: $(UTILS_SRC)/visual.h +slidescreen.o: $(UTILS_SRC)/yarandom.h +slip.o: ../config.h +slip.o: $(srcdir)/fps.h +slip.o: $(srcdir)/recanim.h +slip.o: $(srcdir)/screenhackI.h +slip.o: $(UTILS_SRC)/colors.h +slip.o: $(UTILS_SRC)/erase.h +slip.o: $(UTILS_SRC)/font-retry.h +slip.o: $(UTILS_SRC)/grabscreen.h +slip.o: $(UTILS_SRC)/hsv.h +slip.o: $(UTILS_SRC)/resources.h +slip.o: $(UTILS_SRC)/usleep.h +slip.o: $(UTILS_SRC)/visual.h +slip.o: $(UTILS_SRC)/yarandom.h +slip.o: $(srcdir)/xlockmoreI.h +slip.o: $(srcdir)/xlockmore.h +speedmine.o: ../config.h +speedmine.o: $(srcdir)/fps.h +speedmine.o: $(srcdir)/recanim.h +speedmine.o: $(srcdir)/screenhackI.h +speedmine.o: $(srcdir)/screenhack.h +speedmine.o: $(UTILS_SRC)/colors.h +speedmine.o: $(UTILS_SRC)/erase.h +speedmine.o: $(UTILS_SRC)/font-retry.h +speedmine.o: $(UTILS_SRC)/grabscreen.h +speedmine.o: $(UTILS_SRC)/hsv.h +speedmine.o: $(UTILS_SRC)/resources.h +speedmine.o: $(UTILS_SRC)/usleep.h +speedmine.o: $(UTILS_SRC)/visual.h +speedmine.o: $(UTILS_SRC)/yarandom.h +sphere.o: ../config.h +sphere.o: $(srcdir)/fps.h +sphere.o: $(srcdir)/recanim.h +sphere.o: $(srcdir)/screenhackI.h +sphere.o: $(UTILS_SRC)/colors.h +sphere.o: $(UTILS_SRC)/erase.h +sphere.o: $(UTILS_SRC)/font-retry.h +sphere.o: $(UTILS_SRC)/grabscreen.h +sphere.o: $(UTILS_SRC)/hsv.h +sphere.o: $(UTILS_SRC)/resources.h +sphere.o: $(UTILS_SRC)/usleep.h +sphere.o: $(UTILS_SRC)/visual.h +sphere.o: $(UTILS_SRC)/yarandom.h +sphere.o: $(srcdir)/xlockmoreI.h +sphere.o: $(srcdir)/xlockmore.h +spiral.o: ../config.h +spiral.o: $(srcdir)/fps.h +spiral.o: $(srcdir)/recanim.h +spiral.o: $(srcdir)/screenhackI.h +spiral.o: $(UTILS_SRC)/colors.h +spiral.o: $(UTILS_SRC)/erase.h +spiral.o: $(UTILS_SRC)/font-retry.h +spiral.o: $(UTILS_SRC)/grabscreen.h +spiral.o: $(UTILS_SRC)/hsv.h +spiral.o: $(UTILS_SRC)/resources.h +spiral.o: $(UTILS_SRC)/usleep.h +spiral.o: $(UTILS_SRC)/visual.h +spiral.o: $(UTILS_SRC)/yarandom.h +spiral.o: $(srcdir)/xlockmoreI.h +spiral.o: $(srcdir)/xlockmore.h +spotlight.o: ../config.h +spotlight.o: $(srcdir)/fps.h +spotlight.o: $(srcdir)/recanim.h +spotlight.o: $(srcdir)/screenhackI.h +spotlight.o: $(srcdir)/screenhack.h +spotlight.o: $(UTILS_SRC)/colors.h +spotlight.o: $(UTILS_SRC)/font-retry.h +spotlight.o: $(UTILS_SRC)/grabscreen.h +spotlight.o: $(UTILS_SRC)/hsv.h +spotlight.o: $(UTILS_SRC)/resources.h +spotlight.o: $(UTILS_SRC)/usleep.h +spotlight.o: $(UTILS_SRC)/visual.h +spotlight.o: $(UTILS_SRC)/yarandom.h +squiral.o: ../config.h +squiral.o: $(srcdir)/fps.h +squiral.o: $(srcdir)/recanim.h +squiral.o: $(srcdir)/screenhackI.h +squiral.o: $(srcdir)/screenhack.h +squiral.o: $(UTILS_SRC)/colors.h +squiral.o: $(UTILS_SRC)/erase.h +squiral.o: $(UTILS_SRC)/font-retry.h +squiral.o: $(UTILS_SRC)/grabscreen.h +squiral.o: $(UTILS_SRC)/hsv.h +squiral.o: $(UTILS_SRC)/resources.h +squiral.o: $(UTILS_SRC)/usleep.h +squiral.o: $(UTILS_SRC)/visual.h +squiral.o: $(UTILS_SRC)/yarandom.h +starfish.o: ../config.h +starfish.o: $(srcdir)/fps.h +starfish.o: $(srcdir)/recanim.h +starfish.o: $(srcdir)/screenhackI.h +starfish.o: $(srcdir)/screenhack.h +starfish.o: $(UTILS_SRC)/colors.h +starfish.o: $(UTILS_SRC)/font-retry.h +starfish.o: $(UTILS_SRC)/grabscreen.h +starfish.o: $(UTILS_SRC)/hsv.h +starfish.o: $(UTILS_SRC)/resources.h +starfish.o: $(UTILS_SRC)/spline.h +starfish.o: $(UTILS_SRC)/usleep.h +starfish.o: $(UTILS_SRC)/visual.h +starfish.o: $(UTILS_SRC)/yarandom.h +strange.o: ../config.h +strange.o: $(srcdir)/fps.h +strange.o: $(srcdir)/recanim.h +strange.o: $(srcdir)/screenhackI.h +strange.o: $(UTILS_SRC)/aligned_malloc.h +strange.o: $(UTILS_SRC)/colors.h +strange.o: $(UTILS_SRC)/erase.h +strange.o: $(UTILS_SRC)/font-retry.h +strange.o: $(UTILS_SRC)/grabscreen.h +strange.o: $(UTILS_SRC)/hsv.h +strange.o: $(UTILS_SRC)/pow2.h +strange.o: $(UTILS_SRC)/resources.h +strange.o: $(UTILS_SRC)/thread_util.h +strange.o: $(UTILS_SRC)/usleep.h +strange.o: $(UTILS_SRC)/visual.h +strange.o: $(UTILS_SRC)/xshm.h +strange.o: $(UTILS_SRC)/yarandom.h +strange.o: $(srcdir)/xlockmoreI.h +strange.o: $(srcdir)/xlockmore.h +substrate.o: ../config.h +substrate.o: $(srcdir)/fps.h +substrate.o: $(srcdir)/recanim.h +substrate.o: $(srcdir)/screenhackI.h +substrate.o: $(srcdir)/screenhack.h +substrate.o: $(UTILS_SRC)/colors.h +substrate.o: $(UTILS_SRC)/font-retry.h +substrate.o: $(UTILS_SRC)/grabscreen.h +substrate.o: $(UTILS_SRC)/hsv.h +substrate.o: $(UTILS_SRC)/resources.h +substrate.o: $(UTILS_SRC)/usleep.h +substrate.o: $(UTILS_SRC)/visual.h +substrate.o: $(UTILS_SRC)/yarandom.h +swirl.o: ../config.h +swirl.o: $(srcdir)/fps.h +swirl.o: $(srcdir)/recanim.h +swirl.o: $(srcdir)/screenhackI.h +swirl.o: $(UTILS_SRC)/colors.h +swirl.o: $(UTILS_SRC)/erase.h +swirl.o: $(UTILS_SRC)/font-retry.h +swirl.o: $(UTILS_SRC)/grabscreen.h +swirl.o: $(UTILS_SRC)/hsv.h +swirl.o: $(UTILS_SRC)/resources.h +swirl.o: $(UTILS_SRC)/usleep.h +swirl.o: $(UTILS_SRC)/visual.h +swirl.o: $(UTILS_SRC)/xshm.h +swirl.o: $(UTILS_SRC)/yarandom.h +swirl.o: $(srcdir)/xlockmoreI.h +swirl.o: $(srcdir)/xlockmore.h +t3d.o: ../config.h +t3d.o: $(srcdir)/fps.h +t3d.o: $(srcdir)/recanim.h +t3d.o: $(srcdir)/screenhackI.h +t3d.o: $(srcdir)/screenhack.h +t3d.o: $(UTILS_SRC)/colors.h +t3d.o: $(UTILS_SRC)/font-retry.h +t3d.o: $(UTILS_SRC)/grabscreen.h +t3d.o: $(UTILS_SRC)/hsv.h +t3d.o: $(UTILS_SRC)/resources.h +t3d.o: $(UTILS_SRC)/usleep.h +t3d.o: $(UTILS_SRC)/visual.h +t3d.o: $(UTILS_SRC)/yarandom.h +tessellimage.o: ../config.h +tessellimage.o: $(srcdir)/delaunay.h +tessellimage.o: $(srcdir)/fps.h +tessellimage.o: $(srcdir)/recanim.h +tessellimage.o: $(srcdir)/screenhackI.h +tessellimage.o: $(srcdir)/screenhack.h +tessellimage.o: $(UTILS_SRC)/colors.h +tessellimage.o: $(UTILS_SRC)/font-retry.h +tessellimage.o: $(UTILS_SRC)/grabscreen.h +tessellimage.o: $(UTILS_SRC)/hsv.h +tessellimage.o: $(UTILS_SRC)/resources.h +tessellimage.o: $(UTILS_SRC)/usleep.h +tessellimage.o: $(UTILS_SRC)/visual.h +tessellimage.o: $(UTILS_SRC)/yarandom.h +testx11.o: ../config.h +testx11.o: $(srcdir)/fps.h +testx11.o: $(srcdir)/glx/rotator.h +testx11.o: $(srcdir)/images/gen/logo-180_png.h +testx11.o: $(srcdir)/recanim.h +testx11.o: $(srcdir)/screenhackI.h +testx11.o: $(srcdir)/screenhack.h +testx11.o: $(UTILS_SRC)/colorbars.h +testx11.o: $(UTILS_SRC)/colors.h +testx11.o: $(UTILS_SRC)/erase.h +testx11.o: $(UTILS_SRC)/font-retry.h +testx11.o: $(UTILS_SRC)/grabscreen.h +testx11.o: $(UTILS_SRC)/hsv.h +testx11.o: $(UTILS_SRC)/resources.h +testx11.o: $(UTILS_SRC)/usleep.h +testx11.o: $(UTILS_SRC)/visual.h +testx11.o: $(UTILS_SRC)/yarandom.h +testx11.o: $(srcdir)/ximage-loader.h +thornbird.o: ../config.h +thornbird.o: $(srcdir)/fps.h +thornbird.o: $(srcdir)/recanim.h +thornbird.o: $(srcdir)/screenhackI.h +thornbird.o: $(UTILS_SRC)/colors.h +thornbird.o: $(UTILS_SRC)/erase.h +thornbird.o: $(UTILS_SRC)/font-retry.h +thornbird.o: $(UTILS_SRC)/grabscreen.h +thornbird.o: $(UTILS_SRC)/hsv.h +thornbird.o: $(UTILS_SRC)/resources.h +thornbird.o: $(UTILS_SRC)/usleep.h +thornbird.o: $(UTILS_SRC)/visual.h +thornbird.o: $(UTILS_SRC)/yarandom.h +thornbird.o: $(srcdir)/xlockmoreI.h +thornbird.o: $(srcdir)/xlockmore.h +triangle.o: ../config.h +triangle.o: $(srcdir)/fps.h +triangle.o: $(srcdir)/recanim.h +triangle.o: $(srcdir)/screenhackI.h +triangle.o: $(UTILS_SRC)/colors.h +triangle.o: $(UTILS_SRC)/erase.h +triangle.o: $(UTILS_SRC)/font-retry.h +triangle.o: $(UTILS_SRC)/grabscreen.h +triangle.o: $(UTILS_SRC)/hsv.h +triangle.o: $(UTILS_SRC)/resources.h +triangle.o: $(UTILS_SRC)/usleep.h +triangle.o: $(UTILS_SRC)/visual.h +triangle.o: $(UTILS_SRC)/yarandom.h +triangle.o: $(srcdir)/xlockmoreI.h +triangle.o: $(srcdir)/xlockmore.h +truchet.o: ../config.h +truchet.o: $(srcdir)/fps.h +truchet.o: $(srcdir)/recanim.h +truchet.o: $(srcdir)/screenhackI.h +truchet.o: $(srcdir)/screenhack.h +truchet.o: $(UTILS_SRC)/colors.h +truchet.o: $(UTILS_SRC)/font-retry.h +truchet.o: $(UTILS_SRC)/grabscreen.h +truchet.o: $(UTILS_SRC)/hsv.h +truchet.o: $(UTILS_SRC)/resources.h +truchet.o: $(UTILS_SRC)/usleep.h +truchet.o: $(UTILS_SRC)/visual.h +truchet.o: $(UTILS_SRC)/yarandom.h +twang.o: ../config.h +twang.o: $(srcdir)/fps.h +twang.o: $(srcdir)/recanim.h +twang.o: $(srcdir)/screenhackI.h +twang.o: $(srcdir)/screenhack.h +twang.o: $(UTILS_SRC)/colors.h +twang.o: $(UTILS_SRC)/font-retry.h +twang.o: $(UTILS_SRC)/grabscreen.h +twang.o: $(UTILS_SRC)/hsv.h +twang.o: $(UTILS_SRC)/resources.h +twang.o: $(UTILS_SRC)/usleep.h +twang.o: $(UTILS_SRC)/visual.h +twang.o: $(UTILS_SRC)/xshm.h +twang.o: $(UTILS_SRC)/yarandom.h +vermiculate.o: ../config.h +vermiculate.o: $(srcdir)/fps.h +vermiculate.o: $(srcdir)/recanim.h +vermiculate.o: $(srcdir)/screenhackI.h +vermiculate.o: $(srcdir)/screenhack.h +vermiculate.o: $(UTILS_SRC)/colors.h +vermiculate.o: $(UTILS_SRC)/font-retry.h +vermiculate.o: $(UTILS_SRC)/grabscreen.h +vermiculate.o: $(UTILS_SRC)/hsv.h +vermiculate.o: $(UTILS_SRC)/resources.h +vermiculate.o: $(UTILS_SRC)/usleep.h +vermiculate.o: $(UTILS_SRC)/visual.h +vermiculate.o: $(UTILS_SRC)/yarandom.h +vfeedback.o: $(srcdir)/analogtv.h +vfeedback.o: ../config.h +vfeedback.o: $(srcdir)/fps.h +vfeedback.o: $(srcdir)/recanim.h +vfeedback.o: $(srcdir)/screenhackI.h +vfeedback.o: $(srcdir)/screenhack.h +vfeedback.o: $(UTILS_SRC)/aligned_malloc.h +vfeedback.o: $(UTILS_SRC)/colors.h +vfeedback.o: $(UTILS_SRC)/font-retry.h +vfeedback.o: $(UTILS_SRC)/grabscreen.h +vfeedback.o: $(UTILS_SRC)/hsv.h +vfeedback.o: $(UTILS_SRC)/resources.h +vfeedback.o: $(UTILS_SRC)/thread_util.h +vfeedback.o: $(UTILS_SRC)/usleep.h +vfeedback.o: $(UTILS_SRC)/visual.h +vfeedback.o: $(UTILS_SRC)/xshm.h +vfeedback.o: $(UTILS_SRC)/yarandom.h +vines.o: ../config.h +vines.o: $(srcdir)/fps.h +vines.o: $(srcdir)/recanim.h +vines.o: $(srcdir)/screenhackI.h +vines.o: $(UTILS_SRC)/colors.h +vines.o: $(UTILS_SRC)/erase.h +vines.o: $(UTILS_SRC)/font-retry.h +vines.o: $(UTILS_SRC)/grabscreen.h +vines.o: $(UTILS_SRC)/hsv.h +vines.o: $(UTILS_SRC)/resources.h +vines.o: $(UTILS_SRC)/usleep.h +vines.o: $(UTILS_SRC)/visual.h +vines.o: $(UTILS_SRC)/yarandom.h +vines.o: $(srcdir)/xlockmoreI.h +vines.o: $(srcdir)/xlockmore.h +wander.o: ../config.h +wander.o: $(srcdir)/fps.h +wander.o: $(srcdir)/recanim.h +wander.o: $(srcdir)/screenhackI.h +wander.o: $(srcdir)/screenhack.h +wander.o: $(UTILS_SRC)/colors.h +wander.o: $(UTILS_SRC)/erase.h +wander.o: $(UTILS_SRC)/font-retry.h +wander.o: $(UTILS_SRC)/grabscreen.h +wander.o: $(UTILS_SRC)/hsv.h +wander.o: $(UTILS_SRC)/resources.h +wander.o: $(UTILS_SRC)/usleep.h +wander.o: $(UTILS_SRC)/visual.h +wander.o: $(UTILS_SRC)/yarandom.h +webcollage-cocoa.o: ../config.h +webcollage-cocoa.o: $(srcdir)/fps.h +webcollage-cocoa.o: $(srcdir)/recanim.h +webcollage-cocoa.o: $(srcdir)/screenhackI.h +webcollage-cocoa.o: $(srcdir)/screenhack.h +webcollage-cocoa.o: $(UTILS_SRC)/colors.h +webcollage-cocoa.o: $(UTILS_SRC)/font-retry.h +webcollage-cocoa.o: $(UTILS_SRC)/grabscreen.h +webcollage-cocoa.o: $(UTILS_SRC)/hsv.h +webcollage-cocoa.o: $(UTILS_SRC)/resources.h +webcollage-cocoa.o: $(UTILS_SRC)/usleep.h +webcollage-cocoa.o: $(UTILS_SRC)/visual.h +webcollage-cocoa.o: $(UTILS_SRC)/yarandom.h +webcollage-helper.o: ../config.h +whirlwindwarp.o: ../config.h +whirlwindwarp.o: $(srcdir)/fps.h +whirlwindwarp.o: $(srcdir)/recanim.h +whirlwindwarp.o: $(srcdir)/screenhackI.h +whirlwindwarp.o: $(srcdir)/screenhack.h +whirlwindwarp.o: $(UTILS_SRC)/colors.h +whirlwindwarp.o: $(UTILS_SRC)/erase.h +whirlwindwarp.o: $(UTILS_SRC)/font-retry.h +whirlwindwarp.o: $(UTILS_SRC)/grabscreen.h +whirlwindwarp.o: $(UTILS_SRC)/hsv.h +whirlwindwarp.o: $(UTILS_SRC)/resources.h +whirlwindwarp.o: $(UTILS_SRC)/usleep.h +whirlwindwarp.o: $(UTILS_SRC)/visual.h +whirlwindwarp.o: $(UTILS_SRC)/yarandom.h +whirlygig.o: ../config.h +whirlygig.o: $(srcdir)/fps.h +whirlygig.o: $(srcdir)/recanim.h +whirlygig.o: $(srcdir)/screenhackI.h +whirlygig.o: $(srcdir)/screenhack.h +whirlygig.o: $(UTILS_SRC)/colors.h +whirlygig.o: $(UTILS_SRC)/font-retry.h +whirlygig.o: $(UTILS_SRC)/grabscreen.h +whirlygig.o: $(UTILS_SRC)/hsv.h +whirlygig.o: $(UTILS_SRC)/resources.h +whirlygig.o: $(UTILS_SRC)/usleep.h +whirlygig.o: $(UTILS_SRC)/visual.h +whirlygig.o: $(UTILS_SRC)/xdbe.h +whirlygig.o: $(UTILS_SRC)/yarandom.h +wormhole.o: ../config.h +wormhole.o: $(srcdir)/fps.h +wormhole.o: $(srcdir)/recanim.h +wormhole.o: $(srcdir)/screenhackI.h +wormhole.o: $(srcdir)/screenhack.h +wormhole.o: $(UTILS_SRC)/colors.h +wormhole.o: $(UTILS_SRC)/font-retry.h +wormhole.o: $(UTILS_SRC)/grabscreen.h +wormhole.o: $(UTILS_SRC)/hsv.h +wormhole.o: $(UTILS_SRC)/resources.h +wormhole.o: $(UTILS_SRC)/usleep.h +wormhole.o: $(UTILS_SRC)/visual.h +wormhole.o: $(UTILS_SRC)/yarandom.h +worm.o: ../config.h +worm.o: $(srcdir)/fps.h +worm.o: $(srcdir)/recanim.h +worm.o: $(srcdir)/screenhackI.h +worm.o: $(UTILS_SRC)/colors.h +worm.o: $(UTILS_SRC)/erase.h +worm.o: $(UTILS_SRC)/font-retry.h +worm.o: $(UTILS_SRC)/grabscreen.h +worm.o: $(UTILS_SRC)/hsv.h +worm.o: $(UTILS_SRC)/resources.h +worm.o: $(UTILS_SRC)/usleep.h +worm.o: $(UTILS_SRC)/visual.h +worm.o: $(UTILS_SRC)/yarandom.h +worm.o: $(srcdir)/xlockmoreI.h +worm.o: $(srcdir)/xlockmore.h +xanalogtv.o: $(srcdir)/analogtv.h +xanalogtv.o: ../config.h +xanalogtv.o: $(srcdir)/fps.h +xanalogtv.o: $(srcdir)/images/gen/logo-180_png.h +xanalogtv.o: $(srcdir)/images/gen/testcard_bbcf_png.h +xanalogtv.o: $(srcdir)/images/gen/testcard_pm5544_png.h +xanalogtv.o: $(srcdir)/images/gen/testcard_rca_png.h +xanalogtv.o: $(srcdir)/recanim.h +xanalogtv.o: $(srcdir)/screenhackI.h +xanalogtv.o: $(srcdir)/screenhack.h +xanalogtv.o: $(UTILS_SRC)/aligned_malloc.h +xanalogtv.o: $(UTILS_SRC)/colors.h +xanalogtv.o: $(UTILS_SRC)/font-retry.h +xanalogtv.o: $(UTILS_SRC)/grabscreen.h +xanalogtv.o: $(UTILS_SRC)/hsv.h +xanalogtv.o: $(UTILS_SRC)/resources.h +xanalogtv.o: $(UTILS_SRC)/thread_util.h +xanalogtv.o: $(UTILS_SRC)/usleep.h +xanalogtv.o: $(UTILS_SRC)/visual.h +xanalogtv.o: $(UTILS_SRC)/xshm.h +xanalogtv.o: $(UTILS_SRC)/yarandom.h +xanalogtv.o: $(srcdir)/ximage-loader.h +xflame.o: ../config.h +xflame.o: $(srcdir)/fps.h +xflame.o: $(srcdir)/images/gen/bob_png.h +xflame.o: $(srcdir)/recanim.h +xflame.o: $(srcdir)/screenhackI.h +xflame.o: $(srcdir)/screenhack.h +xflame.o: $(UTILS_SRC)/colors.h +xflame.o: $(UTILS_SRC)/font-retry.h +xflame.o: $(UTILS_SRC)/grabscreen.h +xflame.o: $(UTILS_SRC)/hsv.h +xflame.o: $(UTILS_SRC)/resources.h +xflame.o: $(UTILS_SRC)/usleep.h +xflame.o: $(UTILS_SRC)/visual.h +xflame.o: $(UTILS_SRC)/xshm.h +xflame.o: $(UTILS_SRC)/yarandom.h +xflame.o: $(srcdir)/ximage-loader.h +ximage-loader.o: ../config.h +ximage-loader.o: $(srcdir)/ximage-loader.h +xjack.o: ../config.h +xjack.o: $(srcdir)/fps.h +xjack.o: $(srcdir)/recanim.h +xjack.o: $(srcdir)/screenhackI.h +xjack.o: $(srcdir)/screenhack.h +xjack.o: $(UTILS_SRC)/colors.h +xjack.o: $(UTILS_SRC)/font-retry.h +xjack.o: $(UTILS_SRC)/grabscreen.h +xjack.o: $(UTILS_SRC)/hsv.h +xjack.o: $(UTILS_SRC)/resources.h +xjack.o: $(UTILS_SRC)/usleep.h +xjack.o: $(UTILS_SRC)/visual.h +xjack.o: $(UTILS_SRC)/yarandom.h +xlockmore.o: ../config.h +xlockmore.o: $(srcdir)/fps.h +xlockmore.o: $(srcdir)/recanim.h +xlockmore.o: $(srcdir)/screenhackI.h +xlockmore.o: $(srcdir)/screenhack.h +xlockmore.o: $(UTILS_SRC)/colors.h +xlockmore.o: $(UTILS_SRC)/erase.h +xlockmore.o: $(UTILS_SRC)/font-retry.h +xlockmore.o: $(UTILS_SRC)/grabscreen.h +xlockmore.o: $(UTILS_SRC)/hsv.h +xlockmore.o: $(UTILS_SRC)/resources.h +xlockmore.o: $(UTILS_SRC)/usleep.h +xlockmore.o: $(UTILS_SRC)/visual.h +xlockmore.o: $(UTILS_SRC)/yarandom.h +xlockmore.o: $(srcdir)/xlockmoreI.h +xlyap.o: ../config.h +xlyap.o: $(srcdir)/fps.h +xlyap.o: $(srcdir)/recanim.h +xlyap.o: $(srcdir)/screenhackI.h +xlyap.o: $(srcdir)/screenhack.h +xlyap.o: $(UTILS_SRC)/colors.h +xlyap.o: $(UTILS_SRC)/font-retry.h +xlyap.o: $(UTILS_SRC)/grabscreen.h +xlyap.o: $(UTILS_SRC)/hsv.h +xlyap.o: $(UTILS_SRC)/resources.h +xlyap.o: $(UTILS_SRC)/usleep.h +xlyap.o: $(UTILS_SRC)/visual.h +xlyap.o: $(UTILS_SRC)/yarandom.h +xmatrix.o: ../config.h +xmatrix.o: $(srcdir)/fps.h +xmatrix.o: $(srcdir)/images/gen/matrix1b_png.h +xmatrix.o: $(srcdir)/images/gen/matrix1_png.h +xmatrix.o: $(srcdir)/images/gen/matrix2b_png.h +xmatrix.o: $(srcdir)/images/gen/matrix2_png.h +xmatrix.o: $(srcdir)/recanim.h +xmatrix.o: $(srcdir)/screenhackI.h +xmatrix.o: $(srcdir)/screenhack.h +xmatrix.o: $(UTILS_SRC)/colors.h +xmatrix.o: $(UTILS_SRC)/font-retry.h +xmatrix.o: $(UTILS_SRC)/grabscreen.h +xmatrix.o: $(UTILS_SRC)/hsv.h +xmatrix.o: $(UTILS_SRC)/resources.h +xmatrix.o: $(UTILS_SRC)/textclient.h +xmatrix.o: $(UTILS_SRC)/usleep.h +xmatrix.o: $(UTILS_SRC)/visual.h +xmatrix.o: $(UTILS_SRC)/yarandom.h +xmatrix.o: $(srcdir)/ximage-loader.h +xrayswarm.o: ../config.h +xrayswarm.o: $(srcdir)/fps.h +xrayswarm.o: $(srcdir)/recanim.h +xrayswarm.o: $(srcdir)/screenhackI.h +xrayswarm.o: $(srcdir)/screenhack.h +xrayswarm.o: $(UTILS_SRC)/colors.h +xrayswarm.o: $(UTILS_SRC)/font-retry.h +xrayswarm.o: $(UTILS_SRC)/grabscreen.h +xrayswarm.o: $(UTILS_SRC)/hsv.h +xrayswarm.o: $(UTILS_SRC)/resources.h +xrayswarm.o: $(UTILS_SRC)/usleep.h +xrayswarm.o: $(UTILS_SRC)/visual.h +xrayswarm.o: $(UTILS_SRC)/yarandom.h +xscreensaver-sgigl.o: $(UTILS_SRC)/vroot.h +xspirograph.o: ../config.h +xspirograph.o: $(srcdir)/fps.h +xspirograph.o: $(srcdir)/recanim.h +xspirograph.o: $(srcdir)/screenhackI.h +xspirograph.o: $(srcdir)/screenhack.h +xspirograph.o: $(UTILS_SRC)/colors.h +xspirograph.o: $(UTILS_SRC)/erase.h +xspirograph.o: $(UTILS_SRC)/font-retry.h +xspirograph.o: $(UTILS_SRC)/grabscreen.h +xspirograph.o: $(UTILS_SRC)/hsv.h +xspirograph.o: $(UTILS_SRC)/resources.h +xspirograph.o: $(UTILS_SRC)/usleep.h +xspirograph.o: $(UTILS_SRC)/visual.h +xspirograph.o: $(UTILS_SRC)/yarandom.h +xsublim.o: ../config.h +xsublim.o: $(UTILS_SRC)/font-retry.h +xsublim.o: $(UTILS_SRC)/resources.h +xsublim.o: $(UTILS_SRC)/usleep.h +xsublim.o: $(UTILS_SRC)/vroot.h +xsublim.o: $(UTILS_SRC)/yarandom.h +zoom.o: ../config.h +zoom.o: $(srcdir)/fps.h +zoom.o: $(srcdir)/recanim.h +zoom.o: $(srcdir)/screenhackI.h +zoom.o: $(srcdir)/screenhack.h +zoom.o: $(UTILS_SRC)/colors.h +zoom.o: $(UTILS_SRC)/font-retry.h +zoom.o: $(UTILS_SRC)/grabscreen.h +zoom.o: $(UTILS_SRC)/hsv.h +zoom.o: $(UTILS_SRC)/resources.h +zoom.o: $(UTILS_SRC)/usleep.h +zoom.o: $(UTILS_SRC)/visual.h +zoom.o: $(UTILS_SRC)/yarandom.h + diff --git a/hacks/README b/hacks/README new file mode 100644 index 0000000..34e687e --- /dev/null +++ b/hacks/README @@ -0,0 +1,6 @@ + +This directory contains various graphics hacks. These are independent from +the xscreensaver program (in the ../driver/ directory) but some of them use +the utility functions found in the ../utils/ directory. + +If you have compilation problems, check the parameters in ../config.h. diff --git a/hacks/abstractile.c b/hacks/abstractile.c new file mode 100644 index 0000000..b4394f1 --- /dev/null +++ b/hacks/abstractile.c @@ -0,0 +1,1605 @@ +/* + * Copyright (c) 2004-2009 Steve Sundstrom + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +#include "screenhack.h" +#include "colors.h" +#include "hsv.h" +#include +#include +#include +/*#include */ + +#define MODE_CREATE 0 /* init, create, then finish sleep */ +#define MODE_ERASE 1 /* erase, then reset colors */ +#define MODE_DRAW 2 + +#define DIR_NONE 0 +#define DIR_UP 1 +#define DIR_DOWN 2 +#define DIR_LEFT 3 +#define DIR_RIGHT 4 + +#define LINE_FORCE 1 +#define LINE_NEW 2 +#define LINE_BRIN 3 +#define LINE_BROUT 4 + +#define PT_UL 0 +#define PT_MP 1 +#define PT_LR 2 +#define PT_NL 3 + +#define D3D_NONE 0 +#define D3D_BLOCK 1 +#define D3D_NEON 2 +#define D3D_TILED 3 + +#define TILE_RANDOM 0 +#define TILE_FLAT 1 +#define TILE_THIN 2 +#define TILE_OUTLINE 3 +#define TILE_BLOCK 4 +#define TILE_NEON 5 +#define TILE_TILED 6 + +#define BASECOLORS 30 +#define SHADES 12 +#define MAXCOLORS 40 +#define LAYERS 4 +#define PATTERNS 40 +#define SHAPES 18 +#define DRAWORDERS 40 +#define COLORMAPS 20 +#define WAVES 6 +#define STRETCHES 8 + +struct lineStruct { + unsigned int x, y, len, obj, color, ndol; + int deo; + Bool hv; +}; + +struct gridStruct { + unsigned int line, hl, hr, vu, vd, dhl, dhr, dvu, dvd; +}; + +/* basically the same as global variables, but used to keep them in a bucket + and pass them around easier like the original C++ implementation */ +struct state { + /* window values */ + Display *display; + Window window; + XWindowAttributes xgwa; + GC fgc, bgc; + XColor colors[255]; + + /* memory values */ + struct lineStruct *dline, *eline; + struct gridStruct *grid; + unsigned int *zlist, *fdol; + Bool *odi; + /* draw, erase, fill, init, line, object, z indexes */ + unsigned int di, ei, fi, ii, bi, li, eli, oi, zi; + /* size variables */ + int gridx, gridy; /* grid size */ + unsigned int gridn; + int lwid, bwid, swid;/* line width, background width, shadow width */ + int narray, max_wxh; + int elwid, elpu, egridx, egridy; /* for now */ + /* fill variables */ + int bnratio; /* ratio of branch lines to new lines */ + int maxlen; /* maximum length of line */ + int forcemax; /* make line be max possible length */ + int olen; /* open length set by findopen */ + int bln; /* blocking line number set by findopen, -1=edge */ + /* color variables */ + int ncolors; /* number of colors for screen */ + int shades; + int rco[MAXCOLORS]; /* random ordering of colors for deo */ + int cmap; + int layers; + Bool newcols; /* can we create new colormaps with each screen */ + /* draw variables */ + int dmap, emap; /* pattern by which line draw order is determined */ + int dvar, evar; /* random number added to .deo to vary */ + int ddir, edir; /* draw/erase in forward direction or reverse */ + int lpu; /* lines drawn per update used to adjust speed */ + int d3d; + int round; + int outline; + /* layered draw variables */ + int pattern[LAYERS], shape[LAYERS], mix[LAYERS]; + int csw[LAYERS], wsx[LAYERS], wsy[LAYERS], sec[LAYERS]; + int cs1[LAYERS], cs2[LAYERS], cs3[LAYERS]; int cs4[LAYERS]; + int wave[LAYERS], waveh[LAYERS], wavel[LAYERS]; + int rx1[LAYERS], rx2[LAYERS], rx3[LAYERS]; + int ry1[LAYERS], ry2[LAYERS], ry3[LAYERS]; + /* misc variables */ + int mode, sleep, speed, tile, dialog; + Bool grid_full, resized; + struct timeval time; +}; + +static int +_min(int a, int b) +{ + if (a<=b) + return(a); + return(b); +} + +static int +_max(int a, int b) +{ + if (a>=b) + return(a); + return(b); +} + +static int +_dist(struct state *st, int x1, int x2, int y1, int y2, int s) +{ + double xd=x1-x2; + double yd=y1-y2; + switch(s) { + case 0: + return((int)sqrt(xd*xd+yd*yd)); + case 1: + return((int)sqrt(xd*xd*st->cs1[0]*2+yd*yd)); + case 2: + return((int)sqrt(xd*xd+yd*yd*st->cs2[0]*2)); + default: + return((int)sqrt(xd*xd*st->cs1[0]/st->cs2[0]+yd*yd*st->cs3[0]/st->cs4[0])); + } +} + +static int +_wave(struct state *st, int x, int h, int l, int wave) +{ + l+=1; + switch(wave) { + case 0: /* cos wave*/ + return((int)(cos((double)x*M_PI/l)*h)); + case 1: /* double wave*/ + case 2: /* double wave*/ + return((int)(cos((double)x*M_PI/l)*h)+(int)(sin((double)x*M_PI/l/st->cs1[1])*h)); + case 3: /* zig zag */ + return(abs((x%(l*2)-l))*h/l); + case 4: /* giant zig zag */ + return(abs((x%(l*4)-l*2))*h*3/l); + case 5: /* sawtooth */ + return((x%(l))*h/l); + default: /* no wave */ + return(0); + } +} + +static int +_triangle(struct state *st, int x, int y, int rx, int ry, int t) +{ + switch(t) { + case 1: + return(_min(_min(x+y+rx-(st->gridx/2),st->gridx-x+y),(st->gridy-y+(ry/2))*3/2)); + case 2: + return(_min(_min(x-rx,y-ry),(rx+ry-x-y)*2/3)); + case 3: + return(_min(_min(st->gridx-x-rx,y-ry),(rx+ry-st->gridx+x-y)*2/3)); + case 4: + return(_min(_min(x-rx,st->gridy-y-ry),(rx+ry-x-st->gridy+y)*2/3)); + } + return(_min(_min(st->gridx-x-rx,st->gridy-y-ry),(rx+ry-st->gridx+x-st->gridy+y)*2/3)); +} + +static void +_init_zlist(struct state *st) +{ + unsigned int tmp, y, z; + + st->gridx=st->xgwa.width/st->lwid; + st->gridy=st->xgwa.height/st->lwid; + if ((st->gridx <= 0) || (st->gridy <= 0)) abort(); + st->gridn=st->gridx*st->gridy; + /* clear grid */ + for (z=0; zgridn; z++) { + st->grid[z].line=st->grid[z].hl=st->grid[z].hr=st->grid[z].vu=st->grid[z].vd=st->grid[z].dhl=st->grid[z].dhr=st->grid[z].dvu=st->grid[z].dvd=0; + st->zlist[z]=z; + } + /* rather than pull x,y points randomly and wait to hit final empy cells a + list of all points is created and mixed so empty cells do get hit last */ + for (z=0; zgridn; z++) { + y=random()%st->gridn; + tmp=st->zlist[y]; + st->zlist[y]=st->zlist[z]; + st->zlist[z]=tmp; + } +} + +static void +make_color_ramp_rgb (Screen *screen, Visual *visual, Colormap cmap, + int r1, int g1, int b1, int r2, int g2, int b2, + XColor *colors, int *ncolorsP, Bool closed_p) +{ + int h1, h2; + double s1, s2, v1, v2; + rgb_to_hsv(r1, g1, b1, &h1, &s1, &v1); + rgb_to_hsv(r2, g2, b2, &h2, &s2, &v2); + make_color_ramp(screen, visual, cmap, h1, s1, v1, h2, s2, v2, + colors, ncolorsP, False, True, 0); +} + + +static void +_init_colors(struct state *st) +{ + int col[BASECOLORS]; + int c1, c2, c3, h1, h2, h3; + int r1, g1, b1, r2, g2, b2, r3, g3, b3; + double s1, s2, s3, v1, v2, v3; + XColor tmp_col1[16], tmp_col2[16], tmp_col3[16]; + + unsigned short basecol[BASECOLORS][3]={ + /* 0 dgray */ {0x3333,0x3333,0x3333}, + /* 1 dbrown */ {0x6666,0x3333,0x0000}, + /* 2 dred */ {0x9999,0x0000,0x0000}, + /* 3 orange */ {0xFFFF,0x6666,0x0000}, + /* 4 gold */ {0xFFFF,0xCCCC,0x0000}, + /* 5 olive */ {0x6666,0x6666,0x0000}, + /* 6 ivy */ {0x0000,0x6666,0x0000}, + /* 7 dgreen */ {0x0000,0x9999,0x0000}, + /* 8 bluegray */ {0x3333,0x6666,0x6666}, + /* 9 dblue */ {0x0000,0x0000,0x9999}, + /* 10 blue */ {0x3333,0x3333,0xFFFF}, + /* 11 dpurple */ {0x6666,0x0000,0xCCCC}, + /* 12 purple */ {0x6666,0x3333,0xFFFF}, + /* 13 violet */ {0x9999,0x3333,0x9999}, + /* 14 magenta */ {0xCCCC,0x3333,0xCCCC}, + /* lights */ + /* 15 gray */ {0x3333,0x3333,0x3333}, + /* 16 brown */ {0x9999,0x6666,0x3333}, + /* 17 tan */ {0xCCCC,0x9999,0x3333}, + /* 18 red */ {0xFFFF,0x0000,0x0000}, + /* 19 lorange */ {0xFFFF,0x9999,0x0000}, + /* 20 yellow */ {0xFFFF,0xFFFF,0x0000}, + /* 21 lolive */ {0x9999,0x9999,0x0000}, + /* 22 green */ {0x3333,0xCCCC,0x0000}, + /* 23 lgreen */ {0x3333,0xFFFF,0x3333}, + /* 24 cyan */ {0x0000,0xCCCC,0xCCCC}, + /* 25 sky */ {0x3333,0xFFFF,0xFFFF}, + /* 26 marine */ {0x3333,0x6666,0xFFFF}, + /* 27 lblue */ {0x3333,0xCCCC,0xFFFF}, + /* 28 lpurple */ {0x9999,0x9999,0xFFFF}, + /* 29 pink */ {0xFFFF,0x9999,0xFFFF}}; + + if (st->d3d) { + st->shades = (st->d3d==D3D_TILED) ? 5 : st->lwid/2+1; + st->ncolors=4+random()%4; + if (st->cmap>0) { /* tint the basecolors a bit */ + for (c1=0; c1cmap%4) { + case 0: /* all */ + for (c1=0; c1ncolors; c1++) + col[c1]=random()%BASECOLORS; + break; + case 1: /* darks */ + for (c1=0; c1ncolors; c1++) + col[c1]=random()%15; + break; + case 2: /* semi consecutive darks */ + col[0]=random()%15; + for (c1=1; c1ncolors; c1++) + col[c1]=(col[c1-1]+1+random()%2)%15; + break; + case 3: /* consecutive darks */ + col[0]=random()%(15-st->ncolors); + for (c1=1; c1ncolors; c1++) + col[c1]=col[c1-1]+1; + break; + } + for (c1=0; c1ncolors; c1++) { + /* adjust colors already set */ + for (h1=c1*st->shades-1; h1>=0; h1--) + st->colors[h1+st->shades]=st->colors[h1]; + make_color_ramp_rgb(st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + basecol[col[c1]][0], basecol[col[c1]][1], basecol[col[c1]][2], + 0xFFFF, 0xFFFF, 0xFFFF, st->colors, &st->shades, + False); + } + return; + } + /* not 3d */ + st->shades=1; + if (st->cmap%2) { /* basecolors */ + if (random()%3) { + c1=random()%15; + c2=(c1+3+(random()%5))%15; + c3=(c2+3+(random()%5))%15; + } else { + c1=random()%BASECOLORS; + c2=(c1+5+(random()%10))%BASECOLORS; + c3=(c2+5+(random()%10))%BASECOLORS; + } + r1=basecol[c1][0]; + g1=basecol[c1][1]; + b1=basecol[c1][2]; + r2=basecol[c2][0]; + g2=basecol[c2][1]; + b2=basecol[c2][2]; + r3=basecol[c3][0]; + g3=basecol[c3][1]; + b3=basecol[c3][2]; + } else { /* random rgb's */ + r1=random()%65535; + g1=random()%65535; + b1=random()%65535; + r2=(r1+16384+random()%32768)%65535; + g2=(g1+16384+random()%32768)%65535; + b2=(b1+16384+random()%32768)%65535; + r3=(r2+16384+random()%32768)%65535; + g3=(g2+16384+random()%32768)%65535; + b3=(b2+16384+random()%32768)%65535; + } + switch(st->cmap) { + case 0: /* make_color_ramp color->color */ + case 1: + case 2: /* make_color_ramp color->white */ + case 3: + st->ncolors=5+random()%5; + if (st->cmap>1) + r2=g2=b2=0xFFFF; + make_color_ramp_rgb(st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + r1, g1, b1, r2, g2, b2, + st->colors, &st->ncolors, random()%2); + break; + case 4: /* 3 color make_color_loop */ + case 5: + case 6: + case 7: + st->ncolors=8+random()%12; + rgb_to_hsv(r1, g1, b1, &h1, &s1, &v1); + rgb_to_hsv(r2, g2, b2, &h2, &s2, &v2); + rgb_to_hsv(r3, g3, b3, &h3, &s3, &v3); + + make_color_loop(st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + h1, s1, v1, h2, s2, v2, h3, s3, v3, + st->colors, &st->ncolors, True, False); + break; + case 8: /* random smooth */ + case 9: + st->ncolors=(random()%4)*6+12; + make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, + st->xgwa.colormap, st->colors, &st->ncolors, + True, False, True); + break; + case 10: /* rainbow */ + st->ncolors=(random()%4)*6+12; + make_uniform_colormap (st->xgwa.screen, st->xgwa.visual, + st->xgwa.colormap, st->colors, &st->ncolors, + True, False, True); + break; + case 11: /* dark to light blend */ + case 12: + case 13: + case 14: + st->ncolors=7; + make_color_ramp_rgb(st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + r1, g1, b1, 0xFFFF, 0xFFFF, 0xFFFF, + tmp_col1, &st->ncolors, False); + make_color_ramp_rgb(st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + r2, g2, b2, 0xFFFF, 0xFFFF, 0xFFFF, + tmp_col2, &st->ncolors, False); + if (st->cmap<13) { + for(c1=0; c1<=4; c1++) { + st->colors[c1*2]=tmp_col1[c1]; + st->colors[c1*2+1]=tmp_col2[c1]; + } + st->ncolors=10; + } else { + make_color_ramp_rgb(st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + r3, g3, b3, 0xFFFF, 0xFFFF, 0xFFFF, + tmp_col3, &st->ncolors, False); + for(c1=0; c1<=4; c1++) { + st->colors[c1*3]=tmp_col1[c1]; + st->colors[c1*3+1]=tmp_col2[c1]; + st->colors[c1*3+2]=tmp_col3[c1]; + } + st->ncolors=15; + } + break; + default: /* random */ + st->ncolors=(random()%4)*6+12; + make_random_colormap (st->xgwa.screen, st->xgwa.visual, + st->xgwa.colormap, st->colors, &st->ncolors, + False, True, False, True); + break; + } + + /* set random color order for drawing and erasing */ + for (c1=0; c1rco[c1]=c1; + for (c1=0; c1rco[c1]; + st->rco[c1]=st->rco[c3]; + st->rco[c3]=c2; + } +} + +static int _comparedeo(const void *i, const void *j) +{ + struct lineStruct *h1, *h2; + + h1=(struct lineStruct *)i; + h2=(struct lineStruct *)j; + if (h1->deo > h2->deo) + return(1); + if (h1->deo < h2->deo) + return(-1); + return(0); +} + +static int +_hv(struct state *st, int x, int y, int d1, int d2, int pn, Bool de) +{ + int v1, v2, r; + + switch (d1) { + case 0: + v1 = (de) ? st->egridx-x : st->gridx-x; + break; + case 1: + v1 = y; + break; + case 2: + v1 = x; + break; + default: + v1 = (de) ? st->egridy-y : st->gridy-y; + break; + } + switch (d2) { + case 0: + v2 = (de) ? st->egridx-x : st->gridx-x; + break; + case 1: + v2 = y; + break; + case 2: + v2 = x; + break; + default: + v2 = (de) ? st->egridy-y : st->gridy-y; + break; + } + r = (de) ? (st->dline[st->li].hv) ? (v1+10000)*pn : (v2+10000)*-pn : + (st->eline[st->li].hv) ? (v1+10000)*pn : (v2+10000)*-pn; + return(r); +} + +static int +_getdeo(struct state *st, int x, int y, int map, int de) +{ + int cr; + switch(map) { + case 0: /* horizontal one side */ + return(x); + case 1: /* vertical one side */ + return(y); + case 2: /* horizontal two side */ + return(_min(x,st->gridx-x)+1); + case 3: /* vertical two side */ + return(_min(y,st->gridy-y)+1); + case 4: /* square */ + return(_max(abs(x-st->rx3[de]),abs(y-st->ry3[de]))+1); + case 5: /* two squares */ + return(_min(_max(abs(x-(st->rx3[de]/2)),abs(y-st->ry3[de])),_max(abs(x-(st->gridx-(st->rx2[de]/2))),abs(y-st->ry2[de])))+1); + case 6: /* horizontal rectangle */ + return(_max(abs(x-st->rx3[de]),abs(y-(st->ry3[de]))*st->cs1[de])+1); + case 7: /* vertical rectangle */ + return(_max(abs(x-st->rx3[de])*st->cs1[de],abs(y-(st->ry3[de])))+1); + case 8: /* + cross */ + return(_min(abs(x-st->rx3[de]),abs(y-(st->ry3[de])))+1); + case 9: /* diagonal */ + return((x*3/4+y)+1); + case 10: /* opposite diagonal */ + return((x*3/4+st->gridy-y)+1); + case 11: /* diamond */ + return((abs(x-st->rx3[de])+abs(y-st->ry3[de]))/2+1); + case 12: /* two diamonds */ + return(_min(abs(x-(st->rx3[de]/2))+abs(y-st->ry3[de]),abs(x-(st->gridx-(st->rx2[de]/2)))+abs(y-st->ry2[de]))/2+1); + case 13: /* circle */ + return(_dist(st,x,st->rx3[de],y,st->ry3[de],0)+1); + case 14: /* horizontal ellipse */ + return(_dist(st,x,st->rx3[de],y,st->ry3[de],1)+1); + case 15: /* vertical ellipse */ + return(_dist(st,x,st->rx3[de],y,st->ry3[de],2)+1); + case 16: /* two circles */ + return(_min(_dist(st,x,st->rx3[de]/2,y,st->ry3[de],0),_dist(st,x,st->gridx-(st->rx2[de]/2),y,st->ry2[de],0))+1); + case 17: /* horizontal straight wave */ + return(x+_wave(st,st->gridy+y,st->csw[0]*st->cs1[0],st->csw[0]*st->cs2[0],st->wave[de])); + case 18: /* vertical straight wave */ + return(y+_wave(st,st->gridx+x,st->csw[0]*st->cs1[0],st->csw[0]*st->cs2[0],st->wave[de])); + case 19: /* horizontal wavey wave */ + return(x+_wave(st,st->gridy+y+((x/5)*st->edir),st->csw[de]*st->cs1[de],st->csw[de]*st->cs2[de],st->wave[de])+1); + case 20: /* vertical wavey wave */ + return(y+_wave(st,st->gridx+x+((y/5)*st->edir),st->csw[de]*st->cs1[de],st->csw[de]*st->cs2[de],st->wave[de])+1); +/* no d3d for 21,22 */ + case 21: /* simultaneous directional */ + return(_hv(st,x,y,st->cs1[0]%2,st->cs2[0]%2,1,de)); + case 22: /* reverse directional */ + return(_hv(st,x,y,st->cs1[0]%2,st->cs2[0]%2,-1,de)); + case 23: /* length */ + if (de) + return(st->dline[st->li].len*1000+random()%5000); + else + return(st->eline[st->li].len*1000+random()%5000); + case 24: /* object */ + case 25: + case 26: + case 27: + if (de) + return(st->dline[st->li].obj*100); + else + return(st->eline[st->li].obj*100); + default: /* color */ + cr = (de) ? st->dline[st->li].color : st->eline[st->li].color; + if (map<34) cr=st->rco[cr]; + if ((map%6<4) || (de)) { /* by color */ + cr*=1000; + cr+=random()%1000; + } else if (map%6==4) { /* by color horizontaly */ + cr*=st->gridx; + cr+=(x+random()%(st->gridx/2)); + } else { /* by color vertically */ + cr*=st->gridy; + cr+=(y+random()%(st->gridy/2)); + } + return(cr); + } + return(1); +} + +static void +_init_screen(struct state *st) +{ + int nstr, x; + struct lineStruct *tmp; + + /* malloc memory in case of resize */ + if (st->resized) { + st->max_wxh=st->xgwa.width*st->xgwa.height; + if (st->dline!=NULL) + free(st->dline); + if (st->eline!=NULL) + free(st->eline); + if (st->grid!=NULL) + free(st->grid); + if (st->zlist!=NULL) + free(st->zlist); + if (st->fdol!=NULL) + free(st->fdol); + if (st->odi!=NULL) + free(st->odi); + st->narray = (st->xgwa.width+1)*(st->xgwa.height+1)/4+1; + st->dline = calloc(st->narray, sizeof(struct lineStruct)); + st->eline = calloc(st->narray, sizeof(struct lineStruct)); + st->grid = calloc(st->narray, sizeof(struct gridStruct)); + st->zlist = calloc(st->narray, sizeof(unsigned int)); + st->fdol = calloc(st->narray, sizeof(unsigned int)); + st->odi = calloc(st->narray, sizeof(Bool)); + if ((st->dline == NULL) || (st->eline == NULL) || + (st->grid == NULL) || (st->zlist == NULL) || + (st->fdol == NULL) || (st->odi == NULL)) { + fprintf(stderr, "not enough memory\n"); + exit(1); + } + st->dialog = (st->xgwa.width<500) ? 1 : 0; + st->resized=False; + } + if (st->ii) { + /* swap st->dline and st->eline pointers to resort and erase */ + tmp=st->eline; + st->eline=st->dline; + st->dline=tmp; + st->eli=st->li; + st->elwid=st->lwid; + st->elpu=st->lpu; + st->egridx=st->gridx; + st->egridy=st->gridy; + + /* create new erase order */ + for (st->li=1; st->li<=st->eli; st->li++) + st->eline[st->li].deo=(_getdeo(st,st->eline[st->li].x,st->eline[st->li].y,st->emap,0) + (random()%st->evar) + (random()%st->evar))*st->edir; + qsort(st->eline, st->eli+1, sizeof(struct lineStruct), _comparedeo); + } + st->ii++; + + /* clear arrays and other counters */ + st->di=st->ei=st->fi=st->li=st->oi=st->zi=0; + st->grid_full=False; + /* li starts from 1 */ + st->dline[0].x=st->dline[0].y=st->dline[0].len=0; + /* to keep it first after sorting so di is never null */ + st->dline[0].deo=-999999999; + + /* set random screen variables */ + st->lwid = (st->ii==1) ? 3 : 2+((random()%6)%4); + st->d3d = ((st->tile==TILE_FLAT) || (st->tile==TILE_THIN) || + (st->tile==TILE_OUTLINE)) ? D3D_NONE : + (st->tile==TILE_BLOCK) ? D3D_BLOCK : + (st->tile==TILE_NEON) ? D3D_NEON : + (st->tile==TILE_TILED) ? D3D_TILED : + /* force TILE_D3D on first screen to properly load all shades */ + ((st->ii==1) && (!st->newcols)) ? D3D_TILED : (random()%5)%4; +/* st->d3d=D3D_BLOCK; st->lwid=2; */ + st->outline = (st->tile==TILE_OUTLINE) ? 1 : + ((st->tile!=TILE_RANDOM) || (random()%5)) ? 0 : 1; + st->round = (st->d3d==D3D_NEON) ? 1 : + ((st->d3d==D3D_BLOCK) || (st->outline) || (random()%6)) ? 0 : 1; + if ((st->d3d) || (st->outline) || (st->round)) + st->lwid+=2; + if ((!st->d3d) && (!st->round) && (!st->outline) && (st->lwid>3)) + st->lwid-=2; + if (st->d3d==D3D_TILED) + st->lwid++; + if (st->tile==TILE_THIN) + st->lwid=2; + + _init_zlist(st); + + st->maxlen=(st->lwid>6) ? 2+(random()%4) : + (st->lwid>4) ? 2+(random()%8)%6 : + (st->lwid>2) ? 2+(random()%12)%8 : 2+(random()%15)%10; + st->bnratio = 4+(random()%4)+(random()%4); + st->forcemax = (random()%6) ? 0 : 1; + + if ((st->ii==1) || (st->newcols)) + _init_colors(st); + + st->dmap = (st->emap+5+(random()%5))%DRAWORDERS; + + st->dmap=20+random()%20; + + st->dvar = (st->dmap>22) ? 100 : 10+(st->csw[0]*(random()%5)); + st->ddir= (random()%2) ? 1 : -1; + + st->emap = (st->dmap+10+(random()%10))%20; + st->evar = (st->emap>22) ? 100 : 10+(st->csw[0]*(random()%5)); + st->edir= (random()%2) ? 1 : -1; + + st->layers= (random()%2) ? 2 : (random()%2) ? 1 : (random()%2) ? 3 : 4; + st->cmap=(st->cmap+5+(random()%10))%COLORMAPS; + + for (x=0; xpattern[x]=random()%PATTERNS; + st->shape[x]=random()%SHAPES; + st->mix[x]=random()%20; + nstr = (st->lwid==2) ? 20+random()%12 : + (st->lwid==3) ? 16+random()%8 : + (st->lwid==4) ? 12+random()%6 : + (st->lwid==5) ? 10+random()%5 : + (st->lwid==6) ? 8+random()%4 : + 5+random()%5; + st->csw[x] = _max(5,st->gridy/nstr); + st->wsx[x] = (st->wsx[x]+3+(random()%3))%STRETCHES; + st->wsy[x] = (st->wsy[x]+3+(random()%3))%STRETCHES; + st->sec[x] = random()%5; + if ((!st->dialog) && (st->sec[x]<2)) st->csw[x]/=2; + st->cs1[x] = (st->dialog) ? 1+random()%3 : 2+random()%5; + st->cs2[x] = (st->dialog) ? 1+random()%3 : 2+random()%5; + st->cs3[x] = (st->dialog) ? 1+random()%3 : 2+random()%5; + st->cs4[x] = (st->dialog) ? 1+random()%3 : 2+random()%5; + st->wave[x]=random()%WAVES; + st->wavel[x]=st->csw[x]*(2+random()%6); + st->waveh[x]=st->csw[x]*(1+random()%3); + st->rx1[x]=(st->gridx/10+random()%(st->gridx*8/10)); + st->ry1[x]=(st->gridy/10+random()%(st->gridy*8/10)); + st->rx2[x]=(st->gridx*2/10+random()%(st->gridx*6/10)); + st->ry2[x]=(st->gridy*2/10+random()%(st->gridy*6/10)); + st->rx3[x]=(st->gridx*3/10+random()%(st->gridx*4/10)); + st->ry3[x]=(st->gridy*3/10+random()%(st->gridy*4/10)); + } +} + +static int +_shape(struct state *st, int x, int y, int rx, int ry, int n) +{ + switch(st->shape[n]) { + case 0: /* square/rectangle */ + case 1: + case 2: + return(1+_max(abs(x-rx)*st->cs1[n]/st->cs2[n],abs(y-ry)*st->cs3[n]/st->cs4[n])); + case 3: /* diamond */ + case 4: + return(1+(abs(x-rx)*st->cs1[n]/st->cs2[n]+abs(y-ry)*st->cs3[n]/st->cs4[n])); + case 5: /* 8 point star */ + return(1+_min(_max(abs(x-rx),abs(y-ry))*3/2,abs(x-rx)+abs(y-ry))); + case 6: /* circle/oval */ + case 7: + case 8: + return(1+_dist(st,x,rx,y,ry,st->cs1[n])); + case 9: /* black hole circle */ + return(1+(st->gridx*st->gridy/(1+(_dist(st,x,rx,y,ry,st->cs2[n]))))); + case 10: /* sun */ + return(1+_min(abs(x-rx)*st->gridx/(abs(y-ry)+1),abs(y-ry)*st->gridx/(abs(x-rx)+1))); + case 11: /* 2 circles+inverted circle */ + return(1+(_dist(st,x,rx,y,ry,st->cs1[n])*_dist(st,x,(rx*3)%st->gridx,y,(ry*5)%st->gridy,st->cs1[n])/(1+_dist(st,x,(rx*4)%st->gridx,y,(ry*7)%st->gridy,st->cs1[n])))); + case 12: /* star */ + return(1+(int)sqrt(abs((x-rx)*(y-ry)))); + case 13: /* centered ellipse */ + return(1+_dist(st,x,rx,y,ry,0)+_dist(st,x,st->gridx-rx,y,st->gridy-ry,0)); + default: /* triangle */ + return(1+_triangle(st,x,y,rx,ry,st->cs4[n])); + } + return(1+_triangle(st,x,y,rx,ry,st->cs4[n])); +} + +static int +_pattern(struct state *st, int x, int y, int n) +{ + int v=0, ox; + ox=x; + switch(st->wsx[n]) { + case 0: /* slants */ + x+=y/(1+st->cs4[n]); + break; + case 1: + x+=(st->gridy-y)/(1+st->cs4[n]); + break; + case 2: /* curves */ + x+=_wave(st,y,st->gridx/(1+st->cs1[n]),st->gridy,0); + break; + case 3: + x+=_wave(st,st->gridy-y,st->gridy/(1+st->cs1[n]),st->gridy,0); + break; + case 4: /* U curves */ + x+=_wave(st,y,st->cs1[n]*st->csw[n]/2,st->gridy*2/M_PI,0); + break; + case 5: + x-=_wave(st,y,st->cs1[n]*st->csw[n]/2,st->gridy*2/M_PI,0); + break; + } + switch(st->wsy[0]) { + case 0: /* slants */ + y+=ox/(1+st->cs1[n]); + break; + case 1: + y+=(st->gridx-ox)/(1+st->cs1[n]); + break; + case 2: /* curves */ + y+=_wave(st,ox,st->gridx/(1+st->cs1[n]),st->gridx,0); + break; + case 3: + y+=_wave(st,st->gridx-ox,st->gridx/(1+st->cs1[n]),st->gridx,0); + break; + case 4: /* U curves */ + y+=_wave(st,ox,st->cs1[n]*st->csw[n]/2,st->gridy*2/M_PI,0); + break; + case 5: + y-=_wave(st,ox,st->cs1[n]*st->csw[n]/2,st->gridy*2/M_PI,0); + break; + } + switch(st->pattern[n]) { + case 0: /* horizontal stripes */ + v=y; + break; + case 1: /* vertical stripes */ + v=x; + break; + case 2: /* diagonal stripes */ + v=(x+(y*st->cs1[n]/st->cs2[n])); + break; + case 3: /* reverse diagonal stripes */ + v=(x-(y*st->cs1[n]/st->cs2[n])); + break; + case 4: /* checkerboard */ + v=(y/st->csw[n]*3+x/st->csw[n])*st->csw[n]; + break; + case 5: /* diagonal checkerboard */ + v=((x+y)/2/st->csw[n]+(x+st->gridy-y)/2/st->csw[n]*3)*st->csw[n]; + break; + case 6: /* + cross */ + v=st->gridx+(_min(abs(x-st->rx3[n]),abs(y-st->ry3[n]))*2); + break; + case 7: /* double + cross */ + v=_min(_min(abs(x-st->rx2[n]),abs(y-st->ry2[n])),_min(abs(x-st->rx1[n]),abs(y-st->ry1[n])))*2; + break; + case 8: /* X cross */ + v=st->gridx+(_min(abs(x-st->rx3[n])*st->cs1[n]/st->cs2[n]+abs(y-st->ry2[n])*st->cs3[n]/st->cs4[n],abs(x-st->rx3[n])*st->cs1[n]/st->cs2[n]-abs(y-st->ry3[n])*st->cs3[n]/st->cs4[n])*2); + break; + case 9: /* double X cross */ + v=_min(_min(abs(x-st->rx2[n])+abs(y-st->ry2[n]),abs(x-st->rx2[n])-abs(y-st->ry2[n])),_min(abs(x-st->rx1[n])+abs(y-st->ry1[n]),abs(x-st->rx1[n])-abs(y-st->ry1[n])))*2; + break; + case 10: /* horizontal stripes/waves */ + v=st->gridy+(y+_wave(st,x,st->waveh[n],st->wavel[n],st->wave[n])); + break; + case 11: /* vertical stripes/waves */ + v=st->gridx+(x+_wave(st,y,st->waveh[n],st->wavel[n],st->wave[n])); + break; + case 12: /* diagonal stripes/waves */ + v=st->gridx+(x+(y*st->cs1[n]/st->cs2[n])+_wave(st,x,st->waveh[n],st->wavel[n],st->wave[n])); + break; + case 13: /* diagonal stripes/waves */ + v=st->gridx+(x-(y*st->cs1[n]/st->cs2[n])+_wave(st,y,st->waveh[n],st->wavel[n],st->wave[n])); + break; + case 14: /* horizontal spikey waves */ + v=y+(st->csw[n]*st->cs4[n]/st->cs3[n])+_wave(st,x+((y/st->cs3[n])*st->edir),st->csw[n]/2*st->cs1[n]/st->cs2[n],st->csw[n]/2*st->cs2[n]/st->cs1[n],st->wave[n]); + break; + case 15: /* vertical spikey waves */ + v=x+(st->csw[n]*st->cs1[n]/st->cs2[n])+_wave(st,y+((x/st->cs3[n])*st->edir),st->csw[n]/2*st->cs1[n]/st->cs2[n],st->csw[n]/2*st->cs3[n]/st->cs4[n],st->wave[n]); + break; + case 16: /* big slanted hwaves */ + v=st->gridy-y-(x*st->cs1[n]/st->cs3[n])+(st->csw[n]*st->cs1[n]*st->cs2[n]) +_wave(st,x,st->csw[n]/3*st->cs1[n]*st->cs2[n],st->csw[n]/3*st->cs3[n]*st->cs2[n],st->wave[n]); + break; + case 17: /* big slanted vwaves */ + v=x-(y*st->cs1[n]/st->cs3[n])+(st->csw[n]*st->cs1[n]*st->cs2[n]) +_wave(st,y, st->csw[n]/3*st->cs1[n]*st->cs2[n], st->csw[n]/3*st->cs3[n]*st->cs2[n], st->wave[n]); + break; + case 18: /* double hwave */ + v=y+(y+st->csw[n]*st->cs3[n])+_wave(st,x,st->csw[n]/3*st->cs3[n],st->csw[n]/3*st->cs2[n],st->wave[n])+_wave(st,x,st->csw[n]/3*st->cs4[n],st->csw[n]/3*st->cs1[n]*3/2,st->wave[n]); + break; + case 19: /* double vwave */ + v=x+(x+st->csw[n]*st->cs1[n])+_wave(st,y,st->csw[n]/3*st->cs1[n],st->csw[n]/3*st->cs3[n],st->wave[n])+_wave(st,y,st->csw[n]/3*st->cs2[n],st->csw[n]/3*st->cs4[n]*3/2,st->wave[n]); + break; + case 20: /* one shape */ + case 21: + case 22: + v=_shape(st,x, y, st->rx3[n], st->ry3[n], n); + break; + case 23: /* two shapes */ + case 24: + case 25: + v=_min(_shape(st,x, y, st->rx1[n], st->ry1[n], n),_shape(st,x, y, st->rx2[n], st->ry2[n], n)); + break; + case 26: /* two shapes opposites */ + case 27: + v=_min(_shape(st,x, y, st->rx2[n], st->ry2[n], n),_shape(st,x, y, st->gridx-st->rx2[n], st->gridy-st->rx2[n], n)); + break; + case 28: /* two shape checkerboard */ + case 29: + v=((_shape(st,x, y, st->rx1[n], st->ry1[n], n)/st->csw[n])+(_shape(st,x, y, st->rx2[n], st->ry2[n], n)/st->csw[n]))*st->csw[n]; + break; + case 30: /* two shape blob */ + case 31: + v=(_shape(st,x, y, st->rx1[n], st->ry1[n], n)+_shape(st,x, y, st->rx2[n], st->ry2[n], n))/2; + break; + case 32: /* inverted two shape blob */ + case 33: + v=(_shape(st,x, y, st->rx1[n], st->ry1[n], n)+_shape(st,st->gridx-x, st->gridy-y, st->rx1[n], st->ry1[n], n))/2; + break; + case 34: /* three shapes */ + case 35: + v=_min(_shape(st,x, y, st->rx3[n], st->ry3[n], n),_min(_shape(st,x, y, st->rx1[n], st->ry1[n], n),_shape(st,x, y, st->rx2[n], st->ry2[n], n))); + break; + case 36: /* three shape blob */ + case 37: + v=(_shape(st,x, y, st->rx1[n], st->ry1[n], n)+_shape(st,x, y, st->rx2[n], st->ry2[n], n)+_shape(st,x, y, st->rx3[n], st->ry3[n], n))/3; + break; + case 38: /* 4 shapes */ + v=(_min(_shape(st,x, y, st->rx2[n], st->ry2[n], n),_shape(st,x, y, st->gridx-st->rx2[n], st->gridy-st->ry2[n], n)),_min(_shape(st,x, y, st->gridx-st->rx2[n], st->ry2[n], n),_shape(st,x, y, st->rx2[n], st->gridy-st->ry2[n], n))); + break; + case 39: /* four rainbows */ + v=(_min(_shape(st,x, y, st->gridx-st->rx2[n]/2, st->csw[n], n),_shape(st,x, y, st->csw[n], st->ry2[n]/2, n)),_min(_shape(st,x, y, st->rx2[n]/2, st->gridy-st->csw[n], n),_shape(st,x, y, st->gridx-st->csw[n], st->gridy-(st->ry2[n]/2), n))); + break; + } + /* stretch or contract stripe */ + switch(st->sec[n]) { + case 0: + v=(int)sqrt((int)sqrt(abs(v)*st->gridx)*st->gridx); + break; + case 1: + v=((int)pow(v,2)/st->gridx); + break; + } + return (abs(v)); +} + +static int +_getcolor(struct state *st, int x, int y) +{ + int n, cv[LAYERS]; + + cv[0] = 0; + for (n=0; nlayers; n++) { + cv[n]=_pattern(st,x,y,n); + /* first wave/shape */ + cv[0] = (!n) ? cv[0]/st->csw[0] : + /* checkerboard+1 */ + (st->mix[n]<5) ? (cv[0]*st->csw[0]+cv[n])/st->csw[n] : + /* checkerboard+ncol/2 */ + (st->mix[n]<12) ? cv[0]+(cv[n]/st->csw[n]*st->ncolors/2) : + /* add mix */ + (st->mix[n]<16) ? cv[0]+(cv[n]/st->csw[n]) : + /* subtract mix */ + (st->mix[n]<18) ? cv[0]-(cv[n]/st->csw[n]) : + /* r to l morph mix */ + (st->mix[n]==18) ? ((cv[0]*x)+(cv[n]*(st->gridx-x)/st->csw[n]))/st->gridx : + /* u to d morph mix */ + ((cv[0]*y)+(cv[n]*(st->gridy-y)/st->csw[n]))/st->gridy; + } + return(cv[0]); +} + +/* return value=line direction + st->olen=open space to edge or next blocking line + st->bln=blocking line number or -1 if edge blocks */ +static int +_findopen(struct state *st, int x, int y, int z) +{ + int dir, od[4], no=0; + + if (((st->grid[z].hl) || (st->grid[z].hr)) && + ((st->grid[z].vu) || (st->grid[z].vd))) + return(DIR_NONE); + if ((z>st->gridx) && (!st->grid[z].hl) && (!st->grid[z].hr) && + (!st->grid[z-st->gridx].line)) { + od[no]=DIR_UP; + no++; + } + if ((zgridn-st->gridx) && (!st->grid[z].hl) && + (!st->grid[z].hr) && (!st->grid[z+st->gridx].line)) { + od[no]=DIR_DOWN; + no++; + } + if ((x) && (!st->grid[z].hl) && (!st->grid[z].hr) && + (!st->grid[z-1].line)) { + od[no]=DIR_LEFT; + no++; + } + if (((z+1)%st->gridx) && (!st->grid[z].hl) && (!st->grid[z].hr) && + (!st->grid[z+1].line)) { + od[no]=DIR_RIGHT; + no++; + } + if (!no) + return(DIR_NONE); + dir=od[random()%no]; + st->olen=st->bln=0; + while ((st->olen<=st->maxlen) && (!st->bln)) { + st->olen++; + if (dir==DIR_UP) + st->bln = (y-st->olen<0) ? -1 : + st->grid[z-(st->olen*st->gridx)].line; + if (dir==DIR_DOWN) + st->bln = (y+st->olen>=st->gridy) ? -1 : + st->grid[z+(st->olen*st->gridx)].line; + if (dir==DIR_LEFT) + st->bln = (x-st->olen<0) ? -1 : + st->grid[z-st->olen].line; + if (dir==DIR_RIGHT) + st->bln = (x+st->olen>=st->gridx) ? -1 : + st->grid[z+st->olen].line; + } + st->olen--; + return(dir); +} + +static void +_fillgrid(struct state *st) +{ + unsigned int gridc, n, add; + + gridc=st->gridx*st->dline[st->li].y+st->dline[st->li].x; + add = (st->dline[st->li].hv) ? 1 : st->gridx; + for (n=0; n<=st->dline[st->li].len; n++) { + if (n) + gridc+=add; + if (!st->grid[gridc].line) { + st->fi++; + st->grid[gridc].line=st->li; + } + if (st->dline[st->li].hv) { + if (n) + st->grid[gridc].hr=st->li; + if (ndline[st->li].len) + st->grid[gridc].hl=st->li; + } else { + if (n) + st->grid[gridc].vd=st->li; + if (ndline[st->li].len) + st->grid[gridc].vu=st->li; + } + if (st->fi>=st->gridn) { + st->grid_full=True; + return; + } + } +} + +static void +_newline(struct state *st) +{ + int bl, bz, dir, lt, x, y, z; + + bl=0; + z=st->zlist[st->zi]; + x=z%st->gridx; + y=z/st->gridx; + st->zi++; + dir=_findopen(st,x,y,z); + + if (!st->grid[z].line) { + /* this is an empty space, make a new line unless nothing is open around it */ + if (dir==DIR_NONE) { + /* nothing is open, force a len 1 branch in any direction */ + lt=LINE_FORCE; + while ((dir==DIR_NONE) || + ((dir==DIR_UP) && (!y)) || + ((dir==DIR_DOWN) && (y+1==st->gridy)) || + ((dir==DIR_LEFT) && (!x)) || + ((dir==DIR_RIGHT) && (x+1==st->gridx))) { + dir=random()%4; + } + bz = (dir==DIR_UP) ? z-st->gridx : (dir==DIR_DOWN) ? z+st->gridx : (dir==DIR_LEFT) ? z-1 : z+1; + bl = st->grid[bz].line; + } else if ((st->bnratio>1) && (st->bln>0) && + (st->olenmaxlen) && (random()%st->bnratio)) { + /* branch into blocking line */ + lt=LINE_BRIN; + bl = st->bln; + } else { + /* make a new line and new object */ + lt=LINE_NEW; + st->oi++; + } + } else { + /* this is a filled space, make a branch unless nothing is open around it */ + if (dir==DIR_NONE) + return; + /* make a branch out of this line */ + lt=LINE_BROUT; + bl=st->grid[z].line; + } + st->li++; + st->dline[st->li].len = (lt==LINE_FORCE) ? 1 : (lt==LINE_BRIN) ? + st->olen+1 : (!st->forcemax) ? st->olen : 1+random()%st->olen; + st->dline[st->li].x=x; + if (dir==DIR_LEFT) + st->dline[st->li].x-=st->dline[st->li].len; + st->dline[st->li].y=y; + if (dir==DIR_UP) + st->dline[st->li].y-=st->dline[st->li].len; + st->dline[st->li].hv = ((dir==DIR_LEFT) || (dir==DIR_RIGHT)) ? + True : False; + st->dline[st->li].obj = (lt==LINE_NEW) ? st->oi : + st->dline[bl].obj; + if (lt==LINE_NEW) { + int color = (_getcolor(st,x,y))%st->ncolors; + if (color < 0) color += st->ncolors; + st->dline[st->li].color = color; + } else { + st->dline[st->li].color = st->dline[bl].color; + } + st->dline[st->li].deo=(_getdeo(st,x,y,st->dmap,1) + + (random()%st->dvar) + (random()%st->dvar))*st->ddir; + st->dline[st->li].ndol=0; + _fillgrid(st); +} + +static void +_create_screen(struct state *st) +{ + while(!st->grid_full) + _newline(st); + qsort(st->dline, st->li+1, sizeof(struct lineStruct), _comparedeo); +/*st->lpu=st->li/20/((6-st->speed)*3); + Used to use a computed lpu, lines per update to control draw speed + draw 1/lpu of the lines before each XSync which takes a split second + the higher the lpu, the quicker the screen draws. This worked somewhat + after the 4->5 update, however with the Mac updating so much more slowly, + values tuned for it draw the screen in a blink on Linux. Therefore we + draw 1/200th of the screen with each update and sleep, if necessary */ + st->lpu = (st->dialog) ? st->li/50 : st->li/200; + if (!st->lpu) st->lpu = 1; + st->bi=1; + st->mode=MODE_ERASE; +} + +static void +_fill_outline(struct state *st, int di) +{ + int x, y, h, w; + + if (!di) + return; + x=st->dline[di].x*st->lwid+1; + y=st->dline[di].y*st->lwid+1; + if (st->dline[di].hv) { + w=(st->dline[di].len+1)*st->lwid-3; + h=st->lwid-3; + } else { + w=st->lwid-3; + h=(st->dline[di].len+1)*st->lwid-3; + } + XFillRectangle (st->display, st->window, st->bgc, x, y, w, h); +} + +static void +_XFillRectangle(struct state *st, int di, int adj) +{ + int a, b, x, y, w, h; + + x=st->dline[di].x*st->lwid; + y=st->dline[di].y*st->lwid; + if (st->dline[di].hv) { + w=(st->dline[di].len+1)*st->lwid-1; + h=st->lwid-1; + } else { + w=st->lwid-1; + h=(st->dline[di].len+1)*st->lwid-1; + } + switch (st->d3d) { + case D3D_NEON: + x+=adj; + y+=adj; + w-=adj*2; + h-=adj*2; + break; + case D3D_BLOCK: + x+=adj; + y+=adj; + w-=st->lwid/2-1; + h-=st->lwid/2-1; + break; + } + if (!st->round) { + XFillRectangle(st->display, st->window, st->fgc, x, y, w, h); + } else { + if (hlwid) { /* horizontal */ + a=(h-1)/2; + for (b=0; b<=a; b++) + XFillRectangle(st->display, st->window, st->fgc, + x+b, y+a-b, w-b*2, h-((a-b)*2)); + } else { /* vertical */ + a=(w-1)/2; + for (b=0; b<=a; b++) + XFillRectangle(st->display, st->window, st->fgc, + x+a-b, y+b, w-((a-b)*2), h-b*2); + } + } +} + +static void +_XFillTriangle(struct state *st, int color, int x1, int y1, int x2, int y2, + int x3, int y3) +{ + XPoint points[3]; + + points[0].x=x1; + points[0].y=y1; + points[1].x=x2; + points[1].y=y2; + points[2].x=x3; + points[2].y=y3; + XSetForeground(st->display, st->fgc, st->colors[color].pixel); + XFillPolygon (st->display, st->window, st->fgc, points, 3, Convex, + CoordModeOrigin); +} + +static void +_XFillPolygon4(struct state *st, int color, int x1, int y1, int x2, int y2, + int x3, int y3, int x4, int y4) +{ + XPoint points[4]; + + points[0].x=x1; + points[0].y=y1; + points[1].x=x2; + points[1].y=y2; + points[2].x=x3; + points[2].y=y3; + points[3].x=x4; + points[3].y=y4; + XSetForeground(st->display, st->fgc, st->colors[color].pixel); + XFillPolygon (st->display, st->window, st->fgc, points, 4, Convex, + CoordModeOrigin); +} + +static void +_draw_tiled(struct state *st, int color) +{ + int a, c, d, x, y, z, m1, m2, lr, nl, w, h; + a = (st->dline[st->di].hv) ? 1 : st->gridx; + z = st->dline[st->di].y*st->gridx+st->dline[st->di].x; + m1 = (st->lwid-1)/2; + m2 = st->lwid/2; + lr = st->lwid-1; + nl = st->lwid; + + /* draw tiles one grid cell at a time */ + for (c=0; c<=st->dline[st->di].len; c++) { + if (st->dline[st->di].hv) { + x = (st->dline[st->di].x+c)*st->lwid; + y = st->dline[st->di].y*st->lwid; + if (c) + st->grid[z].dhr=st->di; + if (cdline[st->di].len) + st->grid[z].dhl=st->di; + } else { + x = st->dline[st->di].x*st->lwid; + y = (st->dline[st->di].y+c)*st->lwid; + if (c) + st->grid[z].dvd=st->di; + if (cdline[st->di].len) + st->grid[z].dvu=st->di; + } + d=0; + if (st->grid[z].dhl) + d+=8; + if (st->grid[z].dhr) + d+=4; + if (st->grid[z].dvu) + d+=2; + if (st->grid[z].dvd) + d++; + /* draw line base */ + switch (d) { + case 1: + case 2: /* vertical */ + case 3: + case 5: + case 6: + case 7: + case 11: + case 15: + h = ((d==1) || (d==5)) ? lr : nl; + XSetForeground(st->display, st->fgc, + st->colors[color].pixel); + XFillRectangle (st->display, st->window, st->fgc, + x, y, m2, h); + XSetForeground(st->display, st->fgc, + st->colors[color+3].pixel); + XFillRectangle (st->display, st->window, st->fgc, + x+m2, y, m1, h); + break; + case 4: + case 8: /* horizontal */ + case 9: + case 10: + case 12: + case 13: + case 14: + w = (d==4) ? lr : nl; + XSetForeground(st->display, st->fgc, + st->colors[color+1].pixel); + XFillRectangle (st->display, st->window, st->fgc, + x, y, w, m2); + XSetForeground(st->display, st->fgc, + st->colors[color+2].pixel); + XFillRectangle (st->display, st->window, st->fgc, + x, y+m2, w, m1); + break; + } + /* draw angles */ + switch(d) { + case 1: /* bottom end ^ */ + _XFillTriangle(st,color+2, x, y+lr, x+lr, y+lr, x+m2, y+m2); + break; + case 2: /* top end \/ */ + _XFillTriangle(st,color+1, x, y, x+lr, y, x+m2, y+m2); + break; + case 4: /* right end < */ + _XFillTriangle(st,color+3, x+lr, y, x+lr, y+lr, x+m2, y+m2); + break; + case 5: /* LR corner */ + _XFillTriangle(st,color+1, x, y+m2, x+m2, y+m2, x, y); + _XFillPolygon4(st,color+2, x, y+m2, x+m2, y+m2, x+lr, y+lr, x, y+lr); + break; + case 6: /* UR corner */ + _XFillPolygon4(st,color+1, x, y+m2, x+m2, y+m2, x+lr, y, x, y); + _XFillTriangle(st,color+2, x, y+m2, x+m2, y+m2, x, y+lr); + break; + case 7: /* T > into line */ + _XFillTriangle(st,color+1, x, y+m2, x+m2, y+m2, x, y); + _XFillTriangle(st,color+2, x, y+m2, x+m2, y+m2, x, y+lr); + break; + case 8: /* left end > */ + _XFillTriangle(st,color, x, y, x, y+lr, x+m2, y+m2); + break; + case 9: /* LL corner */ + _XFillPolygon4(st,color, x+m2, y, x+m2, y+m2, x, y+lr, x, y); + _XFillTriangle(st,color+3, x+m2, y, x+m2, y+m2, x+lr, y); + break; + case 10: /* UL corner */ + _XFillPolygon4(st,color, x+m2, y+nl, x+m2, y+m2, x, y, x, y+nl); + _XFillPolygon4(st,color+3, x+m2, y+nl, x+m2, y+m2, x+lr, y+lr, x+lr, y+nl); + break; + case 11: /* T < into line */ + _XFillPolygon4(st,color+1, x+nl, y+m2, x+m2, y+m2, x+lr, y, x+nl, y); + _XFillPolygon4(st,color+2, x+nl, y+m2, x+m2, y+m2, x+lr, y+lr, x+nl, y+lr); + break; + case 13: /* T \/ into line */ + _XFillTriangle(st,color, x+m2, y, x+m2, y+m2, x, y); + _XFillTriangle(st,color+3, x+m2, y, x+m2, y+m2, x+lr, y); + break; + case 14: /* T ^ into line */ + _XFillPolygon4(st,color, x+m2, y+nl, x+m2, y+m2, x, y+lr, x, y+nl); + _XFillPolygon4(st,color+3, x+m2, y+nl, x+m2, y+m2, x+lr, y+lr, x+lr, y+nl); + break; + case 15: /* X intersection */ + _XFillTriangle(st,color+1, x, y+m2, x+m2, y+m2, x, y); + _XFillTriangle(st,color+2, x, y+m2, x+m2, y+m2, x, y+lr); + _XFillPolygon4(st,color+1, x+nl, y+m2, x+m2, y+m2, x+lr, y, x+nl, y); + _XFillPolygon4(st,color+2, x+nl, y+m2, x+m2, y+m2, x+lr, y+lr, x+nl, y+lr); + break; + } + z+=a; + } +} + +static long +_mselapsed(struct state *st) +{ + struct timeval t; + gettimeofday(&t, NULL); + t.tv_sec -= st->time.tv_sec; + t.tv_usec -= st->time.tv_usec; + return ((long)t.tv_sec*1000000+t.tv_usec); +} + +static void +_draw_lines(struct state *st) +{ + int n, z, a, color, sh, di; + if (st->bi==1) + for (a=0; a<=st->oi; a++) + st->fdol[a]=0; + + for (st->di=st->bi; st->di<_min(st->li+1,st->bi+st->lpu); st->di++) { + color=(st->dline[st->di].color%st->ncolors)*st->shades; + XSetForeground(st->display, st->fgc, st->colors[color].pixel); + + switch (st->d3d) { + case D3D_NEON: + st->dline[st->di].ndol=st->fdol[st->dline[st->di].obj]; + st->fdol[st->dline[st->di].obj]=st->di; + for (sh=0; shlwid/2; sh++) { + XSetForeground(st->display, st->fgc, + st->colors[color+sh].pixel); + di=st->di; + while(di>0) { + _XFillRectangle(st,di,sh); + di=st->dline[di].ndol; + } + } + break; + case D3D_BLOCK: + st->dline[st->di].ndol=st->fdol[st->dline[st->di].obj]; + st->fdol[st->dline[st->di].obj]=st->di; + for (sh=0; shlwid/2; sh++) { + XSetForeground(st->display, st->fgc, + st->colors[color+(st->lwid/2)-sh-1].pixel); + di=st->di; + while(di>0) { + _XFillRectangle(st,di,sh); + di=st->dline[di].ndol; + } + } + break; + case D3D_TILED: + _draw_tiled(st,color); + break; + default: /* D3D_NONE */ + _XFillRectangle(st,st->di,0); + if (st->outline) { + _fill_outline(st, st->di); + z=st->dline[st->di].y*st->gridx+st->dline[st->di].x; + a = (st->dline[st->di].hv) ? 1 : st->gridx; + for (n=0; n<=st->dline[st->di].len; n++) { + _fill_outline(st, st->grid[z].dhl); + _fill_outline(st, st->grid[z].dhr); + _fill_outline(st, st->grid[z].dvu); + _fill_outline(st, st->grid[z].dvd); + if (st->dline[st->di].hv) { + if (n) + st->grid[z].dhr=st->di; + if (ndline[st->di].len) + st->grid[z].dhl=st->di; + } else { + if (n) + st->grid[z].dvd=st->di; + if (ndline[st->di].len) + st->grid[z].dvu=st->di; + } + z+=a; + } + } + break; + } + } + if (st->di>st->li) { + st->bi=1; + st->mode=MODE_CREATE; + } else { + st->bi+=st->lpu; + } +} + +static void +_erase_lines(struct state *st) +{ + if (!st->ii) + return; + for (st->di=st->bi; st->di<_min(st->eli+1,st->bi+st->elpu); st->di++) { + if (st->eline[st->di].hv) { + XFillRectangle (st->display, st->window, st->bgc, + st->eline[st->di].x*st->elwid, + st->eline[st->di].y*st->elwid, + (st->eline[st->di].len+1)*st->elwid, st->elwid); + } else { + XFillRectangle (st->display, st->window, st->bgc, + st->eline[st->di].x*st->elwid, + st->eline[st->di].y*st->elwid, + st->elwid, (st->eline[st->di].len+1)*st->elwid); + } + if (st->di==st->eli) /* clear just in case */ + XFillRectangle(st->display, st->window, st->bgc, 0, 0, + st->xgwa.width, st->xgwa.height); + } + if (st->di>st->eli) { + st->bi=1; + if (st->resized) { + st->mode=MODE_CREATE; + } else { + st->mode=MODE_DRAW; + } + } else { + st->bi+=st->elpu; + } +} + +static void * +abstractile_init(Display *display, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; +/* struct utsname os;*/ + + char *tile = get_string_resource(display, "tile", "Tile"); + if (tile && !strcmp(tile, "random")) st->tile = TILE_RANDOM; + else if (tile && !strcmp(tile, "flat")) st->tile = TILE_FLAT; + else if (tile && !strcmp(tile, "thin")) st->tile = TILE_THIN; + else if (tile && !strcmp(tile, "outline")) st->tile = TILE_OUTLINE; + else if (tile && !strcmp(tile, "block")) st->tile = TILE_BLOCK; + else if (tile && !strcmp(tile, "neon")) st->tile = TILE_NEON; + else if (tile && !strcmp(tile, "tiled")) st->tile = TILE_TILED; + else { + if (tile && *tile && !!strcmp(tile, "random")) + fprintf(stderr, "%s: unknown tile option %s\n", progname, tile); + st->tile = TILE_RANDOM; + } + + st->speed = get_integer_resource(display, "speed", "Integer"); + if (st->speed < 0) st->speed = 0; + if (st->speed > 5) st->speed = 5; + st->sleep = get_integer_resource(display, "sleep", "Integer"); + if (st->sleep < 0) st->sleep = 0; + if (st->sleep > 60) st->sleep = 60; + + st->display=display; + st->window=window; + + /* get screen size and create Graphics Contexts */ + XGetWindowAttributes (display, window, &st->xgwa); + gcv.foreground = get_pixel_resource(display, st->xgwa.colormap, + "foreground", "Foreground"); + st->fgc = XCreateGC (display, window, GCForeground, &gcv); + gcv.foreground = get_pixel_resource(display, st->xgwa.colormap, + "background", "Background"); + st->bgc = XCreateGC (display, window, GCForeground, &gcv); + +/* Um, no. This is obscene. -jwz. + uname(&os); + st->newcols=((!strcmp(os.sysname,"Linux")) || (!strcmp(os.sysname,"Darwin"))) + ? True : False; +*/ + st->newcols=False; + + st->mode=MODE_CREATE; + st->ii=0; + st->resized=True; + return st; +} + +static unsigned long +abstractile_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int mse, usleep; + + gettimeofday(&st->time, NULL); + + /* If the window is too small, do nothing, sorry! */ + if (st->xgwa.width > 20 && st->xgwa.height > 20) { + switch (st->mode) { + case MODE_CREATE: + _init_screen(st); + _create_screen(st); + break; + case MODE_ERASE: + _erase_lines(st); + break; + case MODE_DRAW: + _draw_lines(st); + break; + } + } + mse=_mselapsed(st); + usleep = ((!st->ii) && (st->mode==MODE_CREATE)) ? 0 : + (st->mode==MODE_CREATE) ? st->sleep*1000000-mse : + /* speed=0-5, goal is 10,8,6,4,2,0 sec normal and 5,4,3,2,1,0 dialog */ + (5-st->speed)*(2-st->dialog)*100000/st->lpu-mse; + if (usleep>=0) + return usleep; + return 0; +} + +static void +abstractile_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->xgwa.width = w; + st->xgwa.height = h; + if (w*h>st->max_wxh) + st->resized=True; +} + +static Bool +abstractile_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + struct state *st = (struct state *) closure; + if (screenhack_event_helper (dpy, window, event)) + { + st->mode=MODE_CREATE; + return True; + } + + return False; +} + +static void +abstractile_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + +static const char *abstractile_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*sleep: 3", + "*speed: 3", + "*tile: random", +#ifdef HAVE_MOBILE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec abstractile_options [] = { + { "-sleep", ".sleep", XrmoptionSepArg, 0 }, + { "-speed", ".speed", XrmoptionSepArg, 0 }, + { "-tile", ".tile", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Abstractile", abstractile) diff --git a/hacks/abstractile.man b/hacks/abstractile.man new file mode 100644 index 0000000..d043ce7 --- /dev/null +++ b/hacks/abstractile.man @@ -0,0 +1,52 @@ +.TH XScreenSaver 1 "27-Apr-97" "X Version 11" +.SH NAME +abstractile - draw abstract mosaic patterns of interlocking tiles +.SH SYNOPSIS +.B abstractile +[\-sleep \fIseconds\fP] [\-speed \fIint\fP] [\-tile \fItile_mode\fP] +[\-fps] +.SH DESCRIPTION +The \fIabstractile\fP program draws chaotic grids of randomly colored +and shaped interlocking tiles. +.SH OPTIONS +.I abstractile +accepts the following options: +.TP 8 +.B \-sleep \fIseconds\fP +Specify the number of seconds to sleep between screens (0-60). +.TP 8 +.B \-speed \fIint\fP +A value between 0 and 5 used to specify the speed at which each screen is drawn. +.TP 8 +.B \-tile \fItile_mode\fP +The type of tile that is drawn on each screen. Legal values are +\fIrandom\fP, \fIflat\fP, \fIthin\fP, \fIoutline\fP, +\fIblock\fP, \fIneon\fP, and \fItiled\fP +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1) +.SH COPYRIGHT +Copyright \(co 2004 by Steve Sundstrom. Based on +examples from the hacks directory of xscreensaver, +Copyright (c) 1997, 1998, 2002 Jamie Zawinski + + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. +.SH AUTHOR +Steve Sundstrom diff --git a/hacks/analogtv.c b/hacks/analogtv.c new file mode 100644 index 0000000..fd7f504 --- /dev/null +++ b/hacks/analogtv.c @@ -0,0 +1,2431 @@ +/* analogtv, Copyright (c) 2003-2018 Trevor Blackwell + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +/* + + This is the code for implementing something that looks like a conventional + analog TV set. It simulates the following characteristics of standard + televisions: + + - Realistic rendering of a composite video signal + - Compression & brightening on the right, as the scan gets truncated + because of saturation in the flyback transformer + - Blooming of the picture dependent on brightness + - Overscan, cutting off a few pixels on the left side. + - Colored text in mixed graphics/text modes + + It's amazing how much it makes your high-end monitor look like at large + late-70s TV. All you need is to put a big "Solid State" logo in curly script + on it and you'd be set. + + In DirectColor or TrueColor modes, it generates pixel values + directly from RGB values it calculates across each scan line. In + PseudoColor mode, it consider each possible pattern of 5 preceding + bit values in each possible position modulo 4 and allocates a color + for each. A few things, like the brightening on the right side as + the horizontal trace slows down, aren't done in PseudoColor. + + I originally wrote it for the Apple ][ emulator, and generalized it + here for use with a rewrite of xteevee and possibly others. + + A maxim of technology is that failures reveal underlying mechanism. + A good way to learn how something works is to push it to failure. + The way it fails will usually tell you a lot about how it works. The + corollary for this piece of software is that in order to emulate + realistic failures of a TV set, it has to work just like a TV set. + So there is lots of DSP-style emulation of analog circuitry for + things like color decoding, H and V sync following, and more. In + 2003, computers are just fast enough to do this at television signal + rates. We use a 14 MHz sample rate here, so we can do on the order + of a couple hundred instructions per sample and keep a good frame + rate. + + Trevor Blackwell +*/ + +/* + 2014-04-20, Dave Odell : + API change: Folded analogtv_init_signal and *_add_signal into *_draw(). + Added SMP support. + Replaced doubles with floats, including constants and transcendental functions. + Fixed a bug or two. +*/ + +/* 2015-02-27, Tomasz Sulej : + - tint_control variable is used now + - removed unusable hashnoise code + */ + +/* + 2016-10-09, Dave Odell : + Updated for new xshm.c. +*/ + +#ifdef HAVE_JWXYZ +# include "jwxyz.h" +#else /* !HAVE_JWXYZ */ +# include +# include +#endif +#include + +#include +#include +#include "utils.h" +#include "resources.h" +#include "analogtv.h" +#include "yarandom.h" +#include "grabscreen.h" +#include "visual.h" +#include "font-retry.h" +#include "ximage-loader.h" + +/* #define DEBUG 1 */ + +#if defined(DEBUG) && (defined(__linux) || defined(__FreeBSD__)) +/* only works on linux + freebsd */ +#include + +#define DTIME_DECL u_int64_t dtimes[100]; int n_dtimes +#define DTIME_START do {n_dtimes=0; dtimes[n_dtimes++]=rdtsc(); } while (0) +#define DTIME dtimes[n_dtimes++]=rdtsc() +#define DTIME_SHOW(DIV) \ +do { \ + double _dtime_div=(DIV); \ + printf("time/%.1f: ",_dtime_div); \ + for (i=1; ipowerup-start; + float ret; + if (pt<0.0f) return 0.0f; + if (pt>900.0f || pt/tc>8.0f) return 1.0f; + + ret=(1.0f-expf(-pt/tc))*over; + if (ret>1.0f) return 1.0f; + return ret*ret; +} + +/* + There are actual standards for TV signals: NTSC and RS-170A describe the + system used in the US and Japan. Europe has slightly different systems, but + not different enough to make substantially different screensaver displays. + Sadly, the standards bodies don't do anything so useful as publish the spec on + the web. Best bets are: + + http://www.ee.washington.edu/conselec/CE/kuhn/ntsc/95x4.htm + http://www.ntsc-tv.com/ntsc-index-02.htm + + In DirectColor or TrueColor modes, it generates pixel values directly from RGB + values it calculates across each scan line. In PseudoColor mode, it consider + each possible pattern of 5 preceding bit values in each possible position + modulo 4 and allocates a color for each. A few things, like the brightening on + the right side as the horizontal trace slows down, aren't done in PseudoColor. + + I'd like to add a bit of visible retrace, but it conflicts with being able to + bitcopy the image when fast scrolling. After another couple of CPU + generations, we could probably regenerate the whole image from scratch every + time. On a P4 2 GHz it can manage this fine for blinking text, but scrolling + looks too slow. +*/ + +/* localbyteorder is MSBFirst or LSBFirst */ +static int localbyteorder; +static const double float_low8_ofs=8388608.0; +static int float_extraction_works; + +typedef union { + float f; + int i; +} float_extract_t; + +static void +analogtv_init(void) +{ + int i; + { + unsigned int localbyteorder_loc = (MSBFirst<<24) | (LSBFirst<<0); + localbyteorder=*(char *)&localbyteorder_loc; + } + + if (1) { + float_extract_t fe; + int ans; + + float_extraction_works=1; + for (i=0; i<256*4; i++) { + fe.f=float_low8_ofs+(double)i; + ans=fe.i&0x3ff; + if (ans != i) { +#ifdef DEBUG + printf("Float extraction failed for %d => %d\n",i,ans); +#endif + float_extraction_works=0; + break; + } + } + } + +} + +void +analogtv_set_defaults(analogtv *it, char *prefix) +{ + char buf[256]; + + sprintf(buf,"%sTVTint",prefix); + it->tint_control = get_float_resource(it->dpy, buf,"TVTint"); + sprintf(buf,"%sTVColor",prefix); + it->color_control = get_float_resource(it->dpy, buf,"TVColor")/100.0; + sprintf(buf,"%sTVBrightness",prefix); + it->brightness_control = get_float_resource(it->dpy, buf,"TVBrightness") / 100.0; + sprintf(buf,"%sTVContrast",prefix); + it->contrast_control = get_float_resource(it->dpy, buf,"TVContrast") / 100.0; + it->height_control = 1.0; + it->width_control = 1.0; + it->squish_control = 0.0; + it->powerup=1000.0; + + it->hashnoise_rpm=0; + it->hashnoise_on=0; + it->hashnoise_enable=1; + + it->horiz_desync=frand(10.0)-5.0; + it->squeezebottom=frand(5.0)-1.0; + +#ifdef DEBUG + printf("analogtv: prefix=%s\n",prefix); + printf(" use: cmap=%d color=%d\n", + it->use_cmap,it->use_color); + printf(" controls: tint=%g color=%g brightness=%g contrast=%g\n", + it->tint_control, it->color_control, it->brightness_control, + it->contrast_control); +/* printf(" freq_error %g: %g %d\n", + it->freq_error, it->freq_error_inc, it->flutter_tint); */ + printf(" desync: %g %d\n", + it->horiz_desync, it->flutter_horiz_desync); + printf(" hashnoise rpm: %g\n", + it->hashnoise_rpm); + printf(" vis: %d %d\n", + it->visclass, it->visdepth); + printf(" shift: %d-%d %d-%d %d-%d\n", + it->red_invprec,it->red_shift, + it->green_invprec,it->green_shift, + it->blue_invprec,it->blue_shift); + printf(" size: %d %d %d %d xrepl=%d\n", + it->usewidth, it->useheight, + it->screen_xo, it->screen_yo, it->xrepl); + + printf(" ANALOGTV_V=%d\n",ANALOGTV_V); + printf(" ANALOGTV_TOP=%d\n",ANALOGTV_TOP); + printf(" ANALOGTV_VISLINES=%d\n",ANALOGTV_VISLINES); + printf(" ANALOGTV_BOT=%d\n",ANALOGTV_BOT); + printf(" ANALOGTV_H=%d\n",ANALOGTV_H); + printf(" ANALOGTV_SYNC_START=%d\n",ANALOGTV_SYNC_START); + printf(" ANALOGTV_BP_START=%d\n",ANALOGTV_BP_START); + printf(" ANALOGTV_CB_START=%d\n",ANALOGTV_CB_START); + printf(" ANALOGTV_PIC_START=%d\n",ANALOGTV_PIC_START); + printf(" ANALOGTV_PIC_LEN=%d\n",ANALOGTV_PIC_LEN); + printf(" ANALOGTV_FP_START=%d\n",ANALOGTV_FP_START); + printf(" ANALOGTV_PIC_END=%d\n",ANALOGTV_PIC_END); + printf(" ANALOGTV_HASHNOISE_LEN=%d\n",ANALOGTV_HASHNOISE_LEN); + +#endif + +} + +extern Bool mono_p; /* shoot me */ + +static void +analogtv_free_image(analogtv *it) +{ + if (it->image) { + destroy_xshm_image(it->dpy, it->image, &it->shm_info); + it->image=NULL; + } +} + +static void +analogtv_alloc_image(analogtv *it) +{ + /* On failure, it->image is NULL. */ + + unsigned bits_per_pixel = visual_pixmap_depth(it->screen, it->xgwa.visual); + unsigned align = thread_memory_alignment(it->dpy) * 8 - 1; + /* Width is in bits. */ + unsigned width = (it->usewidth * bits_per_pixel + align) & ~align; + + it->image=create_xshm_image(it->dpy, it->xgwa.visual, it->xgwa.depth, + ZPixmap, &it->shm_info, + width / bits_per_pixel, it->useheight); + + if (it->image) { + memset (it->image->data, 0, it->image->height * it->image->bytes_per_line); + } else { + /* Not enough memory. Maybe try a smaller window. */ + fprintf(stderr, "analogtv: %s\n", strerror(ENOMEM)); + } +} + + +static void +analogtv_configure(analogtv *it) +{ + int oldwidth=it->usewidth; + int oldheight=it->useheight; + int wlim,hlim,height_diff; + + /* If the window is very small, don't let the image we draw get lower + than the actual TV resolution (266x200.) + + If the aspect ratio of the window is close to a 4:3 or 16:9 ratio -- + or if it is a completely weird aspect ratio -- + then scale the image to exactly fill the window. + + Otherwise, center the image either horizontally or vertically, + letterboxing or pillarboxing (but not both). + + If it's very close (2.5%) to a multiple of VISLINES, make it exact + For example, it maps 1024 => 1000. + */ + float percent = 0.15; + float min_ratio = 4.0 / 3.0 * (1 - percent); + float max_ratio = 16.0 / 9.0 * (1 + percent); + float crazy_min_ratio = 10; + float crazy_max_ratio = 1/crazy_min_ratio; + float ratio; + float height_snap=0.025; + + hlim = it->xgwa.height; + wlim = it->xgwa.width; + ratio = wlim / (float) hlim; + +#ifdef HAVE_MOBILE + /* Fill the whole iPhone screen, even though that distorts the image. */ + min_ratio = 0; + max_ratio = 10; +#endif + + if (wlim < 266 || hlim < 200) + { + wlim = 266; + hlim = 200; +# ifdef DEBUG + fprintf (stderr, + "size: minimal: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n", + wlim, hlim, it->xgwa.width, it->xgwa.height, + min_ratio, ratio, max_ratio); +# endif + } + else if (ratio > min_ratio && ratio < max_ratio) + { +# ifdef DEBUG + fprintf (stderr, + "size: close enough: %dx%d (%.3f < %.3f < %.3f)\n", + wlim, hlim, min_ratio, ratio, max_ratio); +# endif + } + else if (ratio >= max_ratio) + { + wlim = hlim*max_ratio; +# ifdef DEBUG + fprintf (stderr, + "size: center H: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n", + wlim, hlim, it->xgwa.width, it->xgwa.height, + min_ratio, ratio, max_ratio); +# endif + } + else /* ratio <= min_ratio */ + { + hlim = wlim/min_ratio; +# ifdef DEBUG + fprintf (stderr, + "size: center V: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n", + wlim, hlim, it->xgwa.width, it->xgwa.height, + min_ratio, ratio, max_ratio); +# endif + } + + if (ratio < crazy_min_ratio || ratio > crazy_max_ratio) + { + if (ratio < crazy_min_ratio) + hlim = it->xgwa.height; + else + wlim = it->xgwa.width; +# ifdef DEBUG + fprintf (stderr, + "size: aspect: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n", + wlim, hlim, it->xgwa.width, it->xgwa.height, + min_ratio, ratio, max_ratio); +# endif + } + + + height_diff = ((hlim + ANALOGTV_VISLINES/2) % ANALOGTV_VISLINES) - ANALOGTV_VISLINES/2; + if (height_diff != 0 && abs(height_diff) < hlim * height_snap) + { + hlim -= height_diff; + } + + + /* Most times this doesn't change */ + if (wlim != oldwidth || hlim != oldheight) { + + it->usewidth=wlim; + it->useheight=hlim; + + it->xrepl=1+it->usewidth/640; + if (it->xrepl>2) it->xrepl=2; + it->subwidth=it->usewidth/it->xrepl; + + analogtv_free_image(it); + analogtv_alloc_image(it); + } + + it->screen_xo = (it->xgwa.width-it->usewidth)/2; + it->screen_yo = (it->xgwa.height-it->useheight)/2; + it->need_clear=1; +} + +void +analogtv_reconfigure(analogtv *it) +{ + XGetWindowAttributes (it->dpy, it->window, &it->xgwa); + analogtv_configure(it); +} + +/* Can be any power-of-two <= 32. 16 a slightly better choice for 2-3 threads. */ +#define ANALOGTV_SUBTOTAL_LEN 32 + +typedef struct analogtv_thread_s +{ + analogtv *it; + unsigned thread_id; + size_t signal_start, signal_end; +} analogtv_thread; + +#define SIGNAL_OFFSET(thread_id) \ + ((ANALOGTV_SIGNAL_LEN * (thread_id) / threads->count) & align) + +static int analogtv_thread_create(void *thread_raw, struct threadpool *threads, + unsigned thread_id) +{ + analogtv_thread *thread = (analogtv_thread *)thread_raw; + unsigned align; + + thread->it = GET_PARENT_OBJ(analogtv, threads, threads); + thread->thread_id = thread_id; + + align = thread_memory_alignment(thread->it->dpy) / + sizeof(thread->it->signal_subtotals[0]); + if (!align) + align = 1; + align = ~(align * ANALOGTV_SUBTOTAL_LEN - 1); + + thread->signal_start = SIGNAL_OFFSET(thread_id); + thread->signal_end = thread_id + 1 == threads->count ? + ANALOGTV_SIGNAL_LEN : + SIGNAL_OFFSET(thread_id + 1); + + return 0; +} + +static void analogtv_thread_destroy(void *thread_raw) +{ +} + +analogtv * +analogtv_allocate(Display *dpy, Window window) +{ + static const struct threadpool_class cls = { + sizeof(analogtv_thread), + analogtv_thread_create, + analogtv_thread_destroy + }; + + XGCValues gcv; + analogtv *it=NULL; + int i; + const size_t rx_signal_len = ANALOGTV_SIGNAL_LEN + 2*ANALOGTV_H; + + analogtv_init(); + + it=(analogtv *)calloc(1,sizeof(analogtv)); + if (!it) return 0; + it->threads.count=0; + it->rx_signal=NULL; + it->signal_subtotals=NULL; + + it->dpy=dpy; + it->window=window; + + if (thread_malloc((void **)&it->rx_signal, dpy, + sizeof(it->rx_signal[0]) * rx_signal_len)) + goto fail; + + assert(!(ANALOGTV_SIGNAL_LEN % ANALOGTV_SUBTOTAL_LEN)); + if (thread_malloc((void **)&it->signal_subtotals, dpy, + sizeof(it->signal_subtotals[0]) * + (rx_signal_len / ANALOGTV_SUBTOTAL_LEN))) + goto fail; + + if (threadpool_create(&it->threads, &cls, dpy, hardware_concurrency(dpy))) + goto fail; + + assert(it->threads.count); + + it->shrinkpulse=-1; + + it->n_colors=0; + + XGetWindowAttributes (it->dpy, it->window, &it->xgwa); + + it->screen=it->xgwa.screen; + it->colormap=it->xgwa.colormap; + it->visclass=visual_class(it->xgwa.screen, it->xgwa.visual); + it->visdepth=it->xgwa.depth; + if (it->visclass == TrueColor || it->visclass == DirectColor) { + if (get_integer_resource (it->dpy, "use_cmap", "Integer")) { + it->use_cmap=1; + } else { + it->use_cmap=0; + } + it->use_color=!mono_p; + } + else if (it->visclass == PseudoColor || it->visclass == StaticColor) { + it->use_cmap=1; + it->use_color=!mono_p; + } + else { + it->use_cmap=1; + it->use_color=0; + } + + visual_rgb_masks (it->xgwa.screen, it->xgwa.visual, + &it->red_mask, &it->green_mask, &it->blue_mask); + it->red_shift=it->red_invprec=-1; + it->green_shift=it->green_invprec=-1; + it->blue_shift=it->blue_invprec=-1; + if (!it->use_cmap) { + /* Is there a standard way to do this? Does this handle all cases? */ + int shift, prec; + for (shift=0; shift<32; shift++) { + for (prec=1; prec<16 && prec<40-shift; prec++) { + unsigned long mask=(0xffffUL>>(16-prec)) << shift; + if (it->red_shift<0 && mask==it->red_mask) + it->red_shift=shift, it->red_invprec=16-prec; + if (it->green_shift<0 && mask==it->green_mask) + it->green_shift=shift, it->green_invprec=16-prec; + if (it->blue_shift<0 && mask==it->blue_mask) + it->blue_shift=shift, it->blue_invprec=16-prec; + } + } + if (it->red_shift<0 || it->green_shift<0 || it->blue_shift<0) { + if (0) fprintf(stderr,"Can't figure out color space\n"); + goto fail; + } + + for (i=0; i65535) intensity=65535; + it->red_values[i]=((intensity>>it->red_invprec)<red_shift); + it->green_values[i]=((intensity>>it->green_invprec)<green_shift); + it->blue_values[i]=((intensity>>it->blue_invprec)<blue_shift); + } + + } + + gcv.background=get_pixel_resource(it->dpy, it->colormap, + "background", "Background"); + + it->gc = XCreateGC(it->dpy, it->window, GCBackground, &gcv); +# ifdef HAVE_JWXYZ + jwxyz_XSetAntiAliasing (it->dpy, it->gc, False); +# endif + XSetWindowBackground(it->dpy, it->window, gcv.background); + XClearWindow(dpy,window); + + analogtv_configure(it); + + return it; + + fail: + if (it) { + if(it->threads.count) + threadpool_destroy(&it->threads); + thread_free(it->signal_subtotals); + thread_free(it->rx_signal); + free(it); + } + return NULL; +} + +void +analogtv_release(analogtv *it) +{ + if (it->image) { + destroy_xshm_image(it->dpy, it->image, &it->shm_info); + it->image=NULL; + } + if (it->gc) XFreeGC(it->dpy, it->gc); + it->gc=NULL; + if (it->n_colors) XFreeColors(it->dpy, it->colormap, it->colors, it->n_colors, 0L); + it->n_colors=0; + threadpool_destroy(&it->threads); + thread_free(it->rx_signal); + thread_free(it->signal_subtotals); + free(it); +} + + +/* + First generate the I and Q reference signals, which we'll multiply + the input signal by to accomplish the demodulation. Normally they + are shifted 33 degrees from the colorburst. I think this was convenient + for inductor-capacitor-vacuum tube implementation. + + The tint control, FWIW, just adds a phase shift to the chroma signal, + and the color control controls the amplitude. + + In text modes (colormode==0) the system disabled the color burst, and no + color was detected by the monitor. + + freq_error gives a mismatch between the built-in oscillator and the + TV's colorbust. Some II Plus machines seemed to occasionally get + instability problems -- the crystal oscillator was a single + transistor if I remember correctly -- and the frequency would vary + enough that the tint would change across the width of the screen. + The left side would be in correct tint because it had just gotten + resynchronized with the color burst. + + If we're using a colormap, set it up. +*/ +int +analogtv_set_demod(analogtv *it) +{ + int y_levels=10,i_levels=5,q_levels=5; + + /* + In principle, we might be able to figure out how to adjust the + color map frame-by-frame to get some nice color bummage. But I'm + terrified of changing the color map because we'll get flashing. + + I can hardly believe we still have to deal with colormaps. They're + like having NEAR PTRs: an enormous hassle for the programmer just + to save on memory. They should have been deprecated by 1995 or + so. */ + + cmap_again: + if (it->use_cmap && !it->n_colors) { + + if (it->n_colors) { + XFreeColors(it->dpy, it->colormap, it->colors, it->n_colors, 0L); + it->n_colors=0; + } + + { + int yli,qli,ili; + for (yli=0; yli65535) r=65535; + if (g<0) g=0; + if (g>65535) g=65535; + if (b<0) b=0; + if (b>65535) b=65535; + +#ifdef DEBUG + printf("%0.2f %0.2f %0.2f => %02x%02x%02x\n", + interpy, interpi, interpq, + r/256,g/256,b/256); +#endif + + col.red=r; + col.green=g; + col.blue=b; + col.pixel=0; + if (!XAllocColor(it->dpy, it->colormap, &col)) { + if (q_levels > y_levels*4/12) + q_levels--; + else if (i_levels > y_levels*5/12) + i_levels--; + else + y_levels--; + + if (y_levels<2) + return -1; + goto cmap_again; + } + it->colors[it->n_colors++]=col.pixel; + } + } + } + + it->cmap_y_levels=y_levels; + it->cmap_i_levels=i_levels; + it->cmap_q_levels=q_levels; + } + } + + return 0; +} + +#if 0 +unsigned int +analogtv_line_signature(analogtv_input *input, int lineno) +{ + int i; + char *origsignal=&input->signal[(lineno+input->vsync) + %ANALOGTV_V][input->line_hsync[lineno]]; + unsigned int hash=0; + + /* probably lame */ + for (i=0; iline_hsync[lineno]; + hash ^= hash >> 2; + /* + hash += input->hashnoise_times[lineno]; + hash ^= hash >> 2; + */ + + return hash; +} +#endif + + +/* Here we model the analog circuitry of an NTSC television. + Basically, it splits the signal into 3 signals: Y, I and Q. Y + corresponds to luminance, and you get it by low-pass filtering the + input signal to below 3.57 MHz. + + I and Q are the in-phase and quadrature components of the 3.57 MHz + subcarrier. We get them by multiplying by cos(3.57 MHz*t) and + sin(3.57 MHz*t), and low-pass filtering. Because the eye has less + resolution in some colors than others, the I component gets + low-pass filtered at 1.5 MHz and the Q at 0.5 MHz. The I component + is approximately orange-blue, and Q is roughly purple-green. See + http://www.ntsc-tv.com for details. + + We actually do an awful lot to the signal here. I suspect it would + make sense to wrap them all up together by calculating impulse + response and doing FFT convolutions. + +*/ + +static void +analogtv_ntsc_to_yiq(const analogtv *it, int lineno, const float *signal, + int start, int end, struct analogtv_yiq_s *it_yiq) +{ + enum {MAXDELAY=32}; + int i; + const float *sp; + int phasecorr=(signal-it->rx_signal)&3; + struct analogtv_yiq_s *yiq; + int colormode; + float agclevel=it->agclevel; + float brightadd=it->brightness_control*100.0 - ANALOGTV_BLACK_LEVEL; + float delay[MAXDELAY+ANALOGTV_PIC_LEN], *dp; + float multiq2[4]; + + { + + double cb_i=(it->line_cb_phase[lineno][(2+phasecorr)&3]- + it->line_cb_phase[lineno][(0+phasecorr)&3])/16.0; + double cb_q=(it->line_cb_phase[lineno][(3+phasecorr)&3]- + it->line_cb_phase[lineno][(1+phasecorr)&3])/16.0; + + colormode = (cb_i * cb_i + cb_q * cb_q) > 2.8; + + if (colormode) { + multiq2[0] = (cb_i*it->tint_i - cb_q*it->tint_q) * it->color_control; + multiq2[1] = (cb_q*it->tint_i + cb_i*it->tint_q) * it->color_control; + multiq2[2]=-multiq2[0]; + multiq2[3]=-multiq2[1]; + } + } + +#if 0 + if (lineno==100) { + printf("multiq = [%0.3f %0.3f %0.3f %0.3f] ", + it->multiq[60],it->multiq[61],it->multiq[62],it->multiq[63]); + printf("it->line_cb_phase = [%0.3f %0.3f %0.3f %0.3f]\n", + it->line_cb_phase[lineno][0],it->line_cb_phase[lineno][1], + it->line_cb_phase[lineno][2],it->line_cb_phase[lineno][3]); + printf("multiq2 = [%0.3f %0.3f %0.3f %0.3f]\n", + multiq2[0],multiq2[1],multiq2[2],multiq2[3]); + } +#endif + + dp=delay+ANALOGTV_PIC_LEN-MAXDELAY; + for (i=0; i<5; i++) dp[i]=0.0f; + + assert(start>=0); + assert(end < ANALOGTV_PIC_LEN+10); + + dp=delay+ANALOGTV_PIC_LEN-MAXDELAY; + for (i=0; i<24; i++) dp[i]=0.0; + for (i=start, yiq=it_yiq+start, sp=signal+start; + iy = dp[8] + brightadd; + } + + if (colormode) { + dp=delay+ANALOGTV_PIC_LEN-MAXDELAY; + for (i=0; i<27; i++) dp[i]=0.0; + + for (i=start, yiq=it_yiq+start, sp=signal+start; + ii=dp[8] = (dp[5] + dp[0] + +3.0f*(dp[4] + dp[1]) + +4.0f*(dp[3] + dp[2]) + -0.3333333333f * dp[10]); + + dp[16] = sig*multiq2[(i+3)&3] * 0.0833333333333f; + yiq->q=dp[24] = (dp[16+5] + dp[16+0] + +3.0f*(dp[16+4] + dp[16+1]) + +4.0f*(dp[16+3] + dp[16+2]) + -0.3333333333f * dp[24+2]); + } + } else { + for (i=start, yiq=it_yiq+start; ii = yiq->q = 0.0f; + } + } +} + +void +analogtv_setup_teletext(analogtv_input *input) +{ + int x,y; + int teletext=ANALOGTV_BLACK_LEVEL; + + /* Teletext goes in line 21. But I suspect there are other things + in the vertical retrace interval */ + + for (y=19; y<22; y++) { + for (x=ANALOGTV_PIC_START; xsignal[y][x]=teletext; + } + } +} + +void +analogtv_setup_frame(analogtv *it) +{ + /* int i,x,y;*/ + + it->redraw_all=0; + + if (it->flutter_horiz_desync) { + /* Horizontal sync during vertical sync instability. */ + it->horiz_desync += -0.10*(it->horiz_desync-3.0) + + ((int)(random()&0xff)-0x80) * + ((int)(random()&0xff)-0x80) * + ((int)(random()&0xff)-0x80) * 0.000001; + } + + /* it wasn't used + for (i=0; ihashnoise_times[i]=0; + } + */ + + /* let's leave it to process shrinkpulse */ + if (it->hashnoise_enable && !it->hashnoise_on) { + if (random()%10000==0) { + it->hashnoise_on=1; + it->shrinkpulse=random()%ANALOGTV_V; + } + } + if (random()%1000==0) { + it->hashnoise_on=0; + } + +#if 0 /* never used */ + if (it->hashnoise_on) { + it->hashnoise_rpm += (15000.0 - it->hashnoise_rpm)*0.05 + + ((int)(random()%2000)-1000)*0.1; + } else { + it->hashnoise_rpm -= 100 + 0.01*it->hashnoise_rpm; + if (it->hashnoise_rpm<0.0) it->hashnoise_rpm=0.0; + } + if (it->hashnoise_rpm > 0.0) { + int hni; + double hni_double; + int hnc=it->hashnoise_counter; /* in 24.8 format */ + + /* Convert rpm of a 16-pole motor into dots in 24.8 format */ + hni_double = ANALOGTV_V * ANALOGTV_H * 256.0 / + (it->hashnoise_rpm * 16.0 / 60.0 / 60.0); + hni = (hni_double <= INT_MAX) ? (int)hni_double : INT_MAX; + + while (hnc < (ANALOGTV_V * ANALOGTV_H)<<8) { + y=(hnc>>8)/ANALOGTV_H; + x=(hnc>>8)%ANALOGTV_H; + + if (x>0 && xhashnoise_times[y]=x; + } + /* hnc += hni + (int)(random()%65536)-32768; */ + { + hnc += (int)(random()%65536)-32768; + if ((hnc >= 0) && (INT_MAX - hnc < hni)) break; + hnc += hni; + } + } + } +#endif /* 0 */ + +/* hnc -= (ANALOGTV_V * ANALOGTV_H)<<8;*/ + + + if (it->rx_signal_level != 0.0) + it->agclevel = 1.0/it->rx_signal_level; + + +#ifdef DEBUG2 + printf("filter: "); + for (i=0; ighostfir[i]); + } + printf(" siglevel=%g agc=%g\n", siglevel, it->agclevel); +#endif +} + +void +analogtv_setup_sync(analogtv_input *input, int do_cb, int do_ssavi) +{ + int i,lineno,vsync; + signed char *sig; + + int synclevel = do_ssavi ? ANALOGTV_WHITE_LEVEL : ANALOGTV_SYNC_LEVEL; + + for (lineno=0; lineno=3 && lineno<7; + + sig=input->signal[lineno]; + + i=ANALOGTV_SYNC_START; + if (vsync) { + while (icur_hsync; + int cur_vsync=it->cur_vsync; + int lineno = 0; + int i,j; + float osc,filt; + float *sp; + float cbfc=1.0f/128.0f; + +/* sp = it->rx_signal + lineno*ANALOGTV_H + cur_hsync;*/ + for (i=-32; i<32; i++) { + lineno = (cur_vsync + i + ANALOGTV_V) % ANALOGTV_V; + sp = it->rx_signal + lineno*ANALOGTV_H; + filt=0.0f; + for (j=0; jagclevel; + + osc = (float)(ANALOGTV_V+i)/(float)ANALOGTV_V; + + if (osc >= 1.05f+0.0002f * filt) break; + } + cur_vsync = (cur_vsync + i + ANALOGTV_V) % ANALOGTV_V; + + for (lineno=0; lineno5 && linenorx_signal + lineno2*ANALOGTV_H + cur_hsync; + for (i=-8; i<8; i++) { + osc = (float)(ANALOGTV_H+i)/(float)ANALOGTV_H; + filt=(sp[i-3]+sp[i-2]+sp[i-1]+sp[i]) * it->agclevel; + + if (osc >= 1.005f + 0.0001f*filt) break; + } + cur_hsync = (cur_hsync + i + ANALOGTV_H) % ANALOGTV_H; + } + + it->line_hsync[lineno]=(cur_hsync + ANALOGTV_PIC_START + + ANALOGTV_H) % ANALOGTV_H; + + /* Now look for the colorburst, which is a few cycles after the H + sync pulse, and store its phase. + The colorburst is 9 cycles long, and we look at the middle 5 + cycles. + */ + + if (lineno>15) { + sp = it->rx_signal + lineno*ANALOGTV_H + (cur_hsync&~3); + for (i=ANALOGTV_CB_START+8; icb_phase[i&3] = it->cb_phase[i&3]*(1.0f-cbfc) + + sp[i]*it->agclevel*cbfc; + } + } + + { + float tot=0.1f; + float cbgain; + + for (i=0; i<4; i++) { + tot += it->cb_phase[i]*it->cb_phase[i]; + } + cbgain = 32.0f/sqrtf(tot); + + for (i=0; i<4; i++) { + it->line_cb_phase[lineno][i]=it->cb_phase[i]*cbgain; + } + } + +#ifdef DEBUG + if (0) printf("hs=%d cb=[%0.3f %0.3f %0.3f %0.3f]\n", + cur_hsync, + it->cb_phase[0], it->cb_phase[1], + it->cb_phase[2], it->cb_phase[3]); +#endif + + /* if (random()%2000==0) cur_hsync=random()%ANALOGTV_H; */ + } + + it->cur_hsync = cur_hsync; + it->cur_vsync = cur_vsync; +} + +static double +analogtv_levelmult(const analogtv *it, int level) +{ + static const double levelfac[3]={-7.5, 5.5, 24.5}; + return (40.0 + levelfac[level]*puramp(it, 3.0, 6.0, 1.0))/256.0; +} + +static int +analogtv_level(const analogtv *it, int y, int ytop, int ybot) +{ + int level; + if (ybot-ytop>=7) { + if (y==ytop || y==ybot-1) level=0; + else if (y==ytop+1 || y==ybot-2) level=1; + else level=2; + } + else if (ybot-ytop>=5) { + if (y==ytop || y==ybot-1) level=0; + else level=2; + } + else if (ybot-ytop>=3) { + if (y==ytop) level=0; + else level=2; + } + else { + level=2; + } + return level; +} + +/* + The point of this stuff is to ensure that when useheight is not a + multiple of VISLINES so that TV scan lines map to different numbers + of vertical screen pixels, the total brightness of each scan line + remains the same. + ANALOGTV_MAX_LINEHEIGHT corresponds to 2400 vertical pixels, beyond which + it interpolates extra black lines. + */ + +static void +analogtv_setup_levels(analogtv *it, double avgheight) +{ + int i,height; + static const double levelfac[3]={-7.5, 5.5, 24.5}; + + for (height=0; heightleveltable[height][i].index = 2; + } + + if (avgheight>=3) { + it->leveltable[height][0].index=0; + } + if (avgheight>=5) { + if (height >= 1) it->leveltable[height][height-1].index=0; + } + if (avgheight>=7) { + it->leveltable[height][1].index=1; + if (height >= 2) it->leveltable[height][height-2].index=1; + } + + for (i=0; ileveltable[height][i].value = + (40.0 + levelfac[it->leveltable[height][i].index]*puramp(it, 3.0, 6.0, 1.0)) / 256.0; + } + + } +} + +static void rnd_combine(unsigned *a0, unsigned *c0, unsigned a1, unsigned c1) +{ + *a0 = (*a0 * a1) & 0xffffffffu; + *c0 = (c1 + a1 * *c0) & 0xffffffffu; +} + +static void rnd_seek_ac(unsigned *a, unsigned *c, unsigned dist) +{ + unsigned int a1 = *a, c1 = *c; + *a = 1, *c = 0; + + while(dist) + { + if(dist & 1) + rnd_combine(a, c, a1, c1); + dist >>= 1; + rnd_combine(&a1, &c1, a1, c1); + } +} + +static unsigned int rnd_seek(unsigned a, unsigned c, unsigned rnd, unsigned dist) +{ + rnd_seek_ac(&a, &c, dist); + return a * rnd + c; +} + +static void analogtv_init_signal(const analogtv *it, double noiselevel, unsigned start, unsigned end) +{ + float *ps=it->rx_signal + start; + float *pe=it->rx_signal + end; + float *p=ps; + unsigned int fastrnd=rnd_seek(FASTRND_A, FASTRND_C, it->random0, start); + unsigned int fastrnd_offset; + float nm1,nm2; + float noisemul = sqrt(noiselevel*150)/(float)0x7fffffff; + + fastrnd_offset = fastrnd - 0x7fffffff; + nm1 = (fastrnd_offset <= INT_MAX ? (int)fastrnd_offset : -1 - (int)(UINT_MAX - fastrnd_offset)) * noisemul; + while (p != pe) { + nm2=nm1; + fastrnd = (fastrnd*FASTRND_A+FASTRND_C) & 0xffffffffu; + fastrnd_offset = fastrnd - 0x7fffffff; + nm1 = (fastrnd_offset <= INT_MAX ? (int)fastrnd_offset : -1 - (int)(UINT_MAX - fastrnd_offset)) * noisemul; + *p++ = nm1*nm2; + } +} + +static void analogtv_add_signal(const analogtv *it, const analogtv_reception *rec, unsigned start, unsigned end, int ec) +{ + analogtv_input *inp=rec->input; + float *ps=it->rx_signal + start; + float *pe=it->rx_signal + end; + float *p=ps; + signed char *ss=&inp->signal[0][0]; + signed char *se=&inp->signal[0][0] + ANALOGTV_SIGNAL_LEN; + signed char *s=ss + ((start + (unsigned)rec->ofs) % ANALOGTV_SIGNAL_LEN); + signed char *s2; + int i; + float level=rec->level; + float hfloss=rec->hfloss; + unsigned int fastrnd=rnd_seek(FASTRND_A, FASTRND_C, it->random1, start); + float dp[5]; + + const float noise_decay = 0.99995f; + float noise_ampl = 1.3f * powf(noise_decay, start); + + if (ec > end) + ec = end; + + /* assert((se-ss)%4==0 && (se-s)%4==0); */ + + for (i = start; i < ec; i++) { /* Sometimes start > ec. */ + + /* Do a big noisy transition. We can make the transition noise of + high constant strength regardless of signal strength. + + There are two separate state machines. here, One is the noise + process and the other is the + + We don't bother with the FIR filter here + */ + + float sig0=(float)s[0]; + unsigned int fastrnd_offset = fastrnd - 0x7fffffff; + float noise = (fastrnd_offset <= INT_MAX ? (int)fastrnd_offset : -1 - (int)(UINT_MAX - fastrnd_offset)) * (50.0f/(float)0x7fffffff); + fastrnd = (fastrnd*FASTRND_A+FASTRND_C) & 0xffffffffu; + + p[0] += sig0 * level * (1.0f - noise_ampl) + noise * noise_ampl; + + noise_ampl *= noise_decay; + + p++; + s++; + if (s>=se) s=ss; + } + + dp[0]=0.0; + s2 = s; + for (i=1; i<5; i++) { + s2 -= 4; + if (s2 < ss) + s2 += ANALOGTV_SIGNAL_LEN; + dp[i] = (float)((int)s2[0]+(int)s2[1]+(int)s2[2]+(int)s2[3]); + } + + assert(p <= pe); + assert(!((pe - p) % 4)); + while (p != pe) { + float sig0,sig1,sig2,sig3,sigr; + + sig0=(float)s[0]; + sig1=(float)s[1]; + sig2=(float)s[2]; + sig3=(float)s[3]; + + dp[0]=sig0+sig1+sig2+sig3; + + /* Get the video out signal, and add some ghosting, typical of RF + monitor cables. This corresponds to a pretty long cable, but + looks right to me. + */ + + sigr=(dp[1]*rec->ghostfir[0] + dp[2]*rec->ghostfir[1] + + dp[3]*rec->ghostfir[2] + dp[4]*rec->ghostfir[3]); + dp[4]=dp[3]; dp[3]=dp[2]; dp[2]=dp[1]; dp[1]=dp[0]; + + p[0] += (sig0+sigr + sig2*hfloss) * level; + p[1] += (sig1+sigr + sig3*hfloss) * level; + p[2] += (sig2+sigr + sig0*hfloss) * level; + p[3] += (sig3+sigr + sig1*hfloss) * level; + + p += 4; + s += 4; + if (s>=se) s = ss + (s-se); + } + + assert(p == pe); +} + +static void analogtv_thread_add_signals(void *thread_raw) +{ + const analogtv_thread *thread = (analogtv_thread *)thread_raw; + const analogtv *it = thread->it; + unsigned i, j; + unsigned subtotal_end; + + unsigned start = thread->signal_start; + while(start != thread->signal_end) + { + float *p; + + /* Work on 8 KB blocks; these should fit in L1. */ + /* (Though it doesn't seem to help much on my system.) */ + unsigned end = start + 2048; + if(end > thread->signal_end) + end = thread->signal_end; + + analogtv_init_signal (it, it->noiselevel, start, end); + + for (i = 0; i != it->rec_count; ++i) { + analogtv_add_signal (it, it->recs[i], start, end, + !i ? it->channel_change_cycles : 0); + } + + assert (!(start % ANALOGTV_SUBTOTAL_LEN)); + assert (!(end % ANALOGTV_SUBTOTAL_LEN)); + + p = it->rx_signal + start; + subtotal_end = end / ANALOGTV_SUBTOTAL_LEN; + for (i = start / ANALOGTV_SUBTOTAL_LEN; i != subtotal_end; ++i) { + float sum = p[0]; + for (j = 1; j != ANALOGTV_SUBTOTAL_LEN; ++j) + sum += p[j]; + it->signal_subtotals[i] = sum; + p += ANALOGTV_SUBTOTAL_LEN; + } + + start = end; + } +} + +static int analogtv_get_line(const analogtv *it, int lineno, int *slineno, + int *ytop, int *ybot, unsigned *signal_offset) +{ + *slineno=lineno-ANALOGTV_TOP; + *ytop=(int)((*slineno*it->useheight/ANALOGTV_VISLINES - + it->useheight/2)*it->puheight) + it->useheight/2; + *ybot=(int)(((*slineno+1)*it->useheight/ANALOGTV_VISLINES - + it->useheight/2)*it->puheight) + it->useheight/2; +#if 0 + int linesig=analogtv_line_signature(input,lineno) + + it->hashnoise_times[lineno]; +#endif + *signal_offset = ((lineno+it->cur_vsync+ANALOGTV_V) % ANALOGTV_V) * ANALOGTV_H + + it->line_hsync[lineno]; + + if (*ytop==*ybot) return 0; + if (*ybot<0 || *ytop>it->useheight) return 0; + if (*ytop<0) *ytop=0; + if (*ybot>it->useheight) *ybot=it->useheight; + + if (*ybot > *ytop+ANALOGTV_MAX_LINEHEIGHT) *ybot=*ytop+ANALOGTV_MAX_LINEHEIGHT; + return 1; +} + +static void +analogtv_blast_imagerow(const analogtv *it, + float *rgbf, float *rgbf_end, + int ytop, int ybot) +{ + int i,j,x,y; + float *rpf; + char *level_copyfrom[3]; + int xrepl=it->xrepl; + unsigned lineheight = ybot - ytop; + if (lineheight > ANALOGTV_MAX_LINEHEIGHT) lineheight = ANALOGTV_MAX_LINEHEIGHT; + for (i=0; i<3; i++) level_copyfrom[i]=NULL; + + for (y=ytop; yimage->data + y*it->image->bytes_per_line; + unsigned line = y-ytop; + + int level=it->leveltable[lineheight][line].index; + float levelmult=it->leveltable[lineheight][line].value; + + /* Fast special cases to avoid the slow XPutPixel. Ugh. It goes to show + why standard graphics sw has to be fast, or else people will have to + work around it and risk incompatibility. The quickdraw folks + understood this. The other answer would be for X11 to have fewer + formats for bitm.. oh, never mind. If neither of these cases work + (they probably cover 99% of setups) it falls back on the Xlib + routines. */ + + if (level_copyfrom[level]) { + memcpy(rowdata, level_copyfrom[level], it->image->bytes_per_line); + } + else { + level_copyfrom[level] = rowdata; + + if (0) { + } + else if (it->image->format==ZPixmap && + it->image->bits_per_pixel==32 && + sizeof(unsigned int)==4 && + it->image->byte_order==localbyteorder) { + /* int is more likely to be 32 bits than long */ + unsigned int *pixelptr=(unsigned int *)rowdata; + unsigned int pix; + + for (rpf=rgbf; rpf!=rgbf_end; rpf+=3) { + int ntscri=rpf[0]*levelmult; + int ntscgi=rpf[1]*levelmult; + int ntscbi=rpf[2]*levelmult; + if (ntscri>=ANALOGTV_CV_MAX) ntscri=ANALOGTV_CV_MAX-1; + if (ntscgi>=ANALOGTV_CV_MAX) ntscgi=ANALOGTV_CV_MAX-1; + if (ntscbi>=ANALOGTV_CV_MAX) ntscbi=ANALOGTV_CV_MAX-1; + pix = (it->red_values[ntscri] | + it->green_values[ntscgi] | + it->blue_values[ntscbi]); + pixelptr[0] = pix; + if (xrepl>=2) { + pixelptr[1] = pix; + if (xrepl>=3) pixelptr[2] = pix; + } + pixelptr+=xrepl; + } + } + else if (it->image->format==ZPixmap && + it->image->bits_per_pixel==16 && + sizeof(unsigned short)==2 && + float_extraction_works && + it->image->byte_order==localbyteorder) { + unsigned short *pixelptr=(unsigned short *)rowdata; + float r2,g2,b2; + float_extract_t r1,g1,b1; + unsigned short pix; + + for (rpf=rgbf; rpf!=rgbf_end; rpf+=3) { + r2=rpf[0]; g2=rpf[1]; b2=rpf[2]; + r1.f=r2 * levelmult+float_low8_ofs; + g1.f=g2 * levelmult+float_low8_ofs; + b1.f=b2 * levelmult+float_low8_ofs; + pix = (it->red_values[r1.i & 0x3ff] | + it->green_values[g1.i & 0x3ff] | + it->blue_values[b1.i & 0x3ff]); + pixelptr[0] = pix; + if (xrepl>=2) { + pixelptr[1] = pix; + if (xrepl>=3) pixelptr[2] = pix; + } + pixelptr+=xrepl; + } + } + else if (it->image->format==ZPixmap && + it->image->bits_per_pixel==16 && + sizeof(unsigned short)==2 && + it->image->byte_order==localbyteorder) { + unsigned short *pixelptr=(unsigned short *)rowdata; + unsigned short pix; + + for (rpf=rgbf; rpf!=rgbf_end; rpf+=3) { + int r1=rpf[0] * levelmult; + int g1=rpf[1] * levelmult; + int b1=rpf[2] * levelmult; + if (r1>=ANALOGTV_CV_MAX) r1=ANALOGTV_CV_MAX-1; + if (g1>=ANALOGTV_CV_MAX) g1=ANALOGTV_CV_MAX-1; + if (b1>=ANALOGTV_CV_MAX) b1=ANALOGTV_CV_MAX-1; + pix = it->red_values[r1] | it->green_values[g1] | it->blue_values[b1]; + pixelptr[0] = pix; + if (xrepl>=2) { + pixelptr[1] = pix; + if (xrepl>=3) pixelptr[2] = pix; + } + pixelptr+=xrepl; + } + } + else { + for (x=0, rpf=rgbf; rpf!=rgbf_end ; x++, rpf+=3) { + int ntscri=rpf[0]*levelmult; + int ntscgi=rpf[1]*levelmult; + int ntscbi=rpf[2]*levelmult; + if (ntscri>=ANALOGTV_CV_MAX) ntscri=ANALOGTV_CV_MAX-1; + if (ntscgi>=ANALOGTV_CV_MAX) ntscgi=ANALOGTV_CV_MAX-1; + if (ntscbi>=ANALOGTV_CV_MAX) ntscbi=ANALOGTV_CV_MAX-1; + for (j=0; jimage, x*xrepl + j, y, + it->red_values[ntscri] | it->green_values[ntscgi] | + it->blue_values[ntscbi]); + } + } + } + } + } +} + +static void analogtv_thread_draw_lines(void *thread_raw) +{ + const analogtv_thread *thread = (analogtv_thread *)thread_raw; + const analogtv *it = thread->it; + + int lineno; + + float *raw_rgb_start; + float *raw_rgb_end; + raw_rgb_start=(float *)calloc(it->subwidth*3, sizeof(float)); + + if (! raw_rgb_start) return; + + raw_rgb_end=raw_rgb_start+3*it->subwidth; + + for (lineno=ANALOGTV_TOP + thread->thread_id; + linenothreads.count) { + int i,j,x,y; + + int slineno, ytop, ybot; + unsigned signal_offset; + + const float *signal; + + int scanstart_i,scanend_i,squishright_i,squishdiv,pixrate; + float *rgb_start, *rgb_end; + float pixbright; + int pixmultinc; + + float *rrp; + + struct analogtv_yiq_s yiq[ANALOGTV_PIC_LEN+10]; + + if (! analogtv_get_line(it, lineno, &slineno, &ytop, &ybot, + &signal_offset)) + continue; + + signal = it->rx_signal + signal_offset; + + { + + float bloomthisrow,shiftthisrow; + float viswidth,middle; + float scanwidth; + int scw,scl,scr; + + bloomthisrow = -10.0f * it->crtload[lineno]; + if (bloomthisrow<-10.0f) bloomthisrow=-10.0f; + if (bloomthisrow>2.0f) bloomthisrow=2.0f; + if (slineno<16) { + shiftthisrow=it->horiz_desync * (expf(-0.17f*slineno) * + (0.7f+cosf(slineno*0.6f))); + } else { + shiftthisrow=0.0f; + } + + viswidth=ANALOGTV_PIC_LEN * 0.79f - 5.0f*bloomthisrow; + middle=ANALOGTV_PIC_LEN/2 - shiftthisrow; + + scanwidth=it->width_control * puramp(it, 0.5f, 0.3f, 1.0f); + + scw=it->subwidth*scanwidth; + if (scw>it->subwidth) scw=it->usewidth; + scl=it->subwidth/2 - scw/2; + scr=it->subwidth/2 + scw/2; + + pixrate=(int)((viswidth*65536.0f*1.0f)/it->subwidth)/scanwidth; + scanstart_i=(int)((middle-viswidth*0.5f)*65536.0f); + scanend_i=(ANALOGTV_PIC_LEN-1)*65536; + squishright_i=(int)((middle+viswidth*(0.25f + 0.25f*puramp(it, 2.0f, 0.0f, 1.1f) + - it->squish_control)) *65536.0f); + squishdiv=it->subwidth/15; + + rgb_start=raw_rgb_start+scl*3; + rgb_end=raw_rgb_start+scr*3; + + assert(scanstart_i>=0); + +#ifdef DEBUG + if (0) printf("scan %d: %0.3f %0.3f %0.3f scl=%d scr=%d scw=%d\n", + lineno, + scanstart_i/65536.0f, + squishright_i/65536.0f, + scanend_i/65536.0f, + scl,scr,scw); +#endif + } + + if (it->use_cmap) { + for (y=ytop; ycontrast_control + * puramp(it, 1.0f, 0.0f, 1.0f) / (0.5f+0.5f*it->puheight) * 0.070f; + float levelmult_iq = levelmult * 0.090f; + + analogtv_ntsc_to_yiq(it, lineno, signal, + (scanstart_i>>16)-10, (scanend_i>>16)+10, yiq); + pixmultinc=pixrate; + + x=0; + i=scanstart_i; + while (i<0 && xusewidth) { + XPutPixel(it->image, x, y, it->colors[0]); + i+=pixmultinc; + x++; + } + + while (iusewidth) { + float pixfrac=(i&0xffff)/65536.0f; + float invpixfrac=(1.0f-pixfrac); + int pati=i>>16; + int yli,ili,qli,cmi; + + float interpy=(yiq[pati].y*invpixfrac + + yiq[pati+1].y*pixfrac) * levelmult_y; + float interpi=(yiq[pati].i*invpixfrac + + yiq[pati+1].i*pixfrac) * levelmult_iq; + float interpq=(yiq[pati].q*invpixfrac + + yiq[pati+1].q*pixfrac) * levelmult_iq; + + yli = (int)(interpy * it->cmap_y_levels); + ili = (int)((interpi+0.5f) * it->cmap_i_levels); + qli = (int)((interpq+0.5f) * it->cmap_q_levels); + if (yli<0) yli=0; + if (yli>=it->cmap_y_levels) yli=it->cmap_y_levels-1; + if (ili<0) ili=0; + if (ili>=it->cmap_i_levels) ili=it->cmap_i_levels-1; + if (qli<0) qli=0; + if (qli>=it->cmap_q_levels) qli=it->cmap_q_levels-1; + + cmi=qli + it->cmap_i_levels*(ili + it->cmap_q_levels*yli); + +#ifdef DEBUG + if ((random()%65536)==0) { + printf("%0.3f %0.3f %0.3f => %d %d %d => %d\n", + interpy, interpi, interpq, + yli, ili, qli, + cmi); + } +#endif + + for (j=0; jxrepl; j++) { + XPutPixel(it->image, x, y, + it->colors[cmi]); + x++; + } + if (i >= squishright_i) { + pixmultinc += pixmultinc/squishdiv; + } + i+=pixmultinc; + } + while (xusewidth) { + XPutPixel(it->image, x, y, it->colors[0]); + x++; + } + } + } + else { + analogtv_ntsc_to_yiq(it, lineno, signal, + (scanstart_i>>16)-10, (scanend_i>>16)+10, yiq); + + pixbright=it->contrast_control * puramp(it, 1.0f, 0.0f, 1.0f) + / (0.5f+0.5f*it->puheight) * 1024.0f/100.0f; + pixmultinc=pixrate; + i=scanstart_i; rrp=rgb_start; + while (i<0 && rrp!=rgb_end) { + rrp[0]=rrp[1]=rrp[2]=0; + i+=pixmultinc; + rrp+=3; + } + while (i>16; + float r,g,b; + + float interpy=(yiq[pati].y*invpixfrac + yiq[pati+1].y*pixfrac); + float interpi=(yiq[pati].i*invpixfrac + yiq[pati+1].i*pixfrac); + float interpq=(yiq[pati].q*invpixfrac + yiq[pati+1].q*pixfrac); + + /* + According to the NTSC spec, Y,I,Q are generated as: + + y=0.30 r + 0.59 g + 0.11 b + i=0.60 r - 0.28 g - 0.32 b + q=0.21 r - 0.52 g + 0.31 b + + So if you invert the implied 3x3 matrix you get what standard + televisions implement with a bunch of resistors (or directly in the + CRT -- don't ask): + + r = y + 0.948 i + 0.624 q + g = y - 0.276 i - 0.639 q + b = y - 1.105 i + 1.729 q + */ + + r=(interpy + 0.948f*interpi + 0.624f*interpq) * pixbright; + g=(interpy - 0.276f*interpi - 0.639f*interpq) * pixbright; + b=(interpy - 1.105f*interpi + 1.729f*interpq) * pixbright; + if (r<0.0f) r=0.0f; + if (g<0.0f) g=0.0f; + if (b<0.0f) b=0.0f; + rrp[0]=r; + rrp[1]=g; + rrp[2]=b; + + if (i>=squishright_i) { + pixmultinc += pixmultinc/squishdiv; + pixbright += pixbright/squishdiv/2; + } + i+=pixmultinc; + rrp+=3; + } + while (rrp != rgb_end) { + rrp[0]=rrp[1]=rrp[2]=0.0f; + rrp+=3; + } + + analogtv_blast_imagerow(it, raw_rgb_start, raw_rgb_end, + ytop,ybot); + } + } + + free(raw_rgb_start); +} + +void +analogtv_draw(analogtv *it, double noiselevel, + const analogtv_reception *const *recs, unsigned rec_count) +{ + int i,lineno; + /* int bigloadchange,drawcount;*/ + double baseload; + int overall_top, overall_bot; + + /* AnalogTV isn't very interesting if there isn't enough RAM. */ + if (!it->image) + return; + + it->rx_signal_level = noiselevel; + for (i = 0; i != rec_count; ++i) { + const analogtv_reception *rec = recs[i]; + double level = rec->level; + analogtv_input *inp=rec->input; + + it->rx_signal_level = + sqrt(it->rx_signal_level * it->rx_signal_level + + (level * level * (1.0 + 4.0*(rec->ghostfir[0] + rec->ghostfir[1] + + rec->ghostfir[2] + rec->ghostfir[3])))); + + /* duplicate the first line into the Nth line to ease wraparound computation */ + memcpy(inp->signal[ANALOGTV_V], inp->signal[0], + ANALOGTV_H * sizeof(inp->signal[0][0])); + } + + analogtv_setup_frame(it); + analogtv_set_demod(it); + + it->random0 = random(); + it->random1 = random(); + it->noiselevel = noiselevel; + it->recs = recs; + it->rec_count = rec_count; + threadpool_run(&it->threads, analogtv_thread_add_signals); + threadpool_wait(&it->threads); + + it->channel_change_cycles=0; + + /* rx_signal has an extra 2 lines at the end, where we copy the + first 2 lines so we can index into it while only worrying about + wraparound on a per-line level */ + memcpy(&it->rx_signal[ANALOGTV_SIGNAL_LEN], + &it->rx_signal[0], + 2*ANALOGTV_H*sizeof(it->rx_signal[0])); + + /* Repeat for signal_subtotals. */ + + memcpy(&it->signal_subtotals[ANALOGTV_SIGNAL_LEN / ANALOGTV_SUBTOTAL_LEN], + &it->signal_subtotals[0], + (2*ANALOGTV_H/ANALOGTV_SUBTOTAL_LEN)*sizeof(it->signal_subtotals[0])); + + analogtv_sync(it); /* Requires the add_signals be complete. */ + + baseload=0.5; + /* if (it->hashnoise_on) baseload=0.5; */ + + /*bigloadchange=1; + drawcount=0;*/ + it->crtload[ANALOGTV_TOP-1]=baseload; + it->puheight = puramp(it, 2.0, 1.0, 1.3) * it->height_control * + (1.125 - 0.125*puramp(it, 2.0, 2.0, 1.1)); + + analogtv_setup_levels(it, it->puheight * (double)it->useheight/(double)ANALOGTV_VISLINES); + + /* calculate tint once per frame */ + it->tint_i = -cos((103 + it->tint_control)*3.1415926/180); + it->tint_q = sin((103 + it->tint_control)*3.1415926/180); + + for (lineno=ANALOGTV_TOP; linenoshrinkpulse) { + baseload += 0.4; + /*bigloadchange=1;*/ + it->shrinkpulse=-1; + } + +#if 0 + if (it->hashnoise_rpm>0.0 && + !(bigloadchange || + it->redraw_all || + (slineno<20 && it->flutter_horiz_desync) || + it->gaussiannoise_level>30 || + ((it->gaussiannoise_level>2.0 || + it->multipath) && random()%4) || + linesig != it->onscreen_signature[lineno])) { + continue; + } + it->onscreen_signature[lineno] = linesig; +#endif + /* drawcount++;*/ + + /* + Interpolate the 600-dotclock line into however many horizontal + screen pixels we're using, and convert to RGB. + + We add some 'bloom', variations in the horizontal scan width with + the amount of brightness, extremely common on period TV sets. They + had a single oscillator which generated both the horizontal scan and + (during the horizontal retrace interval) the high voltage for the + electron beam. More brightness meant more load on the oscillator, + which caused an decrease in horizontal deflection. Look for + (bloomthisrow). + + Also, the A2 did a bad job of generating horizontal sync pulses + during the vertical blanking interval. This, and the fact that the + horizontal frequency was a bit off meant that TVs usually went a bit + out of sync during the vertical retrace, and the top of the screen + would be bent a bit to the left or right. Look for (shiftthisrow). + + We also add a teeny bit of left overscan, just enough to be + annoying, but you can still read the left column of text. + + We also simulate compression & brightening on the right side of the + screen. Most TVs do this, but you don't notice because they overscan + so it's off the right edge of the CRT. But the A2 video system used + so much of the horizontal scan line that you had to crank the + horizontal width down in order to not lose the right few characters, + and you'd see the compression on the right edge. Associated with + compression is brightening; since the electron beam was scanning + slower, the same drive signal hit the phosphor harder. Look for + (squishright_i) and (squishdiv). + */ + + { + /* This used to be an int, I suspect by mistake. - Dave */ + float totsignal=0; + float ncl/*,diff*/; + unsigned frac; + size_t end0, end1; + const float *p; + + frac = signal_offset & (ANALOGTV_SUBTOTAL_LEN - 1); + p = it->rx_signal + (signal_offset & ~(ANALOGTV_SUBTOTAL_LEN - 1)); + for (i=0; i != frac; i++) { + totsignal -= p[i]; + } + + end0 = (signal_offset + ANALOGTV_PIC_LEN); + + end1 = end0 / ANALOGTV_SUBTOTAL_LEN; + for (i=signal_offset / ANALOGTV_SUBTOTAL_LEN; isignal_subtotals[i]; + } + + frac = end0 & (ANALOGTV_SUBTOTAL_LEN - 1); + p = it->rx_signal + (end0 & ~(ANALOGTV_SUBTOTAL_LEN - 1)); + for (i=0; i != frac; i++) { + totsignal += p[i]; + } + + totsignal *= it->agclevel; + ncl = 0.95f * it->crtload[lineno-1] + + 0.05f*(baseload + + (totsignal-30000)/100000.0f + + (slineno>184 ? (slineno-184)*(lineno-184)*0.001f * it->squeezebottom + : 0.0f)); + /*diff=ncl - it->crtload[lineno];*/ + /*bigloadchange = (diff>0.01 || diff<-0.01);*/ + it->crtload[lineno]=ncl; + } + } + + threadpool_run(&it->threads, analogtv_thread_draw_lines); + threadpool_wait(&it->threads); + +#if 0 + /* poor attempt at visible retrace */ + for (i=0; i<15; i++) { + int ytop=(int)((i*it->useheight/15 - + it->useheight/2)*puheight) + it->useheight/2; + int ybot=(int)(((i+1)*it->useheight/15 - + it->useheight/2)*puheight) + it->useheight/2; + int div=it->usewidth*3/2; + + for (x=0; xusewidth; x++) { + y = ytop + (ybot-ytop)*x / div; + if (y<0 || y>=it->useheight) continue; + XPutPixel(it->image, x, y, 0xffffff); + } + } +#endif + + if (it->need_clear) { + XClearWindow(it->dpy, it->window); + it->need_clear=0; + } + + /* + Subtle change: overall_bot was the bottom of the last scan line. Now it's + the top of the next-after-the-last scan line. This is the same until + the y-dimension is > 2400, note ANALOGTV_MAX_LINEHEIGHT. + */ + + overall_top=(int)(it->useheight*(1-it->puheight)/2); + overall_bot=(int)(it->useheight*(1+it->puheight)/2); + + if (overall_top<0) overall_top=0; + if (overall_bot>it->useheight) overall_bot=it->useheight; + + if (overall_top>0) { + XClearArea(it->dpy, it->window, + it->screen_xo, it->screen_yo, + it->usewidth, overall_top, 0); + } + if (it->useheight > overall_bot) { + XClearArea(it->dpy, it->window, + it->screen_xo, it->screen_yo+overall_bot, + it->usewidth, it->useheight-overall_bot, 0); + } + + if (overall_bot > overall_top) { + put_xshm_image(it->dpy, it->window, it->gc, it->image, + 0, overall_top, + it->screen_xo, it->screen_yo+overall_top, + it->usewidth, overall_bot - overall_top, + &it->shm_info); + } + +#ifdef DEBUG + if (0) { + struct timeval tv; + double fps; + char buf[256]; + gettimeofday(&tv,NULL); + + fps=1.0/((tv.tv_sec - it->last_display_time.tv_sec) + + 0.000001*(tv.tv_usec - it->last_display_time.tv_usec)); + sprintf(buf, "FPS=%0.1f",fps); + XDrawString(it->dpy, it->window, it->gc, 50, it->useheight*2/3, + buf, strlen(buf)); + + it->last_display_time=tv; + } +#endif +} + +analogtv_input * +analogtv_input_allocate() +{ + analogtv_input *ret=(analogtv_input *)calloc(1,sizeof(analogtv_input)); + + return ret; +} + +/* + This takes a screen image and encodes it as a video camera would, + including all the bandlimiting and YIQ modulation. + This isn't especially tuned for speed. + + xoff, yoff: top left corner of rendered image, in window pixels. + w, h: scaled size of rendered image, in window pixels. + mask: BlackPixel means don't render (it's not full alpha) +*/ + +int +analogtv_load_ximage(analogtv *it, analogtv_input *input, + XImage *pic_im, XImage *mask_im, + int xoff, int yoff, int target_w, int target_h) +{ + int i,x,y; + int img_w,img_h; + int fyx[7],fyy[7]; + int fix[4],fiy[4]; + int fqx[4],fqy[4]; + XColor col1[ANALOGTV_PIC_LEN]; + XColor col2[ANALOGTV_PIC_LEN]; + char mask[ANALOGTV_PIC_LEN]; + int multiq[ANALOGTV_PIC_LEN+4]; + unsigned long black = 0; /* not BlackPixelOfScreen (it->xgwa.screen); */ + + int x_length=ANALOGTV_PIC_LEN; + int y_overscan=5; /* overscan this much top and bottom */ + int y_scanlength=ANALOGTV_VISLINES+2*y_overscan; + + if (target_w > 0) x_length = x_length * target_w / it->xgwa.width; + if (target_h > 0) y_scanlength = y_scanlength * target_h / it->xgwa.height; + + img_w = pic_im->width; + img_h = pic_im->height; + + xoff = ANALOGTV_PIC_LEN * xoff / it->xgwa.width; + yoff = ANALOGTV_VISLINES * yoff / it->xgwa.height; + + for (i=0; idpy, it->colormap, col1, x_length); + XQueryColors(it->dpy, it->colormap, col2, x_length); + for (i=0; i<7; i++) fyx[i]=fyy[i]=0; + for (i=0; i<4; i++) fix[i]=fiy[i]=fqx[i]=fqy[i]=0.0; + + for (x=0; x>7; + rawi=(10*col1[x].red - 4*col1[x].green - 5*col1[x].blue + + 10*col2[x].red - 4*col2[x].green - 5*col2[x].blue)>>7; + rawq=( 3*col1[x].red - 8*col1[x].green + 5*col1[x].blue + + 3*col2[x].red - 8*col2[x].green + 5*col2[x].blue)>>7; + + /* Filter y at with a 4-pole low-pass Butterworth filter at 3.5 MHz + with an extra zero at 3.5 MHz, from + mkfilter -Bu -Lp -o 4 -a 2.1428571429e-01 0 -Z 2.5e-01 -l */ + + fyx[0] = fyx[1]; fyx[1] = fyx[2]; fyx[2] = fyx[3]; + fyx[3] = fyx[4]; fyx[4] = fyx[5]; fyx[5] = fyx[6]; + fyx[6] = (rawy * 1897) >> 16; + fyy[0] = fyy[1]; fyy[1] = fyy[2]; fyy[2] = fyy[3]; + fyy[3] = fyy[4]; fyy[4] = fyy[5]; fyy[5] = fyy[6]; + fyy[6] = (fyx[0]+fyx[6]) + 4*(fyx[1]+fyx[5]) + 7*(fyx[2]+fyx[4]) + 8*fyx[3] + + ((-151*fyy[2] + 8115*fyy[3] - 38312*fyy[4] + 36586*fyy[5]) >> 16); + filty = fyy[6]; + + /* Filter I at 1.5 MHz. 3 pole Butterworth from + mkfilter -Bu -Lp -o 3 -a 1.0714285714e-01 0 */ + + fix[0] = fix[1]; fix[1] = fix[2]; fix[2] = fix[3]; + fix[3] = (rawi * 1413) >> 16; + fiy[0] = fiy[1]; fiy[1] = fiy[2]; fiy[2] = fiy[3]; + fiy[3] = (fix[0]+fix[3]) + 3*(fix[1]+fix[2]) + + ((16559*fiy[0] - 72008*fiy[1] + 109682*fiy[2]) >> 16); + filti = fiy[3]; + + /* Filter Q at 0.5 MHz. 3 pole Butterworth from + mkfilter -Bu -Lp -o 3 -a 3.5714285714e-02 0 -l */ + + fqx[0] = fqx[1]; fqx[1] = fqx[2]; fqx[2] = fqx[3]; + fqx[3] = (rawq * 75) >> 16; + fqy[0] = fqy[1]; fqy[1] = fqy[2]; fqy[2] = fqy[3]; + fqy[3] = (fqx[0]+fqx[3]) + 3 * (fqx[1]+fqx[2]) + + ((2612*fqy[0] - 9007*fqy[1] + 10453 * fqy[2]) >> 12); + filtq = fqy[3]; + + + composite = filty + ((multiq[x] * filti + multiq[x+3] * filtq)>>12); + composite = ((composite*100)>>14) + ANALOGTV_BLACK_LEVEL; + if (composite>125) composite=125; + if (composite<0) composite=0; + + input->signal[y-y_overscan+ANALOGTV_TOP+yoff][x+ANALOGTV_PIC_START+xoff] = composite; + } + } + + return 1; +} + +#if 0 +void analogtv_channel_noise(analogtv_input *it, analogtv_input *s2) +{ + int x,y,newsig; + int change=random()%ANALOGTV_V; + unsigned int fastrnd=random(); + double hso=(int)(random()%1000)-500; + int yofs=random()%ANALOGTV_V; + int noise; + + for (y=change; yline_hsync[y] = s2->line_hsync[y] + (int)hso; + hso *= 0.9; + for (x=0; x>16; + newsig=s2->signal[s2y][x] + noise; + if (newsig>120) newsig=120; + if (newsig<0) newsig=0; + it->signal[y][x]=newsig; + } + } + s2->vsync=yofs; +} +#endif + + +#ifdef FIXME +/* add hash */ + if (it->hashnoise_times[lineno]) { + int hnt=it->hashnoise_times[lineno] - input->line_hsync[lineno]; + + if (hnt>=0 && hnt ANALOGTV_PIC_LEN-hnt) len=ANALOGTV_PIC_LEN-hnt; + for (i=0; imultipath > 0.0) { + for (i=0; ighostfir2[i] += + -(rec->ghostfir2[i]/16.0) + rec->multipath * (frand(0.02)-0.01); + } + if (random()%20==0) { + rec->ghostfir2[random()%(ANALOGTV_GHOSTFIR_LEN)] + = rec->multipath * (frand(0.08)-0.04); + } + for (i=0; ighostfir[i] = 0.8*rec->ghostfir[i] + 0.2*rec->ghostfir2[i]; + } + + if (0) { + rec->hfloss2 += -(rec->hfloss2/16.0) + rec->multipath * (frand(0.08)-0.04); + rec->hfloss = 0.5*rec->hfloss + 0.5*rec->hfloss2; + } + + } else { + for (i=0; ighostfir[i] = (i>=ANALOGTV_GHOSTFIR_LEN/2) ? ((i&1) ? +0.04 : -0.08) /ANALOGTV_GHOSTFIR_LEN + : 0.0; + } + } +} + + +/* jwz: since MacOS doesn't have "6x10", I dumped this font to a PNG... + */ + +#include "images/gen/6x10font_png.h" + +void +analogtv_make_font(Display *dpy, Window window, analogtv_font *f, + int w, int h, char *fontname) +{ + int i; + XFontStruct *font; + Pixmap text_pm; + GC gc; + XGCValues gcv; + XWindowAttributes xgwa; + + f->char_w = w; + f->char_h = h; + + XGetWindowAttributes (dpy, window, &xgwa); + + if (fontname && !strcmp (fontname, "6x10")) { + + int pix_w, pix_h; + XWindowAttributes xgwa; + Pixmap m = 0; + Pixmap p = image_data_to_pixmap (dpy, window, + _6x10font_png, sizeof(_6x10font_png), + &pix_w, &pix_h, &m); + XImage *im = XGetImage (dpy, p, 0, 0, pix_w, pix_h, ~0L, ZPixmap); + XImage *mm = XGetImage (dpy, m, 0, 0, pix_w, pix_h, 1, XYPixmap); + unsigned long black = BlackPixelOfScreen (DefaultScreenOfDisplay (dpy)); + int x, y; + + XFreePixmap (dpy, p); + XFreePixmap (dpy, m); + if (pix_w != 256*7) abort(); + if (pix_h != 10) abort(); + + XGetWindowAttributes (dpy, window, &xgwa); + f->text_im = XCreateImage (dpy, xgwa.visual, 1, XYBitmap, 0, 0, + pix_w, pix_h, 8, 0); + f->text_im->data = malloc (f->text_im->bytes_per_line * f->text_im->height); + + /* Convert deep image to 1 bit */ + for (y = 0; y < pix_h; y++) + for (x = 0; x < pix_w; x++) + XPutPixel (f->text_im, x, y, + (XGetPixel (mm, x, y) + ? XGetPixel (im, x, y) == black + : 0)); + XDestroyImage (im); + XDestroyImage (mm); + + } else if (fontname) { + + font = load_font_retry (dpy, fontname); + if (!font) { + fprintf(stderr, "analogtv: can't load font %s\n", fontname); + abort(); + } + + text_pm=XCreatePixmap(dpy, window, 256*f->char_w, f->char_h, 1); + + memset(&gcv, 0, sizeof(gcv)); + gcv.foreground=1; + gcv.background=0; + gcv.font=font->fid; + gc=XCreateGC(dpy, text_pm, GCFont|GCBackground|GCForeground, &gcv); +# ifdef HAVE_JWXYZ + jwxyz_XSetAntiAliasing (dpy, gc, False); +# endif + + XSetForeground(dpy, gc, 0); + XFillRectangle(dpy, text_pm, gc, 0, 0, 256*f->char_w, f->char_h); + XSetForeground(dpy, gc, 1); + for (i=0; i<256; i++) { + char c=i; + int x=f->char_w*i+1; + int y=f->char_h*8/10; + XDrawString(dpy, text_pm, gc, x, y, &c, 1); + } + f->text_im = XGetImage(dpy, text_pm, 0, 0, 256*f->char_w, f->char_h, + 1, XYPixmap); +# if 0 + XWriteBitmapFile(dpy, "/tmp/tvfont.xbm", text_pm, + 256*f->char_w, f->char_h, -1, -1); +# endif + XFreeGC(dpy, gc); + XFreePixmap(dpy, text_pm); + } else { + f->text_im = XCreateImage(dpy, xgwa.visual, 1, XYPixmap, 0, 0, + 256*f->char_w, f->char_h, 8, 0); + f->text_im->data = (char *)calloc(f->text_im->height, + f->text_im->bytes_per_line); + + } + f->x_mult=4; + f->y_mult=2; +} + +int +analogtv_font_pixel(analogtv_font *f, int c, int x, int y) +{ + if (x<0 || x>=f->char_w) return 0; + if (y<0 || y>=f->char_h) return 0; + if (c<0 || c>=256) return 0; + return XGetPixel(f->text_im, c*f->char_w + x, y) ? 1 : 0; +} + +void +analogtv_font_set_pixel(analogtv_font *f, int c, int x, int y, int value) +{ + if (x<0 || x>=f->char_w) return; + if (y<0 || y>=f->char_h) return; + if (c<0 || c>=256) return; + + XPutPixel(f->text_im, c*f->char_w + x, y, value); +} + +void +analogtv_font_set_char(analogtv_font *f, int c, char *s) +{ + int value,x,y; + + if (c<0 || c>=256) return; + + for (y=0; ychar_h; y++) { + for (x=0; xchar_w; x++) { + if (!*s) return; + value=(*s==' ') ? 0 : 1; + analogtv_font_set_pixel(f, c, x, y, value); + s++; + } + } +} + +void +analogtv_lcp_to_ntsc(double luma, double chroma, double phase, int ntsc[4]) +{ + int i; + for (i=0; i<4; i++) { + double w=90.0*i + phase; + double val=luma + chroma * (cos(3.1415926/180.0*w)); + if (val<0.0) val=0.0; + if (val>127.0) val=127.0; + ntsc[i]=(int)val; + } +} + +void +analogtv_draw_solid(analogtv_input *input, + int left, int right, int top, int bot, + int ntsc[4]) +{ + int x,y; + + if (right-left<4) right=left+4; + if (bot-top<1) bot=top+1; + + for (y=top; ysignal[y][x] = ntsc[x&3]; + } + } +} + + +void +analogtv_draw_solid_rel_lcp(analogtv_input *input, + double left, double right, double top, double bot, + double luma, double chroma, double phase) +{ + int ntsc[4]; + + int topi=(int)(ANALOGTV_TOP + ANALOGTV_VISLINES*top); + int boti=(int)(ANALOGTV_TOP + ANALOGTV_VISLINES*bot); + int lefti=(int)(ANALOGTV_VIS_START + ANALOGTV_VIS_LEN*left); + int righti=(int)(ANALOGTV_VIS_START + ANALOGTV_VIS_LEN*right); + + analogtv_lcp_to_ntsc(luma, chroma, phase, ntsc); + analogtv_draw_solid(input, lefti, righti, topi, boti, ntsc); +} + + +void +analogtv_draw_char(analogtv_input *input, analogtv_font *f, + int c, int x, int y, int ntsc[4]) +{ + int yc,xc,ys,xs,pix; + + for (yc=0; ycchar_h; yc++) { + for (ys=y + yc*f->y_mult; ysy_mult; ys++) { + if (ys<0 || ys>=ANALOGTV_V) continue; + + for (xc=0; xcchar_w; xc++) { + pix=analogtv_font_pixel(f, c, xc, yc); + + for (xs=x + xc*f->x_mult; xsx_mult; xs++) { + if (xs<0 || xs>=ANALOGTV_H) continue; + if (pix) { + input->signal[ys][xs] = ntsc[xs&3]; + } + } + } + } + } +} + +void +analogtv_draw_string(analogtv_input *input, analogtv_font *f, + char *s, int x, int y, int ntsc[4]) +{ + while (*s) { + analogtv_draw_char(input, f, *s, x, y, ntsc); + x += f->char_w * 4; + s++; + } +} + +void +analogtv_draw_string_centered(analogtv_input *input, analogtv_font *f, + char *s, int x, int y, int ntsc[4]) +{ + int width=strlen(s) * f->char_w * 4; + x -= width/2; + + analogtv_draw_string(input, f, s, x, y, ntsc); +} diff --git a/hacks/analogtv.h b/hacks/analogtv.h new file mode 100644 index 0000000..e3170f1 --- /dev/null +++ b/hacks/analogtv.h @@ -0,0 +1,338 @@ +/* analogtv, Copyright (c) 2003-2018 Trevor Blackwell + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +#ifndef _XSCREENSAVER_ANALOGTV_H +#define _XSCREENSAVER_ANALOGTV_H + +#include "thread_util.h" +#include "xshm.h" + +#if defined(USE_IPHONE) || defined(HAVE_ANDROID) +# define HAVE_MOBILE +#endif + +/* + You'll need these to generate standard NTSC TV signals + */ +enum { + /* We don't handle interlace here */ + ANALOGTV_V=262, + ANALOGTV_TOP=30, + ANALOGTV_VISLINES=200, + ANALOGTV_BOT=ANALOGTV_TOP + ANALOGTV_VISLINES, + + /* This really defines our sampling rate, 4x the colorburst + frequency. Handily equal to the Apple II's dot clock. + You could also make a case for using 3x the colorburst freq, + but 4x isn't hard to deal with. */ + ANALOGTV_H=912, + + /* Each line is 63500 nS long. The sync pulse is 4700 nS long, etc. + Define sync, back porch, colorburst, picture, and front porch + positions */ + ANALOGTV_SYNC_START=0, + ANALOGTV_BP_START=4700*ANALOGTV_H/63500, + ANALOGTV_CB_START=5800*ANALOGTV_H/63500, + /* signal[row][ANALOGTV_PIC_START] is the first displayed pixel */ + ANALOGTV_PIC_START=9400*ANALOGTV_H/63500, + ANALOGTV_PIC_LEN=52600*ANALOGTV_H/63500, + ANALOGTV_FP_START=62000*ANALOGTV_H/63500, + ANALOGTV_PIC_END=ANALOGTV_FP_START, + + /* TVs scan past the edges of the picture tube, so normally you only + want to use about the middle 3/4 of the nominal scan line. + */ + ANALOGTV_VIS_START=ANALOGTV_PIC_START + (ANALOGTV_PIC_LEN*1/8), + ANALOGTV_VIS_END=ANALOGTV_PIC_START + (ANALOGTV_PIC_LEN*7/8), + ANALOGTV_VIS_LEN=ANALOGTV_VIS_END-ANALOGTV_VIS_START, + + ANALOGTV_HASHNOISE_LEN=6, + + ANALOGTV_GHOSTFIR_LEN=4, + + /* analogtv.signal is in IRE units, as defined below: */ + ANALOGTV_WHITE_LEVEL=100, + ANALOGTV_GRAY50_LEVEL=55, + ANALOGTV_GRAY30_LEVEL=35, + ANALOGTV_BLACK_LEVEL=10, + ANALOGTV_BLANK_LEVEL=0, + ANALOGTV_SYNC_LEVEL=-40, + ANALOGTV_CB_LEVEL=20, + + ANALOGTV_SIGNAL_LEN=ANALOGTV_V*ANALOGTV_H, + + /* The number of intensity levels we deal with for gamma correction &c */ + ANALOGTV_CV_MAX=1024, + + /* MAX_LINEHEIGHT corresponds to 2400 vertical pixels, beyond which + it interpolates extra black lines. */ + ANALOGTV_MAX_LINEHEIGHT=12 + +}; + +typedef struct analogtv_input_s { + signed char signal[ANALOGTV_V+1][ANALOGTV_H]; + + int do_teletext; + + /* for client use */ + void (*updater)(struct analogtv_input_s *inp); + void *client_data; + double next_update_time; + +} analogtv_input; + +typedef struct analogtv_font_s { + XImage *text_im; + int char_w, char_h; + int x_mult, y_mult; +} analogtv_font; + +typedef struct analogtv_reception_s { + + analogtv_input *input; + double ofs; + double level; + double multipath; + double freqerr; + + double ghostfir[ANALOGTV_GHOSTFIR_LEN]; + double ghostfir2[ANALOGTV_GHOSTFIR_LEN]; + + double hfloss; + double hfloss2; + +} analogtv_reception; + +/* + The rest of this should be considered mostly opaque to the analogtv module. + */ + +struct analogtv_yiq_s { + float y,i,q; +} /*yiq[ANALOGTV_PIC_LEN+10] */; + +typedef struct analogtv_s { + + Display *dpy; + Window window; + Screen *screen; + XWindowAttributes xgwa; + + struct threadpool threads; + +#if 0 + unsigned int onscreen_signature[ANALOGTV_V]; +#endif + + int n_colors; + + int interlace; + int interlace_counter; + + float agclevel; + + /* If you change these, call analogtv_set_demod */ + float tint_control,color_control,brightness_control,contrast_control; + float height_control, width_control, squish_control; + float horiz_desync; + float squeezebottom; + float powerup; + + /* internal cache */ + int blur_mult; + + /* For fast display, set fakeit_top, fakeit_bot to + the scanlines (0..ANALOGTV_V) that can be preserved on screen. + fakeit_scroll is the number of scan lines to scroll it up, + or 0 to not scroll at all. It will DTRT if asked to scroll from + an offscreen region. + */ + int fakeit_top; + int fakeit_bot; + int fakeit_scroll; + int redraw_all; + + int use_cmap,use_color; + int bilevel_signal; + + XShmSegmentInfo shm_info; + int visdepth,visclass,visbits; + int red_invprec, red_shift; + int green_invprec, green_shift; + int blue_invprec, blue_shift; + unsigned long red_mask, green_mask, blue_mask; + + Colormap colormap; + int usewidth,useheight,xrepl,subwidth; + XImage *image; /* usewidth * useheight */ + GC gc; + int screen_xo,screen_yo; /* centers image in window */ + + int flutter_horiz_desync; + int flutter_tint; + + struct timeval last_display_time; + int need_clear; + + + /* Add hash (in the radio sense, not the programming sense.) These + are the small white streaks that appear in quasi-regular patterns + all over the screen when someone is running the vacuum cleaner or + the blender. We also set shrinkpulse for one period which + squishes the image horizontally to simulate the temporary line + voltate drop when someone turns on a big motor */ + double hashnoise_rpm; + int hashnoise_counter; + int hashnoise_times[ANALOGTV_V]; + int hashnoise_signal[ANALOGTV_V]; + int hashnoise_on; + int hashnoise_enable; + int shrinkpulse; + + float crtload[ANALOGTV_V]; + + unsigned int red_values[ANALOGTV_CV_MAX]; + unsigned int green_values[ANALOGTV_CV_MAX]; + unsigned int blue_values[ANALOGTV_CV_MAX]; + + unsigned long colors[256]; + int cmap_y_levels; + int cmap_i_levels; + int cmap_q_levels; + + float tint_i, tint_q; + + int cur_hsync; + int line_hsync[ANALOGTV_V]; + int cur_vsync; + double cb_phase[4]; + double line_cb_phase[ANALOGTV_V][4]; + + int channel_change_cycles; + double rx_signal_level; + float *rx_signal; + + struct { + int index; + double value; + } leveltable[ANALOGTV_MAX_LINEHEIGHT+1][ANALOGTV_MAX_LINEHEIGHT+1]; + + /* Only valid during draw. */ + unsigned random0, random1; + double noiselevel; + const analogtv_reception *const *recs; + unsigned rec_count; + + float *signal_subtotals; + + float puheight; +} analogtv; + + +analogtv *analogtv_allocate(Display *dpy, Window window); +analogtv_input *analogtv_input_allocate(void); + +/* call if window size changes */ +void analogtv_reconfigure(analogtv *it); + +void analogtv_set_defaults(analogtv *it, char *prefix); +void analogtv_release(analogtv *it); +int analogtv_set_demod(analogtv *it); +void analogtv_setup_frame(analogtv *it); +void analogtv_setup_sync(analogtv_input *input, int do_cb, int do_ssavi); +void analogtv_draw(analogtv *it, double noiselevel, + const analogtv_reception *const *recs, unsigned rec_count); + +int analogtv_load_ximage(analogtv *it, analogtv_input *input, + XImage *pic_im, XImage *mask_im, + int xoff, int yoff, int width, int height); + +void analogtv_reception_update(analogtv_reception *inp); + +void analogtv_setup_teletext(analogtv_input *input); + + +/* Functions for rendering content into an analogtv_input */ + +void analogtv_make_font(Display *dpy, Window window, + analogtv_font *f, int w, int h, char *fontname); +int analogtv_font_pixel(analogtv_font *f, int c, int x, int y); +void analogtv_font_set_pixel(analogtv_font *f, int c, int x, int y, int value); +void analogtv_font_set_char(analogtv_font *f, int c, char *s); +void analogtv_lcp_to_ntsc(double luma, double chroma, double phase, + int ntsc[4]); + + +void analogtv_draw_solid(analogtv_input *input, + int left, int right, int top, int bot, + int ntsc[4]); + +void analogtv_draw_solid_rel_lcp(analogtv_input *input, + double left, double right, + double top, double bot, + double luma, double chroma, double phase); + +void analogtv_draw_char(analogtv_input *input, analogtv_font *f, + int c, int x, int y, int ntsc[4]); +void analogtv_draw_string(analogtv_input *input, analogtv_font *f, + char *s, int x, int y, int ntsc[4]); +void analogtv_draw_string_centered(analogtv_input *input, analogtv_font *f, + char *s, int x, int y, int ntsc[4]); + +int analogtv_handle_events (analogtv *it); + +#ifdef HAVE_XSHM_EXTENSION +#define ANALOGTV_DEFAULTS_SHM "*useSHM: True", +#else +#define ANALOGTV_DEFAULTS_SHM +#endif + +#ifndef HAVE_MOBILE +# define ANALOGTV_DEF_BRIGHTNESS "2" +# define ANALOGTV_DEF_CONTRAST "150" +#else + /* Need to really crank this up for it to look good on the iPhone screen. */ +# define ANALOGTV_DEF_BRIGHTNESS "3" +# define ANALOGTV_DEF_CONTRAST "400" +#endif + +/* Brightness: useful range is around -75 to 100. + Contrast: useful range is around 0 - 500. + Color: useful range is around +/- 500. + Tint: range is mod 360. + + The values in the 'analogtv' struct are the resource divided by 100.0, + except for tint, which is exact. + */ + +#define ANALOGTV_DEFAULTS \ + "*TVColor: 70", \ + "*TVTint: 5", \ + "*TVBrightness: " ANALOGTV_DEF_BRIGHTNESS, \ + "*TVContrast: " ANALOGTV_DEF_CONTRAST, \ + "*Background: Black", \ + "*use_cmap: 0", \ + "*geometry: 800x600", \ + "*fpsSolid: True", \ + "*lowrez: True", \ + THREAD_DEFAULTS \ + ANALOGTV_DEFAULTS_SHM + +#define ANALOGTV_OPTIONS \ + THREAD_OPTIONS \ + { "-use-cmap", ".use_cmap", XrmoptionSepArg, 0 }, \ + { "-tv-color", ".TVColor", XrmoptionSepArg, 0 }, \ + { "-tv-tint", ".TVTint", XrmoptionSepArg, 0 }, \ + { "-tv-brightness", ".TVBrightness", XrmoptionSepArg, 0 }, \ + { "-tv-contrast", ".TVContrast", XrmoptionSepArg, 0 }, + +#endif /* _XSCREENSAVER_ANALOGTV_H */ diff --git a/hacks/anemone.c b/hacks/anemone.c new file mode 100644 index 0000000..deedb27 --- /dev/null +++ b/hacks/anemone.c @@ -0,0 +1,448 @@ +/* anemone, Copyright (c) 2001 Gabriel Finch + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +/*------------------------------------------------------------------------ + | + | FILE anemone.c + | MODULE OF xscreensaver + | + | DESCRIPTION Anemone. + | + | WRITTEN BY Gabriel Finch + | + | + | + | MODIFICATIONS june 2001 started + | + +----------------------------------------------------------------------*/ + + +#include +#include "screenhack.h" + + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION +#include "xdbe.h" +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + + +/*-----------------------------------------------------------------------+ + | PRIVATE DATA | + +-----------------------------------------------------------------------*/ + + +#define TWO_PI (2.0 * M_PI) +#define RND(x) (random() % (x)) +#define MAXPEND 2000 +#define MAXPTS 200 +#define TRUE 1 +#define FALSE 0 + + +typedef struct { + double x,y,z; + int sx,sy,sz; +} vPend; + +typedef struct { + long col; + int numpt; + int growth; + unsigned short rate; +} appDef; + +struct state { + Display *dpy; + Pixmap b, ba, bb; + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + XdbeBackBuffer backb; +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + + int arms; /* number of arms */ + int finpoints; /* final number of points in each array. */ + long delay; /* usecs to wait between updates. */ + + int scrWidth, scrHeight; + GC gcDraw, gcClear; + + Bool dbuf; + int width; + + vPend *vPendage; /* 3D representation of appendages */ + appDef *appD; /* defaults */ + vPend *vCurr, *vNext; + appDef *aCurr; + + double turn, turndelta; + + int mx, my; /* max screen coordinates. */ + int withdraw; + + XGCValues gcv; + Colormap cmap; + XColor *colors; + int ncolors; +}; + + + +/*-----------------------------------------------------------------------+ + | PUBLIC DATA | + +-----------------------------------------------------------------------*/ + + + +/*-----------------------------------------------------------------------+ + | PRIVATE FUNCTIONS | + +-----------------------------------------------------------------------*/ + +static void * +xmalloc(size_t size) +{ + void *ret; + + if ((ret = malloc(size)) == NULL) { + fprintf(stderr, "anemone: out of memory\n"); + exit(1); + } + return ret; +} + + +static void +initAppendages(struct state *st) +{ + int i; + /*int marginx, marginy; */ + + /*double scalex, scaley;*/ + + double x,y,z,dist; + + st->mx = st->scrWidth - 1; + st->my = st->scrHeight - 1; + + /* each appendage will have: colour, + number of points, and a grow or shrink indicator */ + + /* added: growth rate 1-10 (smaller==faster growth) */ + /* each appendage needs virtual coords (x,y,z) with y and z combining to + give the screen y */ + + st->vPendage = (vPend *) xmalloc((st->finpoints + 1) * sizeof(vPend) * st->arms); + st->appD = (appDef *) xmalloc(sizeof(appDef) * st->arms); + + + for (i = 0; i < st->arms; i++) { + st->aCurr = st->appD + i; + st->vCurr = st->vPendage + (st->finpoints + 1) * i; + st->vNext = st->vCurr + 1; + + st->aCurr->col = st->colors[random() % st->ncolors].pixel; + st->aCurr->numpt = 1; + st->aCurr->growth = st->finpoints / 2 + RND(st->finpoints / 2); + st->aCurr->rate = RND(11) * RND(11); + + do { + x = (1 - RND(1001) / 500); + y = (1 - RND(1001) / 500); + z = (1 - RND(1001) / 500); + dist = x * x + y * y + z * z; + } while (dist >= 1.); + + st->vCurr->x = x * 200; + st->vCurr->y = st->my / 2 + y * 200; + st->vCurr->z = 0 + z * 200; + + /* start the arm going outwards */ + st->vCurr->sx = st->vCurr->x / 5; + st->vCurr->sy = (st->vCurr->y - st->my / 2) / 5; + st->vCurr->sz = (st->vCurr->z) / 5; + + + st->vNext->x = st->vCurr->x + st->vCurr->sx; + st->vNext->y = st->vCurr->y + st->vCurr->sy; + st->vNext->z = st->vCurr->z + st->vCurr->sz; + } +} + +static void * +anemone_init (Display *disp, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XWindowAttributes wa; + + st->dpy = disp; + st->turn = 0.; + + st->width = get_integer_resource(st->dpy, "width", "Integer"); + st->arms = get_integer_resource(st->dpy, "arms", "Integer"); + st->finpoints = get_integer_resource(st->dpy, "finpoints", "Integer"); + st->delay = get_integer_resource(st->dpy, "delay", "Integer"); + st->withdraw = get_integer_resource(st->dpy, "withdraw", "Integer"); + st->turndelta = get_float_resource(st->dpy, "turnspeed", "float") / 100000; + + st->dbuf = TRUE; + +# ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */ + st->dbuf = False; +# endif + + st->b = st->ba = st->bb = 0; /* double-buffer to reduce flicker */ +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + st->b = st->backb = xdbe_get_backbuffer (st->dpy, window, XdbeUndefined); +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + + + XGetWindowAttributes(st->dpy, window, &wa); + st->scrWidth = wa.width; + st->scrHeight = wa.height; + st->cmap = wa.colormap; + + st->ncolors = get_integer_resource (st->dpy, "colors", "Colors"); + st->ncolors += 3; + st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1)); + make_smooth_colormap (wa.screen, wa.visual, st->cmap, + st->colors, &st->ncolors, + True, 0, True); + + st->gcDraw = XCreateGC(st->dpy, window, 0, &st->gcv); + st->gcv.foreground = get_pixel_resource(st->dpy, st->cmap, + "background", "Background"); + st->gcClear = XCreateGC(st->dpy, window, GCForeground, &st->gcv); + + if (st->dbuf) { + if (!st->b) + { + st->ba = XCreatePixmap (st->dpy, window, st->scrWidth, st->scrHeight, wa.depth); + st->bb = XCreatePixmap (st->dpy, window, st->scrWidth, st->scrHeight, wa.depth); + st->b = st->ba; + } + } + else + { + st->b = window; + } + + if (st->ba) XFillRectangle (st->dpy, st->ba, st->gcClear, 0, 0, st->scrWidth, st->scrHeight); + if (st->bb) XFillRectangle (st->dpy, st->bb, st->gcClear, 0, 0, st->scrWidth, st->scrHeight); + + XClearWindow(st->dpy, window); + XSetLineAttributes(st->dpy, st->gcDraw, st->width, LineSolid, CapRound, JoinBevel); + + initAppendages(st); + + return st; +} + + +static void +createPoints(struct state *st) +{ + int i; + int withdrawall = RND(st->withdraw); + + for (i = 0; i< st->arms; i++) { + st->aCurr = st->appD + i; + if (!withdrawall) { + st->aCurr->growth = -st->finpoints; + st->turndelta = -st->turndelta; + } + + else if (withdrawall<11) st->aCurr->growth = -st->aCurr->numpt; + + else if (RND(100)aCurr->rate) { + if (st->aCurr->growth>0) { + if (!(--st->aCurr->growth)) st->aCurr->growth = -RND(st->finpoints) - 1; + st->vCurr = st->vPendage + (st->finpoints + 1) * i + st->aCurr->numpt - 1; + if (st->aCurr->numptfinpoints - 1) { + /* add a piece */ + st->vNext = st->vCurr + 1; + st->aCurr->numpt++; + st->vNext->sx = st->vCurr->sx + RND(3) - 1; + st->vNext->sy = st->vCurr->sy + RND(3) - 1; + st->vNext->sz = st->vCurr->sz + RND(3) - 1; + st->vCurr = st->vNext + 1; + st->vCurr->x = st->vNext->x + st->vNext->sx; + st->vCurr->y = st->vNext->y + st->vNext->sy; + st->vCurr->z = st->vNext->z + st->vNext->sz; + } + } + } + } +} + + +static void +drawImage(struct state *st, Drawable curr_window, double sint, double cost) +{ + int q,numpt,mx2 = st->mx / 2; + double cx,cy,cz,nx = 0,ny = 0,nz = 0; + + if ((numpt = st->aCurr->numpt)==1) return; + XSetForeground(st->dpy, st->gcDraw, st->aCurr->col); + + st->vNext = st->vCurr + 1; + + cx = st->vCurr->x; + cy = st->vCurr->y; + cz = st->vCurr->z; + + + for (q = 0; q < numpt - 1; q++) { + nx = st->vNext->x + 2 - RND(5); + ny = st->vNext->y + 2 - RND(5); + nz = st->vNext->z + 2 - RND(5); + + XDrawLine(st->dpy, curr_window, st->gcDraw, + mx2 + cx * cost - cz * sint, cy, + mx2 + nx * cost - nz * sint, ny); + st->vCurr++; + st->vNext++; + + cx = nx; + cy = ny; + cz = nz; + } + XSetLineAttributes(st->dpy, st->gcDraw, st->width * 3, + LineSolid, CapRound, JoinBevel); + XDrawLine(st->dpy, curr_window, st->gcDraw, + st->mx / 2 + cx * cost - cz * sint, cy, + st->mx / 2 + nx * cost - nz * sint, ny); + XSetLineAttributes(st->dpy, st->gcDraw, st->width, + LineSolid, CapRound, JoinBevel); + +} + +static void +animateAnemone(struct state *st, Drawable curr_window) +{ + int i; + double sint = sin(st->turn),cost = cos(st->turn); + + st->aCurr = st->appD; + for (i = 0; i< st->arms; i++) { + st->vCurr = st->vPendage + (st->finpoints + 1) * i; + if (RND(25)aCurr->rate) { + if (st->aCurr->growth<0) { + st->aCurr->numpt -= st->aCurr->numpt>1; + if (!(++st->aCurr->growth)) st->aCurr->growth = RND(st->finpoints - st->aCurr->numpt) + 1; + } + } + drawImage(st, curr_window, sint, cost); + st->turn += st->turndelta; + st->aCurr++; + } + createPoints(st); + + if (st->turn >= TWO_PI) st->turn -= TWO_PI; +} + +static unsigned long +anemone_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + XFillRectangle (st->dpy, st->b, st->gcClear, 0, 0, st->scrWidth, st->scrHeight); + + animateAnemone(st, st->b); + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + if (st->backb) + { + XdbeSwapInfo info[1]; + info[0].swap_window = window; + info[0].swap_action = XdbeUndefined; + XdbeSwapBuffers (st->dpy, info, 1); + } + else +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + if (st->dbuf) + { + XCopyArea (st->dpy, st->b, window, st->gcClear, 0, 0, + st->scrWidth, st->scrHeight, 0, 0); + st->b = (st->b == st->ba ? st->bb : st->ba); + } + + return st->delay; +} + + +static void +anemone_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->scrWidth = w; + st->scrHeight = h; +#if 0 + if (st->dbuf) { + XWindowAttributes wa; + XGetWindowAttributes(dpy, window, &wa); + if (st->ba) XFreePixmap (dpy, st->ba); + if (st->bb) XFreePixmap (dpy, st->bb); + st->ba = XCreatePixmap (dpy, window, st->scrWidth, st->scrHeight, wa.depth); + st->bb = XCreatePixmap (dpy, window, st->scrWidth, st->scrHeight, wa.depth); + st->b = st->ba; + } +#endif +} + +static Bool +anemone_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +anemone_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + if (st->vPendage) free (st->vPendage); + if (st->appD) free (st->appD); + free (st); +} + + + +static const char *anemone_defaults [] = { + ".background: black", + "*arms: 128", + "*width: 2", + "*finpoints: 64", + "*delay: 40000", + "*withdraw: 1200", + "*turnspeed: 50", + "*colors: 20", +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + "*useDBE: True", +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ +#ifdef HAVE_MOBILE + "*ignoreRotation: True", +#endif + 0 +}; + + +static XrmOptionDescRec anemone_options [] = { + { "-arms", ".arms", XrmoptionSepArg, 0 }, + { "-finpoints", ".finpoints", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-width", ".width", XrmoptionSepArg, 0 }, + { "-withdraw", ".withdraw", XrmoptionSepArg, 0 }, + { "-turnspeed", ".turnspeed", XrmoptionSepArg, 0 }, + { "-colors", ".colors", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("Anemone", anemone) diff --git a/hacks/anemone.man b/hacks/anemone.man new file mode 100644 index 0000000..463a999 --- /dev/null +++ b/hacks/anemone.man @@ -0,0 +1,74 @@ +.TH XScreenSaver 1 "" "X Version 11" +.SH NAME +anemone - wiggling tentacles. +.SH SYNOPSIS +.B anemone +[\-display \fIhost:display.screen\fP] +[\-visual \fIvisual\fP] +[\-window] +[\-root] +[\-delay \fInumber\fP] +[\-arms \fInumber\fP] +[\-finpoints \fInumber\fP] +[\-width \fInumber\fP] +[\-fps] +.SH DESCRIPTION +Wiggling tentacles. +.SH OPTIONS +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-delay \fInumber\fP +Per-frame delay, in microseconds. Default: 40000 (0.04 seconds.). +.TP 8 +.B \-arms \fInumber\fP +Arms. 2 - 500. Default: 128. +.TP 8 +.B \-finpoints \fInumber\fP +Tentacles. 3 - 200. Default: 64. +.TP 8 +.B \-withdraw \fInumber\fP +Frequency that the arms withdraw. Arms withdraw on randomly generated +values between 1 and 11; this value determines the maximum value of +that range. So 100 spends a lot of time withdrawn, while 1000,000 tends +not to withdraw at all. Default: 1200. +.TP 8 +.B \-turnspeed \fInumber\fP +How fast it turns. At zero, not at all, all they way up to thousands +which are very fast indeed. Default: 50. +.TP 8 +.B \-width \fInumber\fP +Thickness. 1 - 10. Default: 2. +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1) +.SH COPYRIGHT +Copyright \(co 2002 by Gabriel Finch. Permission to use, copy, modify, +distribute, and sell this software and its documentation for any purpose is +hereby granted without fee, provided that the above copyright notice appear +in all copies and that both that copyright notice and this permission notice +appear in supporting documentation. No representations are made about the +suitability of this software for any purpose. It is provided "as is" without +express or implied warranty. +.SH AUTHOR +Gabriel Finch. diff --git a/hacks/anemotaxis.c b/hacks/anemotaxis.c new file mode 100644 index 0000000..9f240e8 --- /dev/null +++ b/hacks/anemotaxis.c @@ -0,0 +1,755 @@ +/* anemotaxis, Copyright (c) 2004 Eugene Balkovski + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation. No representations are made + * about the suitability of this software for any purpose. It is + * provided "as is" without express or implied warranty. + */ + +/*------------------------------------------------------------------------ + | + | FILE anemotaxis.c + | + | DESCRIPTION Anemotaxis + | + | This code illustrates an optimal algorithm designed + | for searching a source of particles on a plane. + | The particles drift in one direction and walk randomly + | in the other. The only information available to the + | searcher is the presence of a particle at its location + | and the local direction from where particle arrived. + | The algorithm "explains" the behavior + | of some animals and insects + | who use olfactory and directional cues to find + | sources of odor (mates, food, home etc) in + | turbulent atmosphere (odor-modulated anemotaxis), + | e.g. male moths locating females who release + | pheromones to attract males. The search trajectories + | resemble the trajectories that the animals follow. + | + | + | WRITTEN BY Eugene Balkovski + | + | MODIFICATIONS june 2004 started + | + +----------------------------------------------------------------------*/ + +/* + Options: + + -distance size of the lattice + -sources number of sources + -searhers number of searcher */ + + +#include "screenhack.h" + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION +#include "xdbe.h" +#endif + + +/*-----------------------------------------------------------------------+ + | PRIVATE DATA | + +-----------------------------------------------------------------------*/ + +#define MAX_DIST 250 +#define MIN_DIST 10 +#define LINE_WIDTH 4 +#define MAX_INV_RATE 5 + +#define RND(x) (random() % (x)) +#define X(x) ((int) (st->ax * (x) + st->bx)) +#define Y(x) ((int) (st->ay * (x) + st->by)) + +typedef struct { + short x; + short y; +} Point; + +typedef struct { + + short y; /* y-coordinate of the particle (relative to the source) */ + + short v; /* velocity of the particle. Allowed values are -1, 0, 1. + 2 means the particle is not valid */ +} YV; + +typedef struct { + + int n; /* size of array xv */ + + YV *yv; /* yv[i] keeps velocity and y-coordinate of the + particle at (i + 1, yv[i].y) relative to the + source */ + + int inv_rate; /* Inverse rate of particle emission (if 0 then + source doesn't emit new particles (although + old ones can still exist )*/ + + Point r; /* Position of the source */ + + long color; + +} Source; + + +typedef struct PList { + Point r; + struct PList *next; +} PList; + +typedef enum {UP_LEFT, UP_RIGHT, LEFT, RIGHT, DONE} State_t; + +typedef struct { + + Point r; /* Current position */ + + Point vertex; /* Position of the vertex of the most recent + cone, which is the region where the source + is located. We do exhaustive search in the + cone until we encounter a new particle, + which gives us a new cone. */ + + State_t state; /* Internal state variable */ + + unsigned char c; /* Concentration at r */ + + short v; /* Velocity at r (good only when c != 0) */ + + PList *hist; /* Trajectory */ + + int rs; /* small shift of x-coordinate to avoid + painting over the same x */ + + long color; + +} Searcher; + +struct state { + Source **source; + Searcher **searcher; + + int max_dist, max_src, max_searcher; + + double ax, ay, bx, by; + int dx, dy; + + Display *dpy; + Window window; + + Pixmap b, ba, bb; + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + XdbeBackBuffer backb; +#endif + + long delay; /* usecs to wait between updates. */ + + int scrWidth, scrHeight; + GC gcDraw, gcClear; + + Bool dbuf; + + XGCValues gcv; + Colormap cmap; + XColor *colors; + int ncolors; +}; + +/*-----------------------------------------------------------------------+ + | PUBLIC DATA | + +-----------------------------------------------------------------------*/ + + + +/*-----------------------------------------------------------------------+ + | PRIVATE FUNCTIONS | + +-----------------------------------------------------------------------*/ + +static void *emalloc(size_t size) +{ + void *ret = malloc(size); + + if (ret == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + return ret; +} + +static Searcher *new_searcher(struct state *st) +{ + Searcher *m = (Searcher *) emalloc(sizeof(Searcher)); + + m->r.x = m->vertex.x = st->max_dist; + + do { + m->r.y = RND(2 * st->max_dist); + } while(m->r.y < MIN_DIST || m->r.y > 2 * st->max_dist - MIN_DIST); + + m->vertex.y = m->r.y; + + m->state = (RND(2) == 0 ? UP_RIGHT : UP_LEFT); + m->hist = NULL; + m->color = st->colors[random() % st->ncolors].pixel; + + m->rs = RND(st->dx); + + return m; +} + +static void destroy_searcher(Searcher *m) +{ + PList *p = m->hist, *q; + + while(p != NULL) { + q = p->next; + free(p); + p = q; + } + + free(m); +} + +static void write_hist(Searcher *m) +{ + PList *l; + + l = m->hist; + m->hist = (PList *) emalloc(sizeof(PList)); + m->hist->next = l; + m->hist->r = m->r; + +} + +static void move_searcher(Searcher *m) +{ + + if(m->c == True) { + write_hist(m); + m->r.x -= 1; + m->r.y -= m->v; + write_hist(m); + m->state = (RND(2) == 0 ? UP_LEFT : UP_RIGHT); + m->vertex = m->r; + return; + + } + + switch(m->state) { + case UP_LEFT: + + m->r.x -= 1; + m->r.y += 1; + m->state = RIGHT; + write_hist(m); + return; + + case RIGHT: + + m->r.y -= 1; + if(m->vertex.x - m->r.x == m->vertex.y - m->r.y) { + write_hist(m); + m->state = UP_RIGHT; + } + return; + + case UP_RIGHT: + + m->r.x -= 1; + m->r.y -= 1; + + m->state = LEFT; + write_hist(m); + return; + + case LEFT: + + m->r.y += 1; + + if(m->vertex.x - m->r.x == m->r.y - m->vertex.y) { + write_hist(m); + m->state = UP_LEFT; + } + return; + + default: + break; + } + +} + +static void evolve_source(Source *s) +{ + + int i; + + /* propagate existing particles */ + + for(i = s->n - 1; i > 0; i--) { + + if(s->yv[i - 1].v == 2) + s->yv[i].v = 2; + else { + s->yv[i].v = RND(3) - 1; + s->yv[i].y = s->yv[i - 1].y + s->yv[i].v; + } + + } + + + if(s->inv_rate > 0 && (RND(s->inv_rate) == 0)) /* emit a particle */ + s->yv[0].y = s->yv[0].v = RND(3) - 1; + else + s->yv[0].v = 2; + +} + +static Source *new_source(struct state *st) +{ + int i; + + Source *s = (Source *) emalloc(sizeof(Source)); + if(st->max_searcher == 0) { + s->r.x = 0; + s->r.y = RND(2 * st->max_dist); + } + else { + s->r.x = RND(st->max_dist / 3); + do { + s->r.y = RND(2 * st->max_dist); + } while(s->r.y < MIN_DIST || s->r.y > 2 * st->max_dist - MIN_DIST); + } + + s->n = st->max_dist - s->r.x; + s->yv = emalloc(sizeof(YV) * s->n); + + for(i = 0; i < s->n; i++) + s->yv[i].v = 2; + + s->inv_rate = RND(MAX_INV_RATE); + + if(s->inv_rate == 0) + s->inv_rate = 1; + + s->color = st->colors[random() % st->ncolors].pixel; + + return s; +} + +static void destroy_source(Source *s) +{ + free(s->yv); + free(s); +} + +static void get_v(const Source *s, Searcher *m) +{ + int x = m->r.x - s->r.x - 1; + + m->c = 0; + + if(x < 0 || x >= s->n) + return; + + if((s->yv[x].v == 2) || (s->yv[x].y != m->r.y - s->r.y)) + return; + + m->c = 1; + m->v = s->yv[x].v; + m->color = s->color; +} + + +static void * +anemotaxis_init (Display *disp, Window win) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XWindowAttributes wa; + + st->dpy = disp; + st->window = win; + + XGetWindowAttributes(st->dpy, st->window, &wa); + + st->ncolors = get_integer_resource (st->dpy, "colors", "Colors"); + st->ncolors++; + st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1)); + make_random_colormap (wa.screen, wa.visual, wa.colormap, + st->colors, &st->ncolors, + True, True, 0, True); + + st->delay = get_integer_resource(st->dpy, "delay", "Integer"); + st->max_dist = get_integer_resource(st->dpy, "distance", "Integer"); + + if(st->max_dist < MIN_DIST) + st->max_dist = MIN_DIST + 1; + if(st->max_dist > MAX_DIST) + st->max_dist = MAX_DIST; + + st->max_src = get_integer_resource(st->dpy, "sources", "Integer"); + + if(st->max_src <= 0) + st->max_src = 1; + + st->max_searcher = get_integer_resource(st->dpy, "searchers", "Integer"); + + if(st->max_searcher < 0) + st->max_searcher = 0; + + st->dbuf = True; + +# ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */ + st->dbuf = False; +# endif + + st->source = (Source **) emalloc(sizeof(Source *) * st->max_src); + memset(st->source, 0, st->max_src * sizeof(Source *)); + + st->source[0] = new_source(st); + + st->searcher = (Searcher **) emalloc(st->max_searcher * sizeof(Searcher *)); + + memset(st->searcher, 0, st->max_searcher * sizeof(Searcher *)); + + st->b = st->ba = st->bb = 0; /* double-buffer to reduce flicker */ + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + st->b = st->backb = xdbe_get_backbuffer (st->dpy, st->window, XdbeUndefined); +#endif + + st->scrWidth = wa.width; + st->scrHeight = wa.height; + st->cmap = wa.colormap; + st->gcDraw = XCreateGC(st->dpy, st->window, 0, &st->gcv); + st->gcv.foreground = get_pixel_resource(st->dpy, st->cmap, + "background", "Background"); + st->gcClear = XCreateGC(st->dpy, st->window, GCForeground, &st->gcv); + + if (st->dbuf) { + if (!st->b) { + st->ba = XCreatePixmap (st->dpy, st->window, st->scrWidth, st->scrHeight, wa.depth); + st->bb = XCreatePixmap (st->dpy, st->window, st->scrWidth, st->scrHeight, wa.depth); + st->b = st->ba; + } + } + else + st->b = st->window; + + + if (st->ba) XFillRectangle (st->dpy, st->ba, st->gcClear, 0, 0, st->scrWidth, st->scrHeight); + if (st->bb) XFillRectangle (st->dpy, st->bb, st->gcClear, 0, 0, st->scrWidth, st->scrHeight); + + st->ax = st->scrWidth / (double) st->max_dist; + st->ay = st->scrHeight / (2. * st->max_dist); + st->bx = 0.; + st->by = 0.; + + if((st->dx = st->scrWidth / (2 * st->max_dist)) == 0) + st->dx = 1; + if((st->dy = st->scrHeight / (4 * st->max_dist)) == 0) + st->dy = 1; + XSetLineAttributes(st->dpy, st->gcDraw, st->dx / 3 + 1, LineSolid, CapRound, JoinRound); + XClearWindow(st->dpy, st->window); + + return st; +} + +static void draw_searcher(struct state *st, Drawable curr_window, int i) +{ + Point r1, r2; + PList *l; + + if(st->searcher[i] == NULL) + return; + + XSetForeground(st->dpy, st->gcDraw, st->searcher[i]->color); + + r1.x = X(st->searcher[i]->r.x) + st->searcher[i]->rs; + r1.y = Y(st->searcher[i]->r.y); + + XFillRectangle(st->dpy, curr_window, st->gcDraw, r1.x - 2, r1.y - 2, 4, 4); + + for(l = st->searcher[i]->hist; l != NULL; l = l->next) { + + r2.x = X(l->r.x) + st->searcher[i]->rs; + r2.y = Y(l->r.y); + + XDrawLine(st->dpy, curr_window, st->gcDraw, r1.x, r1.y, r2.x, r2.y); + + r1 = r2; + } + +} + +static void draw_image(struct state *st, Drawable curr_window) +{ + int i, j; + int x, y; + + for(i = 0; i < st->max_src; i++) { + + if(st->source[i] == NULL) + continue; + + XSetForeground(st->dpy, st->gcDraw, st->source[i]->color); + + if(st->source[i]->inv_rate > 0) { + + if(st->max_searcher > 0) { + x = (int) X(st->source[i]->r.x); + y = (int) Y(st->source[i]->r.y); + j = st->dx * (MAX_INV_RATE + 1 - st->source[i]->inv_rate) / (2 * MAX_INV_RATE); + if(j == 0) + j = 1; + XFillArc(st->dpy, curr_window, st->gcDraw, x - j, y - j, 2 * j, 2 * j, 0, 360 * 64); + }} + + for(j = 0; j < st->source[i]->n; j++) { + + int size = (st->scrWidth > 2560 ? 8 : 4); /* Retina displays */ + + if(st->source[i]->yv[j].v == 2) + continue; + + /* Move the particles slightly off lattice */ + x = X(st->source[i]->r.x + 1 + j) + RND(st->dx); + y = Y(st->source[i]->r.y + st->source[i]->yv[j].y) + RND(st->dy); + XFillArc(st->dpy, curr_window, st->gcDraw, x - size/2, y - size/2, size, size, 0, 360 * 64); + } + + } + + for(i = 0; i < st->max_searcher; i++) + draw_searcher(st, curr_window, i); + +} + +static void animate_anemotaxis(struct state *st, Drawable curr_window) +{ + int i, j; + Bool dead; + + for(i = 0; i < st->max_src; i++) { + + if(st->source[i] == NULL) + continue; + + evolve_source(st->source[i]); + + /* reap dead sources for which all particles are gone */ + if(st->source[i]->inv_rate == 0) { + + dead = True; + + for(j = 0; j < st->source[i]->n; j++) { + if(st->source[i]->yv[j].v != 2) { + dead = False; + break; + } + } + + if(dead == True) { + destroy_source(st->source[i]); + st->source[i] = NULL; + } + } + } + + /* Decide if we want to add new sources */ + + for(i = 0; i < st->max_src; i++) { + if(st->source[i] == NULL && RND(st->max_dist * st->max_src) == 0) + st->source[i] = new_source(st); + } + + if(st->max_searcher == 0) { /* kill some sources when searchers don't do that */ + for(i = 0; i < st->max_src; i++) { + if(st->source[i] != NULL && RND(st->max_dist * st->max_src) == 0) { + destroy_source(st->source[i]); + st->source[i] = 0; + } + } + } + + /* Now deal with searchers */ + + for(i = 0; i < st->max_searcher; i++) { + + if((st->searcher[i] != NULL) && (st->searcher[i]->state == DONE)) { + destroy_searcher(st->searcher[i]); + st->searcher[i] = NULL; + } + + if(st->searcher[i] == NULL) { + + if(RND(st->max_dist * st->max_searcher) == 0) { + + st->searcher[i] = new_searcher(st); + + } + } + + if(st->searcher[i] == NULL) + continue; + + /* Check if searcher found a source or missed all of them */ + for(j = 0; j < st->max_src; j++) { + + if(st->source[j] == NULL || st->source[j]->inv_rate == 0) + continue; + + if(st->searcher[i]->r.x < 0) { + st->searcher[i]->state = DONE; + break; + } + + if((st->source[j]->r.y == st->searcher[i]->r.y) && + (st->source[j]->r.x == st->searcher[i]->r.x)) { + st->searcher[i]->state = DONE; + st->source[j]->inv_rate = 0; /* source disappears */ + + /* Make it flash */ + st->searcher[i]->color = WhitePixel(st->dpy, DefaultScreen(st->dpy)); + + break; + } + } + + st->searcher[i]->c = 0; /* set it here in case we don't get to get_v() */ + + /* Find the concentration at searcher's location */ + + if(st->searcher[i]->state != DONE) { + for(j = 0; j < st->max_src; j++) { + + if(st->source[j] == NULL) + continue; + + get_v(st->source[j], st->searcher[i]); + + if(st->searcher[i]->c == 1) + break; + } + } + + move_searcher(st->searcher[i]); + + } + + draw_image(st, curr_window); +} + +static unsigned long +anemotaxis_draw (Display *disp, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + XWindowAttributes wa; + int w, h; + + + XGetWindowAttributes(st->dpy, st->window, &wa); + + w = wa.width; + h = wa.height; + + if(w != st->scrWidth || h != st->scrHeight) { + st->scrWidth = w; + st->scrHeight = h; + st->ax = st->scrWidth / (double) st->max_dist; + st->ay = st->scrHeight / (2. * st->max_dist); + st->bx = 0.; + st->by = 0.; + + if((st->dx = st->scrWidth / (2 * st->max_dist)) == 0) + st->dx = 1; + if((st->dy = st->scrHeight / (4 * st->max_dist)) == 0) + st->dy = 1; + XSetLineAttributes(st->dpy, st->gcDraw, st->dx / 3 + 1, LineSolid, CapRound, JoinRound); + } + + XFillRectangle (st->dpy, st->b, st->gcClear, 0, 0, st->scrWidth, st->scrHeight); + animate_anemotaxis(st, st->b); + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + if (st->backb) { + XdbeSwapInfo info[1]; + info[0].swap_window = st->window; + info[0].swap_action = XdbeUndefined; + XdbeSwapBuffers (st->dpy, info, 1); + } + else +#endif + if (st->dbuf) { + XCopyArea (st->dpy, st->b, st->window, st->gcClear, 0, 0, + st->scrWidth, st->scrHeight, 0, 0); + st->b = (st->b == st->ba ? st->bb : st->ba); + } + + return st->delay; +} + + + +static void +anemotaxis_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +static Bool +anemotaxis_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +anemotaxis_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int i; + if (st->source) { + for (i = 0; i < st->max_src; i++) + if (st->source[i]) destroy_source (st->source[i]); + free (st->source); + } + if (st->searcher) { + for (i = 0; i < st->max_searcher; i++) + if (st->searcher[i]) destroy_searcher (st->searcher[i]); + free (st->searcher); + } + free (st); +} + + + + +static const char *anemotaxis_defaults [] = { + ".background: black", + "*distance: 40", + "*sources: 25", + "*searchers: 25", + "*delay: 20000", + "*colors: 20", +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + "*useDBE: True", +#endif + 0 +}; + + +static XrmOptionDescRec anemotaxis_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-distance", ".distance", XrmoptionSepArg, 0 }, + { "-sources", ".sources", XrmoptionSepArg, 0 }, + { "-searchers", ".searchers", XrmoptionSepArg, 0 }, + { "-colors", ".colors", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("Anemotaxis", anemotaxis) diff --git a/hacks/anemotaxis.man b/hacks/anemotaxis.man new file mode 100644 index 0000000..cf5c1ea --- /dev/null +++ b/hacks/anemotaxis.man @@ -0,0 +1,78 @@ +.TH XScreenSaver 1 "" "X Version 11" +.SH NAME +anemotaxis - directional search on a plane. +.SH SYNOPSIS +.B anemotaxis +[\-display \fIhost:display.screen\fP] +[\-visual \fIvisual\fP] +[\-window] +[\-root] +[\-delay \fInumber\fP] +[\-distance \fInumber\fP] +[\-sources \fInumber\fP] +[\-searchers \fInumber\fP] +[\-fps] +.SH DESCRIPTION +The program demonstrates a search algorithm designed for locating a +source of odor in turbulent atmosphere. The odor is convected by wind +which has a constant mean direction and fluctuations around it. The +searcher is able to sense the odor and determine local instantaneous +wind direction. The goal is to find the source in the shortest mean +time. Some animals face this task to find mates, food, home etc. They +exhibit very particular, zigzagging search trajectories. + +This is modeled as a search on a discrete two-dimensional lattice. The +source releases particles that drift with constant velocity in one +direction and walk randomly in the other direction. The searcher knows +if it hit a particle, and if so, particle's position one time step +earlier (local wind direction). The program paints sources and +particles released by them as well as trajectories of searchers who are +trying to capture the sources. +.SH OPTIONS +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-delay \fInumber\fP +Per-frame delay, in microseconds. Default: 20000 (0.02 seconds.). +.TP 8 +.B \-distance \fInumber\fP +Max initial distance to the source . 10 - 250. Default: 40. +.TP 8 +.B \-sources \fInumber\fP +Max number of sources. Default: 25. +.TP 8 +.B \-searchers \fInumber\fP +Max number of searchers. Default: 25. +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1) +.SH COPYRIGHT +Copyright \(co 2004 by Eugene Balkovsky. Permission to use, copy, modify, +distribute, and sell this software and its documentation for any purpose is +hereby granted without fee, provided that the above copyright notice appear +in all copies and that both that copyright notice and this permission notice +appear in supporting documentation. No representations are made about the +suitability of this software for any purpose. It is provided "as is" without +express or implied warranty. +.SH AUTHOR +Eugene Balkovsky diff --git a/hacks/ant.c b/hacks/ant.c new file mode 100644 index 0000000..56d3036 --- /dev/null +++ b/hacks/ant.c @@ -0,0 +1,1350 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/*- + * ant --- Chris Langton's generalized turing machine ants (also known + * as Greg Turk's turmites) whose tape is the screen + */ + +#if 0 +static const char sccsid[] = "@(#)ant.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1995 by David Bagley. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation. + * + * This file is provided AS IS with no warranties of any kind. The author + * shall have no liability with respect to the infringement of copyrights, + * trade secrets or any patents by this file or any part thereof. In no + * event will the author be liable for any lost revenue or profits or + * other special, indirect and consequential damages. + * + * Revision History: + * 01-Nov-2000: Allocation checks + * 10-May-1997: Compatible with xscreensaver + * 16-Apr-1997: -neighbors 3 and 8 added + * 01-Jan-1997: Updated ant.c to handle more kinds of ants. Thanks to + * J Austin David . Check it out in + * java at http://havoc.gtf.gatech.edu/austin He thought up the + * new Ladder ant. + * 04-Apr-1996: -neighbors 6 runtime-time option added for hexagonal ants + * (bees), coded from an idea of Jim Propp's in Science News, + * Oct 28, 1995 VOL. 148 page 287 + * 20-Sep-1995: Memory leak in ant fixed. Now random colors. + * 05-Sep-1995: Coded from A.K. Dewdney's "Computer Recreations", Scientific + * American Magazine" Sep 1989 pp 180-183, Mar 1990 p 121 + * Also used Ian Stewart's Mathematical Recreations, Scientific + * American Jul 1994 pp 104-107 + * also used demon.c and life.c as a guide. + */ + +/*- + Species Grid Number of Neighbors + ------- ---- ------------------ + Ants Square 4 (or 8) + Bees Hexagon 6 + Bees Triangle 3 (or 9, 12) + + Neighbors 6 and neighbors 3 produce the same Turk ants. +*/ + +#ifndef HAVE_JWXYZ +/*# define DO_STIPPLE*/ +#endif + +#ifdef STANDALONE +# define MODE_ant +# define DEFAULTS "*delay: 20000 \n" \ + "*count: -3 \n" \ + "*cycles: 40000 \n" \ + "*size: -12 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + +# define reshape_ant 0 +# define release_ant 0 +# define ant_handle_event 0 +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ +#include "automata.h" + +#ifdef MODE_ant + +/*- + * neighbors of 0 randomizes it for 3, 4, 6, 8, 12 (last 2 are less likely) + */ + +#define DEF_NEIGHBORS "0" /* choose random value */ +#define DEF_TRUCHET "False" +#define DEF_EYES "False" +#define DEF_SHARPTURN "False" + +static int neighbors; +static Bool truchet; +static Bool eyes; +static Bool sharpturn; + +static XrmOptionDescRec opts[] = +{ + {"-neighbors", ".ant.neighbors", XrmoptionSepArg, 0}, + {"-truchet", ".ant.truchet", XrmoptionNoArg, "on"}, + {"+truchet", ".ant.truchet", XrmoptionNoArg, "off"}, + {"-eyes", ".ant.eyes", XrmoptionNoArg, "on"}, + {"+eyes", ".ant.eyes", XrmoptionNoArg, "off"}, + {"-sharpturn", ".ant.sharpturn", XrmoptionNoArg, "on"}, + {"+sharpturn", ".ant.sharpturn", XrmoptionNoArg, "off"}, +}; +static argtype vars[] = +{ + {&neighbors, "neighbors", "Neighbors", DEF_NEIGHBORS, t_Int}, + {&truchet, "truchet", "Truchet", DEF_TRUCHET, t_Bool}, + {&eyes, "eyes", "Eyes", DEF_EYES, t_Bool}, + {&sharpturn, "sharpturn", "SharpTurn", DEF_SHARPTURN, t_Bool}, +}; +static OptionStruct desc[] = +{ + {"-neighbors num", "squares 4 or 8, hexagons 6, triangles 3 or 12"}, + {"-/+truchet", "turn on/off Truchet lines"}, + {"-/+eyes", "turn on/off eyes"}, + {"-/+sharpturn", "turn on/off sharp turns (6, 8 or 12 neighbors only)"} +}; + +ENTRYPOINT ModeSpecOpt ant_opts = +{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; + +#ifdef USE_MODULES +const ModStruct ant_description = +{"ant", + "init_ant", "draw_ant", (char *) NULL, + "refresh_ant", "init_ant", "free_ant", &ant_opts, + 1000, -3, 40000, -12, 64, 1.0, "", + "Shows Langton's and Turk's generalized ants", 0, NULL}; + +#endif + +#define ANTBITS(n,w,h)\ + if ((ap->pixmaps[ap->init_bits]=\ + XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\ + free_ant(mi); return;} else {ap->init_bits++;} + +/* If you change the table you may have to change the following 2 constants */ +#define STATES 2 +#define MINANTS 1 +#define REDRAWSTEP 2000 /* How much tape to draw per cycle */ +#define MINGRIDSIZE 24 +#define MINSIZE 1 +#define MINRANDOMSIZE 5 +#define ANGLES 360 + +typedef struct { + unsigned char color; + short direction; + unsigned char next; +} statestruct; + +typedef struct { + int col, row; + short direction; + unsigned char state; +} antstruct; + +typedef struct { + Bool painted; + int neighbors; + int generation; + int xs, ys; + int xb, yb; + int init_dir; + int nrows, ncols; + int width, height; + unsigned char ncolors, nstates; + int n; + int redrawing, redrawpos; + int truchet; /* Only for Turk modes */ + int eyes; + int sharpturn; + statestruct machine[NUMSTIPPLES * STATES]; + unsigned char *tape; + unsigned char *truchet_state; + antstruct *ants; + int init_bits; + unsigned char colors[NUMSTIPPLES - 1]; +# ifdef DO_STIPPLE + GC stippledGC; +# endif /* DO_STIPPLE */ + Pixmap pixmaps[NUMSTIPPLES - 1]; + union { + XPoint hexagon[7]; /* Need more than 6 for truchet */ + XPoint triangle[2][4]; /* Need more than 3 for truchet */ + } shape; +} antfarmstruct; + +static char plots[] = +{3, 4, 6, 8, +#ifdef NUMBER_9 + 9, +#endif + 12}; + +#define NEIGHBORKINDS ((long) (sizeof plots / sizeof *plots)) +#define GOODNEIGHBORKINDS 3 + +/* Relative ant moves */ +#define FS 0 /* Step */ +#define TRS 1 /* Turn right, then step */ +#define THRS 2 /* Turn hard right, then step */ +#define TBS 3 /* Turn back, then step */ +#define THLS 4 /* Turn hard left, then step */ +#define TLS 5 /* Turn left, then step */ +#define SF 6 /* Step */ +#define STR 7 /* Step then turn right */ +#define STHR 8 /* Step then turn hard right */ +#define STB 9 /* Step then turn back */ +#define STHL 10 /* Step then turn hard left */ +#define STL 11 /* Step then turn left */ + +static antfarmstruct *antfarms = (antfarmstruct *) NULL; + +/* LANGTON'S ANT (10) Chaotic after 500, Builder after 10,000 (104p) */ +/* TURK'S 100 ANT Always chaotic?, tested past 150,000,000 */ +/* TURK'S 101 ANT Always chaotic? */ +/* TURK'S 110 ANT Builder at 150 (18p) */ +/* TURK'S 1000 ANT Always chaotic? */ +/* TURK'S 1100 SYMMETRIC ANT all even run 1's and 0's are symmetric */ +/* other examples 1001, 110011, 110000, 1001101 */ +/* TURK'S 1101 ANT Builder after 250,000 (388p) */ +/* Once saw a chess horse type builder (i.e. non-45 degree builder) */ + +/* BEE ONLY */ +/* All alternating 10 appear symmetric, no proof (i.e. 10, 1010, etc) */ +/* Even runs of 0's and 1's are also symmetric */ +/* I have seen Hexagonal builders but they are more rare. */ + +static unsigned char tables[][3 * NUMSTIPPLES * STATES + 2] = +{ +#if 0 + /* Here just so you can figure out notation */ + { /* Langton's ant */ + 2, 1, + 1, TLS, 0, 0, TRS, 0 + }, +#else + /* First 2 numbers are the size (ncolors, nstates) */ + { /* LADDER BUILDER */ + 4, 1, + 1, STR, 0, 2, STL, 0, 3, TRS, 0, 0, TLS, 0 + }, + { /* SPIRALING PATTERN */ + 2, 2, + 1, TLS, 0, 0, FS, 1, + 1, TRS, 0, 1, TRS, 0 + }, + { /* SQUARE (HEXAGON) BUILDER */ + 2, 2, + 1, TLS, 0, 0, FS, 1, + 0, TRS, 0, 1, TRS, 0 + }, +#endif +}; + +#define NTABLES (sizeof tables / sizeof tables[0]) + +static void +position_of_neighbor(antfarmstruct * ap, int dir, int *pcol, int *prow) +{ + int col = *pcol, row = *prow; + + if (ap->neighbors == 6) { + switch (dir) { + case 0: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + break; + case 60: + if (!(row & 1)) + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 120: + if (row & 1) + col = (!col) ? ap->ncols - 1 : col - 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 180: + col = (!col) ? ap->ncols - 1 : col - 1; + break; + case 240: + if (row & 1) + col = (!col) ? ap->ncols - 1 : col - 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 300: + if (!(row & 1)) + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + default: + (void) fprintf(stderr, "wrong direction %d\n", dir); + } + } else if (ap->neighbors == 4 || ap->neighbors == 8) { + switch (dir) { + case 0: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + break; + case 45: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 90: + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 135: + col = (!col) ? ap->ncols - 1 : col - 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 180: + col = (!col) ? ap->ncols - 1 : col - 1; + break; + case 225: + col = (!col) ? ap->ncols - 1 : col - 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 270: + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 315: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + default: + (void) fprintf(stderr, "wrong direction %d\n", dir); + } + } else { /* TRI */ + if ((col + row) % 2) { /* right */ + switch (dir) { + case 0: + col = (!col) ? ap->ncols - 1 : col - 1; + break; + case 30: + case 40: + col = (!col) ? ap->ncols - 1 : col - 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 60: + col = (!col) ? ap->ncols - 1 : col - 1; + if (!row) + row = ap->nrows - 2; + else if (!(row - 1)) + row = ap->nrows - 1; + else + row = row - 2; + break; + case 80: + case 90: + if (!row) + row = ap->nrows - 2; + else if (!(row - 1)) + row = ap->nrows - 1; + else + row = row - 2; + break; + case 120: + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 150: + case 160: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 180: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + break; + case 200: + case 210: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 240: + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 270: + case 280: + if (row + 1 == ap->nrows) + row = 1; + else if (row + 2 == ap->nrows) + row = 0; + else + row = row + 2; + break; + case 300: + col = (!col) ? ap->ncols - 1 : col - 1; + if (row + 1 == ap->nrows) + row = 1; + else if (row + 2 == ap->nrows) + row = 0; + else + row = row + 2; + break; + case 320: + case 330: + col = (!col) ? ap->ncols - 1 : col - 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + default: + (void) fprintf(stderr, "wrong direction %d\n", dir); + } + } else { /* left */ + switch (dir) { + case 0: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + break; + case 30: + case 40: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 60: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + if (row + 1 == ap->nrows) + row = 1; + else if (row + 2 == ap->nrows) + row = 0; + else + row = row + 2; + break; + case 80: + case 90: + if (row + 1 == ap->nrows) + row = 1; + else if (row + 2 == ap->nrows) + row = 0; + else + row = row + 2; + break; + case 120: + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 150: + case 160: + col = (!col) ? ap->ncols - 1 : col - 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 180: + col = (!col) ? ap->ncols - 1 : col - 1; + break; + case 200: + case 210: + col = (!col) ? ap->ncols - 1 : col - 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 240: + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 270: + case 280: + if (!row) + row = ap->nrows - 2; + else if (row == 1) + row = ap->nrows - 1; + else + row = row - 2; + break; + case 300: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + if (!row) + row = ap->nrows - 2; + else if (row == 1) + row = ap->nrows - 1; + else + row = row - 2; + break; + case 320: + case 330: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + default: + (void) fprintf(stderr, "wrong direction %d\n", dir); + } + } + } + *pcol = col; + *prow = row; +} + +static void +fillcell(ModeInfo * mi, GC gc, int col, int row) +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + + if (ap->neighbors == 6) { + int ccol = 2 * col + !(row & 1), crow = 2 * row; + + ap->shape.hexagon[0].x = ap->xb + ccol * ap->xs; + ap->shape.hexagon[0].y = ap->yb + crow * ap->ys; + if (ap->xs == 1 && ap->ys == 1) + XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + ap->shape.hexagon[0].x, ap->shape.hexagon[0].y); + else + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + ap->shape.hexagon, 6, Convex, CoordModePrevious); + } else if (ap->neighbors == 4 || ap->neighbors == 8) { + XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + ap->xb + ap->xs * col, ap->yb + ap->ys * row, + ap->xs - (ap->xs > 3), ap->ys - (ap->ys > 3)); + } else { /* TRI */ + int orient = (col + row) % 2; /* O left 1 right */ + + ap->shape.triangle[orient][0].x = ap->xb + col * ap->xs; + ap->shape.triangle[orient][0].y = ap->yb + row * ap->ys; + if (ap->xs <= 3 || ap->ys <= 3) + XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + ((orient) ? -1 : 1) + ap->shape.triangle[orient][0].x, + ap->shape.triangle[orient][0].y); + else { + if (orient) + ap->shape.triangle[orient][0].x += (ap->xs / 2 - 1); + else + ap->shape.triangle[orient][0].x -= (ap->xs / 2 - 1); + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + ap->shape.triangle[orient], 3, Convex, CoordModePrevious); + } + } +} + +static void +truchetcell(ModeInfo * mi, int col, int row, int truchetstate) +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + + if (ap->neighbors == 6) { + + int ccol = 2 * col + !(row & 1), crow = 2 * row; + int side; + int fudge = 7; /* fudge because the hexagons are not exact */ + XPoint hex, hex2; + + if (ap->sharpturn) { + hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs / 2.0) - 1; + hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys / 2.0) - 1; + for (side = 0; side < 6; side++) { + if (side) { + hex.x += ap->shape.hexagon[side].x; + hex.y += ap->shape.hexagon[side].y; + } + if (truchetstate == side % 2) + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + hex.x, hex.y, ap->xs, ap->ys, + ((570 - (side * 60) + fudge) % 360) * 64, (120 - 2 * fudge) * 64); + } + } else { + /* Very crude approx of Sqrt 3, so it will not cause drawing errors. */ + hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs * 1.6 / 2.0) - 1; + hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys * 1.6 / 2.0) - 1; + for (side = 0; side < 6; side++) { + if (side) { + hex.x += ap->shape.hexagon[side].x; + hex.y += ap->shape.hexagon[side].y; + } + hex2.x = hex.x + ap->shape.hexagon[side + 1].x / 2; + hex2.y = hex.y + ap->shape.hexagon[side + 1].y / 2 + 1; + /* Lots of fudging here */ + if (side == 1) { + hex2.x += (short) (ap->xs * 0.1 + 1); + hex2.y += (short) (ap->ys * 0.1 - ((ap->ys > 5) ? 1 : 0)); + } else if (side == 2) { + hex2.x += (short) (ap->xs * 0.1); + } else if (side == 4) { + hex2.x += (short) (ap->xs * 0.1); + hex2.y += (short) (ap->ys * 0.1 - 1); + } else if (side == 5) { + hex2.x += (short) (ap->xs * 0.5); + hex2.y += (short) (-ap->ys * 0.3 + 1); + } + if (truchetstate == side % 3) + /* Crude approx of 120 deg, so it will not cause drawing errors. */ + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + hex2.x, hex2.y, + (int) ((double) ap->xs * 1.5), (int) ((double) ap->ys * 1.5), + ((555 - (side * 60)) % 360) * 64, 90 * 64); + } + } + } else if (ap->neighbors == 4) { + if (truchetstate) { + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + ap->xb + ap->xs * col - ap->xs / 2 + 1, + ap->yb + ap->ys * row + ap->ys / 2 - 1, + ap->xs - 2, ap->ys - 2, + 0 * 64, 90 * 64); + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + ap->xb + ap->xs * col + ap->xs / 2 - 1, + ap->yb + ap->ys * row - ap->ys / 2 + 1, + ap->xs - 2, ap->ys - 2, + -90 * 64, -90 * 64); + } else { + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + ap->xb + ap->xs * col - ap->xs / 2 + 1, + ap->yb + ap->ys * row - ap->ys / 2 + 1, + ap->xs - 2, ap->ys - 2, + 0 * 64, -90 * 64); + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + ap->xb + ap->xs * col + ap->xs / 2 - 1, + ap->yb + ap->ys * row + ap->ys / 2 - 1, + ap->xs - 2, ap->ys - 2, + 90 * 64, 90 * 64); + } + } else if (ap->neighbors == 3) { + int orient = (col + row) % 2; /* O left 1 right */ + int side, ang; + int fudge = 7; /* fudge because the triangles are not exact */ + double fudge2 = 1.18; + XPoint tri; + + tri.x = ap->xb + col * ap->xs; + tri.y = ap->yb + row * ap->ys; + if (orient) { + tri.x += (ap->xs / 2 - 1); + } else { + tri.x -= (ap->xs / 2 - 1); + } + for (side = 0; side < 3; side++) { + if (side > 0) { + tri.x += ap->shape.triangle[orient][side].x; + tri.y += ap->shape.triangle[orient][side].y; + } + if (truchetstate == side) { + if (orient) + ang = (510 - side * 120) % 360; /* Right */ + else + ang = (690 - side * 120) % 360; /* Left */ + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + (int) (tri.x - ap->xs * fudge2 / 2), + (int) (tri.y - 3 * ap->ys * fudge2 / 4), + (unsigned int) (ap->xs * fudge2), + (unsigned int) (3 * ap->ys * fudge2 / 2), + (ang + fudge) * 64, (60 - 2 * fudge) * 64); + } + } + } +} + +static void +drawcell(ModeInfo * mi, int col, int row, unsigned char color) +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + GC gc; + + if (!color) { + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + gc = MI_GC(mi); +# ifdef DO_STIPPLE + } else if (MI_NPIXELS(mi) <= 2) { + XGCValues gcv; + gcv.foreground = MI_WHITE_PIXEL(mi); + gcv.background = MI_BLACK_PIXEL(mi); + gcv.stipple = ap->pixmaps[color - 1]; + XChangeGC(MI_DISPLAY(mi), ap->stippledGC, + GCStipple | GCForeground | GCBackground, &gcv); + gc = ap->stippledGC; +# endif /* !DO_STIPPLE */ + } else { + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), + MI_PIXEL(mi, ap->colors[color - 1])); + gc = MI_GC(mi); + } + fillcell(mi, gc, col, row); +} + +static void +drawtruchet(ModeInfo * mi, int col, int row, + unsigned char color, unsigned char truchetstate) +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + + if (!color) + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); + else if (MI_NPIXELS(mi) > 2 || color > ap->ncolors / 2) + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + else + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); + truchetcell(mi, col, row, truchetstate); +} + +static void +draw_anant(ModeInfo * mi, int direction, int col, int row) +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + + XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi)); + fillcell(mi, MI_GC(mi), col, row); + if (ap->eyes) { /* Draw Eyes */ + XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi)); + if (ap->neighbors == 6) { + int ccol = 2 * col + !(row & 1), crow = 2 * row; + int side, ang; + XPoint hex; + + if (!(ap->xs > 3 && ap->ys > 3)) + return; + hex.x = ap->xb + ccol * ap->xs; + hex.y = ap->yb + crow * ap->ys + ap->ys / 2; + ang = direction * ap->neighbors / ANGLES; + for (side = 0; side < ap->neighbors; side++) { + if (side) { + hex.x -= ap->shape.hexagon[side].x / 2; + hex.y += ap->shape.hexagon[side].y / 2; + } + if (side == (ap->neighbors + ang - 2) % ap->neighbors) + XDrawPoint(display, window, MI_GC(mi), hex.x, hex.y); + if (side == (ap->neighbors + ang - 1) % ap->neighbors) + XDrawPoint(display, window, MI_GC(mi), hex.x, hex.y); + } + } else if (ap->neighbors == 4 || ap->neighbors == 8) { + if (!(ap->xs > 3 && ap->ys > 3)) + return; + switch (direction) { + case 0: + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * (col + 1) - 3, + ap->yb + ap->ys * row + ap->ys / 2 - 2); + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * (col + 1) - 3, + ap->yb + ap->ys * row + ap->ys / 2); + break; + case 45: + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * (col + 1) - 4, + ap->yb + ap->ys * row + 1); + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * (col + 1) - 3, + ap->yb + ap->ys * row + 2); + break; + case 90: + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * col + ap->xs / 2 - 2, + ap->yb + ap->ys * row + 1); + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * col + ap->xs / 2, + ap->yb + ap->ys * row + 1); + break; + case 135: + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * col + 2, + ap->yb + ap->ys * row + 1); + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * col + 1, + ap->yb + ap->ys * row + 2); + break; + case 180: + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * col + 1, + ap->yb + ap->ys * row + ap->ys / 2 - 2); + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * col + 1, + ap->yb + ap->ys * row + ap->ys / 2); + break; + case 225: + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * col + 2, + ap->yb + ap->ys * (row + 1) - 3); + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * col + 1, + ap->yb + ap->ys * (row + 1) - 4); + break; + case 270: + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * col + ap->xs / 2 - 2, + ap->yb + ap->ys * (row + 1) - 3); + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * col + ap->xs / 2, + ap->yb + ap->ys * (row + 1) - 3); + break; + case 315: + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * (col + 1) - 4, + ap->yb + ap->ys * (row + 1) - 3); + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs * (col + 1) - 3, + ap->yb + ap->ys * (row + 1) - 4); + break; + default: + (void) fprintf(stderr, "wrong eyes direction %d for ant eyes\n", direction); + } + } else { /* TRI */ + int orient = (col + row) % 2; /* O left 1 right */ + int side, ang; + XPoint tri; + + if (!(ap->xs > 6 && ap->ys > 6)) + return; + tri.x = ap->xb + col * ap->xs; + tri.y = ap->yb + row * ap->ys; + if (orient) + tri.x += (ap->xs / 6 - 1); + else + tri.x -= (ap->xs / 6 - 1); + ang = direction * ap->neighbors / ANGLES; + /* approx... does not work that well for even numbers */ + if ( +#ifdef NUMBER_9 + ap->neighbors == 9 || +#endif + ap->neighbors == 12) { +#ifdef UNDER_CONSTRUCTION + /* Not sure why this does not work */ + ang = ((ang + ap->neighbors / 6) / (ap->neighbors / 3)) % 3; +#else + return; +#endif + } + for (side = 0; side < 3; side++) { + if (side) { + tri.x += ap->shape.triangle[orient][side].x / 3; + tri.y += ap->shape.triangle[orient][side].y / 3; + } + /* Either you have the eyes in back or one eye in front */ +#if 0 + if (side == ang) + XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y); +#else + if (side == (ang + 2) % 3) + XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y); + if (side == (ang + 1) % 3) + XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y); +#endif + } + } + } +} + +#if 0 +static void +RandomSoup(mi) + ModeInfo *mi; +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + int row, col, mrow = 0; + + for (row = 0; row < ap->nrows; ++row) { + for (col = 0; col < ap->ncols; ++col) { + ap->old[col + mrow] = (unsigned char) NRAND((int) ap->ncolors); + drawcell(mi, col, row, ap->old[col + mrow]); + } + mrow += ap->nrows; + } +} + +#endif + +static short +fromTableDirection(unsigned char dir, int local_neighbors) +{ + /* Crafted to work for odd number of neighbors */ + switch (dir) { + case FS: + return 0; + case TLS: + return (ANGLES / local_neighbors); + case THLS: + return (2 * ANGLES / local_neighbors); + case TBS: + return ((local_neighbors / 2) * ANGLES / local_neighbors); + case THRS: + return (ANGLES - 2 * ANGLES / local_neighbors); + case TRS: + return (ANGLES - ANGLES / local_neighbors); + case SF: + return ANGLES; + case STL: + return (ANGLES + ANGLES / local_neighbors); + case STHL: + return (ANGLES + 2 * ANGLES / local_neighbors); + case STB: + return (ANGLES + (local_neighbors / 2) * ANGLES / local_neighbors); + case STHR: + return (2 * ANGLES - 2 * ANGLES / local_neighbors); + case STR: + return (2 * ANGLES - ANGLES / local_neighbors); + default: + (void) fprintf(stderr, "wrong direction %d from table\n", dir); + } + return -1; +} + +static void +getTable(ModeInfo * mi, int i) +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + int j, total; + unsigned char *patptr; + + patptr = &tables[i][0]; + ap->ncolors = *patptr++; + ap->nstates = *patptr++; + total = ap->ncolors * ap->nstates; + if (MI_IS_VERBOSE(mi)) + (void) fprintf(stdout, + "ants %d, neighbors %d, table number %d, colors %d, states %d\n", + ap->n, ap->neighbors, i, ap->ncolors, ap->nstates); + for (j = 0; j < total; j++) { + ap->machine[j].color = *patptr++; + if (ap->sharpturn && ap->neighbors > 4) { + int k = *patptr++; + + switch (k) { + case TRS: + k = THRS; + break; + case THRS: + k = TRS; + break; + case THLS: + k = TLS; + break; + case TLS: + k = THLS; + break; + case STR: + k = STHR; + break; + case STHR: + k = STR; + break; + case STHL: + k = STL; + break; + case STL: + k = STHL; + break; + default: + break; + } + ap->machine[j].direction = fromTableDirection(k, ap->neighbors); + } else { + ap->machine[j].direction = fromTableDirection(*patptr++, ap->neighbors); + } + ap->machine[j].next = *patptr++; + } + ap->truchet = False; +} + +static void +getTurk(ModeInfo * mi, int i) +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + int power2, j, number, total; + + /* To force a number, say has i + 2 (or 4) binary digits */ + power2 = 1 << (i + 1); + /* Do not want numbers which in binary are all 1's. */ + number = NRAND(power2 - 1) + power2; + /* To force a particular number, say */ + + ap->ncolors = i + 2; + ap->nstates = 1; + total = ap->ncolors * ap->nstates; + for (j = 0; j < total; j++) { + ap->machine[j].color = (j + 1) % total; + if (ap->sharpturn && ap->neighbors > 4) { + ap->machine[j].direction = (power2 & number) ? + fromTableDirection(THRS, ap->neighbors) : + fromTableDirection(THLS, ap->neighbors); + } else { + ap->machine[j].direction = (power2 & number) ? + fromTableDirection(TRS, ap->neighbors) : + fromTableDirection(TLS, ap->neighbors); + } + ap->machine[j].next = 0; + power2 >>= 1; + } + ap->truchet = (ap->truchet && ap->xs > 2 && ap->ys > 2 && + (ap->neighbors == 3 || ap->neighbors == 4 || ap->neighbors == 6)); + if (MI_IS_VERBOSE(mi)) + (void) fprintf(stdout, + "ants %d, neighbors %d, Turk's number %d, colors %d\n", + ap->n, ap->neighbors, number, ap->ncolors); +} + +ENTRYPOINT void +free_ant(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + int shade; + +#ifdef DO_STIPPLE + if (ap->stippledGC != None) { + XFreeGC(display, ap->stippledGC); + ap->stippledGC = None; + } +#endif /* DO_STIPPLE */ + for (shade = 0; shade < ap->init_bits; shade++) { + XFreePixmap(display, ap->pixmaps[shade]); + } + ap->init_bits = 0; + if (ap->tape != NULL) { + (void) free((void *) ap->tape); + ap->tape = (unsigned char *) NULL; + } + if (ap->ants != NULL) { + (void) free((void *) ap->ants); + ap->ants = (antstruct *) NULL; + } + if (ap->truchet_state != NULL) { + (void) free((void *) ap->truchet_state); + ap->truchet_state = (unsigned char *) NULL; + } +} + +ENTRYPOINT void +init_ant(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + int size = MI_SIZE(mi); + antfarmstruct *ap; + int col, row, dir; + int i; + + MI_INIT(mi, antfarms); + /*if (antfarms == NULL) { + if ((antfarms = (antfarmstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (antfarmstruct))) == NULL) + return; + }*/ + ap = &antfarms[MI_SCREEN(mi)]; + + ap->redrawing = 0; +#ifdef DO_STIPPLE + if (MI_NPIXELS(mi) <= 2) { + Window window = MI_WINDOW(mi); + if (ap->stippledGC == None) { + XGCValues gcv; + + gcv.fill_style = FillOpaqueStippled; + if ((ap->stippledGC = XCreateGC(display, window, + GCFillStyle, + &gcv)) == None) { + free_ant(mi); + return; + } + } + if (ap->init_bits == 0) { + for (i = 1; i < NUMSTIPPLES; i++) { + ANTBITS(stipples[i], STIPPLESIZE, STIPPLESIZE); + } + } + } +#endif /* DO_STIPPLE */ + ap->generation = 0; + ap->n = MI_COUNT(mi); + if (ap->n < -MINANTS) { + /* if ap->n is random ... the size can change */ + if (ap->ants != NULL) { + (void) free((void *) ap->ants); + ap->ants = (antstruct *) NULL; + } + ap->n = NRAND(-ap->n - MINANTS + 1) + MINANTS; + } else if (ap->n < MINANTS) + ap->n = MINANTS; + + ap->width = MI_WIDTH(mi); + ap->height = MI_HEIGHT(mi); + + for (i = 0; i < NEIGHBORKINDS; i++) { + if (neighbors == plots[i]) { + ap->neighbors = plots[i]; + break; + } + if (i == NEIGHBORKINDS - 1) { + if (!NRAND(10)) { + /* Make above 6 rare */ + ap->neighbors = plots[NRAND(NEIGHBORKINDS)]; + } else { + ap->neighbors = plots[NRAND(GOODNEIGHBORKINDS)]; + } + break; + } + } + + if (ap->neighbors == 6) { + int nccols, ncrows; + + if (ap->width < 8) + ap->width = 8; + if (ap->height < 8) + ap->height = 8; + if (size < -MINSIZE) { + ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) / + MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; + if (ap->ys < MINRANDOMSIZE) + ap->ys = MIN(MINRANDOMSIZE, + MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE)); + } else if (size < MINSIZE) { + if (!size) + ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE); + else + ap->ys = MINSIZE; + } else + ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) / + MINGRIDSIZE)); + ap->xs = ap->ys; + nccols = MAX(ap->width / ap->xs - 2, 2); + ncrows = MAX(ap->height / ap->ys - 1, 4); + ap->ncols = nccols / 2; + ap->nrows = 2 * (ncrows / 4); + ap->xb = (ap->width - ap->xs * nccols) / 2 + ap->xs / 2; + ap->yb = (ap->height - ap->ys * (ncrows / 2) * 2) / 2 + ap->ys - 2; + for (i = 0; i < 6; i++) { + ap->shape.hexagon[i].x = (ap->xs - 1) * hexagonUnit[i].x; + ap->shape.hexagon[i].y = ((ap->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3; + } + /* Avoid array bounds read of hexagonUnit */ + ap->shape.hexagon[6].x = 0; + ap->shape.hexagon[6].y = 0; + } else if (ap->neighbors == 4 || ap->neighbors == 8) { + if (size < -MINSIZE) { + ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) / + MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; + if (ap->ys < MINRANDOMSIZE) + ap->ys = MIN(MINRANDOMSIZE, + MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE)); + } else if (size < MINSIZE) { + if (!size) + ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE); + else + ap->ys = MINSIZE; + } else + ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) / + MINGRIDSIZE)); + ap->xs = ap->ys; + ap->ncols = MAX(ap->width / ap->xs, 2); + ap->nrows = MAX(ap->height / ap->ys, 2); + ap->xb = (ap->width - ap->xs * ap->ncols) / 2; + ap->yb = (ap->height - ap->ys * ap->nrows) / 2; + } else { /* TRI */ + int orient; + + if (ap->width < 2) + ap->width = 2; + if (ap->height < 2) + ap->height = 2; + if (size < -MINSIZE) { + ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) / + MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; + if (ap->ys < MINRANDOMSIZE) + ap->ys = MIN(MINRANDOMSIZE, + MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE)); + } else if (size < MINSIZE) { + if (!size) + ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE); + else + ap->ys = MINSIZE; + } else + ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) / + MINGRIDSIZE)); + ap->xs = (int) (1.52 * ap->ys); + ap->ncols = (MAX(ap->width / ap->xs - 1, 2) / 2) * 2; + ap->nrows = (MAX(ap->height / ap->ys - 1, 2) / 2) * 2; + ap->xb = (ap->width - ap->xs * ap->ncols) / 2 + ap->xs / 2; + ap->yb = (ap->height - ap->ys * ap->nrows) / 2 + ap->ys; + for (orient = 0; orient < 2; orient++) { + for (i = 0; i < 3; i++) { + ap->shape.triangle[orient][i].x = + (ap->xs - 2) * triangleUnit[orient][i].x; + ap->shape.triangle[orient][i].y = + (ap->ys - 2) * triangleUnit[orient][i].y; + } + /* Avoid array bounds read of triangleUnit */ + ap->shape.triangle[orient][3].x = 0; + ap->shape.triangle[orient][3].y = 0; + } + } + + XSetLineAttributes(display, MI_GC(mi), 1, LineSolid, CapNotLast, JoinMiter); + MI_CLEARWINDOW(mi); + ap->painted = False; + + if (MI_IS_FULLRANDOM(mi)) { + ap->truchet = (Bool) (LRAND() & 1); + ap->eyes = (Bool) (LRAND() & 1); + ap->sharpturn = (Bool) (LRAND() & 1); + } else { + ap->truchet = truchet; + ap->eyes = eyes; + ap->sharpturn = sharpturn; + } + if (!NRAND(NUMSTIPPLES)) { + getTable(mi, (int) (NRAND(NTABLES))); + } else + getTurk(mi, (int) (NRAND(NUMSTIPPLES - 1))); + if (MI_NPIXELS(mi) > 2) + for (i = 0; i < (int) ap->ncolors - 1; i++) + ap->colors[i] = (unsigned char) (NRAND(MI_NPIXELS(mi)) + + i * MI_NPIXELS(mi)) / ((int) (ap->ncolors - 1)); + if (ap->ants == NULL) { + if ((ap->ants = (antstruct *) malloc(ap->n * sizeof (antstruct))) == + NULL) { + free_ant(mi); + return; + } + } + if (ap->tape != NULL) + (void) free((void *) ap->tape); + if ((ap->tape = (unsigned char *) calloc(ap->ncols * ap->nrows, + sizeof (unsigned char))) == NULL) { + free_ant(mi); + return; + } + if (ap->truchet_state != NULL) + (void) free((void *) ap->truchet_state); + if ((ap->truchet_state = (unsigned char *) calloc(ap->ncols * ap->nrows, + sizeof (unsigned char))) == NULL) { + free_ant(mi); + return; + } + + row = ap->nrows / 2; + col = ap->ncols / 2; + if (col > 0 && ((ap->neighbors % 2) || ap->neighbors == 12) && (LRAND() & 1)) + col--; + dir = NRAND(ap->neighbors) * ANGLES / ap->neighbors; + ap->init_dir = dir; +#ifdef NUMBER_9 + if (ap->neighbors == 9 && !((col + row) & 1)) + dir = (dir + ANGLES - ANGLES / (ap->neighbors * 2)) % ANGLES; +#endif + /* Have them all start in the same spot, why not? */ + for (i = 0; i < ap->n; i++) { + ap->ants[i].col = col; + ap->ants[i].row = row; + ap->ants[i].direction = dir; + ap->ants[i].state = 0; + } + draw_anant(mi, dir, col, row); +} + +ENTRYPOINT void +draw_ant(ModeInfo * mi) +{ + antstruct *anant; + statestruct *status; + int i, state_pos, tape_pos; + unsigned char color; + short chg_dir, old_dir; + antfarmstruct *ap; + + if (antfarms == NULL) + return; + ap = &antfarms[MI_SCREEN(mi)]; + if (ap->ants == NULL) + return; + + MI_IS_DRAWN(mi) = True; + ap->painted = True; + for (i = 0; i < ap->n; i++) { + anant = &ap->ants[i]; + tape_pos = anant->col + anant->row * ap->ncols; + color = ap->tape[tape_pos]; /* read tape */ + state_pos = color + anant->state * ap->ncolors; + status = &(ap->machine[state_pos]); + drawcell(mi, anant->col, anant->row, status->color); + ap->tape[tape_pos] = status->color; /* write on tape */ + + /* Find direction of Bees or Ants. */ + /* Translate relative direction to actual direction */ + old_dir = anant->direction; + chg_dir = (2 * ANGLES - status->direction) % ANGLES; + anant->direction = (chg_dir + old_dir) % ANGLES; + if (ap->truchet) { + int a = 0, b; + + if (ap->neighbors == 6) { + if (ap->sharpturn) { + a = (((ANGLES + anant->direction - old_dir) % ANGLES) == 240); + /* should be some way of getting rid of the init_dir dependency... */ + b = !(ap->init_dir % 120); + a = ((a && !b) || (b && !a)); + drawtruchet(mi, anant->col, anant->row, status->color, a); + } else { + a = (old_dir / 60) % 3; + b = (anant->direction / 60) % 3; + a = (a + b + 1) % 3; + drawtruchet(mi, anant->col, anant->row, status->color, a); + } + } else if (ap->neighbors == 4) { + a = old_dir / 180; + b = anant->direction / 180; + a = ((a && !b) || (b && !a)); + drawtruchet(mi, anant->col, anant->row, status->color, a); + } else if (ap->neighbors == 3) { + if (chg_dir == 240) + a = (2 + anant->direction / 120) % 3; + else + a = (1 + anant->direction / 120) % 3; + drawtruchet(mi, anant->col, anant->row, status->color, a); + } + ap->truchet_state[tape_pos] = a + 1; + } + anant->state = status->next; + + /* Allow step first and turn */ + old_dir = ((status->direction < ANGLES) ? anant->direction : old_dir); +#if DEBUG + (void) printf("old_dir %d, col %d, row %d", old_dir, anant->col, anant->row); +#endif + position_of_neighbor(ap, old_dir, &(anant->col), &(anant->row)); +#if DEBUG + (void) printf(", ncol %d, nrow %d\n", anant->col, anant->row); +#endif + draw_anant(mi, anant->direction, anant->col, anant->row); + } + if (++ap->generation > MI_CYCLES(mi)) { + init_ant(mi); + } + if (ap->redrawing) { + for (i = 0; i < REDRAWSTEP; i++) { + if (ap->tape[ap->redrawpos] || + (ap->truchet && ap->truchet_state[ap->redrawpos])) { + drawcell(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols, + ap->tape[ap->redrawpos]); + if (ap->truchet) + drawtruchet(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols, + ap->tape[ap->redrawpos], + ap->truchet_state[ap->redrawpos] - 1); + } + if (++(ap->redrawpos) >= ap->ncols * ap->nrows) { + ap->redrawing = 0; + break; + } + } + } +} + +#ifndef STANDALONE +ENTRYPOINT void +refresh_ant(ModeInfo * mi) +{ + antfarmstruct *ap; + + if (antfarms == NULL) + return; + ap = &antfarms[MI_SCREEN(mi)]; + + if (ap->painted) { + MI_CLEARWINDOW(mi); + ap->redrawing = 1; + ap->redrawpos = 0; + } +} +#endif + +XSCREENSAVER_MODULE ("Ant", ant) + +#endif /* MODE_ant */ diff --git a/hacks/ant.man b/hacks/ant.man new file mode 100644 index 0000000..fb71d57 --- /dev/null +++ b/hacks/ant.man @@ -0,0 +1,96 @@ +.TH XScreenSaver 1 "" "X Version 11" +.SH NAME +ant - cellular automaton. +.SH SYNOPSIS +.B ant +[\-display \fIhost:display.screen\fP] +[\-visual \fIvisual\fP] +[\-window] +[\-install] +[\-noinstall] +[\-root] +[\-eyes] +[\-no-eyes] +[\-truchet] +[\-no-truchet] +[\-sharpturn] +[\-no-sharpturn] +[\-delay \fInumber\fP] +[\-cycles \fInumber\fP] +[\-count \fInumber\fP] +[\-size \fInumber\fP] +[\-neighbors 3] +[\-neighbors 4] +[\-neighbors 6] +[\-neighbors 9] +[\-neighbors 12] +[\-ncolors \fInumber\fP] +[\-fps] +.SH DESCRIPTION +A cellular automaton that is really a two-dimensional Turing machine: as +the heads ("ants") walk along the screen, they change pixel values in +their path. Then, as they pass over changed pixels, their behavior is +influenced. +.SH OPTIONS +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-sharpturns | \-no-sharpturns +Whether to do sharp turns. +.TP 8 +.B \-truchet | \-no-truchet +Whether to use truchet lines. +.TP 8 +.B \-eyes | \-no-eyes +Whether to draw eyes on the ants. +.TP 8 +.B \-delay \fInumber\fP +Per-frame delay, in microseconds. Default: 1000 (0.0001 seconds.). +.TP 8 +.B \-cycles \fInumber\fP +How long to wait until resetting. 0 - 800000. Default: 40000. +.TP 8 +.B \-count \fInumber\fP +Ants Count. -20 - 20. Default: -3. +.TP 8 +.B \-size \fInumber\fP +Ant Size. -18 - 18. Default: -12. +.TP 8 +.B \-neighbors \fIN\fP +How many neighbors each cell has. Legal values are 3, 4, 6, 9, and 12. +.TP 8 +.B \-ncolors \fInumber\fP +Number of colors. Default: 64. +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1) +.SH COPYRIGHT +Copyright \(co 2002 by David Bagley. Permission to use, copy, modify, +distribute, and sell this software and its documentation for any purpose is +hereby granted without fee, provided that the above copyright notice appear +in all copies and that both that copyright notice and this permission notice +appear in supporting documentation. No representations are made about the +suitability of this software for any purpose. It is provided "as is" without +express or implied warranty. +.SH AUTHOR +David Bagley. diff --git a/hacks/apollonian.c b/hacks/apollonian.c new file mode 100644 index 0000000..4b28ac3 --- /dev/null +++ b/hacks/apollonian.c @@ -0,0 +1,810 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* apollonian --- Apollonian Circles */ + +#if 0 +static const char sccsid[] = "@(#)apollonian.c 5.02 2001/07/01 xlockmore"; +#endif + +/*- + * Copyright (c) 2000, 2001 by Allan R. Wilks . + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation. + * + * This file is provided AS IS with no warranties of any kind. The author + * shall have no liability with respect to the infringement of copyrights, + * trade secrets or any patents by this file or any part thereof. In no + * event will the author be liable for any lost revenue or profits or + * other special, indirect and consequential damages. + * + * radius r = 1 / c (curvature) + * + * Descartes Circle Theorem: (a, b, c, d are curvatures of tangential circles) + * Let a, b, c, d be the curvatures of for mutually (externally) tangent + * circles in the plane. Then + * a^2 + b^2 + c^2 + d^2 = (a + b + c + d)^2 / 2 + * + * Complex Descartes Theorem: If the oriented curvatues and (complex) centers + * of an oriented Descrates configuration in the plane are a, b, c, d and + * w, x, y, z respectively, then + * a^2*w^2 + b^2*x^2 + c^2*y^2 + d^2*z^2 = (aw + bx + cy + dz)^2 / 2 + * In addition these quantities satisfy + * a^2*w + b^2*x + c^2*y + d^2*z = (aw + bx + cy + dz)(a + b + c + d) / 2 + * + * Enumerate root integer Descartes quadruples (a,b,c,d) satisfying the + * Descartes condition: + * 2(a^2+b^2+c^2+d^2) = (a+b+c+d)^2 + * i.e., quadruples for which no application of the "pollinate" operator + * z <- 2(a+b+c+d) - 3*z, + * where z is in {a,b,c,d}, gives a quad of strictly smaller sum. This + * is equivalent to the condition: + * sum(a,b,c,d) >= 2*max(a,b,c,d) + * which, because of the Descartes condition, is equivalent to + * sum(a^2,b^2,c^2,d^2) >= 2*max(a,b,c,d)^2 + * + * + * Todo: + * Add a small font + * + * Revision History: + * 25-Jun-2001: Converted from C and Postscript code by David Bagley + * Original code by Allan R. Wilks . + * + * From Circle Math Science News April 21, 2001 VOL. 254-255 + * http://www.sciencenews.org/20010421/toc.asp + * Apollonian Circle Packings Assorted papers from Ronald L Graham, + * Jeffrey Lagarias, Colin Mallows, Allan Wilks, Catherine Yan + * http://front.math.ucdavis.edu/math.NT/0009113 + * http://front.math.ucdavis.edu/math.MG/0101066 + * http://front.math.ucdavis.edu/math.MG/0010298 + * http://front.math.ucdavis.edu/math.MG/0010302 + * http://front.math.ucdavis.edu/math.MG/0010324 + */ + +#ifdef STANDALONE +# define MODE_apollonian +# define DEFAULTS "*delay: 1000000 \n" \ + "*count: 64 \n" \ + "*cycles: 20 \n" \ + "*ncolors: 64 \n" \ + "*font: fixed" "\n" \ + "*fpsTop: true \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True" \ + +# define release_apollonian 0 +# define reshape_apollonian 0 +# define apollonian_handle_event 0 +# include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#ifdef MODE_apollonian + +#define DEF_ALTGEOM "True" +#define DEF_LABEL "True" + +static Bool altgeom; +static Bool label; + +static XrmOptionDescRec opts[] = +{ + {"-altgeom", ".apollonian.altgeom", XrmoptionNoArg, "on"}, + {"+altgeom", ".apollonian.altgeom", XrmoptionNoArg, "off"}, + {"-label", ".apollonian.label", XrmoptionNoArg, "on"}, + {"+label", ".apollonian.label", XrmoptionNoArg, "off"}, +}; +static argtype vars[] = +{ + {&altgeom, "altgeom", "AltGeom", DEF_ALTGEOM, t_Bool}, + {&label, "label", "Label", DEF_LABEL, t_Bool}, +}; +static OptionStruct desc[] = +{ + {"-/+altgeom", "turn on/off alternate geometries (off euclidean space, on includes spherical and hyperbolic)"}, + {"-/+label", "turn on/off alternate space and number labeling"}, +}; + +ENTRYPOINT ModeSpecOpt apollonian_opts = +{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; + +#ifdef DOFONT +extern XFontStruct *getFont(Display * display); +#endif + +#ifdef USE_MODULES +ModStruct apollonian_description = +{"apollonian", "init_apollonian", "draw_apollonian", (char *) NULL, + "init_apollonian", "init_apollonian", "free_apollonian", &apollonian_opts, + 1000000, 64, 20, 1, 64, 1.0, "", + "Shows Apollonian Circles", 0, NULL}; + +#endif + +typedef struct { + int a, b, c, d; +} apollonian_quadruple; + +typedef struct { + double e; /* euclidean bend */ + double s; /* spherical bend */ + double h; /* hyperbolic bend */ + double x, y; /* euclidean bend times euclidean position */ +} circle; +enum space { + euclidean = 0, spherical, hyperbolic +}; + +static const char * space_string[] = { + "euclidean", + "spherical", + "hyperbolic" +}; + +/* +Generate Apollonian packing starting with a quadruple of circles. +The four input lines each contain the 5-tuple (e,s,h,x,y) representing +the circle with radius 1/e and center (x/e,y/e). The s and h is propagated +like e, x and y, but can differ from e so as to represent different +geometries, spherical and hyperbolic, respectively. The "standard" picture, +for example (-1, 2, 2, 3), can be labeled for the three geometries. +Origins of circles z1, z2, z3, z4 +a * z1 = 0 +b * z2 = (a+b)/a +c * z3 = (q123 + a * i)^2/(a*(a+b)) where q123 = sqrt(a*b+a*c+b*c) +d * z4 = (q124 + a * i)^2/(a*(a+b)) where q124 = q123 - a - b +If (e,x,y) represents the Euclidean circle (1/e,x/e,y/e) (so that e is +the label in the standard picture) then the "spherical label" is +(e^2+x^2+y^2-1)/(2*e) (an integer!) and the "hyperbolic label", is +calulated by h + s = e. +*/ +static circle examples[][4] = { +{ /* double semi-bounded */ + { 0, 0, 0, 0, 1}, + { 0, 0, 0, 0, -1}, + { 1, 1, 1, -1, 0}, + { 1, 1, 1, 1, 0} +}, +#if 0 +{ /* standard */ + {-1, 0, -1, 0, 0}, + { 2, 1, 1, 1, 0}, + { 2, 1, 1, -1, 0}, + { 3, 2, 1, 0, 2} +}, +{ /* next simplest */ + {-2, -1, -1, 0.0, 0}, + { 3, 2, 1, 0.5, 0}, + { 6, 3, 3, -2.0, 0}, + { 7, 4, 3, -1.5, 2} +}, +{ /* */ + {-3, -2, -1, 0.0, 0}, + { 4, 3, 1, 1.0 / 3.0, 0}, + {12, 7, 5, -3.0, 0}, + {13, 8, 5, -8.0 / 3.0, 2} +}, +{ /* Mickey */ + {-3, -2, -1, 0.0, 0}, + { 5, 4, 1, 2.0 / 3.0, 0}, + { 8, 5, 3, -4.0 / 3.0, -1}, + { 8, 5, 3, -4.0 / 3.0, 1} +}, +{ /* */ + {-4, -3, -1, 0.00, 0}, + { 5, 4, 1, 0.25, 0}, + {20, 13, 7, -4.00, 0}, + {21, 14, 7, -3.75, 2} +}, +{ /* Mickey2 */ + {-4, -2, -2, 0.0, 0}, + { 8, 4, 4, 1.0, 0}, + { 9, 5, 4, -0.75, -1}, + { 9, 5, 4, -0.75, 1} +}, +{ /* Mickey3 */ + {-5, -4, -1, 0.0, 0}, + { 7, 6, 1, 0.4, 0}, + {18, 13, 5, -2.4, -1}, + {18, 13, 5, -2.4, 1} +}, +{ /* */ + {-6, -5, -1, 0.0, 0}, + { 7, 6, 1, 1.0 / 6.0, 0}, + {42, 31, 11, -6.0, 0}, + {43, 32, 11, -35.0 / 6.0, 2} +}, +{ /* */ + {-6, -3, -3, 0.0, 0}, + {10, 5, 5, 2.0 / 3.0, 0}, + {15, 8, 7, -1.5, 0}, + {19, 10, 9, -5.0 / 6.0, 2} +}, +{ /* asymmetric */ + {-6, -5, -1, 0.0, 0.0}, + {11, 10, 1, 5.0 / 6.0, 0.0}, + {14, 11, 3, -16.0 / 15.0, -0.8}, + {15, 12, 3, -0.9, 1.2} +}, +#endif +/* Non integer stuff */ +#define DELTA 2.154700538 /* ((3+2*sqrt(3))/3) */ +{ /* 3 fold symmetric bounded (x, y calculated later) */ + { -1, -1, -1, 0.0, 0.0}, + {DELTA, DELTA, DELTA, 1.0, 0.0}, + {DELTA, DELTA, DELTA, 1.0, -1.0}, + {DELTA, DELTA, DELTA, -1.0, 1.0} +}, +{ /* semi-bounded (x, y calculated later) */ +#define ALPHA 2.618033989 /* ((3+sqrt(5))/2) */ + { 1.0, 1.0, 1.0, 0, 0}, + { 0.0, 0.0, 0.0, 0, -1}, + {1.0/(ALPHA*ALPHA), 1.0/(ALPHA*ALPHA), 1.0/(ALPHA*ALPHA), -1, 0}, + { 1.0/ALPHA, 1.0/ALPHA, 1.0/ALPHA, -1, 0} +}, +{ /* unbounded (x, y calculated later) */ +/* #define PHI 1.618033989 *//* ((1+sqrt(5))/2) */ +#define BETA 2.890053638 /* (PHI+sqrt(PHI)) */ + { 1.0, 1.0, 1.0, 0, 0}, + {1.0/(BETA*BETA*BETA), 1.0/(BETA*BETA*BETA), 1.0/(BETA*BETA*BETA), 1, 0}, + { 1.0/(BETA*BETA), 1.0/(BETA*BETA), 1.0/(BETA*BETA), 1, 0}, + { 1.0/BETA, 1.0/BETA, 1.0/BETA, 1, 0} +} +}; + +#define PREDEF_CIRCLE_GAMES (sizeof (examples) / (4 * sizeof (circle))) + +#if 0 +Euclidean +0, 0, 1, 1 +-1, 2, 2, 3 +-2, 3, 6, 7 +-3, 5, 8, 8 +-4, 8, 9, 9 +-3, 4, 12, 13 +-6, 11, 14, 15 + -5, 7, 18, 18 + -6, 10, 15, 19 + -7, 12, 17, 20 + -4, 5, 20, 21 + -9, 18, 19, 22 + -8, 13, 21, 24 +Spherical +0, 1, 1, 2 + -1, 2, 3, 4 + -2, 4, 5, 5 + -2, 3, 7, 8 +Hyperbolic +-1, 1, 1, 1 + 0, 0, 1, 3 + -2, 3, 5, 6 + -3, 6, 6, 7 +#endif + +typedef struct { + int size; + XPoint offset; + int geometry; + circle c1, c2, c3, c4; + int color_offset; + int count; + Bool label, altgeom; + apollonian_quadruple *quad; +#ifdef DOFONT + XFontStruct *font; +#endif + int time; + int game; +} apollonianstruct; + +static apollonianstruct *apollonians = (apollonianstruct *) NULL; + +#define FONT_HEIGHT 19 +#define FONT_WIDTH 15 +#define FONT_LENGTH 20 +#define MAX_CHAR 10 +#define K 2.15470053837925152902 /* 1+2/sqrt(3) */ +#define MAXBEND 100 /* Do not want configurable by user since it will take too + much time if increased. */ + +static int +gcd(int a, int b) +{ + int r; + + while (b) { + r = a % b; + a = b; + b = r; + } + return a; +} + +static int +isqrt(int n) +{ + int y; + + if (n < 0) + return -1; + y = (int) (sqrt((double) n) + 0.5); + return ((n == y*y) ? y : -1); +} + +static void +dquad(int n, apollonian_quadruple *quad) +{ + int a, b, c, d; + int counter = 0, B, C; + + for (a = 0; a < MAXBEND; a++) { + B = (int) (K * a); + for (b = a + 1; b <= B; b++) { + C = (int) (((a + b) * (a + b)) / (4.0 * (b - a))); + for (c = b; c <= C; c++) { + d = isqrt(b*c-a*(b+c)); + if (d >= 0 && (gcd(a,gcd(b,c)) <= 1)) { + quad[counter].a = -a; + quad[counter].b = b; + quad[counter].c = c; + quad[counter].d = -a+b+c-2*d; + if (++counter >= n) { + return; + } + } + } + } + } + (void) printf("found only %d below maximum bend of %d\n", + counter, MAXBEND); + for (; counter < n; counter++) { + quad[counter].a = -1; + quad[counter].b = 2; + quad[counter].c = 2; + quad[counter].d = 3; + } + return; +} + +/* + * Given a Descartes quadruple of bends (a,b,c,d), with a<0, find a + * quadruple of circles, represented by (bend,bend*x,bend*y), such + * that the circles have the given bends and the bends times the + * centers are integers. + * + * This just performs an exaustive search, assuming that the outer + * circle has center in the unit square. + * + * It is always sufficient to look in {(x,y):0<=y<=x<=1/2} for the + * center of the outer circle, but this may not lead to a packing + * that can be labelled with integer spherical and hyperbolic labels. + * To effect the smaller search, replace FOR(a) with + * + * for (pa = ea/2; pa <= 0; pa++) for (qa = pa; qa <= 0; qa++) + */ + +#define For(v,l,h) for (v = l; v <= h; v++) +#define FOR(z) For(p##z,lop##z,hip##z) For(q##z,loq##z,hiq##z) +#define H(z) ((e##z*e##z+p##z*p##z+q##z*q##z)%2) +#define UNIT(z) ((abs(e##z)-1)*(abs(e##z)-1) >= p##z*p##z+q##z*q##z) +#define T(z,w) is_tangent(e##z,p##z,q##z,e##w,p##w,q##w) +#define LO(r,z) lo##r##z = iceil(e##z*(r##a+1),ea)-1 +#define HI(r,z) hi##r##z = iflor(e##z*(r##a-1),ea)-1 +#define B(z) LO(p,z); HI(p,z); LO(q,z); HI(q,z) + +static int +is_quad(int a, int b, int c, int d) +{ + int s; + + s = a+b+c+d; + return 2*(a*a+b*b+c*c+d*d) == s*s; +} + +static Bool +is_tangent(int e1, int p1, int q1, int e2, int p2, int q2) +{ + int dx, dy, s; + + dx = p1*e2 - p2*e1; + dy = q1*e2 - q2*e1; + s = e1 + e2; + return dx*dx + dy*dy == s*s; +} + +static int +iflor(int a, int b) +{ + int q; + + if (b == 0) { + (void) printf("iflor: b = 0\n"); + return 0; + } + if (a%b == 0) + return a/b; + q = abs(a)/abs(b); + return ((a<0)^(b<0)) ? -q-1 : q; +} + +static int +iceil(int a, int b) +{ + int q; + + if (b == 0) { + (void) printf("iceil: b = 0\n"); + return 0; + } + if (a%b == 0) + return a/b; + q = abs(a)/abs(b); + return ((a<0)^(b<0)) ? -q : 1+q; +} + +static double +geom(int geometry, int e, int p, int q) +{ + int g = (geometry == spherical) ? -1 : + (geometry == hyperbolic) ? 1 : 0; + + if (g) + return (e*e + (1.0 - p*p - q*q) * g) / (2.0*e); + (void) printf("geom: g = 0\n"); + return e; +} + +static void +cquad(circle *c1, circle *c2, circle *c3, circle *c4) +{ + int ea, eb, ec, ed; + int pa, pb, pc, pd; + int qa, qb, qc, qd; + int lopa, lopb, lopc, lopd; + int hipa, hipb, hipc, hipd; + int loqa, loqb, loqc, loqd; + int hiqa, hiqb, hiqc, hiqd; + + ea = (int) c1->e; + eb = (int) c2->e; + ec = (int) c3->e; + ed = (int) c4->e; + if (ea >= 0) + (void) printf("ea = %d\n", ea); + if (!is_quad(ea,eb,ec,ed)) + (void) printf("Error not quad %d %d %d %d\n", ea, eb, ec, ed); + lopa = loqa = ea; + hipa = hiqa = 0; + FOR(a) { + B(b); B(c); B(d); + if (H(a) && UNIT(a)) FOR(b) { + if (H(b) && T(a,b)) FOR(c) { + if (H(c) && T(a,c) && T(b,c)) FOR(d) { + if (H(d) && T(a,d) && T(b,d) && T(c,d)) { + c1->s = geom(spherical, ea, pa, qa); + c1->h = geom(hyperbolic, ea, pa, qa); + c2->s = geom(spherical, eb, pb, qb); + c2->h = geom(hyperbolic, eb, pb, qb); + c3->s = geom(spherical, ec, pc, qc); + c3->h = geom(hyperbolic, ec, pc, qc); + c4->s = geom(spherical, ed, pd, qd); + c4->h = geom(hyperbolic, ed, pd, qd); + } + } + } + } + } +} + +static void +p(ModeInfo *mi, circle c) +{ + apollonianstruct *cp = &apollonians[MI_SCREEN(mi)]; + char string[15]; + double g, e; + int g_width; + +#ifdef DEBUG + (void) printf("c.e=%g c.s=%g c.h=%g c.x=%g c.y=%g\n", + c.e, c.s, c.h, c.x, c.y); +#endif + g = (cp->geometry == spherical) ? c.s : (cp->geometry == hyperbolic) ? + c.h : c.e; + if (c.e < 0.0) { + if (g < 0.0) + g = -g; + if (MI_NPIXELS(mi) <= 2) + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), + MI_WHITE_PIXEL(mi)); + else + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), + MI_PIXEL(mi, ((int) ((g + cp->color_offset) * + g)) % MI_NPIXELS(mi))); + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + ((int) (cp->size * (-cp->c1.e) * (c.x - 1.0) / + (-2.0 * c.e) + cp->size / 2.0 + cp->offset.x)), + ((int) (cp->size * (-cp->c1.e) * (c.y - 1.0) / + (-2.0 * c.e) + cp->size / 2.0 + cp->offset.y)), + (int) (cp->c1.e * cp->size / c.e), + (int) (cp->c1.e * cp->size / c.e), 0, 23040); + if (!cp->label) { +#ifdef DEBUG + (void) printf("%g\n", -g); +#endif + return; + } + (void) sprintf(string, "%g", (g == 0.0) ? 0 : -g); + if (cp->size >= 10 * FONT_WIDTH) { + /* hard code these to corners */ + XDrawString(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + ((int) (cp->size * c.x / (2.0 * c.e))) + cp->offset.x, + ((int) (cp->size * c.y / (2.0 * c.e))) + FONT_HEIGHT, + string, (g == 0.0) ? 1 : ((g < 10.0) ? 2 : + ((g < 100.0) ? 3 : 4))); + } + if (cp->altgeom && MI_HEIGHT(mi) >= 30 * FONT_WIDTH) { + XDrawString(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + ((int) (cp->size * c.x / (2.0 * c.e) + cp->offset.x)), + ((int) (cp->size * c.y / (2.0 * c.e) + MI_HEIGHT(mi) - + FONT_HEIGHT / 2)), (char *) space_string[cp->geometry], + strlen(space_string[cp->geometry])); + } + return; + } + if (MI_NPIXELS(mi) <= 2) + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); + else + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), + MI_PIXEL(mi, ((int) ((g + cp->color_offset) * g)) % + MI_NPIXELS(mi))); + if (c.e == 0.0) { + if (c.x == 0.0 && c.y != 0.0) { + XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + 0, (int) ((c.y + 1.0) * cp->size / 2.0 + cp->offset.y), + MI_WIDTH(mi), + (int) ((c.y + 1.0) * cp->size / 2.0 + cp->offset.y)); + } else if (c.y == 0.0 && c.x != 0.0) { + XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + (int) ((c.x + 1.0) * cp->size / 2.0 + cp->offset.x), 0, + (int) ((c.x + 1.0) * cp->size / 2.0 + cp->offset.x), + MI_HEIGHT(mi)); + } + return; + } + e = (cp->c1.e >= 0.0) ? 1.0 : -cp->c1.e; + XFillArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + ((int) (cp->size * e * (c.x - 1.0) / (2.0 * c.e) + + cp->size / 2.0 + cp->offset.x)), + ((int) (cp->size * e * (c.y - 1.0) / (2.0 * c.e) + + cp->size / 2.0 + cp->offset.y)), + (int) (e * cp->size / c.e), (int) (e * cp->size / c.e), + 0, 23040); + if (!cp->label) { +#ifdef DEBUG + (void) printf("%g\n", g); +#endif + return; + } + if (MI_NPIXELS(mi) <= 2) + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + else + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), + MI_PIXEL(mi, ((int) ((g + cp->color_offset) * g) + + MI_NPIXELS(mi) / 2) % MI_NPIXELS(mi))); + g_width = (g < 10.0) ? 1: ((g < 100.0) ? 2 : 3); + if (c.e < e * cp->size / (FONT_LENGTH + 5 * g_width) && g < 1000.0) { + (void) sprintf(string, "%g", g); + XDrawString(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + ((int) (cp->size * e * c.x / (2.0 * c.e) + + cp->size / 2.0 + cp->offset.x)) - + g_width * FONT_WIDTH / 2, + ((int) (cp->size * e * c.y / (2.0 * c.e) + + cp->size / 2.0 + cp->offset.y)) + + FONT_HEIGHT / 2, + string, g_width); + } +} + +#define BIG 7 +static void +f(ModeInfo *mi, circle c1, circle c2, circle c3, circle c4, int depth) +{ + apollonianstruct *cp = &apollonians[MI_SCREEN(mi)]; + int e = (int) ((cp->c1.e >= 0.0) ? 1.0 : -cp->c1.e); + circle c; + + if (depth > mi->recursion_depth) mi->recursion_depth = depth; + + c.e = 2*(c1.e+c2.e+c3.e) - c4.e; + c.s = 2*(c1.s+c2.s+c3.s) - c4.s; + c.h = 2*(c1.h+c2.h+c3.h) - c4.h; + c.x = 2*(c1.x+c2.x+c3.x) - c4.x; + c.y = 2*(c1.y+c2.y+c3.y) - c4.y; + if (c.e == 0 || + c.e > cp->size * e || c.x / c.e > BIG || c.y / c.e > BIG || + c.x / c.e < -BIG || c.y / c.e < -BIG) + return; + p(mi, c); + f(mi, c2, c3, c, c1, depth+1); + f(mi, c1, c3, c, c2, depth+1); + f(mi, c1, c2, c, c3, depth+1); +} + +ENTRYPOINT void +free_apollonian (ModeInfo * mi) +{ + apollonianstruct *cp = &apollonians[MI_SCREEN(mi)]; + + if (cp->quad != NULL) { + (void) free((void *) cp->quad); + cp->quad = (apollonian_quadruple *) NULL; + } +#ifdef DOFONT + if (cp->gc != None) { + XFreeGC(display, cp->gc); + cp->gc = None; + } + if (cp->font != None) { + XFreeFont(display, cp->font); + cp->font = None; + } +#endif +} + +#ifndef DEBUG +static void +randomize_c(int randomize, circle * c) +{ + if (randomize / 2) { + double temp; + + temp = c->x; + c->x = c->y; + c->y = temp; + } + if (randomize % 2) { + c->x = -c->x; + c->y = -c->y; + } +} +#endif + +ENTRYPOINT void +init_apollonian (ModeInfo * mi) +{ + apollonianstruct *cp; + int i; + + MI_INIT (mi, apollonians); + cp = &apollonians[MI_SCREEN(mi)]; + + cp->size = MAX(MIN(MI_WIDTH(mi), MI_HEIGHT(mi)) - 1, 1); + cp->offset.x = (MI_WIDTH(mi) - cp->size) / 2; + cp->offset.y = (MI_HEIGHT(mi) - cp->size) / 2; + cp->color_offset = NRAND(MI_NPIXELS(mi)); + +#ifdef DOFONT + if (cp->font == None) { + if ((cp->font = getFont(MI_DISPLAY(mi))) == None) + return False; + } +#endif + cp->label = label; + cp->altgeom = cp->label && altgeom; + + if (cp->quad == NULL) { + cp->count = ABS(MI_COUNT(mi)); + if ((cp->quad = (apollonian_quadruple *) malloc(cp->count * + sizeof (apollonian_quadruple))) == NULL) { + return; + } + dquad(cp->count, cp->quad); + } + cp->game = NRAND(PREDEF_CIRCLE_GAMES + cp->count); + cp->geometry = (cp->game && cp->altgeom) ? NRAND(3) : 0; + + if (cp->game < PREDEF_CIRCLE_GAMES) { + cp->c1 = examples[cp->game][0]; + cp->c2 = examples[cp->game][1]; + cp->c3 = examples[cp->game][2]; + cp->c4 = examples[cp->game][3]; + /* do not label non int */ + cp->label = cp->label && (cp->c4.e == (int) cp->c4.e); + } else { /* uses results of dquad, all int */ + i = cp->game - PREDEF_CIRCLE_GAMES; + cp->c1.e = cp->quad[i].a; + cp->c2.e = cp->quad[i].b; + cp->c3.e = cp->quad[i].c; + cp->c4.e = cp->quad[i].d; + if (cp->geometry) + cquad(&(cp->c1), &(cp->c2), &(cp->c3), &(cp->c4)); + } + cp->time = 0; + MI_CLEARWINDOW(mi); + if (cp->game != 0) { + double q123; + + if (cp->c1.e == 0.0 || cp->c1.e == -cp->c2.e) + return; + cp->c1.x = 0.0; + cp->c1.y = 0.0; + cp->c2.x = -(cp->c1.e + cp->c2.e) / cp->c1.e; + cp->c2.y = 0; + q123 = sqrt(cp->c1.e * cp->c2.e + cp->c1.e * cp->c3.e + + cp->c2.e * cp->c3.e); +#ifdef DEBUG + (void) printf("q123 = %g, ", q123); +#endif + cp->c3.x = (cp->c1.e * cp->c1.e - q123 * q123) / (cp->c1.e * + (cp->c1.e + cp->c2.e)); + cp->c3.y = -2.0 * q123 / (cp->c1.e + cp->c2.e); + q123 = -cp->c1.e - cp->c2.e + q123; + cp->c4.x = (cp->c1.e * cp->c1.e - q123 * q123) / (cp->c1.e * + (cp->c1.e + cp->c2.e)); + cp->c4.y = -2.0 * q123 / (cp->c1.e + cp->c2.e); +#ifdef DEBUG + (void) printf("q124 = %g\n", q123); + (void) printf("%g %g %g %g %g %g %g %g\n", + cp->c1.x, cp->c1.y, cp->c2.x, cp->c2.y, + cp->c3.x, cp->c3.y, cp->c4.x, cp->c4.y); +#endif + } +#ifndef DEBUG + if (LRAND() & 1) { + cp->c3.y = -cp->c3.y; + cp->c4.y = -cp->c4.y; + } + i = NRAND(4); + randomize_c(i, &(cp->c1)); + randomize_c(i, &(cp->c2)); + randomize_c(i, &(cp->c3)); + randomize_c(i, &(cp->c4)); +#endif + + mi->recursion_depth = -1; +} + +ENTRYPOINT void +draw_apollonian (ModeInfo * mi) +{ + apollonianstruct *cp; + + if (apollonians == NULL) + return; + cp = &apollonians[MI_SCREEN(mi)]; + + + MI_IS_DRAWN(mi) = True; + + if (cp->time < 5) { + switch (cp->time) { + case 0: + p(mi, cp->c1); + p(mi, cp->c2); + p(mi, cp->c3); + p(mi, cp->c4); + break; + case 1: + f(mi, cp->c1, cp->c2, cp->c3, cp->c4, 0); + break; + case 2: + f(mi, cp->c1, cp->c2, cp->c4, cp->c3, 0); + break; + case 3: + f(mi, cp->c1, cp->c3, cp->c4, cp->c2, 0); + break; + case 4: + f(mi, cp->c2, cp->c3, cp->c4, cp->c1, 0); + } + } + if (++cp->time > MI_CYCLES(mi)) + init_apollonian(mi); +} + +XSCREENSAVER_MODULE ("Apollonian", apollonian) + +#endif /* MODE_apollonian */ diff --git a/hacks/apollonian.man b/hacks/apollonian.man new file mode 100644 index 0000000..157d109 --- /dev/null +++ b/hacks/apollonian.man @@ -0,0 +1,70 @@ +.TH XScreenSaver 1 "" "X Version 11" +.SH NAME +apollonian - Descartes Circle Theorem. +.SH SYNOPSIS +.B apollonian +[\-display \fIhost:display.screen\fP] +[\-visual \fIvisual\fP] +[\-window] +[\-root] +[\-no-label] +[\-no-altgeom] +[\-cycles \fInumber\fP] +[\-ncolors \fInumber\fP] +[\-delay \fInumber\fP] +[\-fps] +.SH DESCRIPTION +Packs a large circle with smaller circles, demonstrating the Descartes +Circle Theorem. +.SH OPTIONS +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-label | \-no-label +Draw Labels. Boolean. +.TP 8 +.B \-altgeom | \-no-altgeom +Include Alternate Geometries. Boolean. +.TP 8 +.B \-cycles \fInumber\fP +Depth. 1 - 20. Default: 20. +.TP 8 +.B \-ncolors \fInumber\fP +Number of Colors. Default: 64. +.TP 8 +.B \-delay \fInumber\fP +Per-frame delay, in microseconds. Default: 1000000 (1.00 seconds.). +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1) +.SH COPYRIGHT +Copyright \(co 2002 by Allan R. Wilks and David Bagley. Permission to +use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. No representations are made about the suitability of +this software for any purpose. It is provided "as is" without express +or implied warranty. +.SH AUTHOR +Allan R. Wilks and David Bagley. diff --git a/hacks/apple2-main.c b/hacks/apple2-main.c new file mode 100644 index 0000000..3063b58 --- /dev/null +++ b/hacks/apple2-main.c @@ -0,0 +1,1913 @@ +/* xscreensaver, Copyright (c) 1998-2014 Jamie Zawinski + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * Apple ][ CRT simulator, by Trevor Blackwell + * with additional work by Jamie Zawinski + * Pty and vt100 emulation by Fredrik Tolf + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include "screenhack.h" +#include "apple2.h" +#include "textclient.h" +#include "utf8wc.h" + +#undef countof +#define countof(x) (sizeof((x))/sizeof((*x))) + +#define SCREEN_COLS 40 +#define SCREEN_ROWS 24 + + +/* Given a bitmask, returns the position and width of the field. + */ +static void +decode_mask (unsigned int mask, unsigned int *pos_ret, unsigned int *size_ret) +{ + int i; + for (i = 0; i < 32; i++) + if (mask & (1L << i)) + { + int j = 0; + *pos_ret = i; + for (; i < 32; i++, j++) + if (! (mask & (1L << i))) + break; + *size_ret = j; + return; + } +} + + +/* Given a value and a field-width, expands the field to fill out 8 bits. + */ +static unsigned char +spread_bits (unsigned char value, unsigned char width) +{ + switch (width) + { + case 8: return value; + case 7: return (value << 1) | (value >> 6); + case 6: return (value << 2) | (value >> 4); + case 5: return (value << 3) | (value >> 2); + case 4: return (value << 4) | (value); + case 3: return (value << 5) | (value << 2) | (value >> 2); + case 2: return (value << 6) | (value << 4) | (value); + default: abort(); break; + } +} + + +/* Convert an XImage (of any size/depth/visual) to a 32bpp RGB array. + Scales it (without dithering) to WxH. + */ +static void +scale_image (Display *dpy, Window window, XImage *in, + int fromx, int fromy, int fromw, int fromh, + unsigned int *out, int w, int h) +{ + float scale; + int x, y, i; + unsigned int rpos=0, gpos=0, bpos=0; /* bitfield positions */ + unsigned int rsiz=0, gsiz=0, bsiz=0; + unsigned long rmsk=0, gmsk=0, bmsk=0; + unsigned char spread_map[3][256]; + XWindowAttributes xgwa; + XColor *colors = 0; + + if (fromx + fromw > in->width || + fromy + fromh > in->height) + abort(); + + XGetWindowAttributes (dpy, window, &xgwa); + + /* Compute the field offsets for RGB decoding in the XImage, + when in TrueColor mode. Otherwise we use the colormap. + */ + if (visual_class (xgwa.screen, xgwa.visual) == PseudoColor || + visual_class (xgwa.screen, xgwa.visual) == GrayScale) + { + int ncolors = visual_cells (xgwa.screen, xgwa.visual); + colors = (XColor *) calloc (sizeof (*colors), ncolors+1); + for (i = 0; i < ncolors; i++) + colors[i].pixel = i; + XQueryColors (dpy, xgwa.colormap, colors, ncolors); + } + else + { + visual_rgb_masks (xgwa.screen, xgwa.visual, &rmsk, &gmsk, &bmsk); + decode_mask (rmsk, &rpos, &rsiz); + decode_mask (gmsk, &gpos, &gsiz); + decode_mask (bmsk, &bpos, &bsiz); + + for (i = 0; i < 256; i++) + { + spread_map[0][i] = spread_bits (i, rsiz); + spread_map[1][i] = spread_bits (i, gsiz); + spread_map[2][i] = spread_bits (i, bsiz); + } + } + + scale = (fromw > fromh + ? (float) fromw / w + : (float) fromh / h); + + /* Scale the pixmap from window size to Apple][ screen size (but 32bpp) + */ + for (y = 0; y < h-1; y++) /* iterate over dest pixels */ + for (x = 0; x < w-1; x++) + { + int xx, yy; + unsigned int r=0, g=0, b=0; + + int xx1 = x * scale + fromx; + int yy1 = y * scale + fromy; + int xx2 = (x+1) * scale + fromx; + int yy2 = (y+1) * scale + fromy; + + /* Iterate over the source pixels contributing to this one, and sum. */ + for (xx = xx1; xx < xx2; xx++) + for (yy = yy1; yy < yy2; yy++) + { + unsigned char rr, gg, bb; + unsigned long sp = ((xx > in->width || yy > in->height) + ? 0 : XGetPixel (in, xx, yy)); + if (colors) + { + rr = colors[sp].red & 0xFF; + gg = colors[sp].green & 0xFF; + bb = colors[sp].blue & 0xFF; + } + else + { + rr = (sp & rmsk) >> rpos; + gg = (sp & gmsk) >> gpos; + bb = (sp & bmsk) >> bpos; + rr = spread_map[0][rr]; + gg = spread_map[1][gg]; + bb = spread_map[2][bb]; + } + r += rr; + g += gg; + b += bb; + } + + /* Scale summed pixel values down to 8/8/8 range */ + i = (xx2 - xx1) * (yy2 - yy1); + if (i < 1) i = 1; + r /= i; + g /= i; + b /= i; + + out[y * w + x] = (r << 16) | (g << 8) | b; + } +} + + +/* Convert an XImage (of any size/depth/visual) to a 32bpp RGB array. + Picks a random sub-image out of the source image, and scales it to WxH. + */ +static void +pick_a2_subimage (Display *dpy, Window window, XImage *in, + unsigned int *out, int w, int h) +{ + int fromx, fromy, fromw, fromh; + if (in->width <= w || in->height <= h) + { + fromx = 0; + fromy = 0; + fromw = in->width; + fromh = in->height; + } + else + { + int dw, dh; + do { + double scale = (0.5 + frand(0.7) + frand(0.7) + frand(0.7)); + fromw = w * scale; + fromh = h * scale; + } while (fromw > in->width || + fromh > in->height); + + dw = (in->width - fromw) / 2; /* near the center! */ + dh = (in->height - fromh) / 2; + + fromx = (dw <= 0 ? 0 : (random() % dw) + (dw/2)); + fromy = (dh <= 0 ? 0 : (random() % dh) + (dh/2)); + } + + scale_image (dpy, window, in, + fromx, fromy, fromw, fromh, + out, w, h); +} + + +/* Floyd-Steinberg dither. Derived from ppmquant.c, + Copyright (c) 1989, 1991 by Jef Poskanzer. + */ +static void +a2_dither (unsigned int *in, unsigned char *out, int w, int h) +{ + /* + Apple ][ color map. Each pixel can only be 1 or 0, but what that + means depends on whether it's an odd or even pixel, and whether + the high bit in the byte is set or not. If it's 0, it's always + black. + */ + static const int a2_cmap[2][2][3] = { + { + /* hibit=0 */ + {/* odd pixels = blue */ 0x00, 0x80, 0xff}, + {/* even pixels = red */ 0xff, 0x80, 0x00} + }, + { + /* hibit=1 */ + {/* even pixels = purple */ 0xa0, 0x40, 0xa0}, + {/* odd pixels = green */ 0x40, 0xff, 0x40} + } + }; + + int x, y; + unsigned int **pixels; + unsigned int *pP; + int maxval = 255; + long *this_rerr; + long *next_rerr; + long *this_gerr; + long *next_gerr; + long *this_berr; + long *next_berr; + long *temp_err; + int fs_scale = 1024; + int brightness = 75; + +#if 0 + { + FILE *pipe = popen ("xv -", "w"); + fprintf (pipe, "P6\n%d %d\n%d\n", w, h, 255); + for (y = 0; y < h; y++) + for (x = 0; x < w; x++) + { + unsigned int p = in[y * w + x]; + unsigned int r = (p >> 16) & 0xFF; + unsigned int g = (p >> 8) & 0xFF; + unsigned int b = (p ) & 0xFF; + fprintf(pipe, "%c%c%c", r, g, b); + } + fclose (pipe); + } +#endif + + /* Initialize Floyd-Steinberg error vectors. */ + this_rerr = (long *) calloc (w + 2, sizeof(long)); + next_rerr = (long *) calloc (w + 2, sizeof(long)); + this_gerr = (long *) calloc (w + 2, sizeof(long)); + next_gerr = (long *) calloc (w + 2, sizeof(long)); + this_berr = (long *) calloc (w + 2, sizeof(long)); + next_berr = (long *) calloc (w + 2, sizeof(long)); + + + /* #### do we really need more than one element of "pixels" at once? + */ + pixels = (unsigned int **) malloc (h * sizeof (unsigned int *)); + for (y = 0; y < h; y++) + pixels[y] = (unsigned int *) malloc (w * sizeof (unsigned int)); + + for (x = 0; x < w + 2; ++x) + { + this_rerr[x] = random() % (fs_scale * 2) - fs_scale; + this_gerr[x] = random() % (fs_scale * 2) - fs_scale; + this_berr[x] = random() % (fs_scale * 2) - fs_scale; + /* (random errors in [-1 .. 1]) */ + } + + for (y = 0; y < h; y++) + for (x = 0; x < w; x++) + pixels[y][x] = in[y * w + x]; + + for (y = 0; y < h; y++) + { + int xbyte; + int err; + int prev_byte=0; + + for (x = 0; x < w + 2; x++) + next_rerr[x] = next_gerr[x] = next_berr[x] = 0; + + /* It's too complicated to go back and forth on alternate rows, + so we always go left-right here. It doesn't change the result + very much. + + For each group of 7 pixels, we have to try it both with the + high bit=0 and =1. For each high bit value, we add up the + total error and pick the best one. + + Because we have to go through each group of bits twice, we + don't propagate the error values through this_[rgb]err since + it would add them twice. So we keep seperate local_[rgb]err + variables for propagating error within the 7-pixel group. + */ + + pP = pixels[y]; + for (xbyte=0; xbyte<280; xbyte+=7) + { + int best_byte=0; + int best_error=2000000000; + int hibit; + int sr, sg, sb; + int r2, g2, b2; + int local_rerr=0, local_gerr=0, local_berr=0; + + for (hibit=0; hibit<2; hibit++) + { + int byte = hibit<<7; + int tot_error=0; + + for (x=xbyte; x> 16) & 0xFF) * brightness/256; + sg = ((pP[x] >> 8) & 0xFF) * brightness/256; + sb = ((pP[x] ) & 0xFF) * brightness/256; + sr += (this_rerr[x + 1] + local_rerr) / fs_scale; + sg += (this_gerr[x + 1] + local_gerr) / fs_scale; + sb += (this_berr[x + 1] + local_berr) / fs_scale; + + if (sr < 0) sr = 0; + else if (sr > maxval) sr = maxval; + if (sg < 0) sg = 0; + else if (sg > maxval) sg = maxval; + if (sb < 0) sb = 0; + else if (sb > maxval) sb = maxval; + + /* This is the color we'd get if we set the bit 1. For 0, + we get black */ + r2=a2_cmap[hibit][x&1][0]; + g2=a2_cmap[hibit][x&1][1]; + b2=a2_cmap[hibit][x&1][2]; + + /* + dist0 and dist1 are the error (Minkowski 2-metric + distances in the color space) for choosing 0 and + 1 respectively. 0 is black, 1 is the color r2,g2,b2. + */ + dist1= (sr-r2)*(sr-r2) + (sg-g2)*(sg-g2) + (sb-b2)*(sb-b2); + dist0= sr*sr + sg*sg + sb*sb; + + if (dist1>(x-xbyte))&1; + hibit=(best_byte>>7)&1; + + sr = (pP[x] >> 16) & 0xFF; + sg = (pP[x] >> 8) & 0xFF; + sb = (pP[x] ) & 0xFF; + sr += this_rerr[x + 1] / fs_scale; + sg += this_gerr[x + 1] / fs_scale; + sb += this_berr[x + 1] / fs_scale; + + if (sr < 0) sr = 0; + else if (sr > maxval) sr = maxval; + if (sg < 0) sg = 0; + else if (sg > maxval) sg = maxval; + if (sb < 0) sb = 0; + else if (sb > maxval) sb = maxval; + + r2=a2_cmap[hibit][x&1][0] * bit; + g2=a2_cmap[hibit][x&1][1] * bit; + b2=a2_cmap[hibit][x&1][2] * bit; + + pP[x] = (r2<<16) | (g2<<8) | (b2); + + /* Propagate Floyd-Steinberg error terms. */ + err = (sr - r2) * fs_scale; + this_rerr[x + 2] += (err * 7) / 16; + next_rerr[x ] += (err * 3) / 16; + next_rerr[x + 1] += (err * 5) / 16; + next_rerr[x + 2] += (err ) / 16; + err = (sg - g2) * fs_scale; + this_gerr[x + 2] += (err * 7) / 16; + next_gerr[x ] += (err * 3) / 16; + next_gerr[x + 1] += (err * 5) / 16; + next_gerr[x + 2] += (err ) / 16; + err = (sb - b2) * fs_scale; + this_berr[x + 2] += (err * 7) / 16; + next_berr[x ] += (err * 3) / 16; + next_berr[x + 1] += (err * 5) / 16; + next_berr[x + 2] += (err ) / 16; + } + + /* + And put the actual byte into out. + */ + + out[y*(w/7) + xbyte/7] = best_byte; + + } + + temp_err = this_rerr; + this_rerr = next_rerr; + next_rerr = temp_err; + temp_err = this_gerr; + this_gerr = next_gerr; + next_gerr = temp_err; + temp_err = this_berr; + this_berr = next_berr; + next_berr = temp_err; + } + + free (this_rerr); + free (next_rerr); + free (this_gerr); + free (next_gerr); + free (this_berr); + free (next_berr); + + for (y=0; y>16)&0xff; + unsigned int g = (pixels[y][x]>>8)&0xff; + unsigned int b = (pixels[y][x]>>0)&0xff; + fprintf(pipe, "%c%c%c", r, g, b); + } + fclose (pipe); + } +#endif +} + +typedef struct slideshow_data_s { + int slideno; + int render_img_lineno; + unsigned char *render_img; + char *img_filename; + Bool image_loading_p; +} slideshow_data; + + +static void +image_loaded_cb (Screen *screen, Window window, Drawable p, + const char *name, XRectangle *geometry, + void *closure) +{ + Display *dpy = DisplayOfScreen (screen); + apple2_sim_t *sim = (apple2_sim_t *) closure; + slideshow_data *mine = (slideshow_data *) sim->controller_data; + XWindowAttributes xgwa; + int w = 280; + int h = 192; + XImage *image; + unsigned int *buf32 = (unsigned int *) calloc (w, h * 4); + unsigned char *buf8 = (unsigned char *) calloc (w/7, h); + + if (!buf32 || !buf8) + { + fprintf (stderr, "%s: out of memory (%dx%d)\n", progname, w, h); + exit (1); + } + + XGetWindowAttributes (dpy, window, &xgwa); + + image = XGetImage (dpy, p, 0, 0, xgwa.width, xgwa.height, ~0, ZPixmap); + XFreePixmap (dpy, p); + p = 0; + + /* Scale the XImage down to Apple][ size, and convert it to a 32bpp + image (regardless of whether it started as TrueColor/PseudoColor.) + */ + pick_a2_subimage (dpy, window, image, buf32, w, h); + free(image->data); + image->data = 0; + XDestroyImage(image); + + /* Then dither the 32bpp image to a 6-color Apple][ colormap. + */ + a2_dither (buf32, buf8, w, h); + + free (buf32); + + mine->image_loading_p = False; + mine->img_filename = (name ? strdup (name) : 0); + mine->render_img = buf8; +} + + + +static const char *apple2_defaults [] = { + ".background: black", + ".foreground: white", + "*mode: random", + "*duration: 60", + "*program: xscreensaver-text --cols 40", + "*metaSendsESC: True", + "*swapBSDEL: True", + "*fast: False", +# ifdef HAVE_FORKPTY + "*usePty: True", +#else + "*usePty: False", +# endif /* !HAVE_FORKPTY */ + + ANALOGTV_DEFAULTS + 0 +}; + +static XrmOptionDescRec apple2_options [] = { + { "-mode", ".mode", XrmoptionSepArg, 0 }, + { "-slideshow", ".mode", XrmoptionNoArg, "slideshow" }, + { "-basic", ".mode", XrmoptionNoArg, "basic" }, + { "-text", ".mode", XrmoptionNoArg, "text" }, + { "-program", ".program", XrmoptionSepArg, 0 }, + { "-duration", ".duration", XrmoptionSepArg, 0 }, + { "-pty", ".usePty", XrmoptionNoArg, "True" }, + { "-pipe", ".usePty", XrmoptionNoArg, "False" }, + { "-meta", ".metaSendsESC", XrmoptionNoArg, "False" }, + { "-esc", ".metaSendsESC", XrmoptionNoArg, "True" }, + { "-bs", ".swapBSDEL", XrmoptionNoArg, "False" }, + { "-del", ".swapBSDEL", XrmoptionNoArg, "True" }, + { "-fast", ".fast", XrmoptionNoArg, "True" }, + ANALOGTV_OPTIONS + { 0, 0, 0, 0 } +}; + +/* + TODO: this should load 10 images at startup time, then cycle through them + to avoid the pause while it loads. + */ + +static void slideshow_controller(apple2_sim_t *sim, int *stepno, + double *next_actiontime) +{ + apple2_state_t *st=sim->st; + int i; + slideshow_data *mine; + + if (!sim->controller_data) + sim->controller_data = calloc (1, sizeof(*mine)); + mine = (slideshow_data *) sim->controller_data; + + switch(*stepno) { + + case 0: + a2_invalidate(st); + a2_clear_hgr(st); + a2_cls(st); + sim->typing_rate = 0.3; + sim->dec->powerup=0.0; + + a2_goto(st, 0, 16); + a2_prints(st, "APPLE ]["); + a2_goto(st,23,0); + a2_printc(st,']'); + + *stepno=10; + break; + + case 10: + { + XWindowAttributes xgwa; + Pixmap p; + XGetWindowAttributes (sim->dpy, sim->window, &xgwa); + p = XCreatePixmap (sim->dpy, sim->window, xgwa.width, xgwa.height, + xgwa.depth); + mine->image_loading_p = True; + load_image_async (xgwa.screen, sim->window, p, image_loaded_cb, sim); + + /* pause with a blank screen for a bit, while the image loads in the + background. */ + *next_actiontime += 2.0; + *stepno=11; + } + break; + + case 11: + if (! mine->image_loading_p) { /* image is finally loaded */ + if (st->gr_mode) { + *stepno=30; + } else { + *stepno=20; + } + *next_actiontime += 3.0; + } + break; + + case 20: + sim->typing="HGR\n"; + *stepno=29; + break; + + case 29: + sim->printing="]"; + *stepno=30; + break; + + case 30: + st->gr_mode=A2_GR_HIRES; + if (mine->img_filename) { + char *basename, *tmp; + char *s; + + basename = tmp = strdup (mine->img_filename); + while (1) + { + char *slash = strchr(basename, '/'); + if (!slash || !slash[1]) break; + basename = slash+1; + } + { + char *dot=strrchr(basename,'.'); + if (dot) *dot=0; + } + if (strlen(basename)>20) basename[20]=0; + for (s=basename; *s; s++) { + *s = toupper (*s); + if (*s <= ' ') *s = '_'; + } + sprintf(sim->typing_buf, "BLOAD %s\n", basename); + sim->typing = sim->typing_buf; + + free(tmp); + } else { + sim->typing = "BLOAD IMAGE\n"; + } + mine->render_img_lineno=0; + + *stepno=35; + break; + + case 35: + *next_actiontime += 0.7; + *stepno=40; + break; + + case 40: + if (mine->render_img_lineno>=192) { + sim->printing="]"; + sim->typing="POKE 49234,0\n"; + *stepno=50; + return; + } + + for (i=0; i<6 && mine->render_img_lineno<192; i++) { + a2_display_image_loading(st, mine->render_img, + mine->render_img_lineno++); + } + + /* The disk would have to seek every 13 sectors == 78 lines. + (This ain't no newfangled 16-sector operating system) */ + if ((mine->render_img_lineno%78)==0) { + *next_actiontime += 0.5; + } else { + *next_actiontime += 0.08; + } + break; + + case 50: + st->gr_mode |= A2_GR_FULL; + *stepno=60; + /* Note that sim->delay is sometimes "infinite" in this controller. + These images are kinda dull anyway, so don't leave it on too long. */ + *next_actiontime += 2; + break; + + case 60: + sim->printing="]"; + sim->typing="POKE 49235,0\n"; + *stepno=70; + break; + + case 70: + sim->printing="]"; + st->gr_mode &= ~A2_GR_FULL; + if (mine->render_img) { + free(mine->render_img); + mine->render_img=NULL; + } + if (mine->img_filename) { + free(mine->img_filename); + mine->img_filename=NULL; + } + *stepno=10; + break; + + case 80: + /* Do nothing, just wait */ + *next_actiontime += 2.0; + *stepno = A2CONTROLLER_FREE; + break; + + case A2CONTROLLER_FREE: + /* It is possible that still image is being loaded, + in that case mine cannot be freed, because + callback function tries to use it, so wait. + */ + if (mine->image_loading_p) { + *stepno = 80; + break; + } + free(mine->render_img); + free(mine->img_filename); + free(mine); + mine = 0; + return; + + } +} + +#define NPAR 16 + +struct terminal_controller_data { + Display *dpy; + char curword[256]; + unsigned char lastc; + double last_emit_time; + text_data *tc; + + int escstate; + int csiparam[NPAR]; + int curparam; + int cursor_x, cursor_y; + int saved_x, saved_y; + int unicruds; char unicrud[7]; + union { + struct { + unsigned int bold : 1; + unsigned int blink : 1; + unsigned int rev : 1; + } bf; + int w; + } termattrib; + Bool fast_p; + +}; + + +/* The structure of closure linkage throughout this code is so amazingly + baroque that I can't get to the 'struct state' from where I need it. */ +static const char *global_program; +static Bool global_fast_p; + + +static void +terminal_closegen(struct terminal_controller_data *mine) +{ + if (mine->tc) { + textclient_close (mine->tc); + mine->tc = 0; + } +} + +static int +terminal_read(struct terminal_controller_data *mine, unsigned char *buf, int n) +{ + if (!mine || !mine->tc) { + return 0; + } else { + int i, count = 0; + for (i = 0; i < n; i++) { + int c = textclient_getc (mine->tc); + if (c <= 0) break; + buf[i] = c; + mine->lastc = c; + count++; + } + return count; + } +} + + +static int +terminal_keypress_handler (Display *dpy, XEvent *event, void *data) +{ + struct terminal_controller_data *mine = + (struct terminal_controller_data *) data; + mine->dpy = dpy; + if (event->xany.type == KeyPress && mine->tc) + return textclient_putc (mine->tc, &event->xkey); + return 0; +} + + +static void +a2_ascii_printc (apple2_state_t *st, unsigned char c, + Bool bold_p, Bool blink_p, Bool rev_p, + Bool scroll_p) +{ + if (c >= 'a' && c <= 'z') /* upcase lower-case chars */ + { + c &= 0xDF; + } + else if ((c >= 'A'+128) || /* upcase and blink */ + (c < ' ' && c != 014 && /* high-bit & ctl chrs */ + c != '\r' && c != '\n' && c!='\t')) + { + c = (c & 0x1F) | 0x80; + } + else if (c >= 'A' && c <= 'Z') /* invert upper-case chars */ + { + c |= 0x80; + } + + if (bold_p) c |= 0xc0; + if (blink_p) c = (c & ~0x40) | 0x80; + if (rev_p) c |= 0xc0; + + if (scroll_p) + a2_printc(st, c); + else + a2_printc_noscroll(st, c); +} + + +static void +a2_vt100_printc (apple2_sim_t *sim, struct terminal_controller_data *state, + unsigned char c) +{ + apple2_state_t *st=sim->st; + int cols = SCREEN_COLS; + int rows = SCREEN_ROWS; + + int i; + int start, end; + + /* Mostly duplicated in phosphor.c */ + + switch (state->escstate) + { + case 0: + switch (c) + { + case 7: /* BEL */ + /* Dummy case - we don't want the screensaver to beep */ + /* #### But maybe this should flash the screen? */ + break; + case 8: /* BS */ + if (state->cursor_x > 0) + state->cursor_x--; + break; + case 9: /* HT */ + if (state->cursor_x < cols - 8) + { + state->cursor_x = (state->cursor_x & ~7) + 8; + } + else + { + state->cursor_x = 0; + if (state->cursor_y < rows - 1) + state->cursor_y++; + else + a2_scroll (st); + } + break; + case 10: /* LF */ +# ifndef HAVE_FORKPTY + state->cursor_x = 0; /* No ptys on iPhone; assume CRLF. */ +# endif + case 11: /* VT */ + case 12: /* FF */ + if (state->cursor_y < rows - 1) + state->cursor_y++; + else + a2_scroll (st); + break; + case 13: /* CR */ + state->cursor_x = 0; + break; + case 14: /* SO */ + case 15: /* SI */ + /* Dummy case - there is one and only one font. */ + break; + case 24: /* CAN */ + case 26: /* SUB */ + /* Dummy case - these interrupt escape sequences, so + they don't do anything in this state */ + break; + case 27: /* ESC */ + state->escstate = 1; + break; + case 127: /* DEL */ + /* Dummy case - this is supposed to be ignored */ + break; + case 155: /* CSI */ + state->escstate = 2; + for(i = 0; i < NPAR; i++) + state->csiparam[i] = 0; + state->curparam = 0; + break; + default: + + /* states 102-106 are for UTF-8 decoding */ + + if ((c & 0xE0) == 0xC0) { /* 110xxxxx - 11 bits, 2 bytes */ + state->unicruds = 1; + state->unicrud[0] = c; + state->escstate = 102; + break; + } else if ((c & 0xF0) == 0xE0) { /* 1110xxxx - 16 bits, 3 bytes */ + state->unicruds = 1; + state->unicrud[0] = c; + state->escstate = 103; + break; + } else if ((c & 0xF8) == 0xF0) { /* 11110xxx - 21 bits, 4 bytes */ + state->unicruds = 1; + state->unicrud[0] = c; + state->escstate = 104; + break; + } else if ((c & 0xFC) == 0xF8) { /* 111110xx - 26 bits, 5 bytes */ + state->unicruds = 1; + state->unicrud[0] = c; + state->escstate = 105; + break; + } else if ((c & 0xFE) == 0xFC) { /* 1111110x - 31 bits, 6 bytes */ + state->unicruds = 1; + state->unicrud[0] = c; + state->escstate = 106; + break; + } + + PRINT: + + /* If the cursor is in column 39 and we print a character, then + that character shows up in column 39, and the cursor is no longer + visible on the screen (it's in "column 40".) If another character + is printed, then that character shows up in column 0, and the + cursor moves to column 1. + + This is empirically what xterm and gnome-terminal do, so that must + be the right thing. (In xterm, the cursor vanishes, whereas; in + gnome-terminal, the cursor overprints the character in col 39.) + */ + if (state->cursor_x >= cols) + { + state->cursor_x = 0; + if (state->cursor_y >= rows - 1) + a2_scroll (st); + else + state->cursor_y++; + } + + a2_goto(st, state->cursor_y, state->cursor_x); /* clips range */ + a2_ascii_printc (st, c, + state->termattrib.bf.bold, + state->termattrib.bf.blink, + state->termattrib.bf.rev, + False); + state->cursor_x++; + + break; + } + break; + case 1: + switch (c) + { + case 24: /* CAN */ + case 26: /* SUB */ + state->escstate = 0; + break; + case 'c': /* Reset */ + a2_cls(st); + state->escstate = 0; + break; + case 'D': /* Linefeed */ + if (state->cursor_y < rows - 1) + state->cursor_y++; + else + a2_scroll (st); + state->escstate = 0; + break; + case 'E': /* Newline */ + state->cursor_x = 0; + state->escstate = 0; + break; + case 'M': /* Reverse newline */ + if (state->cursor_y > 0) + state->cursor_y--; + state->escstate = 0; + break; + case '7': /* Save state */ + state->saved_x = state->cursor_x; + state->saved_y = state->cursor_y; + state->escstate = 0; + break; + case '8': /* Restore state */ + state->cursor_x = state->saved_x; + state->cursor_y = state->saved_y; + state->escstate = 0; + break; + case '[': /* CSI */ + state->escstate = 2; + for(i = 0; i < NPAR; i++) + state->csiparam[i] = 0; + state->curparam = 0; + break; + case '%': /* Select charset */ + /* @: Select default (ISO 646 / ISO 8859-1) + G: Select UTF-8 + 8: Select UTF-8 (obsolete) + + We can just ignore this and always process UTF-8, I think? + We must still catch the last byte, though. + */ + case '(': + case ')': + /* I don't support different fonts either - see above + for SO and SI */ + state->escstate = 3; + break; + default: + /* Escape sequences not supported: + * + * H - Set tab stop + * Z - Terminal identification + * > - Keypad change + * = - Other keypad change + * ] - OS command + */ + state->escstate = 0; + break; + } + break; + case 2: + switch (c) + { + case 24: /* CAN */ + case 26: /* SUB */ + state->escstate = 0; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (state->curparam < NPAR) + state->csiparam[state->curparam] = + (state->csiparam[state->curparam] * 10) + (c - '0'); + break; + case ';': + state->csiparam[++state->curparam] = 0; + break; + case '[': + state->escstate = 3; + break; + case '@': + for (i = 0; i < state->csiparam[0]; i++) + { + if(++state->cursor_x > cols) + { + state->cursor_x = 0; + if (state->cursor_y < rows - 1) + state->cursor_y++; + else + a2_scroll (st); + } + } + state->escstate = 0; + break; + case 'F': + state->cursor_x = 0; + case 'A': + if (state->csiparam[0] == 0) + state->csiparam[0] = 1; + if ((state->cursor_y -= state->csiparam[0]) < 0) + state->cursor_y = 0; + state->escstate = 0; + break; + case 'E': + state->cursor_x = 0; + case 'e': + case 'B': + if (state->csiparam[0] == 0) + state->csiparam[0] = 1; + if ((state->cursor_y += state->csiparam[0]) >= rows) + state->cursor_y = rows - 1; + state->escstate = 0; + break; + case 'a': + case 'C': + if (state->csiparam[0] == 0) + state->csiparam[0] = 1; + if ((state->cursor_x += state->csiparam[0]) >= cols) + state->cursor_x = cols - 1; + state->escstate = 0; + break; + case 'D': + if (state->csiparam[0] == 0) + state->csiparam[0] = 1; + if ((state->cursor_x -= state->csiparam[0]) < 0) + state->cursor_x = 0; + state->escstate = 0; + break; + case 'd': + if ((state->cursor_y = (state->csiparam[0] - 1)) >= rows) + state->cursor_y = rows - 1; + state->escstate = 0; + break; + case '`': + case 'G': + if ((state->cursor_x = (state->csiparam[0] - 1)) >= cols) + state->cursor_x = cols - 1; + state->escstate = 0; + break; + case 'f': + case 'H': + if ((state->cursor_y = (state->csiparam[0] - 1)) >= rows) + state->cursor_y = rows - 1; + if ((state->cursor_x = (state->csiparam[1] - 1)) >= cols) + state->cursor_x = cols - 1; + if(state->cursor_y < 0) + state->cursor_y = 0; + if(state->cursor_x < 0) + state->cursor_x = 0; + state->escstate = 0; + break; + case 'J': + start = 0; + end = rows * cols; + if (state->csiparam[0] == 0) + start = cols * state->cursor_y + state->cursor_x; + if (state->csiparam[0] == 1) + end = cols * state->cursor_y + state->cursor_x; + + a2_goto(st, state->cursor_y, state->cursor_x); + for (i = start; i < end; i++) + { + a2_ascii_printc(st, ' ', False, False, False, False); + } + state->escstate = 0; + break; + case 'K': + start = 0; + end = cols; + if (state->csiparam[0] == 0) + start = state->cursor_x; + if (state->csiparam[1] == 1) + end = state->cursor_x; + + a2_goto(st, state->cursor_y, state->cursor_x); + for (i = start; i < end; i++) + { + a2_ascii_printc(st, ' ', False, False, False, False); + } + state->escstate = 0; + break; + case 'm': /* Set attributes */ + for (i = 0; i <= state->curparam; i++) + { + switch(state->csiparam[i]) + { + case 0: + state->termattrib.w = 0; + break; + case 1: + state->termattrib.bf.bold = 1; + break; + case 5: + state->termattrib.bf.blink = 1; + break; + case 7: + state->termattrib.bf.rev = 1; + break; + case 21: + case 22: + state->termattrib.bf.bold = 0; + break; + case 25: + state->termattrib.bf.blink = 0; + break; + case 27: + state->termattrib.bf.rev = 0; + break; + } + } + state->escstate = 0; + break; + case 's': /* Save position */ + state->saved_x = state->cursor_x; + state->saved_y = state->cursor_y; + state->escstate = 0; + break; + case 'u': /* Restore position */ + state->cursor_x = state->saved_x; + state->cursor_y = state->saved_y; + state->escstate = 0; + break; + case '?': /* DEC Private modes */ + if ((state->curparam != 0) || (state->csiparam[0] != 0)) + state->escstate = 0; + break; + default: + /* Known unsupported CSIs: + * + * L - Insert blank lines + * M - Delete lines (I don't know what this means...) + * P - Delete characters + * X - Erase characters (difference with P being...?) + * c - Terminal identification + * g - Clear tab stop(s) + * h - Set mode (Mainly due to its complexity and lack of good + docs) + * l - Clear mode + * m - Set mode (Phosphor is, per defenition, green on black) + * n - Status report + * q - Set keyboard LEDs + * r - Set scrolling region (too exhausting - noone uses this, + right?) + */ + state->escstate = 0; + break; + } + break; + case 3: + state->escstate = 0; + break; + + case 102: + case 103: + case 104: + case 105: + case 106: + { + int total = state->escstate - 100; /* see what I did there */ + if (state->unicruds < total) { + /* Buffer more bytes of the UTF-8 sequence */ + state->unicrud[state->unicruds++] = c; + } + + if (state->unicruds >= total) { + /* Done! Convert it to ASCII and print that. */ + char *s; + state->unicrud[state->unicruds] = 0; + s = utf8_to_latin1 ((const char *) state->unicrud, True); + state->unicruds = 0; + state->escstate = 0; + if (s) { + c = s[0]; + free (s); + goto PRINT; + } else { + /* c = 0; */ + } + } + } + break; + + default: + abort(); + } + a2_goto(st, state->cursor_y, state->cursor_x); +} + + +/* + It's fun to put things like "gdb" as the command. For one, it's + amusing how the standard mumble (version, no warranty, it's + GNU/Linux dammit) occupies an entire screen on the Apple ][. +*/ + +static void +terminal_controller(apple2_sim_t *sim, int *stepno, double *next_actiontime) +{ + apple2_state_t *st=sim->st; + int c; + int i; + + struct terminal_controller_data *mine; + if (!sim->controller_data) + sim->controller_data=calloc(sizeof(struct terminal_controller_data),1); + mine=(struct terminal_controller_data *) sim->controller_data; + mine->dpy = sim->dpy; + + mine->fast_p = global_fast_p; + + switch(*stepno) { + + case 0: + if (random()%2) + st->gr_mode |= A2_GR_FULL; /* Turn on color mode even through it's + showing text */ + a2_cls(st); + a2_goto(st,0,16); + a2_prints(st, "APPLE ]["); + a2_goto(st,2,0); + mine->cursor_y = 2; + + if (! mine->tc) { + mine->tc = textclient_open (mine->dpy); + textclient_reshape (mine->tc, + SCREEN_COLS, SCREEN_ROWS, + SCREEN_COLS, SCREEN_ROWS, + 0); + } + + if (! mine->fast_p) + *next_actiontime += 4.0; + *stepno = 10; + + mine->last_emit_time = sim->curtime; + break; + + case 10: + case 11: + { + Bool first_line_p = (*stepno == 10); + unsigned char buf[1024]; + int nr,nwant; + double elapsed; + + elapsed=sim->curtime - mine->last_emit_time; + + nwant = elapsed * 25.0; /* characters per second */ + + if (first_line_p) { + *stepno = 11; + nwant = 1; + } + + if (nwant > 40) nwant = 40; + + if (mine->fast_p) + nwant = sizeof(buf)-1; + + if (nwant <= 0) break; + + mine->last_emit_time = sim->curtime; + + nr=terminal_read(mine, buf, nwant); + for (i=0; itc) + a2_vt100_printc (sim, mine, c); + else + a2_ascii_printc (st, c, False, False, False, True); + } + } + break; + + case A2CONTROLLER_FREE: + terminal_closegen(mine); + free(mine); + mine = 0; + return; + } +} + +struct basic_controller_data { + int prog_line; + int x,y,k; + const char * const * progtext; + int progstep; + char *rep_str; + int rep_pos; + double prog_start_time; + char error_buf[256]; +}; + +/* + Adding more programs is easy. Just add a listing here and to all_programs, + then add the state machine to actually execute it to basic_controller. + */ +static const char * const moire_program[]={ + "10 HGR2\n", + "20 FOR Y = 0 TO 190 STEP 2\n", + "30 HCOLOR=4 : REM BLACK\n", + "40 HPLOT 0,191-Y TO 279,Y\n", + "60 HCOLOR=7 : REM WHITE\n", + "80 HPLOT 0,190-Y TO 279,Y+1\n", + "90 NEXT Y\n", + "100 FOR X = 0 TO 278 STEP 3\n", + "110 HCOLOR=4\n", + "120 HPLOT 279-X,0 TO X,191\n", + "140 HCOLOR=7\n", + "150 HPLOT 278-X,0 TO X+1,191\n", + "160 NEXT X\n", + NULL +}; + +static const char * const sinewave_program[] = { + "10 HGR\n", + "25 K=0\n", + "30 FOR X = 0 TO 279\n", + "32 HCOLOR= 0\n", + "35 HPLOT X,0 TO X,159\n", + "38 HCOLOR= 3\n", + "40 Y = 80 + SIN(15*(X-K)/279) * 40\n", + "50 HPLOT X,Y\n", + "60 NEXT X\n", + "70 K=K+4\n", + "80 GOTO 30\n", + NULL +}; + +#if 0 +static const char * const dumb_program[]={ + "10 PRINT \"APPLE ][ ROOLZ! TRS-80 DROOLZ!\"\n", + "20 GOTO 10\n", + NULL +}; +#endif + +static const char * const random_lores_program[]={ + "1 REM APPLE ][ SCREEN SAVER\n", + "10 GR\n", + "100 COLOR= RND(1)*16\n", + + "110 X=RND(1)*40\n", + "120 Y1=RND(1)*40\n", + "130 Y2=RND(1)*40\n", + "140 FOR Y = Y1 TO Y2\n", + "150 PLOT X,Y\n", + "160 NEXT Y\n", + + "210 Y=RND(1)*40\n", + "220 X1=RND(1)*40\n", + "230 X2=RND(1)*40\n", + "240 FOR X = X1 TO X2\n", + "250 PLOT X,Y\n", + "260 NEXT X\n", + "300 GOTO 100\n", + + NULL +}; + +static char typo_map[256]; + +static int make_typo(char *out_buf, const char *orig, char *err_buf) +{ + int i,j; + int errc; + int success=0; + err_buf[0]=0; + + typo_map['A']='Q'; + typo_map['S']='A'; + typo_map['D']='S'; + typo_map['F']='G'; + typo_map['G']='H'; + typo_map['H']='J'; + typo_map['J']='H'; + typo_map['K']='L'; + typo_map['L']=';'; + + typo_map['Q']='1'; + typo_map['W']='Q'; + typo_map['E']='3'; + typo_map['R']='T'; + typo_map['T']='Y'; + typo_map['Y']='U'; + typo_map['U']='Y'; + typo_map['I']='O'; + typo_map['O']='P'; + typo_map['P']='['; + + typo_map['Z']='X'; + typo_map['X']='C'; + typo_map['C']='V'; + typo_map['V']='C'; + typo_map['B']='N'; + typo_map['N']='B'; + typo_map['M']='N'; + typo_map[',']='.'; + typo_map['.']=','; + + typo_map['!']='1'; + typo_map['@']='2'; + typo_map['#']='3'; + typo_map['$']='4'; + typo_map['%']='5'; + typo_map['^']='6'; + typo_map['&']='7'; + typo_map['*']='8'; + typo_map['(']='9'; + typo_map[')']='0'; + + typo_map['1']='Q'; + typo_map['2']='W'; + typo_map['3']='E'; + typo_map['4']='R'; + typo_map['5']='T'; + typo_map['6']='Y'; + typo_map['7']='U'; + typo_map['8']='I'; + typo_map['9']='O'; + typo_map['0']='-'; + + strcpy(out_buf, orig); + for (i=0; out_buf[i]; i++) { + char *p = out_buf+i; + + if (i>2 && p[-2]=='R' && p[-1]=='E' && p[0]=='M') + break; + + if (isalpha(p[0]) && + isalpha(p[1]) && + p[0] != p[1] && + random()%15==0) + { + int tmp=p[1]; + p[1]=p[0]; + p[0]=tmp; + success=1; + sprintf(err_buf,"?SYNTAX ERROR\n"); + break; + } + + if (random()%10==0 && strlen(p)>=4 && (errc=typo_map[(int)(unsigned char)p[0]])) { + int remain=strlen(p); + int past=random()%(remain-2)+1; + memmove(p+past+past, p, remain+1); + p[0]=errc; + for (j=0; jst; + int i; + + struct basic_controller_data *mine; + if (!sim->controller_data) + sim->controller_data=calloc(sizeof(struct basic_controller_data),1); + mine=(struct basic_controller_data *) sim->controller_data; + + switch (*stepno) { + case 0: + st->gr_mode=0; + a2_cls(st); + a2_goto(st,0,16); + a2_prints(st, "APPLE ]["); + a2_goto(st,23,0); + a2_printc(st,']'); + sim->typing_rate=0.2; + + i=random()%countof(all_programs); + mine->progtext=all_programs[i].progtext; + mine->progstep=all_programs[i].progstep; + mine->prog_line=0; + + *next_actiontime += 1.0; + *stepno=10; + break; + + case 10: + if (st->cursx==0) a2_printc(st,']'); + if (mine->progtext[mine->prog_line]) { + if (random()%4==0) { + int err=make_typo(sim->typing_buf, + mine->progtext[mine->prog_line], + mine->error_buf); + sim->typing=sim->typing_buf; + if (err) { + *stepno=11; + } else { + mine->prog_line++; + } + } else { + sim->typing=mine->progtext[mine->prog_line++]; + } + } else { + *stepno=15; + } + break; + + case 11: + sim->printing=mine->error_buf; + *stepno=12; + break; + + case 12: + if (st->cursx==0) a2_printc(st,']'); + *next_actiontime+=1.0; + *stepno=10; + break; + + case 15: + sim->typing="RUN\n"; + mine->y=0; + mine->x=0; + mine->k=0; + mine->prog_start_time=*next_actiontime; + *stepno=mine->progstep; + break; + + /* moire_program */ + case 100: + st->gr_mode=A2_GR_HIRES|A2_GR_FULL; + for (i=0; i<24 && mine->y<192; i++) + { + a2_hline(st, 4, 0, 191-mine->y, 279, mine->y); + a2_hline(st, 7, 0, 191-mine->y-1, 279, mine->y+1); + mine->y += 2; + } + if (mine->y>=192) { + mine->x = 0; + *stepno = 110; + } + break; + + case 110: + for (i=0; i<24 && mine->x<280; i++) + { + a2_hline(st, 4, 279-mine->x, 0, mine->x, 192); + a2_hline(st, 7, 279-mine->x-1, 0, mine->x+1, 192); + mine->x+=3; + } + if (mine->x >= 280) *stepno=120; + break; + + case 120: + if (*next_actiontime > mine->prog_start_time+sim->delay) *stepno=999; + break; + + /* dumb_program */ + case 200: + mine->rep_str="\nAPPLE ][ ROOLZ! TRS-80 DROOLZ!"; + for (i=0; i<30; i++) { + a2_prints(st, mine->rep_str); + } + *stepno=210; + break; + + case 210: + i=random()%strlen(mine->rep_str); + while (mine->rep_pos != i) { + a2_printc(st, mine->rep_str[mine->rep_pos]); + mine->rep_pos++; + if (!mine->rep_str[mine->rep_pos]) mine->rep_pos=0; + } + if (*next_actiontime > mine->prog_start_time+sim->delay) *stepno=999; + break; + + /* sinewave_program */ + case 400: + st->gr_mode=A2_GR_HIRES; + *stepno=410; + break; + + case 410: + for (i=0; i<48; i++) { + int y=80 + (int)(75.0*sin(15.0*(mine->x-mine->k)/279.0)); + a2_hline(st, 0, mine->x, 0, mine->x, 159); + a2_hplot(st, 3, mine->x, y); + mine->x += 1; + if (mine->x>=279) { + mine->x=0; + mine->k+=4; + } + } + if (*next_actiontime > mine->prog_start_time+sim->delay) *stepno=999; + break; + + case 420: + a2_prints(st, "]"); + *stepno=999; + break; + + /* random_lores_program */ + case 500: + st->gr_mode=A2_GR_LORES|A2_GR_FULL; + a2_clear_gr(st); + *stepno=510; + + case 510: + for (i=0; i<10; i++) { + int color,x,y,x1,x2,y1,y2; + + color=random()%15; + x=random()%40; + y1=random()%48; + y2=random()%48; + for (y=y1; y mine->prog_start_time+sim->delay) *stepno=999; + break; + + case 999: + *stepno=0; + break; + + case A2CONTROLLER_FREE: + free(mine); + mine = 0; + break; + } + +} + +static void (* const controllers[]) (apple2_sim_t *sim, int *stepno, + double *next_actiontime) = { + slideshow_controller, + terminal_controller, + basic_controller +}; + +struct state { + int duration; + Bool random_p; + apple2_sim_t *sim; + void (*controller) (apple2_sim_t *sim, int *stepno, double *next_actiontime); +}; + + +static void * +apple2_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + char *s; + + st->duration = get_integer_resource (dpy, "duration", "Integer"); + + st->controller = 0; + if (st->duration < 1) st->duration = 1; + + s = get_string_resource (dpy, "mode", "Mode"); + if (!s || !*s || !strcasecmp(s, "random")) + st->random_p = True; + else if (!strcasecmp(s, "text")) + st->controller = terminal_controller; + else if (!strcasecmp(s, "slideshow")) + st->controller = slideshow_controller; + else if (!strcasecmp(s, "basic")) + st->controller = basic_controller; + else + { + fprintf (stderr, "%s: mode must be text, slideshow, or random; not %s\n", + progname, s); + exit (1); + } + if (s) free (s); + + global_program = get_string_resource (dpy, "program", "Program"); + global_fast_p = get_boolean_resource (dpy, "fast", "Boolean"); + + + /* Kludge for MacOS standalone mode: see OSX/SaverRunner.m. */ + { + const char *s = getenv ("XSCREENSAVER_STANDALONE"); + if (s && *s && strcmp(s, "0")) + { + st->controller = terminal_controller; + st->random_p = False; + global_program = getenv ("SHELL"); + global_fast_p = True; + } + } + + + if (! st->random_p) { + if (st->controller == terminal_controller || + st->controller == slideshow_controller) + st->duration = 999999; /* these run "forever" */ + } + + return st; +} + +static unsigned long +apple2_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + if (! st->sim) { + if (st->random_p) + st->controller = controllers[random() % (countof(controllers))]; + st->sim = apple2_start (dpy, window, st->duration, st->controller); + } + + if (! apple2_one_frame (st->sim)) { + st->sim = 0; + } + +#ifdef HAVE_MOBILE + return 0; +#else + return 5000; +#endif +} + +static void +apple2_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + if (st->sim) + analogtv_reconfigure (st->sim->dec); +} + +static Bool +apple2_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + struct state *st = (struct state *) closure; + + if (st->sim && + st->controller == terminal_controller && + event->xany.type == KeyPress) { + terminal_keypress_handler (dpy, event, st->sim->controller_data); + return True; + } + + return False; +} + +static void +apple2_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + if (st->sim) { + st->sim->stepno = A2CONTROLLER_DONE; + if (apple2_one_frame (st->sim)) + abort(); /* should have freed! */ + } + free (st); +} + + +XSCREENSAVER_MODULE ("Apple2", apple2) diff --git a/hacks/apple2.c b/hacks/apple2.c new file mode 100644 index 0000000..1918a5c --- /dev/null +++ b/hacks/apple2.c @@ -0,0 +1,885 @@ +/* xscreensaver, Copyright (c) 1998-2010 Jamie Zawinski + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * Apple ][ CRT simulator, by Trevor Blackwell + * with additional work by Jamie Zawinski + */ + +#include +#include "screenhackI.h" +#include "apple2.h" +#include "ximage-loader.h" + +#ifdef HAVE_XSHM_EXTENSION +#include "xshm.h" +#endif + +/* + * Implementation notes + * + * The A2 had 3 display modes: text, lores, and hires. Text was 40x24, and it + * disabled color in the TV. Lores gave you 40x48 graphics blocks, using the + * same memory as the text screen. Each could be one of 16 colors. Hires gave + * you 280x192 pixels. Odd pixels were blue or purple, and even pixels were + * orange or green depending on the setting of the high bit in each byte. + * + * The graphics modes could also have 4 lines of text at the bottom. This was + * fairly unreadable if you had a color monitor. + * + * Each mode had 2 different screens using different memory space. In hires + * mode this was sometimes used for double buffering, but more often the lower + * screen was full of code/data and the upper screen was used for display, so + * you got random garbage on the screen. + * + * The text font is based on X's standard 6x10 font, with a few tweaks like + * putting a slash across the zero. + * + * To use this, you'll call apple2(display, window, duration, + * controller) where the function controller defines what will happen. + * See bsod.c and apple2-main.c for example controllers. The + * controller function gets called whenever the machine ready to start + * something new. By setting sim->printing or sim->typing, it'll be + * busy for some time spitting characters out one at a time. By + * setting *next_actiontime+=X.X, it'll pause and just update the screen + * for that long before calling the controller function again. + * + * By setting stepno to A2CONTROLLER_DONE, the loop will end. It will also end + * after the time specified by the delay parameter. In either case, it calls + * the controller with stepno==A2CONTROLLER_FREE to allow it to release any + * memory. + * + * The void* apple2_sim_t::controller_data is for the use of the controller. + * It will be initialize to NULL, and the controller can store its own state + * there. + * + */ + +void +a2_scroll(apple2_state_t *st) +{ + int i; + st->textlines[st->cursy][st->cursx] |= 0xc0; /* turn off cursor */ + + for (i=0; i<23; i++) { + memcpy(st->textlines[i],st->textlines[i+1],40); + } + memset(st->textlines[23],0xe0,40); +} + +static void +a2_printc_1(apple2_state_t *st, char c, int scroll_p) +{ + st->textlines[st->cursy][st->cursx] |= 0xc0; /* turn off blink */ + + if (c == '\n') /* ^J == NL */ + { + if (st->cursy==23) + { + if (scroll_p) + a2_scroll(st); + } + else + { + st->cursy++; + } + st->cursx=0; + } + else if (c == 014) /* ^L == CLS, Home */ + { + a2_cls(st); + a2_goto(st,0,0); + } + else if (c == '\t') /* ^I == tab */ + { + a2_goto(st, st->cursy, (st->cursx+8)&~7); + } + else if (c == 010) /* ^H == backspace */ + { + st->textlines[st->cursy][st->cursx]=0xe0; + a2_goto(st, st->cursy, st->cursx-1); + } + else if (c == '\r') /* ^M == CR */ + { + st->cursx=0; + } + else + { + st->textlines[st->cursy][st->cursx]=c ^ 0xc0; + st->cursx++; + if (st->cursx==40) { + if (st->cursy==23) { + if (scroll_p) + a2_scroll(st); + } else { + st->cursy++; + } + st->cursx=0; + } + } + + st->textlines[st->cursy][st->cursx] &= 0x7f; /* turn on blink */ +} + +void +a2_printc(apple2_state_t *st, char c) +{ + a2_printc_1(st, c, 1); +} + +void +a2_printc_noscroll(apple2_state_t *st, char c) +{ + a2_printc_1(st, c, 0); +} + + +void +a2_prints(apple2_state_t *st, char *s) +{ + while (*s) a2_printc(st, *s++); +} + +void +a2_goto(apple2_state_t *st, int r, int c) +{ + if (r > 23) r = 23; + if (c > 39) c = 39; + st->textlines[st->cursy][st->cursx] |= 0xc0; /* turn off blink */ + st->cursy=r; + st->cursx=c; + st->textlines[st->cursy][st->cursx] &= 0x7f; /* turn on blink */ +} + +void +a2_cls(apple2_state_t *st) +{ + int i; + for (i=0; i<24; i++) { + memset(st->textlines[i],0xe0,40); + } +} + +void +a2_clear_gr(apple2_state_t *st) +{ + int i; + for (i=0; i<24; i++) { + memset(st->textlines[i],0x00,40); + } +} + +void +a2_clear_hgr(apple2_state_t *st) +{ + int i; + for (i=0; i<192; i++) { + memset(st->hireslines[i],0,40); + } +} + +void +a2_invalidate(apple2_state_t *st) +{ +} + +void +a2_poke(apple2_state_t *st, int addr, int val) +{ + + if (addr>=0x400 && addr<0x800) { + /* text memory */ + int row=((addr&0x380)/0x80) + ((addr&0x7f)/0x28)*8; + int col=(addr&0x7f)%0x28; + if (row<24 && col<40) { + st->textlines[row][col]=val; + if (!(st->gr_mode&(A2_GR_HIRES)) || + (!(st->gr_mode&(A2_GR_FULL)) && row>=20)) { + } + } + } + else if (addr>=0x2000 && addr<0x4000) { + int row=(((addr&0x1c00) / 0x400) * 1 + + ((addr&0x0380) / 0x80) * 8 + + ((addr&0x0078) / 0x28) * 64); + int col=((addr&0x07f)%0x28); + if (row<192 && col<40) { + st->hireslines[row][col]=val; + if (st->gr_mode&A2_GR_HIRES) { + } + } + } +} + +void +a2_hplot(apple2_state_t *st, int hcolor, int x, int y) +{ + int highbit,run; + + highbit=((hcolor<<5)&0x80) ^ 0x80; /* capture bit 2 into bit 7 */ + + if (y<0 || y>=192 || x<0 || x>=280) return; + + for (run=0; run<2 && x<280; run++) { + unsigned char *vidbyte = &st->hireslines[y][x/7]; + unsigned char whichbit=1<<(x%7); + int masked_bit; + + *vidbyte = (*vidbyte & 0x7f) | highbit; + + /* use either bit 0 or 1 of hcolor for odd or even pixels */ + masked_bit = (hcolor>>(1-(x&1)))&1; + + /* Set whichbit to 1 or 0 depending on color */ + *vidbyte = (*vidbyte & ~whichbit) | (masked_bit ? whichbit : 0); + + x++; + } +} + +void +a2_hline(apple2_state_t *st, int hcolor, int x1, int y1, int x2, int y2) +{ + int dx,dy,incx,incy,x,y,balance; + + /* Bresenham's line drawing algorithm */ + + if (x2>=x1) { + dx=x2-x1; + incx=1; + } else { + dx=x1-x2; + incx=-1; + } + if (y2>=y1) { + dy=y2-y1; + incy=1; + } else { + dy=y1-y2; + incy=-1; + } + + x=x1; y=y1; + + if (dx>=dy) { + dy*=2; + balance=dy-dx; + dx*=2; + while (x!=x2) { + a2_hplot(st, hcolor, x, y); + if (balance>=0) { + y+=incy; + balance-=dx; + } + balance+=dy; + x+=incx; + } + a2_hplot(st, hcolor, x, y); + } else { + dx*=2; + balance=dx-dy; + dy*=2; + while (y!=y2) { + a2_hplot(st, hcolor, x, y); + if (balance>=0) { + x+=incx; + balance-=dy; + } + balance+=dx; + y+=incy; + } + a2_hplot(st, hcolor, x, y); + } +} + +void +a2_plot(apple2_state_t *st, int color, int x, int y) +{ + int textrow=y/2; + unsigned char byte; + + if (x<0 || x>=40 || y<0 || y>=48) return; + + byte=st->textlines[textrow][x]; + if (y&1) { + byte = (byte&0xf0) | (color&0x0f); + } else { + byte = (byte&0x0f) | ((color&0x0f)<<4); + } + st->textlines[textrow][x]=byte; +} + +void +a2_display_image_loading(apple2_state_t *st, unsigned char *image, + int lineno) +{ + /* + When loading images,it would normally just load the big binary + dump into screen memory while you watched. Because of the way + screen memory was laid out, it wouldn't load from the top down, + but in a funny interleaved way. You should call this with lineno + increasing from 0 thru 191 over a period of a few seconds. + */ + + int row=(((lineno / 24) % 8) * 1 + + ((lineno / 3 ) % 8) * 8 + + ((lineno / 1 ) % 3) * 64); + + memcpy (st->hireslines[row], &image[row * 40], 40); +} + +/* + Simulate plausible initial memory contents for running a program. +*/ +void +a2_init_memory_active(apple2_sim_t *sim) +{ + int i,j,x,y,c; + int addr=0; + apple2_state_t *st=sim->st; + + while (addr<0x4000) { + int n; + + switch (random()%4) { + case 0: + case 1: + n=random()%500; + for (i=0; itext_im->width); + for (i=0; i<100; i++) { + for (y=0; y<8; y++) { + c=0; + for (j=0; j<8; j++) { + c |= XGetPixel(sim->text_im, (x+j)%sim->text_im->width, y)<text_im->width); + } + break; + + case 3: + if (addr>0x2000) { + n=random()%200; + for (i=0; idpy, sim->window, + apple2font_png, sizeof(apple2font_png), + &pix_w, &pix_h, &m); + XImage *im = XGetImage (sim->dpy, p, 0, 0, pix_w, pix_h, ~0L, ZPixmap); + XImage *mm = XGetImage (sim->dpy, m, 0, 0, pix_w, pix_h, 1, XYPixmap); + unsigned long black = + BlackPixelOfScreen (DefaultScreenOfDisplay (sim->dpy)); + int x, y; + + XFreePixmap (sim->dpy, p); + XFreePixmap (sim->dpy, m); + if (pix_w != 64*7) abort(); + if (pix_h != 8) abort(); + + XGetWindowAttributes (sim->dpy, sim->window, &xgwa); + sim->text_im = XCreateImage (sim->dpy, xgwa.visual, 1, XYBitmap, 0, 0, + pix_w, pix_h, 8, 0); + sim->text_im->data = malloc (sim->text_im->bytes_per_line * + sim->text_im->height); + + /* Convert deep image to 1 bit */ + for (y = 0; y < pix_h; y++) + for (x = 0; x < pix_w; x++) + XPutPixel (sim->text_im, x, y, + (XGetPixel (mm, x, y) + ? XGetPixel (im, x, y) == black + : 0)); + + XDestroyImage (im); + XDestroyImage (mm); +} + +#else /* 0 */ + +/* This table lists fixes for characters that differ from the standard 6x10 + font. Each encodes a pixel, as (charindex*7 + x) + (y<<10) + (value<<15) + where value is 0 for white and 1 for black. */ +static const unsigned short a2_fixfont[] = { + /* Fix $ */ 0x8421, 0x941d, + /* Fix % */ 0x8024, 0x0028, 0x8425, 0x0426, 0x0825, 0x1027, 0x1426, 0x9427, + 0x1824, 0x9828, + /* Fix * */ 0x8049, 0x8449, 0x8849, 0x0c47, 0x0c48, 0x0c4a, 0x0c4b, 0x9049, + 0x9449, 0x9849, + /* Fix , */ 0x9057, 0x1458, 0x9856, 0x1857, 0x1c56, + /* Fix . */ 0x1465, 0x1864, 0x1866, 0x1c65, + /* Fix / */ 0x006e, 0x186a, + /* Fix 0 */ 0x8874, 0x8c73, 0x9072, + /* Fix 1 */ 0x0878, 0x1878, 0x187c, + /* Fix 5 */ 0x8895, 0x0c94, 0x0c95, + /* Fix 6 */ 0x809f, 0x8c9c, 0x109c, + /* Fix 7 */ 0x8ca4, 0x0ca5, 0x90a3, 0x10a4, + /* Fix 9 */ 0x08b3, 0x8cb3, 0x98b0, + /* Fix : */ 0x04b9, 0x08b8, 0x08ba, 0x0cb9, 0x90b9, 0x14b9, 0x18b8, 0x18b9, + 0x18ba, 0x1cb9, + /* Fix ; */ 0x04c0, 0x08bf, 0x08c1, 0x0cc0, 0x90c0, 0x14c1, 0x98bf, 0x18c0, + 0x1cbf, + /* Fix < */ 0x80c8, 0x00c9, 0x84c7, 0x04c8, 0x88c6, 0x08c7, 0x8cc5, 0x0cc6, + 0x90c6, 0x10c7, + 0x94c7, 0x14c8, 0x98c8, 0x18c9, + /* Fix > */ 0x80d3, 0x00d4, 0x84d4, 0x04d5, 0x88d5, 0x08d6, 0x8cd6, 0x0cd7, + 0x90d5, 0x10d6, + 0x94d4, 0x14d5, 0x98d3, 0x18d4, + /* Fix @ */ 0x88e3, 0x08e4, 0x8ce4, 0x98e5, + /* Fix B */ 0x84ef, 0x04f0, 0x88ef, 0x08f0, 0x8cef, 0x90ef, 0x10f0, 0x94ef, + 0x14f0, + /* Fix D */ 0x84fd, 0x04fe, 0x88fd, 0x08fe, 0x8cfd, 0x0cfe, 0x90fd, 0x10fe, + 0x94fd, 0x14fe, + /* Fix G */ 0x8116, 0x0516, 0x9916, + /* Fix J */ 0x0129, 0x012a, 0x052a, 0x852b, 0x092a, 0x892b, 0x0d2a, 0x8d2b, + 0x112a, 0x912b, + 0x152a, 0x952b, 0x992a, + /* Fix M */ 0x853d, 0x853f, 0x093d, 0x893e, 0x093f, + /* Fix Q */ 0x915a, 0x155a, 0x955b, 0x155c, 0x195b, 0x995c, 0x1d5c, + /* Fix V */ 0x8d7b, 0x0d7c, 0x0d7e, 0x8d7f, 0x917b, 0x117c, 0x117e, 0x917f, + /* Fix [ */ 0x819e, 0x81a2, 0x859e, 0x899e, 0x8d9e, 0x919e, 0x959e, 0x999e, + 0x99a2, + /* Fix \ */ 0x01a5, 0x19a9, + /* Fix ] */ 0x81ac, 0x81b0, 0x85b0, 0x89b0, 0x8db0, 0x91b0, 0x95b0, 0x99ac, + 0x99b0, + /* Fix ^ */ 0x01b5, 0x05b4, 0x05b6, 0x09b3, 0x89b5, 0x09b7, 0x8db4, 0x8db6, + 0x91b3, 0x91b7, + /* Fix _ */ 0x9db9, 0x9dbf, + 0, +}; + +static void +a2_make_font(apple2_sim_t *sim) +{ + /* + Generate the font. It used a 5x7 font which looks a lot like the standard X + 6x10 font, with a few differences. So we render up all the uppercase + letters of 6x10, and make a few tweaks (like putting a slash across the + zero) according to fixfont. + */ + + int i; + const char *def_font="6x10"; + XFontStruct *font; + Pixmap text_pm; + GC gc; + XGCValues gcv; + + font = load_font_retry (sim->dpy, def_font); + if (!font) { + fprintf(stderr, "%s: can't load font %s\n", progname, def_font); + abort(); + } + + text_pm=XCreatePixmap(sim->dpy, sim->window, 64*7, 8, 1); + + memset(&gcv, 0, sizeof(gcv)); + gcv.foreground=1; + gcv.background=0; + gcv.font=font->fid; + gc=XCreateGC(sim->dpy, text_pm, GCFont|GCBackground|GCForeground, &gcv); + + XSetForeground(sim->dpy, gc, 0); + XFillRectangle(sim->dpy, text_pm, gc, 0, 0, 64*7, 8); + XSetForeground(sim->dpy, gc, 1); + for (i=0; i<64; i++) { + char c=32+i; + int x=7*i+1; + int y=7; + if (c=='0') { + c='O'; + XDrawString(sim->dpy, text_pm, gc, x, y, &c, 1); + } else { + XDrawString(sim->dpy, text_pm, gc, x, y, &c, 1); + } + } + +# if 0 + for (i=0; a2_fixfont[i]; i++) { + XSetForeground (sim->dpy, gc, (a2_fixfont[i]>>15)&1); + XDrawPoint(sim->dpy, text_pm, gc, a2_fixfont[i]&0x3ff, + (a2_fixfont[i]>>10)&0xf); + } + XWriteBitmapFile(sim->dpy, "/tmp/a2font.xbm", text_pm, 64*7, 8, -1, -1); +# endif + + sim->text_im = XGetImage(sim->dpy, text_pm, 0, 0, 64*7, 8, ~0L, ZPixmap); + XFreeGC(sim->dpy, gc); + XFreePixmap(sim->dpy, text_pm); + + for (i=0; a2_fixfont[i]; i++) { + XPutPixel(sim->text_im, a2_fixfont[i]&0x3ff, + (a2_fixfont[i]>>10)&0xf, + (a2_fixfont[i]>>15)&1); + } +} + +#endif /* 0 */ + +apple2_sim_t * +apple2_start(Display *dpy, Window window, int delay, + void (*controller)(apple2_sim_t *sim, + int *stepno, + double *next_actiontime)) +{ + apple2_sim_t *sim; + + sim=(apple2_sim_t *)calloc(1,sizeof(apple2_sim_t)); + sim->dpy = dpy; + sim->window = window; + sim->delay = delay; + sim->controller = controller; + + sim->st = (apple2_state_t *)calloc(1,sizeof(apple2_state_t)); + sim->dec = analogtv_allocate(dpy, window); + sim->inp = analogtv_input_allocate(); + + sim->reception.input = sim->inp; + sim->reception.level = 1.0; + + sim->prompt=']'; + + if (random()%4==0 && !sim->dec->use_cmap && sim->dec->use_color && sim->dec->visbits>=8) { + sim->dec->flutter_tint=1; + } + else if (random()%3==0) { + sim->dec->flutter_horiz_desync=1; + } + sim->typing_rate = 1.0; + + analogtv_set_defaults(sim->dec, ""); + sim->dec->squish_control=0.05; + analogtv_setup_sync(sim->inp, 1, 0); + + + a2_make_font(sim); + + sim->stepno=0; + a2_goto(sim->st,23,0); + + if (random()%2==0) sim->basetime_tv.tv_sec -= 1; /* random blink phase */ + sim->next_actiontime=0.0; + + sim->curtime=0.0; + sim->next_actiontime=sim->curtime; + sim->controller (sim, &sim->stepno, &sim->next_actiontime); + +# ifdef GETTIMEOFDAY_TWO_ARGS + gettimeofday(&sim->basetime_tv, NULL); +# else + gettimeofday(&sim->basetime_tv); +# endif + + return sim; +} + +int +apple2_one_frame (apple2_sim_t *sim) +{ + double blinkphase; + int i; + int textrow; + + if (sim->stepno==A2CONTROLLER_DONE) + goto DONE; /* when caller says we're done, be done, dammit! */ + + { + struct timeval curtime_tv; +# ifdef GETTIMEOFDAY_TWO_ARGS + struct timezone tzp; + gettimeofday(&curtime_tv, &tzp); +# else + gettimeofday(&curtime_tv); +# endif + sim->curtime=(curtime_tv.tv_sec - sim->basetime_tv.tv_sec) + + 0.000001*(curtime_tv.tv_usec - sim->basetime_tv.tv_usec); + if (sim->curtime > sim->dec->powerup) + sim->dec->powerup=sim->curtime; + } + + blinkphase=sim->curtime/0.8; + + /* The blinking rate was controlled by 555 timer with a resistor/capacitor + time constant. Because the capacitor was electrolytic, the flash rate + varied somewhat between machines. I'm guessing 1.6 seconds/cycle was + reasonable. (I soldered a resistor in mine to make it blink faster.) */ + i=sim->st->blink; + sim->st->blink=((int)blinkphase)&1; + if (sim->st->blink!=i && !(sim->st->gr_mode&A2_GR_FULL)) { + int downcounter=0; + /* For every row with blinking text, set the changed flag. This basically + works great except with random screen garbage in text mode, when we + end up redrawing the whole screen every second */ + int row, col; + for (row=(sim->st->gr_mode ? 20 : 0); row<24; row++) { + for (col=0; col<40; col++) { + int c=sim->st->textlines[row][col]; + if ((c & 0xc0) == 0x40) { + downcounter=4; + break; + } + } + if (downcounter>0) { + downcounter--; + } + } + } + + if (sim->curtime >= sim->delay) + sim->stepno = A2CONTROLLER_DONE; + + if (sim->printing) { + int nlcnt=0; + while (*sim->printing) { + if (*sim->printing=='\001') { /* pause */ + sim->printing++; + break; + } + else if (*sim->printing=='\n') { + a2_printc(sim->st,*sim->printing); + sim->printing++; + nlcnt++; + if (nlcnt>=2) break; + } + else { + a2_printc(sim->st,*sim->printing); + sim->printing++; + } + } + if (!*sim->printing) sim->printing=NULL; + } + else if (sim->curtime >= sim->next_actiontime) { + if (sim->typing) { + + int c; + /* If we're in the midst of typing a string, emit a character with + random timing. */ + c =*sim->typing; + if (c==0) { + sim->typing=NULL; + } + else { + sim->typing++; + a2_printc(sim->st, c); + if (c=='\r' || c=='\n') { + sim->next_actiontime = sim->curtime; + } + else if (c==010) { + sim->next_actiontime = sim->curtime + 0.1; + } + else { + sim->next_actiontime = (sim->curtime + + (((random()%1000)*0.001 + 0.3) * + sim->typing_rate)); + } + } + } else { + sim->next_actiontime = sim->curtime; + + sim->controller (sim, &sim->stepno, &sim->next_actiontime); + + if (sim->stepno==A2CONTROLLER_DONE) { + + DONE: + sim->stepno=A2CONTROLLER_FREE; + sim->controller (sim, &sim->stepno, &sim->next_actiontime); + /* if stepno is changed, return 1 */ + if (sim->stepno != A2CONTROLLER_FREE) + return 1; + + XClearWindow(sim->dpy, sim->window); + + /* free sim */ + /* This is from a2_make_font */ + free(sim->text_im->data); + sim->text_im->data = 0; + XDestroyImage(sim->text_im); + + /* And free else */ + analogtv_release(sim->dec); + free(sim->st); + free(sim->inp); + free(sim); + + return 0; + } + + } + } + + + analogtv_setup_sync(sim->inp, sim->st->gr_mode? 1 : 0, 0); + analogtv_setup_frame(sim->dec); + + for (textrow=0; textrow<24; textrow++) { + int row; + for (row=textrow*8; rowinp->signal[row+ANALOGTV_TOP+4][ANALOGTV_PIC_START+100]; + + if ((sim->st->gr_mode&A2_GR_HIRES) && + (row<160 || (sim->st->gr_mode&A2_GR_FULL))) { + int col; + + /* Emulate the mysterious pink line, due to a bit getting + stuck in a shift register between the end of the last + row and the beginning of this one. */ + if ((sim->st->hireslines[row][0] & 0x80) && + (sim->st->hireslines[row][39]&0x40)) { + pp[-1]=ANALOGTV_WHITE_LEVEL; + } + + for (col=0; col<40; col++) { + unsigned char b=sim->st->hireslines[row][col]; + int shift=(b&0x80)?0:1; + + /* Each of the low 7 bits in hires mode corresponded to 2 dot + clocks, shifted by one if the high bit was set. */ + for (i=0; i<7; i++) { + pp[shift+1] = pp[shift] = (((b>>i)&1) + ?ANALOGTV_WHITE_LEVEL + :ANALOGTV_BLACK_LEVEL); + pp+=2; + } + } + } + else if ((sim->st->gr_mode&A2_GR_LORES) && + (row<160 || (sim->st->gr_mode&A2_GR_FULL))) { + int col; + for (col=0; col<40; col++) { + unsigned char nib=((sim->st->textlines[textrow][col] >> (((row/4)&1)*4)) + & 0xf); + /* The low or high nybble was shifted out one bit at a time. */ + for (i=0; i<14; i++) { + *pp = (((nib>>((col*14+i)&3))&1) + ?ANALOGTV_WHITE_LEVEL + :ANALOGTV_BLACK_LEVEL); + pp++; + } + } + } + else { + int col; + for (col=0; col<40; col++) { + int rev; + int c=sim->st->textlines[textrow][col]&0xff; + /* hi bits control inverse/blink as follows: + 0x00: inverse + 0x40: blink + 0x80: normal + 0xc0: normal */ + rev=!(c&0x80) && (!(c&0x40) || sim->st->blink); + + for (i=0; i<7; i++) { + unsigned long pix=XGetPixel(sim->text_im, + ((c&0x3f)^0x20)*7+i, + row%8); + pp[1] = pp[2] = ((pix^rev) + ?ANALOGTV_WHITE_LEVEL + :ANALOGTV_BLACK_LEVEL); + pp+=2; + } + } + } + } + } + analogtv_reception_update(&sim->reception); + { + const analogtv_reception *rec = &sim->reception; + analogtv_draw(sim->dec, 0.02, &rec, 1); + } + + return 1; +} + + +#if 0 +void +a2controller_test(apple2_sim_t *sim, int *stepno, double *next_actiontime) +{ + int row,col; + + switch(*stepno) { + case 0: + a2_invalidate(sim->st); + /* + For testing color rendering. The spec is: + red grn blu + 0 black 0 0 0 + 1 red 227 30 96 + 2 dk blue 96 78 189 + 3 purple 255 68 253 + 4 dk green 0 163 96 + 5 gray 156 156 156 + 6 med blue 20 207 253 + 7 lt blue 208 195 255 + 8 brown 96 114 3 + 9 orange 255 106 60 + 10 grey 156 156 156 + 11 pink 255 160 208 + 12 lt green 20 245 60 + 13 yellow 208 221 141 + 14 aqua 114 255 208 + 15 white 255 255 255 + */ + sim->st->gr_mode=A2_GR_LORES; + for (row=0; row<24; row++) { + for (col=0; col<40; col++) { + sim->st->textlines[row][col]=(row&15)*17; + } + } + *next_actiontime+=0.4; + *stepno=99; + break; + + case 99: + if (sim->curtime > 10) *stepno=-1; + break; + } +} +#endif diff --git a/hacks/apple2.h b/hacks/apple2.h new file mode 100644 index 0000000..87f18a9 --- /dev/null +++ b/hacks/apple2.h @@ -0,0 +1,121 @@ +/* xscreensaver, Copyright (c) 1998-2004 Jamie Zawinski + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * Apple ][ CRT simulator, by Trevor Blackwell + * with additional work by Jamie Zawinski + */ + +#ifndef __XSCREENSAVER_APPLE_II__ +#define __XSCREENSAVER_APPLE_II__ + +#include "analogtv.h" + +typedef struct apple2_state { + unsigned char hireslines[192][40]; + unsigned char textlines[24][40]; + int gr_text; + enum { + A2_GR_FULL=1, + A2_GR_LORES=2, + A2_GR_HIRES=4 + } gr_mode; + int cursx; + int cursy; + int blink; + +} apple2_state_t; + + +typedef struct apple2_sim_s apple2_sim_t; +struct apple2_sim_s { + + void *controller_data; + + apple2_state_t *st; + + analogtv *dec; + analogtv_input *inp; + analogtv_reception reception; + + const char *typing; + char typing_buf[1024]; + double typing_rate; + + char *printing; + char printing_buf[1024]; + + char prompt; + + Display *dpy; + Window window; + XWindowAttributes xgwa; + XImage *text_im; + + struct timeval basetime_tv; + double curtime; + double delay; + + int stepno; + double next_actiontime; + void (*controller)(apple2_sim_t *sim, + int *stepno, + double *next_actiontime); + +}; + + +enum { + A2_HCOLOR_BLACK=0, + A2_HCOLOR_GREEN=1, + A2_HCOLOR_PURPLE=2, + A2_HCOLOR_WHITE=3, + A2_HCOLOR_ALTBLACK=4, + A2_HCOLOR_RED=5, + A2_HCOLOR_BLUE=6, + A2_HCOLOR_ALTWHITE=7 + }; + +enum { + A2CONTROLLER_DONE=-1, + A2CONTROLLER_FREE=-2 +}; + + +extern apple2_sim_t * apple2_start (Display *, Window, int delay, + void (*)(apple2_sim_t *, int *stepno, + double *next_actiontime)); +extern int apple2_one_frame (apple2_sim_t *); + + +void a2_poke(apple2_state_t *st, int addr, int val); +void a2_goto(apple2_state_t *st, int r, int c); +void a2_cls(apple2_state_t *st); +void a2_invalidate(apple2_state_t *st); + +void a2_add_disk_item(apple2_state_t *st, char *name, unsigned char *data, + int len, char type); +void a2_scroll(apple2_state_t *st); +void a2_printc(apple2_state_t *st, char c); +void a2_printc_noscroll(apple2_state_t *st, char c); +void a2_prints(apple2_state_t *st, char *s); +void a2_goto(apple2_state_t *st, int r, int c); +void a2_cls(apple2_state_t *st); +void a2_clear_hgr(apple2_state_t *st); +void a2_clear_gr(apple2_state_t *st); +void a2_invalidate(apple2_state_t *st); +void a2_poke(apple2_state_t *st, int addr, int val); +void a2_display_image_loading(apple2_state_t *st, unsigned char *image, + int lineno); +void a2_init_memory_active(apple2_sim_t *sim); +void a2_hplot(apple2_state_t *st, int hcolor, int x, int y); +void a2_hline(apple2_state_t *st, int hcolor, int x1, int y1, int x2, int y2); +void a2_plot(apple2_state_t *st, int color, int x, int y); + +#endif /* __XSCREENSAVER_APPLE_II__ */ diff --git a/hacks/apple2.man b/hacks/apple2.man new file mode 100644 index 0000000..b0d6d5c --- /dev/null +++ b/hacks/apple2.man @@ -0,0 +1,206 @@ +.de EX \"Begin example +.ne 5 +.if n .sp 1 +.if t .sp .5 +.nf +.in +.5i +.. +.de EE +.fi +.in -.5i +.if n .sp 1 +.if t .sp .5 +.. +.TH XScreenSaver 1 "5-May-2004" "X Version 11" +.SH NAME +apple2 - Apple ][ display emulator +.SH SYNOPSIS +.B apple2 +[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] +[\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install] +[\-visual \fIvisual\fP] +[\-program \fIcommand to run\fP] +[\-basic] [\-slideshow] [\-text] +[\-meta] [\-esc] [\-bs] [\-del] [\-fast] +[\-fps] +.SH DESCRIPTION +The +.I apple2 +program simulates an original Apple ][ Plus computer in all its 1979 +glory. It also reproduces the appearance of display on a color +television set of the period. +.PP +There are 3 modes: basic, slideshow, and text. Normally it chooses a +mode randomly, but you can override with the \fI\-basic\fP, +\fI\-slideshow\fP, or \fI\-text\fP options. + +In basic mode a simulated user types in a Basic program and runs it. + +In slideshow mode it chooses a number of images from the image source +you configured into XScreenSaver and displays them within the +limitations of the Apple ][ display hardware. With only 6 available +colors, you can only make out the general shape of the pictures. + +In text mode it displays the output of a command or the contents of +a file or URL (via the default +.BR xscreensaver-text (1) +program, which can be overridden with \fI\-program\fP). + +In text mode, it is also a fully functional (if anachronistic) +vt100 terminal emulator. +.SH OPTIONS +.I apple2 +accepts the following options: +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-mono +If on a color display, pretend we're on a monochrome display. +.TP 8 +.B \-install +Install a private colormap for the window. +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-basic +Choose basic mode +.TP 8 +.B \-slideshow +Choose slideshow mode +.TP 8 +.B \-text +Choose text mode +.TP 8 +.B \-program \fIsh-command\fP +In text mode, the command to run to generate the text to display. This +option may be any string acceptable to /bin/sh. The program will be +run at the end of a pipe, and any characters that it prints to +\fIstdout\fP will be printed on the Apple ][ display. If the program +exits, it will be launched again after 3 seconds. Default: +.BR xscreensaver-text (1). + +In text mode, \fIapple2\fP emulates a vt100 terminal running on a 40x24 +uppercase-only screen. + +For example: +.EX +apple2 -text \\ + -program 'cat /usr/src/linux*/README | fold -sw40' +apple2 -text -program 'ping apple.com' +apple2 -text -program 'ps -e' +apple2 -text -program 'od -txCz -w7 /dev/urandom' +apple2 -text -program 'cat /dev/random' +apple2 -text -fast -program 'xemacs -nw -q -f life' +apple2 -text -fast \\ + -program 'xemacs -nw -q --eval "(hanoi 5)"' +.EE +You can also use \fIapple2\fP as an extremely lo-fi replacement for the +.BR xterm (1) +and +.BR gnome-terminal (1) +terminal emulators: +.EX +apple2 -text -fast -program tcsh +.EE +.TP 8 +.B \-pty +In \fI\-text\fP mode, launch the sub-program under a pty so that it +can address the screen directly. This is the default. +.TP 8 +.B \-pipe +In \fI\-text\fP mode, launch the sub-program at the end of a pipe: +do not let it address the screen directly. +.TP 8 +.B \-esc +When the user types a key with the Alt or Meta keys held down, send an +ESC character first. This is the default. +.TP 8 +.B \-meta +When Meta or Alt are held down, set the high bit on the character instead. +.TP 8 +.B \-del +Swap Backspace and Delete. This is the default. +.TP 8 +.B \-bs +Do not swap Backspace and Delete. +.TP 8 +.B \-fast +Normally, characters are printed at the speed of an original Apple][ +computer; however, when using this program as a terminal emulator, +the novelty of those 300 baud characters might wear off. You can use +the \fI\-fast\fP option to speed things up a bit. +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH TERMINAL EMULATION +By default, \fIapple2\fP allocates a pseudo-tty for the \fI\-text\fP-mode +sub-process to run under. This has the desirable side effect that the +program will be able to use +.BR ioctl (2) +to fetch information about terminal parameters and window size, which +many programs (such as +.BR top (1)) +need to run properly. \fIapple2\fP will also set the environment +variable \fITERM\fP to \fIvt100\fP in the child process. + +Any characters typed on the apple2 window will be passed along to +the sub-process. (Note that this only works when running in "window" +mode, not when running in \fI\-root\fP mode under xscreensaver.) +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.TP 8 +.B TERM +to inform the sub-process of the type of terminal emulation. +.SH X RESOURCES +Notable X resources supported include the following which correspond +to standard TV controls: +.BR analogTVTint , +.BR analogTVColor , +.BR analogTVBrightness , +and +.BR analogTVContrast +which correspond to standard TV controls. They range from 0 to +100,except for tint which is an angle between -180 and +180. +.SH TRADEMARKS +Apple ][ and Applesoft are trademarks of Apple Computer. + +.SH SEE ALSO +.BR xscreensaver (1), +.BR bsod (MANSUFFIX), +.BR xscreensaver-text (1), +.BR fortune (1), +.BR phosphor (MANSUFFIX), +.BR starwars (MANSUFFIX), +.BR ljlatest (MANSUFFIX), +.BR dadadodo (1), +.BR webcollage (MANSUFFIX), +.BR driftnet (1) +.BR EtherPEG , +.BR EtherPeek , +.BR console_codes (4). +.SH COPYRIGHT +Copyright \(co 2002-2003 by Trevor Blackwell. Permission to use, copy, +modify, distribute, and sell this software and its documentation for +any purpose is hereby granted without fee, provided that the above +copyright notice appear in all copies and that both that copyright +notice and this permission notice appear in supporting documentation. +No representations are made about the suitability of this software for +any purpose. It is provided "as is" without express or implied +warranty. +.SH AUTHOR +Television and Apple ][ emulation by Trevor Blackwell . +Slideshow and text mode by Jamie Zawinski . +Pty and vt100 emulation by Fredrik Tolf . diff --git a/hacks/asm6502.c b/hacks/asm6502.c new file mode 100644 index 0000000..27d2824 --- /dev/null +++ b/hacks/asm6502.c @@ -0,0 +1,2275 @@ +/*-*- indent-tabs-mode:nil -*- */ +/* Copyright (C) 2007 Jeremy English + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * Created: 12-April-2007 + */ + +/* + This is a port of the javascript 6502 assembler, compiler and + debugger. The orignal code was copyright 2006 by Stian Soreng - + www.6502asm.com + + I changed the structure of the assembler in this version. +*/ + +#include +#include +/*#include */ +#include +#include +#include +#include +#include +#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#if defined(HAVE_STDINT_H) +# include +#elif defined(HAVE_INTTYPES_H) +# include +#endif +#include + +#include "yarandom.h" +#include "asm6502.h" + +/*#ifdef DEBUGGER +# define random rand +#endif*/ + +#ifndef HAVE_MOBILE +# define READ_FILES +#endif + +typedef enum{ + LEFT, RIGHT + } Side; + +/* + +Bit Flags + _ _ _ _ _ _ _ _ + |N||V||F||B||D||I||Z||C| + - - - - - - - - + 7 6 5 4 3 2 1 0 + +*/ + +typedef enum{ + CARRY_FL = 0, ZERO_FL = 1, INTERRUPT_FL = 2, + DECIMAL_FL = 3, BREAK_FL = 4, FUTURE_FL = 5, + OVERFLOW_FL = 6, NEGATIVE_FL = 7 + } Flags; + + +typedef BOOL (*CharTest) (char); + +/* A jump function takes a pointer to the current machine and a + opcode. The opcode is needed to figure out the memory mode. */ +/*typedef void (*JumpFunc) (machine_6502* AddrMode);*/ + +typedef struct { + m6502_AddrMode type; + Bit32 value[MAX_PARAM_VALUE]; + unsigned int vp; /*value pointer, index into the value table.*/ + char *label; + Bit32 lbladdr; +} Param; + +typedef struct { + Bit32 addr; /* Address of the label */ + char *label; +} Label; + +typedef struct AsmLine AsmLine; +struct AsmLine { + BOOL labelDecl; /* Does the line have a label declaration? */ + Label *label; + char *command; + Param *param; + AsmLine *next; /* in list */ +}; + +typedef struct { + Bit16 addr; + Bit16 value; +} Pointer; + + +/*static void *emalloc(size_t n) { + void *p = malloc(n); + if (! p) abort(); + return p; +}*/ + +static void *ecalloc(uint32_t nelm, size_t nsize){ + void *p = calloc(nelm, nsize); + if (!p) abort(); + return p; +} + +/* estrdup() - Allocates memory for a new string a returns a copy of the source sting in it. */ +static char *estrdup(const char *source){ + int ln = strlen(source) + 1; + char *s = ecalloc(ln, sizeof(char)); + strncpy(s,source,ln); + return s; +} + +static void checkAddress(Bit32 address){ + /* XXX: Do we want to kill the program here? */ + if (address >= MEM_64K) + fprintf(stderr, "Address %d is beyond 64k", address); +} + +/* + * stackPush() - Push byte to stack + * + */ + +static void stackPush(machine_6502 *machine, Bit8 value ) { + if(machine->regSP >= STACK_BOTTOM){ + machine->memory[machine->regSP--] = value; + } + else{ + fprintf(stderr, "The stack is full: %.4x\n", machine->regSP); + machine->codeRunning = FALSE; + } +} + + +/* + * stackPop() - Pop byte from stack + * + */ + +static Bit8 stackPop(machine_6502 *machine) { + if (machine->regSP < STACK_TOP){ + Bit8 value =machine->memory[++machine->regSP]; + return value; + } + else { + /* fprintf(stderr, "The stack is empty.\n"); xxx */ + machine->codeRunning = FALSE; + return 0; + } +} + +static void pushByte(machine_6502 *machine, Bit32 value ) { + Bit32 address = machine->defaultCodePC; + checkAddress(address); + machine->memory[address] = value & 0xff; + machine->codeLen++; + machine->defaultCodePC++; +} + +/* + * pushWord() - Push a word using pushByte twice + * + */ + +static void pushWord(machine_6502 *machine, Bit16 value ) { + pushByte(machine, value & 0xff ); + pushByte(machine, (value>>8) & 0xff ); +} + +/* + * popByte( machine_6502 *machine,) - Pops a byte + * + */ + +static Bit8 popByte( machine_6502 *machine) { + Bit8 value = machine->memory[machine->regPC]; + machine->regPC++; + return value; +} + +/* + * popWord() - Pops a word using popByte() twice + * + */ + +static int popWord(machine_6502 *machine) { + return popByte(machine) + (popByte(machine) << 8); +} + + +/* + * memReadByte() - Peek a byte, don't touch any registers + * + */ + +static int memReadByte( machine_6502 *machine, int addr ) { + if( addr == 0xfe ) return floor( random()%255 ); + return machine->memory[addr]; +} + +static void updateDisplayPixel(machine_6502 *machine, Bit16 addr){ + Bit8 idx = memReadByte(machine,addr) & 0x0f; + Bit8 x,y; + addr -= 0x200; + x = addr & 0x1f; + y = (addr >> 5); + if (machine->plot) { + machine->plot(x,y,idx,machine->plotterState); + } +} + +/* + * memStoreByte() - Poke a byte, don't touch any registers + * + */ + +static void memStoreByte( machine_6502 *machine, int addr, int value ) { + machine->memory[ addr ] = (value & 0xff); + if( (addr >= 0x200) && (addr<=0x5ff) ) + updateDisplayPixel(machine, addr ); +} + + + +/* EMULATION CODE */ + +static Bit8 bitOn(Bit8 value,Flags bit){ + Bit8 mask = 1; + mask = mask << bit; + return ((value & mask) > 0); +} + +static Bit8 bitOff(Bit8 value, Flags bit){ + return (! bitOn(value,bit)); +} + +static Bit8 setBit(Bit8 value, Flags bit, int on){ + Bit8 onMask = 1; + Bit8 offMask = 0xff; + onMask = onMask << bit; + offMask = offMask ^ onMask; + return ((on) ? value | onMask : value & offMask); +} + +static Bit8 nibble(Bit8 value, Side side){ + switch(side){ + case LEFT: return value & 0xf0; + case RIGHT: return value & 0xf; + default: + fprintf(stderr,"nibble unknown side\n"); + return 0; + } +} + + +/* used for tracing. XXX: combined with function getvalue */ +static BOOL peekValue(machine_6502 *machine, m6502_AddrMode adm, Pointer *pointer, Bit16 PC){ + Bit8 zp; + pointer->value = 0; + pointer->addr = 0; + switch(adm){ + case SINGLE: + return FALSE; + case IMMEDIATE_LESS: + case IMMEDIATE_GREAT: + case IMMEDIATE_VALUE: + pointer->value = memReadByte(machine, PC); + return TRUE; + case INDIRECT_X: + zp = memReadByte(machine, PC) + machine->regX; + pointer->addr = memReadByte(machine,zp) + + (memReadByte(machine,zp+1)<<8); + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case INDIRECT_Y: + zp = memReadByte(machine, PC); + pointer->addr = memReadByte(machine,zp) + + (memReadByte(machine,zp+1)<<8) + machine->regY; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ZERO: + pointer->addr = memReadByte(machine, PC); + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ZERO_X: + pointer->addr = memReadByte(machine, PC) + machine->regX; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ZERO_Y: + pointer->addr = memReadByte(machine, PC) + machine->regY; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ABS_OR_BRANCH: + pointer->addr = memReadByte(machine, PC); + return TRUE; + case ABS_VALUE: + pointer->addr = memReadByte(machine, PC) + (memReadByte(machine, PC+1) << 8); + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ABS_LABEL_X: + case ABS_X: + pointer->addr = (memReadByte(machine, PC) + + (memReadByte(machine, PC+1) << 8)) + machine->regX; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ABS_LABEL_Y: + case ABS_Y: + pointer->addr = (memReadByte(machine, PC) + + (memReadByte(machine, PC+1) << 8)) + machine->regY; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case DCB_PARAM: + /* Handled elsewhere */ + break; + } + return FALSE; + +} + + +/* Figure out how to get the value from the addrmode and get it.*/ +static BOOL getValue(machine_6502 *machine, m6502_AddrMode adm, Pointer *pointer){ + Bit8 zp; + pointer->value = 0; + pointer->addr = 0; + switch(adm){ + case SINGLE: + return FALSE; + case IMMEDIATE_LESS: + case IMMEDIATE_GREAT: + case IMMEDIATE_VALUE: + pointer->value = popByte(machine); + return TRUE; + case INDIRECT_X: + zp = popByte(machine) + machine->regX; + pointer->addr = memReadByte(machine,zp) + + (memReadByte(machine,zp+1)<<8); + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case INDIRECT_Y: + zp = popByte(machine); + pointer->addr = memReadByte(machine,zp) + + (memReadByte(machine,zp+1)<<8) + machine->regY; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ZERO: + pointer->addr = popByte(machine); + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ZERO_X: + pointer->addr = popByte(machine) + machine->regX; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ZERO_Y: + pointer->addr = popByte(machine) + machine->regY; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ABS_OR_BRANCH: + pointer->addr = popByte(machine); + return TRUE; + case ABS_VALUE: + pointer->addr = popWord(machine); + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ABS_LABEL_X: + case ABS_X: + pointer->addr = popWord(machine) + machine->regX; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ABS_LABEL_Y: + case ABS_Y: + pointer->addr = popWord(machine) + machine->regY; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case DCB_PARAM: + /* Handled elsewhere */ + break; + } + return FALSE; + +} + +#if 0 +static void dismem(machine_6502 *machine, m6502_AddrMode adm, char *output){ + Bit8 zp; + Bit16 n; + switch(adm){ + case SINGLE: + *output = 0; + break; + case IMMEDIATE_LESS: + case IMMEDIATE_GREAT: + case IMMEDIATE_VALUE: + n = popByte(machine); + sprintf(output,"#$%x",n); + break; + case INDIRECT_X: + zp = popByte(machine); + n = memReadByte(machine,zp) + + (memReadByte(machine,zp+1)<<8); + sprintf(output,"($%x,x)",n); + break; + case INDIRECT_Y: + zp = popByte(machine); + n = memReadByte(machine,zp) + + (memReadByte(machine,zp+1)<<8); + sprintf(output,"($%x),y",n); + break; + case ABS_OR_BRANCH: + case ZERO: + n = popByte(machine); + sprintf(output,"$%x",n); + break; + case ZERO_X: + n = popByte(machine); + sprintf(output,"$%x,x",n); + break; + case ZERO_Y: + n = popByte(machine); + sprintf(output,"$%x,y",n); + break; + case ABS_VALUE: + n = popWord(machine); + sprintf(output,"$%x",n); + break; + case ABS_LABEL_X: + case ABS_X: + n = popWord(machine); + sprintf(output,"$%x,x",n); + break; + case ABS_LABEL_Y: + case ABS_Y: + n = popWord(machine); + sprintf(output,"$%x,x",n); + break; + case DCB_PARAM: + *output = 0; + break; + } +} +#endif + +/* manZeroNeg - Manage the negative and zero flags */ +static void manZeroNeg(machine_6502 *machine, Bit8 value){ + machine->regP = setBit(machine->regP, ZERO_FL, (value == 0)); + machine->regP = setBit(machine->regP, NEGATIVE_FL, bitOn(value,NEGATIVE_FL)); +} + +static void warnValue(BOOL isValue){ + if (! isValue){ + fprintf(stderr,"Invalid Value from getValue.\n"); + } +} + +static void jmpADC(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + Bit16 tmp; + Bit8 c = bitOn(machine->regP, CARRY_FL); + BOOL isValue = getValue(machine, adm, &ptr); + + warnValue(isValue); + + if (bitOn(machine->regA, NEGATIVE_FL) && + bitOn(ptr.value, NEGATIVE_FL)) + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); + else + machine->regP = setBit(machine->regP, OVERFLOW_FL, 1); + + if (bitOn(machine->regP, DECIMAL_FL)) { + tmp = nibble(machine->regA,RIGHT) + nibble(ptr.value,RIGHT ) + c; + /* The decimal part is limited to 0 through 9 */ + if (tmp >= 10){ + tmp = 0x10 | ((tmp + 6) & 0xf); + } + tmp += nibble(machine->regA,LEFT) + nibble(ptr.value,LEFT); + if (tmp >= 160){ + machine->regP = setBit(machine->regP,CARRY_FL,1); + if (bitOn(machine->regP, OVERFLOW_FL) && tmp >= 0x180) + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); + tmp += 0x60; + } + else { + machine->regP = setBit(machine->regP,CARRY_FL,0); + if (bitOn(machine->regP, OVERFLOW_FL) && tmp < 0x80) + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); + } + } /* end decimal */ + else { + tmp = machine->regA + ptr.value + c; + if ( tmp >= 0x100 ){ + machine->regP = setBit(machine->regP,CARRY_FL,1); + if (bitOn(machine->regP, OVERFLOW_FL) && tmp >= 0x180) + machine->regP =setBit(machine->regP, OVERFLOW_FL, 0); + } + else { + machine->regP = setBit(machine->regP,CARRY_FL,0); + if (bitOn(machine->regP, OVERFLOW_FL) && tmp < 0x80) + machine->regP =setBit(machine->regP, OVERFLOW_FL, 0); + } + } + + machine->regA = tmp; + manZeroNeg(machine,machine->regA); +} + +static void jmpAND(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regA &= ptr.value; + manZeroNeg(machine,machine->regA); +} + +static void jmpASL(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + if (isValue){ + machine->regP = setBit(machine->regP, CARRY_FL, bitOn(ptr.value, NEGATIVE_FL)); + ptr.value = ptr.value << 1; + ptr.value = setBit(ptr.value, CARRY_FL, 0); + memStoreByte(machine, ptr.addr, ptr.value); + manZeroNeg(machine,ptr.value); + } + else { /* Accumulator */ + machine->regP = setBit(machine->regP, CARRY_FL, bitOn(machine->regA, NEGATIVE_FL)); + machine->regA = machine->regA << 1; + machine->regA = setBit(machine->regA, CARRY_FL, 0); + manZeroNeg(machine,machine->regA); + } + +} + +static void jmpBIT(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regP = setBit(machine->regP, ZERO_FL, !(ptr.value & machine->regA)); + machine->regP = setBit(machine->regP, OVERFLOW_FL, bitOn(ptr.value, OVERFLOW_FL)); + machine->regP = setBit(machine->regP, NEGATIVE_FL, bitOn(ptr.value, NEGATIVE_FL)); + +} + +static void jumpBranch(machine_6502 *machine, Bit16 offset){ + if ( offset > 0x7f ) + machine->regPC = machine->regPC - (0x100 - offset); + else + machine->regPC = machine->regPC + offset; +} + +static void jmpBPL(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOff(machine->regP,NEGATIVE_FL)) + jumpBranch(machine, ptr.addr); + +} + +static void jmpBMI(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOn(machine->regP,NEGATIVE_FL)) + jumpBranch(machine, ptr.addr); + +} + +static void jmpBVC(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOff(machine->regP,OVERFLOW_FL)) + jumpBranch(machine, ptr.addr); +} + +static void jmpBVS(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOn(machine->regP,OVERFLOW_FL)) + jumpBranch(machine, ptr.addr); +} + +static void jmpBCC(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOff(machine->regP,CARRY_FL)) + jumpBranch(machine, ptr.addr); +} + +static void jmpBCS(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOn(machine->regP,CARRY_FL)) + jumpBranch(machine, ptr.addr); +} + +static void jmpBNE(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOff(machine->regP, ZERO_FL)) + jumpBranch(machine, ptr.addr); +} + +static void jmpBEQ(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOn(machine->regP, ZERO_FL)) + jumpBranch(machine, ptr.addr); +} + +static void doCompare(machine_6502 *machine, Bit16 reg, Pointer *ptr){ + machine->regP = setBit(machine->regP,CARRY_FL, ((reg + ptr->value) > 0xff)); + manZeroNeg(machine,(reg - ptr->value)); +} + +static void jmpCMP(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + doCompare(machine,machine->regA,&ptr); +} + +static void jmpCPX(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + doCompare(machine,machine->regX,&ptr); +} + +static void jmpCPY(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + doCompare(machine,machine->regY,&ptr); +} + +static void jmpDEC(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (ptr.value > 0) + ptr.value--; + else + ptr.value = 0xFF; + memStoreByte(machine, ptr.addr, ptr.value); + manZeroNeg(machine,ptr.value); +} + +static void jmpEOR(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regA ^= ptr.value; + manZeroNeg(machine, machine->regA); +} + +static void jmpCLC(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = setBit(machine->regP, CARRY_FL, 0); +} + +static void jmpSEC(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = setBit(machine->regP, CARRY_FL, 1); +} + +static void jmpCLI(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = setBit(machine->regP, INTERRUPT_FL, 0); +} + +static void jmpSEI(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = setBit(machine->regP, INTERRUPT_FL, 1); +} + +static void jmpCLV(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); +} + +static void jmpCLD(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = setBit(machine->regP, DECIMAL_FL, 0); +} + +static void jmpSED(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = setBit(machine->regP, DECIMAL_FL, 1); +} + +static void jmpINC(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + ptr.value = (ptr.value + 1) & 0xFF; + memStoreByte(machine, ptr.addr, ptr.value); + manZeroNeg(machine,ptr.value); +} + +static void jmpJMP(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regPC = ptr.addr; +} + +static void jmpJSR(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + /* Move past the 2 byte parameter. JSR is always followed by + absolute address. */ + Bit16 currAddr = machine->regPC + 2; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + stackPush(machine, (currAddr >> 8) & 0xff); + stackPush(machine, currAddr & 0xff); + machine->regPC = ptr.addr; +} + +static void jmpLDA(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regA = ptr.value; + manZeroNeg(machine, machine->regA); +} + +static void jmpLDX(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regX = ptr.value; + manZeroNeg(machine, machine->regX); +} + +static void jmpLDY(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regY = ptr.value; + manZeroNeg(machine, machine->regY); +} + +static void jmpLSR(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + if (isValue){ + machine->regP = + setBit(machine->regP, CARRY_FL, + bitOn(ptr.value, CARRY_FL)); + ptr.value = ptr.value >> 1; + ptr.value = setBit(ptr.value,NEGATIVE_FL,0); + memStoreByte(machine,ptr.addr,ptr.value); + manZeroNeg(machine,ptr.value); + } + else { /* Accumulator */ + machine->regP = + setBit(machine->regP, CARRY_FL, + bitOn(machine->regA, CARRY_FL)); + machine->regA = machine->regA >> 1; + machine->regA = setBit(machine->regA,NEGATIVE_FL,0); + manZeroNeg(machine,ptr.value); + } +} + +static void jmpNOP(machine_6502 *machine, m6502_AddrMode adm){ + /* no operation */ +} + +static void jmpORA(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regA |= ptr.value; + manZeroNeg(machine,machine->regA); +} + +static void jmpTAX(machine_6502 *machine, m6502_AddrMode adm){ + machine->regX = machine->regA; + manZeroNeg(machine,machine->regX); +} + +static void jmpTXA(machine_6502 *machine, m6502_AddrMode adm){ + machine->regA = machine->regX; + manZeroNeg(machine,machine->regA); +} + +static void jmpDEX(machine_6502 *machine, m6502_AddrMode adm){ + if (machine->regX > 0) + machine->regX--; + else + machine->regX = 0xFF; + manZeroNeg(machine, machine->regX); +} + +static void jmpINX(machine_6502 *machine, m6502_AddrMode adm){ + Bit16 value = machine->regX + 1; + machine->regX = value & 0xFF; + manZeroNeg(machine, machine->regX); +} + +static void jmpTAY(machine_6502 *machine, m6502_AddrMode adm){ + machine->regY = machine->regA; + manZeroNeg(machine, machine->regY); +} + +static void jmpTYA(machine_6502 *machine, m6502_AddrMode adm){ + machine->regA = machine->regY; + manZeroNeg(machine, machine->regA); +} + +static void jmpDEY(machine_6502 *machine, m6502_AddrMode adm){ + if (machine->regY > 0) + machine->regY--; + else + machine->regY = 0xFF; + manZeroNeg(machine, machine->regY); +} + +static void jmpINY(machine_6502 *machine, m6502_AddrMode adm){ + Bit16 value = machine->regY + 1; + machine->regY = value & 0xff; + manZeroNeg(machine, machine->regY); +} + +static void jmpROR(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + Bit8 cf; + BOOL isValue = getValue(machine, adm, &ptr); + if (isValue) { + cf = bitOn(machine->regP, CARRY_FL); + machine->regP = + setBit(machine->regP, CARRY_FL, + bitOn(ptr.value, CARRY_FL)); + ptr.value = ptr.value >> 1; + ptr.value = setBit(ptr.value, NEGATIVE_FL, cf); + memStoreByte(machine, ptr.addr, ptr.value); + manZeroNeg(machine, ptr.value); + } + else { /* Implied */ + cf = bitOn(machine->regP, CARRY_FL); + machine->regP = + setBit(machine->regP, CARRY_FL, + bitOn(machine->regA, CARRY_FL)); + machine->regA = machine->regA >> 1; + machine->regA = setBit(machine->regA, NEGATIVE_FL, cf); + manZeroNeg(machine, machine->regA); + } +} + +static void jmpROL(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + Bit8 cf; + BOOL isValue = getValue(machine, adm, &ptr); + if (isValue) { + cf = bitOn(machine->regP, CARRY_FL); + machine->regP = + setBit(machine->regP, CARRY_FL, + bitOn(ptr.value, NEGATIVE_FL)); + ptr.value = ptr.value << 1; + ptr.value = setBit(ptr.value, CARRY_FL, cf); + memStoreByte(machine, ptr.addr, ptr.value); + manZeroNeg(machine, ptr.value); + } + else { /* Implied */ + cf = bitOn(machine->regP, CARRY_FL); + machine->regP = + setBit(machine->regP, CARRY_FL, + bitOn(machine->regA,NEGATIVE_FL)); + machine->regA = machine->regA << 1; + machine->regA = setBit(machine->regA, CARRY_FL, cf); + manZeroNeg(machine, machine->regA); + } +} + +static void jmpRTI(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = stackPop(machine); + machine->regPC = stackPop(machine); +} + +static void jmpRTS(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + Bit16 nr = stackPop(machine); + Bit16 nl = stackPop(machine); + warnValue(! isValue); + machine->regPC = (nl << 8) | nr; +} + +static void jmpSBC(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + /*Bit8 vflag;*/ + Bit8 c = bitOn(machine->regP, CARRY_FL); + Bit16 tmp, w; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + /*vflag = (bitOn(machine->regA,NEGATIVE_FL) && + bitOn(ptr.value, NEGATIVE_FL));*/ + + if (bitOn(machine->regP, DECIMAL_FL)) { + Bit8 ar = nibble(machine->regA, RIGHT); + Bit8 br = nibble(ptr.value, RIGHT); + Bit8 al = nibble(machine->regA, LEFT); + Bit8 bl = nibble(ptr.value, LEFT); + + tmp = 0xf + ar - br + c; + if ( tmp < 0x10){ + w = 0; + tmp -= 6; + } + else { + w = 0x10; + tmp -= 0x10; + } + w += 0xf0 + al - bl; + if ( w < 0x100) { + machine->regP = setBit(machine->regP, CARRY_FL, 0); + if (bitOn(machine->regP, OVERFLOW_FL) && w < 0x80) + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); + w -= 0x60; + } + else { + machine->regP = setBit(machine->regP, CARRY_FL, 1); + if (bitOn(machine->regP, OVERFLOW_FL) && w >= 0x180) + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); + } + w += tmp; + } /* end decimal mode */ + else { + w = 0xff + machine->regA - ptr.value + c; + if ( w < 0x100 ){ + machine->regP = setBit(machine->regP, CARRY_FL, 0); + if (bitOn(machine->regP, OVERFLOW_FL) && w < 0x80) + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); + } + else { + machine->regP = setBit(machine->regP, CARRY_FL, 1); + if (bitOn(machine->regP, OVERFLOW_FL) && w >= 0x180) + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); + } + } + machine->regA = w; + manZeroNeg(machine,machine->regA); +} + +static void jmpSTA(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + memStoreByte(machine,ptr.addr,machine->regA); +} + +static void jmpTXS(machine_6502 *machine, m6502_AddrMode adm){ + stackPush(machine,machine->regX); +} + +static void jmpTSX(machine_6502 *machine, m6502_AddrMode adm){ + machine->regX = stackPop(machine); + manZeroNeg(machine, machine->regX); +} + +static void jmpPHA(machine_6502 *machine, m6502_AddrMode adm){ + stackPush(machine, machine->regA); +} + +static void jmpPLA(machine_6502 *machine, m6502_AddrMode adm){ + machine->regA = stackPop(machine); + manZeroNeg(machine, machine->regA); +} + +static void jmpPHP(machine_6502 *machine, m6502_AddrMode adm){ + stackPush(machine,machine->regP); +} + +static void jmpPLP(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = stackPop(machine); + machine->regP = setBit(machine->regP, FUTURE_FL, 1); +} + +static void jmpSTX(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + memStoreByte(machine,ptr.addr,machine->regX); +} + +static void jmpSTY(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + memStoreByte(machine,ptr.addr,machine->regY); +} + + + +/* OPCODES */ +static void assignOpCodes(m6502_Opcodes *opcodes){ + + #define SETOP(num, _name, _Imm, _ZP, _ZPX, _ZPY, _ABS, _ABSX, _ABSY, _INDX, _INDY, _SNGL, _BRA, _func) \ +{opcodes[num].name[3] = '\0'; \ + strncpy(opcodes[num].name, _name, 3); opcodes[num].Imm = _Imm; opcodes[num].ZP = _ZP; \ + opcodes[num].ZPX = _ZPX; opcodes[num].ZPY = _ZPY; opcodes[num].ABS = _ABS; \ + opcodes[num].ABSX = _ABSX; opcodes[num].ABSY = _ABSY; opcodes[num].INDX = _INDX; \ + opcodes[num].INDY = _INDY; opcodes[num].SNGL = _SNGL; opcodes[num].BRA = _BRA; \ + opcodes[num].func = _func;} + + /* OPCODE Imm ZP ZPX ZPY ABS ABSX ABSY INDX INDY SGNL BRA Jump Function*/ + SETOP( 0, "ADC", 0x69, 0x65, 0x75, 0x00, 0x6d, 0x7d, 0x79, 0x61, 0x71, 0x00, 0x00, jmpADC); + SETOP( 1, "AND", 0x29, 0x25, 0x35, 0x31, 0x2d, 0x3d, 0x39, 0x00, 0x00, 0x00, 0x00, jmpAND); + SETOP( 2, "ASL", 0x00, 0x06, 0x16, 0x00, 0x0e, 0x1e, 0x00, 0x00, 0x00, 0x0a, 0x00, jmpASL); + SETOP( 3, "BIT", 0x00, 0x24, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpBIT); + SETOP( 4, "BPL", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, jmpBPL); + SETOP( 5, "BMI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, jmpBMI); + SETOP( 6, "BVC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, jmpBVC); + SETOP( 7, "BVS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, jmpBVS); + SETOP( 8, "BCC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, jmpBCC); + SETOP( 9, "BCS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, jmpBCS); + SETOP(10, "BNE", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, jmpBNE); + SETOP(11, "BEQ", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, jmpBEQ); + SETOP(12, "CMP", 0xc9, 0xc5, 0xd5, 0x00, 0xcd, 0xdd, 0xd9, 0xc1, 0xd1, 0x00, 0x00, jmpCMP); + SETOP(13, "CPX", 0xe0, 0xe4, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpCPX); + SETOP(14, "CPY", 0xc0, 0xc4, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpCPY); + SETOP(15, "DEC", 0x00, 0xc6, 0xd6, 0x00, 0xce, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, jmpDEC); + SETOP(16, "EOR", 0x49, 0x45, 0x55, 0x00, 0x4d, 0x5d, 0x59, 0x41, 0x51, 0x00, 0x00, jmpEOR); + SETOP(17, "CLC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, jmpCLC); + SETOP(18, "SEC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, jmpSEC); + SETOP(19, "CLI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, jmpCLI); + SETOP(20, "SEI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, jmpSEI); + SETOP(21, "CLV", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, jmpCLV); + SETOP(22, "CLD", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, jmpCLD); + SETOP(23, "SED", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, jmpSED); + SETOP(24, "INC", 0x00, 0xe6, 0xf6, 0x00, 0xee, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, jmpINC); + SETOP(25, "JMP", 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpJMP); + SETOP(26, "JSR", 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpJSR); + SETOP(27, "LDA", 0xa9, 0xa5, 0xb5, 0x00, 0xad, 0xbd, 0xb9, 0xa1, 0xb1, 0x00, 0x00, jmpLDA); + SETOP(28, "LDX", 0xa2, 0xa6, 0x00, 0xb6, 0xae, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, jmpLDX); + SETOP(29, "LDY", 0xa0, 0xa4, 0xb4, 0x00, 0xac, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, jmpLDY); + SETOP(30, "LSR", 0x00, 0x46, 0x56, 0x00, 0x4e, 0x5e, 0x00, 0x00, 0x00, 0x4a, 0x00, jmpLSR); + SETOP(31, "NOP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00, jmpNOP); + SETOP(32, "ORA", 0x09, 0x05, 0x15, 0x00, 0x0d, 0x1d, 0x19, 0x01, 0x11, 0x00, 0x00, jmpORA); + SETOP(33, "TAX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, jmpTAX); + SETOP(34, "TXA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, jmpTXA); + SETOP(35, "DEX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x00, jmpDEX); + SETOP(36, "INX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, jmpINX); + SETOP(37, "TAY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, jmpTAY); + SETOP(38, "TYA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, jmpTYA); + SETOP(39, "DEY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, jmpDEY); + SETOP(40, "INY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, jmpINY); + SETOP(41, "ROR", 0x00, 0x66, 0x76, 0x00, 0x6e, 0x7e, 0x00, 0x00, 0x00, 0x6a, 0x00, jmpROR); + SETOP(42, "ROL", 0x00, 0x26, 0x36, 0x00, 0x2e, 0x3e, 0x00, 0x00, 0x00, 0x2a, 0x00, jmpROL); + SETOP(43, "RTI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, jmpRTI); + SETOP(44, "RTS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, jmpRTS); + SETOP(45, "SBC", 0xe9, 0xe5, 0xf5, 0x00, 0xed, 0xfd, 0xf9, 0xe1, 0xf1, 0x00, 0x00, jmpSBC); + SETOP(46, "STA", 0x00, 0x85, 0x95, 0x00, 0x8d, 0x9d, 0x99, 0x81, 0x91, 0x00, 0x00, jmpSTA); + SETOP(47, "TXS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, jmpTXS); + SETOP(48, "TSX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, jmpTSX); + SETOP(49, "PHA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, jmpPHA); + SETOP(50, "PLA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, jmpPLA); + SETOP(51, "PHP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, jmpPHP); + SETOP(52, "PLP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, jmpPLP); + SETOP(53, "STX", 0x00, 0x86, 0x00, 0x96, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpSTX); + SETOP(54, "STY", 0x00, 0x84, 0x94, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpSTY); + SETOP(55, "---", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, NULL); +} + +static void buildIndexCache(machine_6502 *machine){ + unsigned int i; + for (i = 0; i < NUM_OPCODES; i++) { + if (machine->opcodes[i].Imm != 0x00){ + machine->opcache[machine->opcodes[i].Imm].adm = IMMEDIATE_VALUE; + machine->opcache[machine->opcodes[i].Imm].index = i; + } + if (machine->opcodes[i].ZP != 0x00){ + machine->opcache[machine->opcodes[i].ZP].adm = ZERO; + machine->opcache[machine->opcodes[i].ZP].index = i; + } + if (machine->opcodes[i].ZPX != 0x00){ + machine->opcache[machine->opcodes[i].ZPX].adm = ZERO_X; + machine->opcache[machine->opcodes[i].ZPX].index = i;; + } + if (machine->opcodes[i].ZPY != 0x00){ + machine->opcache[machine->opcodes[i].ZPY].adm = ZERO_Y; + machine->opcache[machine->opcodes[i].ZPY].index = i;; + } + if (machine->opcodes[i].ABS != 0x00){ + machine->opcache[machine->opcodes[i].ABS].adm = ABS_VALUE; + machine->opcache[machine->opcodes[i].ABS].index = i;; + } + if (machine->opcodes[i].ABSX != 0x00){ + machine->opcache[machine->opcodes[i].ABSX].adm = ABS_X; + machine->opcache[machine->opcodes[i].ABSX].index = i;; + } + if (machine->opcodes[i].ABSY != 0x00){ + machine->opcache[machine->opcodes[i].ABSY].adm = ABS_Y; + machine->opcache[machine->opcodes[i].ABSY].index = i;; + } + if (machine->opcodes[i].INDX != 0x00){ + machine->opcache[machine->opcodes[i].INDX].adm = INDIRECT_X; + machine->opcache[machine->opcodes[i].INDX].index = i;; + } + if (machine->opcodes[i].INDY != 0x00){ + machine->opcache[machine->opcodes[i].INDY].adm = INDIRECT_Y; + machine->opcache[machine->opcodes[i].INDY].index = i;; + } + if (machine->opcodes[i].SNGL != 0x00){ + machine->opcache[machine->opcodes[i].SNGL].adm = SINGLE; + machine->opcache[machine->opcodes[i].SNGL].index = i; + } + if (machine->opcodes[i].BRA != 0x00){ + machine->opcache[machine->opcodes[i].BRA].adm = ABS_OR_BRANCH; + machine->opcache[machine->opcodes[i].BRA].index = i; + } + } +} + +/* opIndex() - Search the opcode table for a match. If found return + the index into the optable and the address mode of the opcode. If + the opcode is not found then return -1. */ +static int opIndex(machine_6502 *machine, Bit8 opcode, m6502_AddrMode *adm){ + /* XXX could catch errors by setting a addressmode of error or something */ + *adm = machine->opcache[opcode].adm; + return machine->opcache[opcode].index; +} + + +/* Assembly parser */ + +static Param *newParam(void){ + Param *newp; + int i = 0; + + newp = (Param *) ecalloc(1, sizeof(Param)); + newp->type = SINGLE; + for (i = 0; i < MAX_PARAM_VALUE; i++) + newp->value[i] = 0; + newp->vp = 0; + newp->label = ecalloc(MAX_LABEL_LEN,sizeof(char)); + newp->lbladdr = 0; + return newp; +} + +/* Copy the fields from p2 to p1 */ +static void copyParam(Param *p1, Param *p2){ + int i = 0; + strncpy(p1->label,p2->label,MAX_LABEL_LEN); + for(i = 0; i < MAX_PARAM_VALUE; i++) + p1->value[i] = p2->value[i]; + p1->vp = p2->vp; + p1->type = p2->type; +} + +static Label *newLabel(void){ + Label *newp; + + newp = (Label *) ecalloc(1, sizeof(Label)); + newp->addr = 0; + newp->label = ecalloc(MAX_LABEL_LEN,sizeof(char)); + + return newp; +} + +static AsmLine *newAsmLine(char *cmd, char *label, BOOL decl, Param *param, int lc) +{ + AsmLine *newp; + + newp = (AsmLine *) ecalloc(1, sizeof(AsmLine)); + newp->labelDecl = decl; + newp->label = newLabel(); + strncpy(newp->label->label,label,MAX_LABEL_LEN); + newp->command = estrdup(cmd); + newp->param = newParam(); + copyParam(newp->param, param); + newp->next = NULL; + return newp; +} + +static AsmLine *addend(AsmLine *listp, AsmLine *newp) +{ + AsmLine *p; + if(listp == NULL) + return newp; + for (p =listp; p->next != NULL; p = p->next) + ; + p->next = newp; + return listp; +} + +static BOOL apply(AsmLine *listp, BOOL(*fn)(AsmLine*, void*), void *arg) +{ + AsmLine *p; + if(listp == NULL) + return FALSE; + for (p = listp; p != NULL; p = p->next) + if (! fn(p,arg) ) + return FALSE; + return TRUE; +} + +static void freeParam(Param *param){ + free(param->label); + free(param); +} + +static void freeLabel(Label *label){ + free(label->label); + free(label); +} + +static void freeallAsmLine(AsmLine *listp) +{ + AsmLine *next; + for(; listp != NULL; listp = next){ + next = listp->next; + freeParam(listp->param); + freeLabel(listp->label); + free(listp->command); + free(listp); + } +} + +static BOOL addvalue(Param *param,Bit32 value){ + /* jwz: suppress "0 <= unsigned" warning */ + if (/*0 <= param->vp &&*/ param->vp < MAX_PARAM_VALUE) { + param->value[param->vp++] = value; + return TRUE; + } + else { + fprintf(stderr,"Wrong number of parameters: %d. The limit is %d\n",param->vp+1, MAX_PARAM_VALUE); + return FALSE; + } +} + +static void parseError(char *s){ + fprintf(stderr,"6502 Syntax Error: %s\n", s); +} + +/* stoupper() - Destructivley modifies the string making all letters upper case*/ +static void stoupper(char **s){ + int i = 0; + while((*s)[i] != '\0'){ + (*s)[i] = toupper((*s)[i]); + i++; + } +} + +static BOOL isWhite(char c){ + return (c == '\r' || c == '\t' || c == ' '); +} + +static void skipSpace(char **s){ + for(; isWhite(**s); (*s)++) + ; +} + +/* nullify() - fills a string with upto sourceLength null characters. */ +static void nullify(char *token, unsigned int sourceLength){ + unsigned int i = 0; + while (i < sourceLength) + token[i++] = '\0'; +} + +static BOOL isBlank(const char *token){ + return (token[0] == '\0'); +} + +static BOOL isCommand(machine_6502 *machine, const char *token){ + int i = 0; + + while (i < NUM_OPCODES) { + if (strcmp(machine->opcodes[i].name,token) == 0) + return TRUE; + i++; + } + + if (strcmp(token, "DCB") == 0) return TRUE; + return FALSE; +} + +/* hasChar() - Check to see if the current line has a certain + charater */ +static BOOL hasChar(char *s, char c){ + for(; *s != '\0' && *s != '\n'; s++) { + if (*s == c) + return TRUE; + } + return FALSE; +} + +static BOOL ishexdigit(char c){ + if (isdigit(c)) + return TRUE; + else { + char c1 = toupper(c); + return ('A' <= c1 && c1 <= 'F'); + } +} + +/* isCmdChar() - Is this a valid character for a command. All of the + command are alpha except for the entry point code that is "*=" */ +static BOOL isCmdChar(char c){ + return (isalpha(c) || c == '*' || c == '='); +} + + +/* command() - parse a command from the source code. We pass along a + machine so the opcode can be validated. */ +static BOOL command(machine_6502 *machine, char **s, char **cmd){ + int i = 0; + skipSpace(s); + for(;isCmdChar(**s) && i < MAX_CMD_LEN; (*s)++) + (*cmd)[i++] = **s; + if (i == 0) + return TRUE; /* Could be a blank line. */ + else if (strcmp(*cmd,"*=") == 0) + return TRUE; /* This is an entry point. */ + else + return isCommand(machine,*cmd); +} + +static BOOL declareLabel(char **s, char **label){ + int i = 0; + skipSpace(s); + for(;**s != ':' && **s != '\n' && **s != '\0'; (*s)++){ + if (isWhite(**s)) + continue; + (*label)[i++] = **s; + } + if (i == 0) + return FALSE; /* Current line has to have a label */ + else if (**s == ':'){ + (*s)++; /* Skip colon */ + return TRUE; + } + else + return FALSE; +} + +static BOOL parseHex(char **s, Bit32 *value){ + enum { MAX_HEX_LEN = 5 }; + if (**s == '$') { + char *hex = ecalloc(MAX_HEX_LEN, sizeof(char)); + int i = 0; + + (*s)++; /* move pass $ */ + for(; ishexdigit(**s) && i < MAX_HEX_LEN; (*s)++) + hex[i++] = **s; + + *value = strtol(hex,NULL,16); + free(hex); + return TRUE; + } + else + return FALSE; +} + +static BOOL parseDec(char **s, Bit32 *value){ + enum { MAX_DEC_LEN = 4 }; + char *dec = ecalloc(MAX_DEC_LEN, sizeof(char)); + int i; + for(i = 0; isdigit(**s) && i < MAX_DEC_LEN; (*s)++) + dec[i++] = **s; + + if (i > 0){ + *value = atoi(dec); + free(dec); + return TRUE; + } + else{ + free(dec); + return FALSE; + } +} + +static BOOL parseValue(char **s, Bit32 *value){ + skipSpace(s); + if (**s == '$') + return parseHex(s, value); + else + return parseDec(s, value); +} + +static BOOL paramLabel(char **s, char **label){ + int i; + for(i = 0; (isalnum(**s) || **s == '_') && i < MAX_LABEL_LEN; (*s)++) + (*label)[i++] = **s; + + if (i > 0) + return TRUE; + else + return FALSE; +} + +static BOOL immediate(char **s, Param *param){ + if (**s != '#') + return FALSE; + + (*s)++; /*Move past hash */ + if (**s == '<' || **s == '>'){ + char *label = ecalloc(MAX_LABEL_LEN, sizeof(char)); + param->type = (**s == '<') ? IMMEDIATE_LESS : IMMEDIATE_GREAT; + (*s)++; /* move past < or > */ + if (paramLabel(s, &label)){ + int ln = strlen(label) + 1; + strncpy(param->label, label, ln); + free(label); + return TRUE; + } + free(label); + } + else { + Bit32 value; + if (parseValue(s, &value)){ + if (value > 0xFF){ + parseError("Immediate value is too large."); + return FALSE; + } + param->type = IMMEDIATE_VALUE; + return addvalue(param, value); + } + } + return FALSE; +} + +static BOOL isDirection(char c){ + return (c == 'X' || c == 'Y'); +} + +static BOOL getDirection(char **s, char *direction){ + skipSpace(s); + if (**s == ','){ + (*s)++; + skipSpace(s); + if (isDirection(**s)){ + *direction = **s; + (*s)++; + return TRUE; + } + } + return FALSE; +} + +static BOOL indirect(char **s, Param *param){ + Bit32 value; + char c; + if (**s == '(') + (*s)++; + else + return FALSE; + + if (! parseHex(s,&value)) + return FALSE; + if (value > 0xFF) { + parseError("Indirect value is too large."); + return FALSE; + } + if (!addvalue(param, value)) + return FALSE; + skipSpace(s); + if (**s == ')'){ + (*s)++; + if (getDirection(s,&c)) { + if (c == 'Y'){ + param->type = INDIRECT_Y; + return TRUE; + } + } + } + else if (getDirection(s, &c)){ + if (c == 'X'){ + skipSpace(s); + if (**s == ')'){ + (*s)++; + param->type = INDIRECT_X; + return TRUE; + } + } + } + return FALSE; +} + +static BOOL dcbValue(char **s, Param *param){ + Bit32 val; + if (! parseValue(s,&val)) + return FALSE; + + if (val > 0xFF) + return FALSE; + + if (!addvalue(param,val)) + return FALSE; + + param->type = DCB_PARAM; + + skipSpace(s); + if(**s == ','){ + (*s)++; + return dcbValue(s, param); + } + else + return TRUE; +} + +static BOOL value(char **s, Param *param){ + Bit32 val; + BOOL abs; + BOOL dir; + char c = '\0'; + if (! parseValue(s,&val)) + return FALSE; + + abs = (val > 0xFF); + dir = getDirection(s,&c); + if (!addvalue(param,val)) + return FALSE; + + if(abs && dir){ + if (c == 'X') + param->type = ABS_X; + else if (c == 'Y') + param->type = ABS_Y; + else + return FALSE; + } + else if (abs) + param->type = ABS_VALUE; + else if (dir){ + if (c == 'X') + param->type = ZERO_X; + else if (c == 'Y') + param->type = ZERO_Y; + else + return FALSE; + } + else + param->type = ZERO; + + return TRUE; +} + +static BOOL label(char **s, Param *param){ + char *label = ecalloc(MAX_LABEL_LEN, sizeof(char)); + char c; + BOOL labelOk = FALSE; + if (paramLabel(s, &label)){ + labelOk = TRUE; + param->type = ABS_OR_BRANCH; + if (getDirection(s, &c)){ + if (c == 'X') + param->type = ABS_LABEL_X; + else if (c == 'Y') + param->type = ABS_LABEL_Y; + else + labelOk = FALSE; + } + strncpy(param->label,label,MAX_LABEL_LEN); + } + free(label); + return labelOk; +} + +static BOOL parameter(const char *cmd, char **s, Param *param){ + skipSpace(s); + if (**s == '\0' || **s == '\n') + return TRUE; + else if (**s == '#') + return immediate(s,param); + else if (**s == '(') + return indirect(s,param); + else if (**s == '$' || isdigit(**s)){ + if (strcmp(cmd, "DCB") == 0) + return dcbValue(s,param); + else + return value(s,param); + } + else if (isalpha(**s)) + return label(s ,param); + else + return FALSE; /* Invalid Parameter */ +} + +static void comment(char **s){ + skipSpace(s); + if (**s == ';') + for(;**s != '\n' && **s != '\0'; (*s)++) + ; +} + +static void initParam(Param *param){ + int i; + param->type = SINGLE; + for(i = 0; i < MAX_PARAM_VALUE; i++) + param->value[i] = 0; + param->vp = 0; + nullify(param->label,MAX_LABEL_LEN); +} + + +static AsmLine *parseAssembly(machine_6502 *machine, BOOL *codeOk, const char *code){ + char *s; + char *cmd = ecalloc(MAX_CMD_LEN, sizeof(char)); + char *label = ecalloc(MAX_LABEL_LEN, sizeof(char)); + char *start; /*pointer to the start of the code.*/ + unsigned int lc = 1; + Param *param; + BOOL decl; + AsmLine *listp = NULL; + + *codeOk = TRUE; + param = newParam(); + s = estrdup(code); + start = s; + stoupper(&s); + + while(*s != '\0' && *codeOk){ + initParam(param); + nullify(cmd, MAX_CMD_LEN); + nullify(label, MAX_LABEL_LEN); + decl = FALSE; + skipSpace(&s); + comment(&s); + if (*s == '\n'){ + lc++; + s++; + continue; /* blank line */ + } + else if (*s == '\0') + continue; /* no newline at the end of the code */ + else if (hasChar(s,':')){ + decl = TRUE; + if(! declareLabel(&s,&label)){ + *codeOk = FALSE; + break; + } + skipSpace(&s); + } + if(!command(machine, &s, &cmd)){ + *codeOk = FALSE; + break; + } + skipSpace(&s); + comment(&s); + if(!parameter(cmd, &s, param)){ + *codeOk = FALSE; + break; + } + skipSpace(&s); + comment(&s); + if (*s == '\n' || *s == '\0'){ + AsmLine *asmm; + asmm = newAsmLine(cmd,label,decl,param,lc); + listp = addend(listp,asmm); + } + else { + *codeOk = FALSE; + break; + } + } + if (! *codeOk) + fprintf(stderr,"Syntax error at line %u\n", lc); + free(start); + free(cmd); + free(label); + freeParam(param); + return listp; +} + +#ifdef READ_FILES +/* fileToBuffer() - Allocates a buffer and loads all of the file into memory. */ +static char *fileToBuffer(const char *filename){ + const int defaultSize = 1024; + FILE *ifp; + int c; + int size = defaultSize; + int i = 0; + char *buffer = ecalloc(defaultSize,sizeof(char)); + + if (!buffer) abort(); + + ifp = fopen(filename, "rb"); + if (!ifp) abort(); + + while((c = getc(ifp)) != EOF){ + buffer[i++] = c; + if (i == size){ + size += defaultSize; + buffer = realloc(buffer, size); + if (buffer == NULL) { + abort(); + } + } + } + fclose(ifp); + buffer = realloc(buffer, i+2); + if (!buffer) abort(); + /* Make sure we have a line feed at the end */ + buffer[i] = '\n'; + buffer[i+1] = '\0'; + return buffer; +} +#endif + + +/* Routines */ + +/* reset() - Reset CPU and memory. */ +static void reset(machine_6502 *machine){ + int x, y; + for ( y = 0; y < 32; y++ ){ + for (x = 0; x < 32; x++){ + machine->screen[x][y] = 0; + } + } + + for(x=0; x < MEM_64K; x++) + machine->memory[x] = 0; + + machine->codeCompiledOK = FALSE; + machine->regA = 0; + machine->regX = 0; + machine->regY = 0; + machine->regP = setBit(machine->regP, FUTURE_FL, 1); + machine->defaultCodePC = machine->regPC = PROG_START; + machine->regSP = STACK_TOP; + machine->runForever = FALSE; + machine->labelPtr = 0; + machine->codeRunning = FALSE; +} + +/* hexDump() - Dump the memory to output */ +void m6502_hexDump(machine_6502 *machine, Bit16 start, Bit16 numbytes, FILE *output){ + Bit32 address; + Bit32 i; + for( i = 0; i < numbytes; i++){ + address = start + i; + if ( (i&15) == 0 ) { + fprintf(output,"\n%.4x: ", address); + } + fprintf(output,"%.2x%s",machine->memory[address], (i & 1) ? " ":""); + } + fprintf(output,"%s\n",(i&1)?"--":""); +} + +/* XXX */ +/* void save_program(machine_6502 *machine, char *filename){ */ +/* FILE *ofp; */ +/* Bit16 pc = PROG_START; */ +/* Bit16 end = pc + machine->codeLen; */ +/* Bit16 n; */ +/* ofp = fopen(filename, "w"); */ +/* if (!ofp) abort(); */ + +/* fprintf(ofp,"Bit8 prog[%d] =\n{",machine->codeLen); */ +/* n = 1; */ +/* while(pc < end) */ +/* fprintf(ofp,"0x%.2x,%s",machine->memory[pc++],n++%10?" ":"\n"); */ +/* fseek(ofp,-2,SEEK_CUR); */ +/* fprintf(ofp,"};\n"); */ + +/* fclose(ofp); */ +/* } */ + +static BOOL translate(m6502_Opcodes *op,Param *param, machine_6502 *machine){ + switch(param->type){ + case SINGLE: + if (op->SNGL) + pushByte(machine, op->SNGL); + else { + fprintf(stderr,"%s needs a parameter.\n",op->name); + return FALSE; + } + break; + case IMMEDIATE_VALUE: + if (op->Imm) { + pushByte(machine, op->Imm); + pushByte(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take IMMEDIATE_VALUE parameters.\n",op->name); + return FALSE; + } + case IMMEDIATE_GREAT: + if (op->Imm) { + pushByte(machine, op->Imm); + pushByte(machine, param->lbladdr >> 8); + break; + } + else { + fprintf(stderr,"%s does not take IMMEDIATE_GREAT parameters.\n",op->name); + return FALSE; + } + case IMMEDIATE_LESS: + if (op->Imm) { + pushByte(machine, op->Imm); + pushByte(machine, param->lbladdr & 0xFF); + break; + } + else { + fprintf(stderr,"%s does not take IMMEDIATE_LESS parameters.\n",op->name); + return FALSE; + } + case INDIRECT_X: + if (op->INDX) { + pushByte(machine, op->INDX); + pushByte(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take INDIRECT_X parameters.\n",op->name); + return FALSE; + } + case INDIRECT_Y: + if (op->INDY) { + pushByte(machine, op->INDY); + pushByte(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take INDIRECT_Y parameters.\n",op->name); + return FALSE; + } + case ZERO: + if (op->ZP) { + pushByte(machine, op->ZP); + pushByte(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take ZERO parameters.\n",op->name); + return FALSE; + } + case ZERO_X: + if (op->ZPX) { + pushByte(machine, op->ZPX); + pushByte(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take ZERO_X parameters.\n",op->name); + return FALSE; + } + case ZERO_Y: + if (op->ZPY) { + pushByte(machine, op->ZPY); + pushByte(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take ZERO_Y parameters.\n",op->name); + return FALSE; + } + case ABS_VALUE: + if (op->ABS) { + pushByte(machine, op->ABS); + pushWord(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take ABS_VALUE parameters.\n",op->name); + return FALSE; + } + case ABS_OR_BRANCH: + if (op->ABS > 0){ + pushByte(machine, op->ABS); + pushWord(machine, param->lbladdr); + } + else { + if (op->BRA) { + pushByte(machine, op->BRA); + { + int diff = abs((int)param->lbladdr - (int)machine->defaultCodePC); + int backward = (param->lbladdr < machine->defaultCodePC); + pushByte(machine, (backward) ? 0xff - diff : diff - 1); + } + } + else { + fprintf(stderr,"%s does not take BRANCH parameters.\n",op->name); + return FALSE; + } + } + break; + case ABS_X: + if (op->ABSX) { + pushByte(machine, op->ABSX); + pushWord(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take ABS_X parameters.\n",op->name); + return FALSE; + } + case ABS_Y: + if (op->ABSY) { + pushByte(machine, op->ABSY); + pushWord(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take ABS_Y parameters.\n",op->name); + return FALSE; + } + case ABS_LABEL_X: + if (op->ABSX) { + pushByte(machine, op->ABSX); + pushWord(machine, param->lbladdr); + break; + } + else { + fprintf(stderr,"%s does not take ABS_LABEL_X parameters.\n",op->name); + return FALSE; + } + case ABS_LABEL_Y: + if (op->ABSY) { + pushByte(machine, op->ABSY); + pushWord(machine, param->lbladdr); + break; + } + else { + fprintf(stderr,"%s does not take ABS_LABEL_Y parameters.\n",op->name); + return FALSE; + } + case DCB_PARAM: + /* Handled elsewhere */ + break; + } + return TRUE; +} + +/* compileLine() - Compile one line of code. Returns + TRUE if it compile successfully. */ +static BOOL compileLine(AsmLine *asmline, void *args){ + machine_6502 *machine; + machine = args; + if (isBlank(asmline->command)) return TRUE; + if (strcmp("*=",asmline->command) == 0){ + machine->defaultCodePC = asmline->param->value[0]; + } + else if (strcmp("DCB",asmline->command) == 0){ + int i; + for(i = 0; i < asmline->param->vp; i++) + pushByte(machine, asmline->param->value[i]); + } + else{ + int i; + char *command = asmline->command; + m6502_Opcodes op; + for(i = 0; i < NUM_OPCODES; i++){ + if (strcmp(machine->opcodes[i].name, command) == 0){ + op = machine->opcodes[i]; + break; + } + } + if (i == NUM_OPCODES) + return FALSE; /* unknow upcode */ + else + return translate(&op,asmline->param,machine); + } + return TRUE; +} + +/* indexLabels() - Get the address for each label */ +static BOOL indexLabels(AsmLine *asmline, void *arg){ + machine_6502 *machine; + int thisPC; + Bit16 oldDefault; + machine = arg; + oldDefault = machine->defaultCodePC; + thisPC = machine->regPC; + /* Figure out how many bytes this instruction takes */ + machine->codeLen = 0; + + if ( ! compileLine(asmline, machine) ){ + return FALSE; + } + + /* If the machine's defaultCodePC has changed then we encountered a + *= which changes the load address. We need to initials our code + *counter with the current default. */ + if (oldDefault == machine->defaultCodePC){ + machine->regPC += machine->codeLen; + } + else { + machine->regPC = machine->defaultCodePC; + /*oldDefault = machine->defaultCodePC;*/ + } + + if (asmline->labelDecl) { + asmline->label->addr = thisPC; + } + return TRUE; +} + +static BOOL changeParamLabelAddr(AsmLine *asmline, void *label){ + Label *la = label; + if (strcmp(asmline->param->label, la->label) == 0) + asmline->param->lbladdr = la->addr; + return TRUE; +} + +static BOOL linkit(AsmLine *asmline, void *asmlist){ + apply(asmlist,changeParamLabelAddr,asmline->label); + return TRUE; +} + +/* linkLabels - Make sure all of the references to the labels contain + the right address*/ +static void linkLabels(AsmLine *asmlist){ + apply(asmlist,linkit,asmlist); +} + +/* compileCode() - Compile the current assembly code for the machine */ +static BOOL compileCode(machine_6502 *machine, const char *code){ + BOOL codeOk; + AsmLine *asmlist; + + reset(machine); + machine->defaultCodePC = machine->regPC = PROG_START; + asmlist = parseAssembly(machine, &codeOk, code); + + if(codeOk){ + /* First pass: Find the addresses for the labels */ + if (!apply(asmlist, indexLabels, machine)) + return FALSE; + /* update label references */ + linkLabels(asmlist); + +#if 0 /* prints out some debugging information */ + { + AsmLine *p; + if(asmlist != NULL){ + for (p = asmlist; p != NULL; p = p->next) + fprintf(stderr,"%s lbl: %s addr: %x ParamLbl: %s ParamAddr: %x\n", + p->command, p->label->label, p->label->addr, + p->param->label, p->param->lbladdr); + } + } + +#endif + + /* Second pass: translate the instructions */ + machine->codeLen = 0; + /* Link label call push_byte which increments defaultCodePC. + We need to reset it so the compiled code goes in the + correct spot. */ + machine->defaultCodePC = PROG_START; + if (!apply(asmlist, compileLine, machine)) + return FALSE; + + if (machine->defaultCodePC > PROG_START ){ + machine->memory[machine->defaultCodePC] = 0x00; + codeOk = TRUE; + } + else{ + fprintf(stderr,"No Code to run.\n"); + codeOk = FALSE; + } + } + else{ + fprintf(stderr,"An error occured while parsing the file.\n"); + codeOk = FALSE; + } + freeallAsmLine(asmlist); + return codeOk; +} + + +/* + * execute() - Executes one instruction. + * This is the main part of the CPU emulator. + * + */ + +static void execute(machine_6502 *machine){ + Bit8 opcode; + m6502_AddrMode adm; + int opidx; + + if(!machine->codeRunning) return; + + opcode = popByte(machine); + if (opcode == 0x00) + machine->codeRunning = FALSE; + else { + opidx = opIndex(machine,opcode,&adm); + if(opidx > -1) + machine->opcodes[opidx].func(machine, adm); + else + fprintf(stderr,"Invalid opcode!\n"); + } + if( (machine->regPC == 0) || + (!machine->codeRunning) ) { + machine->codeRunning = FALSE; + } +} + +machine_6502 *m6502_build(void){ + machine_6502 *machine; + machine = ecalloc(1, sizeof(machine_6502)); + assignOpCodes(machine->opcodes); + buildIndexCache(machine); + reset(machine); + return machine; +} + +void m6502_destroy6502(machine_6502 *machine){ + free(machine); + machine = NULL; +} + +void m6502_trace(machine_6502 *machine, FILE *output){ + Bit8 opcode = memReadByte(machine,machine->regPC); + m6502_AddrMode adm; + Pointer ptr; + int opidx = opIndex(machine,opcode,&adm); + int stacksz = STACK_TOP - machine->regSP; + + fprintf(output,"\n NVFBDIZC\nP: %d%d%d%d%d%d%d%d ", + bitOn(machine->regP,NEGATIVE_FL), + bitOn(machine->regP,OVERFLOW_FL), + bitOn(machine->regP,FUTURE_FL), + bitOn(machine->regP,BREAK_FL), + bitOn(machine->regP,DECIMAL_FL), + bitOn(machine->regP,INTERRUPT_FL), + bitOn(machine->regP,ZERO_FL), + bitOn(machine->regP,CARRY_FL)); + fprintf(output,"A: %.2x X: %.2x Y: %.2x SP: %.4x PC: %.4x\n", + machine->regA, machine->regX, machine->regY, machine->regSP, machine->regPC); + if (opidx > -1){ + Bit16 pc = machine->regPC; + fprintf(output,"\n%.4x:\t%s",machine->regPC, machine->opcodes[opidx].name); + if (peekValue(machine, adm, &ptr, pc+1)) + fprintf(output,"\tAddress:%.4x\tValue:%.4x\n", + ptr.addr,ptr.value); + else + fprintf(output,"\n"); + } + fprintf(output,"STACK:"); + m6502_hexDump(machine,(STACK_TOP - stacksz) + 1, stacksz, output); +} + +#if 0 +void disassemble(machine_6502 *machine, FILE *output){ + /* Read the opcode + increment the program counter + print the opcode + loop until end of program. */ + m6502_AddrMode adm; + Bit16 addr; + Bit8 opcode; + int opidx; + char *mem; + int i; + Bit16 opc = machine->regPC; + mem = calloc(20,sizeof(char)); + machine->regPC = PROG_START; + do{ + addr = machine->regPC; + opcode = popByte(machine); + opidx = opIndex(machine,opcode,&adm); + for (i = 0; i < 20; i++) mem[i] = '\0'; + dismem(machine, adm, mem); + fprintf(output,"%x\t%s\t%s\n", + addr,machine->opcodes[opidx].name,mem); + }while((machine->regPC - PROG_START) < machine->codeLen); /*XXX - may need to change since defaultCodePC */ + free(mem); + machine->regPC = opc; +} +#endif + + +#ifdef READ_FILES +void m6502_eval_file(machine_6502 *machine, const char *filename, m6502_Plotter plot, void *plotterState){ + char *code = NULL; + + machine->plot = plot; + machine->plotterState = plotterState; + + code = fileToBuffer(filename); + + if (! compileCode(machine, code) ) abort(); + + free(code); + + machine->defaultCodePC = machine->regPC = PROG_START; + machine->codeRunning = TRUE; + do{ + sleep(0); /* XXX */ +#if 0 + m6502_trace(machine, stdout); +#endif + execute(machine); + }while(machine->codeRunning); +} + +void m6502_start_eval_file(machine_6502 *machine, const char *filename, m6502_Plotter plot, void *plotterState){ + char *code = NULL; + reset(machine); + + machine->plot = plot; + machine->plotterState = plotterState; + + code = fileToBuffer(filename); + + if (! compileCode(machine, code) ) abort(); + + free(code); + + machine->defaultCodePC = machine->regPC = PROG_START; + machine->codeRunning = TRUE; + execute(machine); +} +#endif /* READ_FILES */ + +void m6502_start_eval_string(machine_6502 *machine, const char *code, + m6502_Plotter plot, void *plotterState){ + reset(machine); + + machine->plot = plot; + machine->plotterState = plotterState; + + if (! compileCode(machine, code) ){ + fprintf(stderr,"Could not compile code.\n"); + } + + machine->defaultCodePC = machine->regPC = PROG_START; + machine->codeRunning = TRUE; + execute(machine); +} + +/* void start_eval_binary(machine_6502 *machine, Bit8 *program, */ +/* unsigned int proglen, */ +/* Plotter plot, void *plotterState){ */ +/* unsigned int pc, n; */ +/* reset(machine); */ +/* machine->plot = plot; */ +/* machine->plotterState = plotterState; */ + +/* machine->regPC = PROG_START; */ +/* pc = machine->regPC; */ +/* machine->codeLen = proglen; */ +/* n = 0; */ +/* while (n < proglen){ */ +/* machine->memory[pc++] = program[n++]; */ +/* } */ +/* machine->codeRunning = TRUE; */ +/* execute(machine); */ +/* } */ + +void m6502_next_eval(machine_6502 *machine, int insno){ + int i = 0; + for (i = 1; i < insno; i++){ + if (machine->codeRunning){ +#if 0 + trace(machine, stdout); +#endif + execute(machine); + } + else + break; + } +} + diff --git a/hacks/asm6502.h b/hacks/asm6502.h new file mode 100644 index 0000000..79b13a2 --- /dev/null +++ b/hacks/asm6502.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2007 Jeremy English + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * Created: 07-May-2007 + */ + +/* + This is a port of the javascript 6502 assembler, compiler and + debugger. The orignal code was copyright 2006 by Stian Soreng - + www.6502asm.com + + The stack space is in page $100 to $1ff. The video buffer starts at + $200 and is 1024 bytes. Programs get loaded at address + $600. Address $fe is random and byte $ff is used for user input. + + User input is disabled. +*/ + +#ifndef __ASM6502_H__ +#define __ASM6502_H__ + +typedef uint8_t Bit8; +typedef uint16_t Bit16; +typedef uint32_t Bit32; + +#undef BOOL +#undef TRUE +#undef FALSE +#define BOOL Bit8 +#define TRUE 1 +#define FALSE 0 + +enum { + MAX_LABEL_LEN = 80, + NUM_OPCODES = 56, /* Number of unique instructions not counting DCB */ + MEM_64K = 65536, /* We have 64k of memory to work with. */ + MAX_PARAM_VALUE = 25, /* The number of values allowed behind dcb */ + MAX_CMD_LEN = 4, /* Each assembly command is 3 characeters long */ +/* The stack works from the top down in page $100 to $1ff */ + STACK_TOP = 0x1ff, + STACK_BOTTOM = 0x100, + PROG_START = 0x600 /* The default entry point for the program */ +}; + +typedef enum{ + SINGLE, IMMEDIATE_VALUE, IMMEDIATE_GREAT, + IMMEDIATE_LESS, INDIRECT_X, INDIRECT_Y, + ZERO, ZERO_X, ZERO_Y, + ABS_VALUE, ABS_OR_BRANCH, ABS_X, ABS_Y, + ABS_LABEL_X, ABS_LABEL_Y, DCB_PARAM +} m6502_AddrMode; + +typedef struct machine_6502 machine_6502; + +typedef struct { + char name[MAX_CMD_LEN]; + Bit8 Imm; + Bit8 ZP; + Bit8 ZPX; + Bit8 ZPY; + Bit8 ABS; + Bit8 ABSX; + Bit8 ABSY; + Bit8 INDX; + Bit8 INDY; + Bit8 SNGL; + Bit8 BRA; + void (*func) (machine_6502*, m6502_AddrMode); +} m6502_Opcodes; + +/* Used to cache the index of each opcode */ +typedef struct { + Bit8 index; + m6502_AddrMode adm; +} m6502_OpcodeIndex; + +/* Plotter is a function that will be called everytime a pixel + needs to be updated. The first two parameter are the x and y + values. The third parameter is the color index: + + Color Index Table + 00 black #000000 + 01 white #ffffff + 02 Red #880000 + 03 seafoam #aaffee + 04 fuscia #cc44cc + 05 green #00cc55 + 06 blue #0000aa + 07 Yellow #eeee77 + 08 tangerine #dd8855 + 09 brown #664400 + 10 salmon #ff7777 + 11 charcoal #333333 + 12 smoke #777777 + 13 lime #aaff66 + 14 light blue #0088ff + 15 gray #bbbbbb + + The plotter state variable of the machine gets passed as the forth + parameter. You can use this parameter to store state information. + +*/ +typedef void (*m6502_Plotter) (Bit8, Bit8, Bit8, void*); + +struct machine_6502 { + BOOL codeCompiledOK; + Bit8 regA; + Bit8 regX; + Bit8 regY; + Bit8 regP; + Bit16 regPC; /* A pair of 8 bit registers */ + Bit16 regSP; + Bit16 defaultCodePC; + Bit8 memory[MEM_64K]; + BOOL runForever; + int labelPtr; + BOOL codeRunning; + int myInterval; + m6502_Opcodes opcodes[NUM_OPCODES]; + int screen[32][32]; + int codeLen; + m6502_OpcodeIndex opcache[0xff]; + m6502_Plotter plot; + void *plotterState; +}; + +/* build6502() - Creates an instance of the 6502 machine */ +machine_6502 *m6502_build(void); + +/* destroy6502() - compile the file and exectue it until the program + is finished */ +void m6502_destroy6502(machine_6502 *machine); + +/* eval_file() - Compiles and runs a file until the program is + finished */ +void m6502_eval_file(machine_6502 *machine, const char *filename, + m6502_Plotter plot, void *plotterState); + +/* start_eval_file() - Compile the file and execute the first + instruction */ +void m6502_start_eval_file(machine_6502 *machine, const char *filename, + m6502_Plotter plot, void *plotterState); + +/* XXX +void m6502_start_eval_binary(machine_6502 *machine, Bit8 *program, + unsigned int proglen, + Plotter plot, void *plotterState); +*/ + +void m6502_start_eval_string(machine_6502 *machine, const char *code, + m6502_Plotter plot, void *plotterState); + +/* next_eval() - Execute the next insno of machine instructions */ +void m6502_next_eval(machine_6502 *machine, int insno); + +/* hexDump() - Dumps memory to output */ +void m6502_hexDump(machine_6502 *machine, Bit16 start, + Bit16 numbytes, FILE *output); + +/* Disassemble() - Prints the assembly code for the program currently + loaded in memory.*/ +void m6502_disassemble(machine_6502 *machine, FILE *output); + +/* trace() - Prints to output the current value of registers, the + current nmemonic, memory address and value. */ +void m6502_trace(machine_6502 *machine, FILE *output); + +/* save_program() - Writes a binary file of the program loaded in + memory. */ +/* XXX +void save_program(machine_6502 *machine, const char *filename); +*/ +#endif /* __ASM6502_H__ */ diff --git a/hacks/attraction.c b/hacks/attraction.c new file mode 100644 index 0000000..4fe22c2 --- /dev/null +++ b/hacks/attraction.c @@ -0,0 +1,1109 @@ +/* xscreensaver, Copyright (c) 1992-2013 Jamie Zawinski + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +/* Simulation of a pair of quasi-gravitational fields, maybe sorta kinda + a little like the strong and weak electromagnetic forces. Derived from + a Lispm screensaver by John Pezaris . Viscosity added by + Philip Edward Cutone, III . + + John sez: + + The simulation started out as a purely accurate gravitational + simulation, but, with constant simulation step size, I quickly + realized the field being simulated while grossly gravitational + was, in fact, non-conservative. It also had the rather annoying + behavior of dealing very badly with colliding orbs. Therefore, + I implemented a negative-gravity region (with two thresholds; as + I read your code, you only implemented one) to prevent orbs from + every coming too close together, and added a viscosity factor if + the speed of any orb got too fast. This provides a nice stable + system with interesting behavior. + + I had experimented with a number of fields including the van der + Waals force (very interesting orbiting behavior) and 1/r^3 + gravity (not as interesting as 1/r^2). An even normal viscosity + (rather than the thresholded version to bleed excess energy) is + also not interesting. The 1/r^2, -1/r^2, -10/r^2 thresholds + proved not only robust but also interesting -- the orbs never + collided and the threshold viscosity fixed the + non-conservational problem. + + Philip sez: + > An even normal viscosity (rather than the thresholded version to + > bleed excess energy) is also not interesting. + + unless you make about 200 points.... set the viscosity to about .8 + and drag the mouse through it. it makes a nice wave which travels + through the field. + + And (always the troublemaker) Joe Keane sez: + + Despite what John sez, the field being simulated is always + conservative. The real problem is that it uses a simple hack, + computing acceleration *based only on the starting position*, + instead of a real differential equation solver. Thus you'll + always have energy coming out of nowhere, although it's most + blatant when balls get close together. If it were done right, + you wouldn't need viscosity or artificial limits on how close + the balls can get. + + Matt sez: + + Added a switch to remove the walls. + + Added a switch to make the threshold viscosity optional. If + nomaxspeed is specified, then balls going really fast do not + recieve special treatment. + + I've made tail mode prettier by eliminating the first erase line + that drew from the upper left corner to the starting position of + each point. + + Made the balls in modes other than "balls" bounce exactly at the + walls. (Because the graphics for different modes are drawn + differently with respect to the "actual" position of the point, + they used to be able to run somewhat past the walls, or bounce + before hitting them.) + + Added an option to output each ball's speed in the form of a bar + graph drawn on the same window as the balls. If only x or y is + selected, they will be represented on the appropriate axis down + the center of the window. If both are selected, they will both + be displayed along the diagonal such that the x and y bars for + each point start at the same place. If speed is selected, the + speed will be displayed down the left side. */ + +#include +#include +#include "screenhack.h" +#include "spline.h" + +/* The normal (and max) width for a graph bar */ +#define BAR_SIZE 11 +#define MAX_SIZE 16 +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) + + +enum object_mode { + ball_mode, line_mode, polygon_mode, spline_mode, spline_filled_mode, + tail_mode +}; + +enum graph_mode { + graph_none, graph_x, graph_y, graph_both, graph_speed +}; + +struct ball { + double x, y; + double vx, vy; + double dx, dy; + double mass; + int size; + int pixel_index; + int hue; +}; + +struct state { + struct ball *balls; + double *x_vels; + double *y_vels; + double *speeds; + int npoints; + int threshold; + int delay; + int global_size; + int segments; + Bool glow_p; + Bool orbit_p; + Bool walls_p; + Bool maxspeed_p; + Bool cbounce_p; + XPoint *point_stack; + int point_stack_size, point_stack_fp; + XColor *colors; + int ncolors; + int fg_index; + int color_shift; + int xlim, ylim; + Bool no_erase_yet; /* for tail mode fix */ + double viscosity; + + int mouse_ball; /* index of ball being dragged, or 0 if none. */ + unsigned long mouse_pixel; + + enum object_mode mode; + enum graph_mode graph_mode; + + GC draw_gc, erase_gc; + + int total_ticks; + int color_tick; + spline *spl; +}; + + +static void * +attraction_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + int i; + XWindowAttributes xgwa; + XGCValues gcv; + int midx, midy, r, vx, vy; + double th; + Colormap cmap; + char *mode_str, *graph_mode_str; + double size_scale; + + XGetWindowAttributes (dpy, window, &xgwa); + st->xlim = xgwa.width; + st->ylim = xgwa.height; + cmap = xgwa.colormap; + midx = st->xlim/2; + midy = st->ylim/2; + st->walls_p = get_boolean_resource (dpy, "walls", "Boolean"); + + /* if there aren't walls, don't set a limit on the radius */ + r = get_integer_resource (dpy, "radius", "Integer"); + if (r <= 0 || (r > min (st->xlim/2, st->ylim/2) && st->walls_p) ) + r = min (st->xlim/2, st->ylim/2) - 50; + + vx = get_integer_resource (dpy, "vx", "Integer"); + vy = get_integer_resource (dpy, "vy", "Integer"); + + st->npoints = get_integer_resource (dpy, "points", "Integer"); + if (st->npoints < 1) + st->npoints = 3 + (random () % 5); + st->balls = (struct ball *) malloc (st->npoints * sizeof (struct ball)); + + st->no_erase_yet = 1; /* for tail mode fix */ + + st->segments = get_integer_resource (dpy, "segments", "Integer"); + if (st->segments < 0) st->segments = 1; + + st->threshold = get_integer_resource (dpy, "threshold", "Integer"); + if (st->threshold < 0) st->threshold = 0; + + st->delay = get_integer_resource (dpy, "delay", "Integer"); + if (st->delay < 0) st->delay = 0; + + st->global_size = get_integer_resource (dpy, "size", "Integer"); + if (st->global_size < 0) st->global_size = 0; + + st->glow_p = get_boolean_resource (dpy, "glow", "Boolean"); + + st->orbit_p = get_boolean_resource (dpy, "orbit", "Boolean"); + + st->maxspeed_p = get_boolean_resource (dpy, "maxspeed", "Boolean"); + + st->cbounce_p = get_boolean_resource (dpy, "cbounce", "Boolean"); + + st->color_shift = get_integer_resource (dpy, "colorShift", "Integer"); + if (st->color_shift <= 0) st->color_shift = 5; + + st->viscosity = get_float_resource (dpy, "viscosity", "Float"); + + mode_str = get_string_resource (dpy, "mode", "Mode"); + if (! mode_str) st->mode = ball_mode; + else if (!strcmp (mode_str, "balls")) st->mode = ball_mode; + else if (!strcmp (mode_str, "lines")) st->mode = line_mode; + else if (!strcmp (mode_str, "polygons")) st->mode = polygon_mode; + else if (!strcmp (mode_str, "tails")) st->mode = tail_mode; + else if (!strcmp (mode_str, "splines")) st->mode = spline_mode; + else if (!strcmp (mode_str, "filled-splines"))st->mode = spline_filled_mode; + else { + fprintf (stderr, + "%s: mode must be balls, lines, tails, polygons, splines, or\n\ + filled-splines, not \"%s\"\n", + progname, mode_str); + exit (1); + } + + graph_mode_str = get_string_resource (dpy, "graphmode", "Mode"); + if (! graph_mode_str) st->graph_mode = graph_none; + else if (!strcmp (graph_mode_str, "x")) st->graph_mode = graph_x; + else if (!strcmp (graph_mode_str, "y")) st->graph_mode = graph_y; + else if (!strcmp (graph_mode_str, "both")) st->graph_mode = graph_both; + else if (!strcmp (graph_mode_str, "speed")) st->graph_mode = graph_speed; + else if (!strcmp (graph_mode_str, "none")) st->graph_mode = graph_none; + else { + fprintf (stderr, + "%s: graphmode must be speed, x, y, both, or none, not \"%s\"\n", + progname, graph_mode_str); + exit (1); + } + + /* only allocate memory if it is needed */ + if(st->graph_mode != graph_none) + { + if(st->graph_mode == graph_x || st->graph_mode == graph_both) + st->x_vels = (double *) malloc (st->npoints * sizeof (double)); + if(st->graph_mode == graph_y || st->graph_mode == graph_both) + st->y_vels = (double *) malloc (st->npoints * sizeof (double)); + if(st->graph_mode == graph_speed) + st->speeds = (double *) malloc (st->npoints * sizeof (double)); + } + + if (st->mode != ball_mode && st->mode != tail_mode) st->glow_p = False; + + if (st->mode == polygon_mode && st->npoints < 3) + st->mode = line_mode; + + st->ncolors = get_integer_resource (dpy, "colors", "Colors"); + if (st->ncolors < 2) st->ncolors = 2; + if (st->ncolors <= 2) mono_p = True; + st->colors = 0; + + if (!mono_p) + { + st->fg_index = 0; + switch (st->mode) + { + case ball_mode: + if (st->glow_p) + { + int H = random() % 360; + double S1 = 0.25; + double S2 = 1.00; + double V = frand(0.25) + 0.75; + st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1)); + make_color_ramp (xgwa.screen, xgwa.visual, cmap, + H, S1, V, H, S2, V, st->colors, &st->ncolors, + False, True, False); + } + else + { + st->ncolors = st->npoints; + st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1)); + make_random_colormap (xgwa.screen, xgwa.visual, cmap, + st->colors, &st->ncolors, + True, True, False, True); + } + break; + case line_mode: + case polygon_mode: + case spline_mode: + case spline_filled_mode: + case tail_mode: + st->colors = (XColor *) malloc(sizeof(*st->colors) * (st->ncolors+1)); + make_smooth_colormap (xgwa.screen, xgwa.visual, cmap, + st->colors, &st->ncolors, + True, False, True); + break; + default: + abort (); + } + } + + if (!mono_p && st->ncolors <= 2) + { + if (st->colors) free (st->colors); + st->colors = 0; + mono_p = True; + } + + st->mouse_pixel = + get_pixel_resource (dpy, cmap, "mouseForeground", "MouseForeground"); + st->mouse_ball = -1; + + if (st->mode != ball_mode) + { + int size = (st->segments ? st->segments : 1); + st->point_stack_size = size * (st->npoints + 1); + st->point_stack = (XPoint *) calloc (st->point_stack_size, sizeof (XPoint)); + st->point_stack_fp = 0; + } + + gcv.line_width = (st->mode == tail_mode + ? (st->global_size ? st->global_size : (MAX_SIZE * 2 / 3)) + : 1); + gcv.cap_style = (st->mode == tail_mode ? CapRound : CapButt); + + if (mono_p) + gcv.foreground = get_pixel_resource(dpy, cmap, "foreground", "Foreground"); + else + gcv.foreground = st->colors[st->fg_index].pixel; + st->draw_gc = XCreateGC (dpy, window, GCForeground|GCLineWidth|GCCapStyle, &gcv); + + gcv.foreground = get_pixel_resource(dpy, cmap, "background", "Background"); + st->erase_gc = XCreateGC (dpy, window, GCForeground|GCLineWidth|GCCapStyle,&gcv); + + +#ifdef HAVE_JWXYZ + jwxyz_XSetAntiAliasing (dpy, st->draw_gc, False); + jwxyz_XSetAntiAliasing (dpy, st->erase_gc, False); +#endif + + size_scale = 3; + if (xgwa.width < 100 || xgwa.height < 100) /* tiny windows */ + size_scale = 0.75; + + /* let's make the balls bigger by default */ +#define rand_size() (size_scale * (8 + (random () % 7))) + + if (st->orbit_p && !st->global_size) + /* To orbit, all objects must be the same mass, or the math gets + really hairy... */ + st->global_size = rand_size (); + + RETRY_NO_ORBIT: + th = frand (M_PI+M_PI); + for (i = 0; i < st->npoints; i++) + { + int new_size = (st->global_size ? st->global_size : rand_size ()); + st->balls [i].dx = 0; + st->balls [i].dy = 0; + st->balls [i].size = new_size; + st->balls [i].mass = (new_size * new_size * 10); + st->balls [i].x = midx + r * cos (i * ((M_PI+M_PI) / st->npoints) + th); + st->balls [i].y = midy + r * sin (i * ((M_PI+M_PI) / st->npoints) + th); + if (! st->orbit_p) + { + st->balls [i].vx = vx ? vx : ((6.0 - (random () % 11)) / 8.0); + st->balls [i].vy = vy ? vy : ((6.0 - (random () % 11)) / 8.0); + } + if (mono_p || st->mode != ball_mode) + st->balls [i].pixel_index = -1; + else if (st->glow_p) + st->balls [i].pixel_index = 0; + else + st->balls [i].pixel_index = random() % st->ncolors; + } + + /* This lets modes where the points don't really have any size use the whole + window. Otherwise, since the points still have a positive size + assigned to them, they will be bounced somewhat early. Mass and size are + seperate, so this shouldn't cause problems. It's a bit kludgy, tho. + */ + if(st->mode == line_mode || st->mode == spline_mode || + st->mode == spline_filled_mode || st->mode == polygon_mode) + { + for(i = 1; i < st->npoints; i++) + { + st->balls[i].size = 0; + } + } + + if (st->orbit_p) + { + double a = 0; + double v; + double v_mult = get_float_resource (dpy, "vMult", "Float"); + if (v_mult == 0.0) v_mult = 1.0; + + for (i = 1; i < st->npoints; i++) + { + double _2ipi_n = (2 * i * M_PI / st->npoints); + double x = r * cos (_2ipi_n); + double y = r * sin (_2ipi_n); + double distx = r - x; + double dist2 = (distx * distx) + (y * y); + double dist = sqrt (dist2); + double a1 = ((st->balls[i].mass / dist2) * + ((dist < st->threshold) ? -1.0 : 1.0) * + (distx / dist)); + a += a1; + } + if (a < 0.0) + { + /* "domain error: forces on balls too great" */ + fprintf (stderr, "%s: window too small for these orbit settings.\n", + progname); + st->orbit_p = False; + goto RETRY_NO_ORBIT; + } + v = sqrt (a * r) * v_mult; + for (i = 0; i < st->npoints; i++) + { + double k = ((2 * i * M_PI / st->npoints) + th); + st->balls [i].vx = -v * sin (k); + st->balls [i].vy = v * cos (k); + } + } + + if (mono_p) st->glow_p = False; + + XClearWindow (dpy, window); + return st; +} + +static void +compute_force (struct state *st, int i, double *dx_ret, double *dy_ret) +{ + int j; + double x_dist, y_dist, dist, dist2; + *dx_ret = 0; + *dy_ret = 0; + for (j = 0; j < st->npoints; j++) + { + if (i == j) continue; + x_dist = st->balls [j].x - st->balls [i].x; + y_dist = st->balls [j].y - st->balls [i].y; + dist2 = (x_dist * x_dist) + (y_dist * y_dist); + dist = sqrt (dist2); + + if (dist > 0.1) /* the balls are not overlapping */ + { + double new_acc = ((st->balls[j].mass / dist2) * + ((dist < st->threshold) ? -1.0 : 1.0)); + double new_acc_dist = new_acc / dist; + *dx_ret += new_acc_dist * x_dist; + *dy_ret += new_acc_dist * y_dist; + } + else + { /* the balls are overlapping; move randomly */ + *dx_ret += (frand (10.0) - 5.0); + *dy_ret += (frand (10.0) - 5.0); + } + } +} + + +/* Draws meters along the diagonal for the x velocity */ +static void +draw_meter_x(Display *dpy, Window window, struct state *st, int i, int alone) +{ + XWindowAttributes xgwa; + int x1,x2,y,w1,w2,h; + XGetWindowAttributes (dpy, window, &xgwa); + + /* set the width of the bars to use */ + if(xgwa.height < BAR_SIZE*st->npoints) + { + y = i*(xgwa.height/st->npoints); + h = (xgwa.height/st->npoints) - 2; + } + else + { + y = BAR_SIZE*i; + h = BAR_SIZE - 2; + } + + if(alone) + { + x1 = xgwa.width/2; + x2 = x1; + } + else + { + x1 = i*(h+2); + if(x1 < i) + x1 = i; + x2 = x1; + } + + if(y<1) y=i; + if(h<1) h=1; + + w1 = (int)(20*st->x_vels[i]); + w2 = (int)(20*st->balls[i].vx); + st->x_vels[i] = st->balls[i].vx; + + if (w1<0) { + w1=-w1; + x1=x1-w1; + } + if (w2<0) { + w2=-w2; + x2=x2-w2; + } + XDrawRectangle(dpy,window,st->erase_gc,x1+(h+2)/2,y,w1,h); + XDrawRectangle(dpy,window,st->draw_gc,x2+(h+2)/2,y,w2,h); +} + +/* Draws meters along the diagonal for the y velocity. + Is there some way to make draw_meter_x and draw_meter_y + one function instead of two without making them completely unreadable? +*/ +static void +draw_meter_y (Display *dpy, Window window, struct state *st, int i, int alone) +{ + XWindowAttributes xgwa; + int y1,y2,x,h1,h2,w; + XGetWindowAttributes (dpy, window, &xgwa); + + if(xgwa.height < BAR_SIZE*st->npoints){ /*needs to be height still */ + x = i*(xgwa.height/st->npoints); + w = (xgwa.height/st->npoints) - 2; + } + else{ + x = BAR_SIZE*i; + w = BAR_SIZE - 2; + } + + if(alone) + { + y1 = xgwa.height/2; + y2 = y1; + } + else + { + y1 = i*(w+2); + if(y1 < i) + y1 = i; + y2 = y1; + } + + if(x < 1) x = i; + if(w < 1) w = 1; + + h1 = (int)(20*st->y_vels[i]); + h2 = (int)(20*st->balls[i].vy); + st->y_vels[i] = st->balls[i].vy; + + if (h1<0) { + h1=-h1; + y1=y1-h1; + } + if (h2<0) { + h2=-h2; + y2=y2-h2; + } + XDrawRectangle(dpy,window,st->erase_gc,x,y1+(w+2)/2,w,h1); + XDrawRectangle(dpy,window,st->draw_gc,x,y2+(w+2)/2,w,h2); +} + + +/* Draws meters of the total speed of the balls */ +static void +draw_meter_speed (Display *dpy, Window window, struct state *st, int i) +{ + XWindowAttributes xgwa; + int y,x1,x2,h,w1,w2; + XGetWindowAttributes (dpy, window, &xgwa); + + if(xgwa.height < BAR_SIZE*st->npoints) + { + y = i*(xgwa.height/st->npoints); + h = (xgwa.height/st->npoints) - 2; + } + else{ + y = BAR_SIZE*i; + h = BAR_SIZE - 2; + } + + x1 = 0; + x2 = x1; + + if(y < 1) y = i; + if(h < 1) h = 1; + + w1 = (int)(5*st->speeds[i]); + w2 = (int)(5*(st->balls[i].vy*st->balls[i].vy+st->balls[i].vx*st->balls[i].vx)); + st->speeds[i] = st->balls[i].vy*st->balls[i].vy+st->balls[i].vx*st->balls[i].vx; + + XDrawRectangle(dpy,window,st->erase_gc,x1,y,w1,h); + XDrawRectangle(dpy,window,st->draw_gc, x2,y,w2,h); +} + +/* Returns the position of the mouse relative to the root window. + */ +static void +query_mouse (Display *dpy, Window win, int *x, int *y) +{ + Window root1, child1; + int mouse_x, mouse_y, root_x, root_y; + unsigned int mask; + if (XQueryPointer (dpy, win, &root1, &child1, + &root_x, &root_y, &mouse_x, &mouse_y, &mask)) + { + *x = mouse_x; + *y = mouse_y; + } + else + { + *x = -9999; + *y = -9999; + } +} + +static unsigned long +attraction_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int last_point_stack_fp = st->point_stack_fp; + + int i, radius = st->global_size/2; + + st->total_ticks++; + + if(st->global_size == 0) + radius = (MAX_SIZE / 3); + + if(st->graph_mode != graph_none) + { + if(st->graph_mode == graph_both) + { + for(i = 0; i < st->npoints; i++) + { + draw_meter_x(dpy, window, st, i, 0); + draw_meter_y(dpy, window, st, i, 0); + } + } + else if(st->graph_mode == graph_x) + { + for(i = 0; i < st->npoints; i++) + { + draw_meter_x(dpy, window, st, i, 1); + } + } + else if(st->graph_mode == graph_y) + { + for(i = 0; i < st->npoints; i++) + { + draw_meter_y(dpy, window, st, i, 1); + } + } + else if(st->graph_mode == graph_speed) + { + for(i = 0; i < st->npoints; i++) + { + draw_meter_speed(dpy, window, st, i); + } + } + + } + + /* compute the force of attraction/repulsion among all balls */ + for (i = 0; i < st->npoints; i++) + compute_force (st, i, &st->balls[i].dx, &st->balls[i].dy); + + /* move the balls according to the forces now in effect */ + for (i = 0; i < st->npoints; i++) + { + double old_x = st->balls[i].x; + double old_y = st->balls[i].y; + double new_x, new_y; + int size = st->balls[i].size; + + st->balls[i].vx += st->balls[i].dx; + st->balls[i].vy += st->balls[i].dy; + + /* "don't let them get too fast: impose a terminal velocity + (actually, make the medium have friction)" + Well, what this first step really does is give the medium a + viscosity of .9 for balls going over the speed limit. Anyway, + this is now optional + */ + if (fabs(st->balls[i].vx) > 10 && st->maxspeed_p) + { + st->balls[i].vx *= 0.9; + st->balls[i].dx = 0; + } + if (st->viscosity != 1) + { + st->balls[i].vx *= st->viscosity; + } + + if (fabs(st->balls[i].vy) > 10 && st->maxspeed_p) + { + st->balls[i].vy *= 0.9; + st->balls[i].dy = 0; + } + if (st->viscosity != 1) + { + st->balls[i].vy *= st->viscosity; + } + + st->balls[i].x += st->balls[i].vx; + st->balls[i].y += st->balls[i].vy; + + + /* bounce off the walls if desired + note: a ball is actually its upper left corner */ + if(st->walls_p) + { + if(st->cbounce_p) /* with correct bouncing */ + { + /* so long as it's out of range, keep bouncing */ + /* limit the maximum number to bounce to 4.*/ + int bounce_allowed = 4; + + while( bounce_allowed && ( + (st->balls[i].x >= (st->xlim - st->balls[i].size)) || + (st->balls[i].y >= (st->ylim - st->balls[i].size)) || + (st->balls[i].x <= 0) || + (st->balls[i].y <= 0) ) + ) + { + bounce_allowed--; + if (st->balls[i].x >= (st->xlim - st->balls[i].size)) + { + st->balls[i].x = (2*(st->xlim - st->balls[i].size) - st->balls[i].x); + st->balls[i].vx = -st->balls[i].vx; + } + if (st->balls[i].y >= (st->ylim - st->balls[i].size)) + { + st->balls[i].y = (2*(st->ylim - st->balls[i].size) - st->balls[i].y); + st->balls[i].vy = -st->balls[i].vy; + } + if (st->balls[i].x <= 0) + { + st->balls[i].x = -st->balls[i].x; + st->balls[i].vx = -st->balls[i].vx; + } + if (st->balls[i].y <= 0) + { + st->balls[i].y = -st->balls[i].y; + st->balls[i].vy = -st->balls[i].vy; + } + } + } + else /* with old bouncing */ + { + if (st->balls[i].x >= (st->xlim - st->balls[i].size)) + { + st->balls[i].x = (st->xlim - st->balls[i].size - 1); + if (st->balls[i].vx > 0) /* why is this check here? */ + st->balls[i].vx = -st->balls[i].vx; + } + if (st->balls[i].y >= (st->ylim - st->balls[i].size)) + { + st->balls[i].y = (st->ylim - st->balls[i].size - 1); + if (st->balls[i].vy > 0) + st->balls[i].vy = -st->balls[i].vy; + } + if (st->balls[i].x <= 0) + { + st->balls[i].x = 0; + if (st->balls[i].vx < 0) + st->balls[i].vx = -st->balls[i].vx; + } + if (st->balls[i].y <= 0) + { + st->balls[i].y = 0; + if (st->balls[i].vy < 0) + st->balls[i].vy = -st->balls[i].vy; + } + } + } + + if (i == st->mouse_ball) + { + int x, y; + query_mouse (dpy, window, &x, &y); + if (st->mode == ball_mode) + { + x -= st->balls[i].size / 2; + y -= st->balls[i].size / 2; + } + + st->balls[i].x = x; + st->balls[i].y = y; + } + + new_x = st->balls[i].x; + new_y = st->balls[i].y; + + if (!mono_p) + { + if (st->mode == ball_mode) + { + if (st->glow_p) + { + /* make color saturation be related to particle + acceleration. */ + double limit = 0.5; + double s, fraction; + double vx = st->balls [i].dx; + double vy = st->balls [i].dy; + if (vx < 0) vx = -vx; + if (vy < 0) vy = -vy; + fraction = vx + vy; + if (fraction > limit) fraction = limit; + + s = 1 - (fraction / limit); + st->balls[i].pixel_index = (st->ncolors * s); + } + XSetForeground (dpy, st->draw_gc, + (i == st->mouse_ball + ? st->mouse_pixel + : st->colors[st->balls[i].pixel_index].pixel)); + } + } + + if (st->mode == ball_mode) + { + XFillArc (dpy, window, st->erase_gc, (int) old_x, (int) old_y, + size, size, 0, 360*64); + XFillArc (dpy, window, st->draw_gc, (int) new_x, (int) new_y, + size, size, 0, 360*64); + } + else + { + st->point_stack [st->point_stack_fp].x = new_x; + st->point_stack [st->point_stack_fp].y = new_y; + st->point_stack_fp++; + } + } + + /* draw the lines or polygons after computing all points */ + if (st->mode != ball_mode) + { + st->point_stack [st->point_stack_fp].x = st->balls [0].x; /* close the polygon */ + st->point_stack [st->point_stack_fp].y = st->balls [0].y; + st->point_stack_fp++; + if (st->point_stack_fp == st->point_stack_size) + st->point_stack_fp = 0; + else if (st->point_stack_fp > st->point_stack_size) /* better be aligned */ + abort (); + if (!mono_p) + { + if (st->color_tick++ == st->color_shift) + { + st->color_tick = 0; + st->fg_index = (st->fg_index + 1) % st->ncolors; + XSetForeground (dpy, st->draw_gc, st->colors[st->fg_index].pixel); + } + } + } + + switch (st->mode) + { + case ball_mode: + break; + case line_mode: + if (st->segments > 0) + XDrawLines (dpy, window, st->erase_gc, st->point_stack + st->point_stack_fp, + st->npoints + 1, CoordModeOrigin); + XDrawLines (dpy, window, st->draw_gc, st->point_stack + last_point_stack_fp, + st->npoints + 1, CoordModeOrigin); + break; + case polygon_mode: + if (st->segments > 0) + XFillPolygon (dpy, window, st->erase_gc, st->point_stack + st->point_stack_fp, + st->npoints + 1, (st->npoints == 3 ? Convex : Complex), + CoordModeOrigin); + XFillPolygon (dpy, window, st->draw_gc, st->point_stack + last_point_stack_fp, + st->npoints + 1, (st->npoints == 3 ? Convex : Complex), + CoordModeOrigin); + break; + case tail_mode: + { + for (i = 0; i < st->npoints; i++) + { + int index = st->point_stack_fp + i; + int next_index = (index + (st->npoints + 1)) % st->point_stack_size; + if(st->no_erase_yet == 1) + { + if(st->total_ticks >= st->segments) + { + st->no_erase_yet = 0; + XDrawLine (dpy, window, st->erase_gc, + st->point_stack [index].x + radius, + st->point_stack [index].y + radius, + st->point_stack [next_index].x + radius, + st->point_stack [next_index].y + radius); + } + } + else + { + XDrawLine (dpy, window, st->erase_gc, + st->point_stack [index].x + radius, + st->point_stack [index].y + radius, + st->point_stack [next_index].x + radius, + st->point_stack [next_index].y + radius); + } + index = last_point_stack_fp + i; + next_index = (index - (st->npoints + 1)) % st->point_stack_size; + if (next_index < 0) next_index += st->point_stack_size; + if (st->point_stack [next_index].x == 0 && + st->point_stack [next_index].y == 0) + continue; + XDrawLine (dpy, window, st->draw_gc, + st->point_stack [index].x + radius, + st->point_stack [index].y + radius, + st->point_stack [next_index].x + radius, + st->point_stack [next_index].y + radius); + } + } + break; + case spline_mode: + case spline_filled_mode: + { + if (! st->spl) st->spl = make_spline (st->npoints); + if (st->segments > 0) + { + for (i = 0; i < st->npoints; i++) + { + st->spl->control_x [i] = st->point_stack [st->point_stack_fp + i].x; + st->spl->control_y [i] = st->point_stack [st->point_stack_fp + i].y; + } + compute_closed_spline (st->spl); + if (st->mode == spline_filled_mode) + XFillPolygon (dpy, window, st->erase_gc, st->spl->points, st->spl->n_points, + (st->spl->n_points == 3 ? Convex : Complex), + CoordModeOrigin); + else + XDrawLines (dpy, window, st->erase_gc, st->spl->points, st->spl->n_points, + CoordModeOrigin); + } + for (i = 0; i < st->npoints; i++) + { + st->spl->control_x [i] = st->point_stack [last_point_stack_fp + i].x; + st->spl->control_y [i] = st->point_stack [last_point_stack_fp + i].y; + } + compute_closed_spline (st->spl); + if (st->mode == spline_filled_mode) + XFillPolygon (dpy, window, st->draw_gc, st->spl->points, st->spl->n_points, + (st->spl->n_points == 3 ? Convex : Complex), + CoordModeOrigin); + else + XDrawLines (dpy, window, st->draw_gc, st->spl->points, st->spl->n_points, + CoordModeOrigin); + } + break; + default: + abort (); + } + + return st->delay; +} + +static void +attraction_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->xlim = w; + st->ylim = h; +} + +static Bool +attraction_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + struct state *st = (struct state *) closure; + + if (event->xany.type == ButtonPress) + { + int i; + if (st->mouse_ball != -1) /* second down-click? drop the ball. */ + { + st->mouse_ball = -1; + return True; + } + else + { + /* When trying to pick up a ball, first look for a click directly + inside the ball; but if we don't find it, expand the radius + outward until we find something nearby. + */ + int x = event->xbutton.x; + int y = event->xbutton.y; + float max = 10 * (st->global_size ? st->global_size : MAX_SIZE); + float step = max / 100; + float r2; + for (r2 = step; r2 < max; r2 += step) + { + for (i = 0; i < st->npoints; i++) + { + float d = ((st->balls[i].x - x) * (st->balls[i].x - x) + + (st->balls[i].y - y) * (st->balls[i].y - y)); + float r = st->balls[i].size; + if (r2 > r) r = r2; + if (d < r*r) + { + st->mouse_ball = i; + return True; + } + } + } + } + return True; + } + else if (event->xany.type == ButtonRelease) /* drop the ball */ + { + st->mouse_ball = -1; + return True; + } + + + + return False; +} + +static void +attraction_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + if (st->balls) free (st->balls); + if (st->x_vels) free (st->x_vels); + if (st->y_vels) free (st->y_vels); + if (st->speeds) free (st->speeds); + if (st->point_stack) free (st->point_stack); + if (st->colors) free (st->colors); + if (st->spl) free_spline (st->spl); + + free (st); +} + + +static const char *attraction_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*mode: balls", + "*graphmode: none", + "*points: 0", + "*size: 0", + "*colors: 200", + "*threshold: 200", + "*delay: 10000", + "*glow: false", + "*walls: true", + "*maxspeed: true", + "*cbounce: true", + "*viscosity: 1.0", + "*orbit: false", + "*colorShift: 3", + "*segments: 500", + "*vMult: 0.9", + "*radius: 0", + "*vx: 0", + "*vy: 0", + "*mouseForeground: white", +#ifdef HAVE_MOBILE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec attraction_options [] = { + { "-mode", ".mode", XrmoptionSepArg, 0 }, + { "-graphmode", ".graphmode", XrmoptionSepArg, 0 }, + { "-colors", ".colors", XrmoptionSepArg, 0 }, + { "-points", ".points", XrmoptionSepArg, 0 }, + { "-color-shift", ".colorShift", XrmoptionSepArg, 0 }, + { "-threshold", ".threshold", XrmoptionSepArg, 0 }, + { "-segments", ".segments", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-size", ".size", XrmoptionSepArg, 0 }, + { "-radius", ".radius", XrmoptionSepArg, 0 }, + { "-vx", ".vx", XrmoptionSepArg, 0 }, + { "-vy", ".vy", XrmoptionSepArg, 0 }, + { "-vmult", ".vMult", XrmoptionSepArg, 0 }, + { "-viscosity", ".viscosity", XrmoptionSepArg, 0 }, + { "-glow", ".glow", XrmoptionNoArg, "true" }, + { "-noglow", ".glow", XrmoptionNoArg, "false" }, + { "-orbit", ".orbit", XrmoptionNoArg, "true" }, + { "-nowalls", ".walls", XrmoptionNoArg, "false" }, + { "-walls", ".walls", XrmoptionNoArg, "true" }, + { "-nomaxspeed", ".maxspeed", XrmoptionNoArg, "false" }, + { "-maxspeed", ".maxspeed", XrmoptionNoArg, "true" }, + { "-correct-bounce", ".cbounce", XrmoptionNoArg, "false" }, + { "-fast-bounce", ".cbounce", XrmoptionNoArg, "true" }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("Attraction", attraction) diff --git a/hacks/attraction.man b/hacks/attraction.man new file mode 100644 index 0000000..6630355 --- /dev/null +++ b/hacks/attraction.man @@ -0,0 +1,214 @@ +.de EX \"Begin example +.ne 5 +.if n .sp 1 +.if t .sp .5 +.nf +.in +.5i +.. +.de EE +.fi +.in -.5i +.if n .sp 1 +.if t .sp .5 +.. +.TH XScreenSaver 1 "14-Jun-97" "X Version 11" +.SH NAME +attraction - interactions of opposing forces +.SH SYNOPSIS +.B attraction +[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] +[\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install] +[\-visual \fIvisual\fP] [\-points \fIint\fP] [\-threshold \fIint\fP] +[\-mode balls | lines | polygons | splines | filled-splines | tails ] +[\-size \fIint\fP] [\-segments \fIint\fP] [\-delay \fIusecs\fP] +[\-color-shift \fIint\fP] [\-radius \fIint\fP] +[\-vx \fIint\fP] [\-vy \fIint\fP] [\-glow] [\-noglow] +[\-orbit] [\-viscosity \fIfloat\fP] +[\-walls] [\-nowalls] [\-maxspeed] [\-nomaxspeed] +[\-correct-bounce] [\-fast-bounce] +[\-fps] +.SH DESCRIPTION +The \fIattraction\fP program has several visually different modes of +operation, all of which are based on the interactions of a set of control +points which attract each other up to a certain distance, and then begin +to repel each other. The attraction/repulsion is proportional to the +distance between any two particles. +.SH OPTIONS +.I attraction +accepts the following options: +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-mono +If on a color display, pretend we're on a monochrome display. +.TP 8 +.B \-install +Install a private colormap for the window. +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-points integer +How many control points should be used, or 0 to select the number randomly. +Default 0. Between 3 and 15 works best. +.TP 8 +.B \-threshold integer +The distance (in pixels) from each particle at which the attractive force +becomes repulsive. Default 100. +.TP 8 +.B \-mode "balls | lines | polygons | tails | splines | filled-splines" +In \fIballs\fP mode (the default) the control points are drawn as filled +circles. The larger the circle, the more massive the particle. + +In \fIlines\fP mode, the control points are connected by straight lines; +the effect is something like \fIqix\fP. + +In \fIpolygons\fP mode, the control points are connected by straight +lines, and filled in. This is most interesting in color. + +In \fIsplines\fP mode, a closed spline is interpolated from the control +points. + +In \fIfilled-splines\fP mode, the splines are filled in instead of being +outlines. This is most interesting in color. + +In \fItails\fP mode, the path which each particle follows is indicated +by a worm-like trail, whose length is controlled by the \fIsegments\fP +parameter. +.TP 8 +.B \-size integer +The size of the balls in pixels, or 0, meaning to select the sizes +randomly (the default.) If this is specified, then all balls will be +the same size. This option has an effect in all modes, since the ``size'' +of the balls controls their mass. +.TP 8 +.B \-segments integer +If in \fIlines\fP or \fIpolygons\fP mode, how many sets of line segments +or polygons should be drawn. Default 500. This has no effect in \fIballs\fP +mode. If \fIsegments\fP is 0, then no segments will ever be erased (this +is only useful in color.) +.TP 8 +.B \-delay microseconds +How much of a delay should be introduced between steps of the animation. +Default 10000, or about 0.01 seconds. +.TP 8 +.B \-color-shift int +If on a color display, the color of the line segments or polygons will +cycle through the color map. This specifies how many lines will be drawn +before a new color is chosen. (When a small number of colors are available, +increasing this value will yield smoother transitions.) Default 3. +This has no effect in \fIballs\fP mode. +.TP 8 +.B \-radius +The size in pixels of the circle on which the points are initially positioned. +The default is slightly smaller than the size of the window. +.TP 8 +.B \-glow +This is consulted only in \fIballs\fP mode. If this is specified, then +the saturation of the colors of the points will vary according to their +current acceleration. This has the effect that the balls flare brighter +when they are reacting to each other most strongly. + +In \fIglow\fP mode, all of the balls will be drawn the same (random) +color, modulo the saturation shifts. In non-glow mode, the balls will +each be drawn in a random color that doesn't change. +.TP 8 +.B \-noglow +Don't do ``glowing.'' This is the default. +.TP 8 +.B \-vx pixels +.TP 8 +.B \-vy pixels +Initial velocity of the balls. This has no effect in \fB\-orbit\fP mode. +.TP 8 +.B \-orbit +Make the initial force on each ball be tangential to the circle on which +they are initially placed, with the right velocity to hold them in orbit +about each other. After a while, roundoff errors will cause the orbit +to decay. +.TP 8 +.B \-vmult float +In orbit mode, the initial velocity of the balls is multiplied by this; +a number less than 1 will make the balls pull closer together, and a larger +number will make them move apart. The default is 0.9, meaning a slight +inward pull. +.TP 8 +.B \-viscosity float +This sets the viscosity of the hypothetical fluid through which the control +points move; the default is 1, meaning no resistance. Values higher than 1 +aren't interesting; lower values cause less motion. + +One interesting thing to try is +.EX +attraction -viscosity 0.8 -points 300 -size 10 -geometry =500x500 +.EE +Give it a few seconds to settle down into a stable clump, and then move +the drag the mouse through it to make "waves". +.TP 8 +.B \-nowalls +This will cause the balls to continue on past the edge of the +screen or window. They will still be kept track of and can come back. +.TP 8 +.B \-walls +This will cause the balls to bounce when they get +to the edge of the screen or window. This is the default behavior. +.TP 8 +.B \-maxspeed +Imposes a maximum speed (default). If a ball ends up going faster than +this, it will be treated as though there were .9 viscosity until it is +under the limit. This stops the balls from continually accelerating (which +they have a tendency to do), but also causes balls moving very fast to +tend to clump in the lower right corner. +.TP 8 +.B \-nomaxspeed +If this is specified, no maximum speed is set for the balls. +.TP 8 +.B \-fast-bounce +Uses the old, simple bouncing algorithm (default). This simply moves any +ball that is out of bounds back to a wall and reverses its velocity. +This works fine for most cases, but under some circumstances, the +simplification can lead to annoying effects. +.TP 8 +.B \-correct-bounce +Uses a more intelligent bouncing algorithm. This method actually reflects +the balls off the walls until they are within bounds. This can be slow +if balls are bouncing a whole lot, perhaps because of -nomaxspeed. +.TP 8 +.B \-graphmode none | x | y | both | speed +For "x", "y", and "both", displays the given velocities of each ball as a +bar graph in the same window as the balls. For "speed", displays the total +speed of each ball. Default is "none". +.BR +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1) +.SH COPYRIGHT +Copyright \(co 1992, 1993, 1997 by Jamie Zawinski. Permission to use, copy, +modify, distribute, and sell this software and its documentation for any +purpose is hereby granted without fee, provided that the above copyright +notice appear in all copies and that both that copyright notice and this +permission notice appear in supporting documentation. No representations are +made about the suitability of this software for any purpose. It is provided +"as is" without express or implied warranty. +.SH AUTHOR +Jamie Zawinski , 13-aug-92. + +Viscosity support by Philip Edward Cutone, III. + +Walls, speed limit options, new bouncing, graphs, and tail mode fix by +Matthew Strait. 31 March 2001 diff --git a/hacks/automata.h b/hacks/automata.h new file mode 100644 index 0000000..ad30d47 --- /dev/null +++ b/hacks/automata.h @@ -0,0 +1,64 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/*- + * automata.c - special stuff for automata modes + * + * Copyright (c) 1995 by David Bagley. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation. + * + * This file is provided AS IS with no warranties of any kind. The author + * shall have no liability with respect to the infringement of copyrights, + * trade secrets or any patents by this file or any part thereof. In no + * event will the author be liable for any lost revenue or profits or + * other special, indirect and consequential damages. + */ + +#define NUMSTIPPLES 11 +#define STIPPLESIZE 8 + +static XPoint hexagonUnit[6] = +{ + {0, 0}, + {1, 1}, + {0, 2}, + {-1, 1}, + {-1, -1}, + {0, -2} +}; + +static XPoint triangleUnit[2][3] = +{ + { + {0, 0}, + {1, -1}, + {0, 2} + }, + { + {0, 0}, + {-1, 1}, + {0, -2} + } +}; + + +#ifdef DO_STIPPLE +static unsigned char stipples[NUMSTIPPLES][STIPPLESIZE] = +{ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* white */ + {0x11, 0x22, 0x11, 0x22, 0x11, 0x22, 0x11, 0x22}, /* grey+white | stripe */ + {0x00, 0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x00}, /* spots */ + {0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11}, /* lt. / stripe */ + {0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}, /* | bars */ + {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa}, /* 50% grey */ + {0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00}, /* - bars */ + {0xee, 0xdd, 0xbb, 0x77, 0xee, 0xdd, 0xbb, 0x77}, /* dark \ stripe */ + {0xff, 0x99, 0x99, 0xff, 0xff, 0x99, 0x99, 0xff}, /* spots */ + {0xaa, 0xff, 0xff, 0x55, 0xaa, 0xff, 0xff, 0x55}, /* black+grey - stripe */ + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} /* black */ +}; +#endif /* DO_STIPPLE */ + diff --git a/hacks/barcode.c b/hacks/barcode.c new file mode 100644 index 0000000..31574bd --- /dev/null +++ b/hacks/barcode.c @@ -0,0 +1,1995 @@ +/* barcode, draw some barcodes + * by Dan Bornstein, danfuzz@milk.com + * Copyright (c) 2003 Dan Bornstein. All rights reserved. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * See the included man page for more details. + */ + +#include +#include +#include "screenhack.h" + +/* non-user-modifiable immutable definitions */ + +#define FLOAT double + +/* random float in the range (0..1) */ +#define RAND_FLOAT_01 \ + (((FLOAT) ((random() >> 8) & 0xffff)) / ((FLOAT) 0x10000)) + +#define BARCODE_WIDTH (164) +#define BARCODE_HEIGHT (69) +#define MAX_MAG (7) + + +/* simple bitmap structure */ + +typedef struct +{ + int width; + int height; + int widthBytes; + char *buf; +} +Bitmap; + + + +/* the model */ + +typedef struct +{ + int x; /* x coordinate of the left of the barcode */ + int y; /* y coordinate of the left of the barcode */ + int mag; /* magnfication factor */ + Bitmap *bitmap; /* the bitmap */ + char code[128]; /* the barcode string */ + unsigned long pixel; /* the color */ +} +Barcode; + +struct state { + Display *dpy; + Window window; + + /* parameters that are user configurable */ + + /* delay (usec) between iterations */ + int delay; + + /* width and height of the window */ + int windowWidth; + int windowHeight; + + Visual *visual; /* the visual to use */ + Colormap cmap; /* the colormap of the window */ + + GC theGC; /* GC for drawing */ + unsigned long fg_pixel, grid_pixel; + Bool button_down_p; + int grid_alloced_p; + char *strings[200]; + + Barcode *barcodes; /* array of barcodes */ + int barcode_count; /* how many barcodes are currently active */ + int barcode_max; /* the maximum number of active barcodes */ + + XImage *theImage; /* ginormo image for drawing */ + Bitmap *theBitmap; /* ginormo bitmap for drawing */ + + enum { BC_SCROLL, BC_GRID, BC_CLOCK12, BC_CLOCK24 } mode; + + int grid_w; + int grid_h; +}; + +/* a bunch of words */ +static const char *words[] = +{ + "abdomen", + "abeyance", + "abhorrence", + "abrasion", + "abstraction", + "acid", + "addiction", + "alertness", + "Algeria", + "anxiety", + "aorta", + "argyle socks", + "attrition", + "axis of evil", + "bamboo", + "bangle", + "bankruptcy", + "baptism", + "beer", + "bellicosity", + "bells", + "belly", + "bliss", + "bogosity", + "boobies", + "boobs", + "booty", + "bread", + "bubba", + "burrito", + "California", + "capybara", + "cardinality", + "caribou", + "carnage", + "children", + "chocolate", + "CLONE", + "cock", + "constriction", + "contrition", + "cop", + "corpse", + "cowboy", + "crabapple", + "craziness", + "cthulhu", + "Death", + "decepticon", + "deception", + "Decker", + "decoder", + "decoy", + "defenestration", + "democracy", + "dependency", + "despair", + "desperation", + "disease", + "disease", + "doberman", + "DOOM", + "dreams", + "dreams", + "drugs", + "easy", + "ebony", + "election", + "eloquence", + "emergency", + "eureka", + "excommunication", + "fat", + "fatherland", + "Faust", + "fear", + "fever", + "filth", + "flatulence", + "fluff", + "fnord", + "freedom", + "fruit", + "fruit", + "futility", + "gerbils", + "GOD", + "goggles", + "goobers", + "gorilla", + "halibut", + "handmaid", + "happiness", + "hate", + "helplessness", + "hemorrhoid", + "hermaphrodite", + "heroin", + "heroine", + "hope", + "hysteria", + "icepick", + "identity", + "ignorance", + "importance", + "individuality", + "inkling", + "insurrection", + "intoxicant", + "ire", + "irritant", + "jade", + "jaundice", + "Joyce", + "kidney stone", + "kitchenette", + "kiwi", + "lathe", + "lattice", + "lawyer", + "lemming", + "liquidation", + "lobbyist", + "love", + "lozenge", + "magazine", + "magnesium", + "malfunction", + "marmot", + "marshmallow", + "merit", + "merkin", + "mescaline", + "milk", + "mischief", + "mistrust", + "money", + "monkey", + "monkeybutter", + "nationalism", + "nature", + "neuron", + "noise", + "nomenclature", + "nutria", + "OBEY", + "ocelot", + "offspring", + "overseer", + "pain", + "pajamas", + "passenger", + "passion", + "Passover", + "peace", + "penance", + "persimmon", + "petticoat", + "pharmacist", + "PhD", + "pitchfork", + "plague", + "Poindexter", + "politician", + "pony", + "presidency", + "prison", + "prophecy", + "Prozac", + "punishment", + "punk rock", + "punk", + "pussy", + "quagmire", + "quarantine", + "quartz", + "rabies", + "radish", + "rage", + "readout", + "reality", + "rectum", + "reject", + "rejection", + "respect", + "revolution", + "roadrunner", + "rule", + "savor", + "scab", + "scalar", + "Scandinavia", + "schadenfreude", + "security", + "sediment", + "self worth", + "sickness", + "silicone", + "slack", + "slander", + "slavery", + "sledgehammer", + "smegma", + "smelly socks", + "sorrow", + "space program", + "stamen", + "standardization", + "stench", + "subculture", + "subversion", + "suffering", + "surrender", + "surveillance", + "synthesis", + "television", + "tenant", + "tendril", + "terror", + "terrorism", + "terrorist", + "the impossible", + "the unknown", + "toast", + "topography", + "truism", + "turgid", + "underbrush", + "underling", + "unguent", + "unusual", + "uplink", + "urge", + "valor", + "variance", + "vaudeville", + "vector", + "vegetarian", + "venom", + "verifiability", + "viagra", + "vibrator", + "victim", + "vignette", + "villainy", + "W.A.S.T.E.", + "wagon", + "waiver", + "warehouse", + "waste", + "waveform", + "whiffle ball", + "whorl", + "windmill", + "words", + "worm", + "worship", + "worship", + "Xanax", + "Xerxes", + "Xhosa", + "xylophone", + "yellow", + "yesterday", + "your nose", + "Zanzibar", + "zeal", + "zebra", + "zest", + "zinc" +}; + +#define WORD_COUNT (sizeof(words) / sizeof(char *)) + + + +/* ---------------------------------------------------------------------------- + * bitmap manipulation + */ + +/* construct a new bitmap */ +static Bitmap *makeBitmap (int width, int height) +{ + Bitmap *result = malloc (sizeof (Bitmap)); + result->width = width; + result->height = height; + result->widthBytes = (width + 7) / 8; + result->buf = calloc (1, height * result->widthBytes); + return result; +} + +/* clear a bitmap */ +static void bitmapClear (Bitmap *b) +{ + memset (b->buf, 0, b->widthBytes * b->height); +} + +#if 0 +/* free a bitmap */ +static void bitmapFree (Bitmap *b) +{ + free (b->buf); + free (b); +} +#endif + + +/* get the byte value at the given byte-offset coordinates in the given + * bitmap */ +static int bitmapGetByte (Bitmap *b, int xByte, int y) +{ + if ((xByte < 0) || + (xByte >= b->widthBytes) || + (y < 0) || + (y >= b->height)) + { + /* out-of-range get returns 0 */ + return 0; + } + + return b->buf[b->widthBytes * y + xByte]; +} + +/* get the bit value at the given coordinates in the given bitmap */ +static int bitmapGet (Bitmap *b, int x, int y) +{ + int xbyte = x >> 3; + int xbit = x & 0x7; + int byteValue = bitmapGetByte (b, xbyte, y); + + return (byteValue & (1 << xbit)) >> xbit; +} + +/* set the bit value at the given coordinates in the given bitmap */ +static void bitmapSet (Bitmap *b, int x, int y, int value) +{ + int xbyte = x >> 3; + int xbit = x & 0x7; + + if ((x < 0) || + (x >= b->width) || + (y < 0) || + (y >= b->height)) + { + /* ignore out-of-range set */ + return; + } + + if (value) + { + b->buf[b->widthBytes * y + xbyte] |= 1 << xbit; + } + else + { + b->buf[b->widthBytes * y + xbyte] &= ~(1 << xbit); + } +} + +/* copy the given rectangle to the given destination from the given source. */ +static void bitmapCopyRect (Bitmap *dest, int dx, int dy, + Bitmap *src, int sx, int sy, int width, int height) +{ + int x, y; + + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + bitmapSet (dest, x + dx, y + dy, bitmapGet (src, x + sx, y + sy)); + } + } +} + +/* draw a vertical line in the given bitmap */ +static void bitmapVlin (Bitmap *b, int x, int y1, int y2) +{ + while (y1 <= y2) + { + bitmapSet (b, x, y1, 1); + y1++; + } +} + +/* scale a bitmap into another bitmap */ +static void bitmapScale (Bitmap *dest, Bitmap *src, int mag) +{ + int x, y, x2, y2; + + for (y = 0; y < BARCODE_HEIGHT; y++) + { + for (x = 0; x < BARCODE_WIDTH; x++) + { + int v = bitmapGet (src, x, y); + for (x2 = 0; x2 < mag; x2++) + { + for (y2 = 0; y2 < mag; y2++) + { + bitmapSet (dest, x * mag + x2, y * mag + y2, v); + } + } + } + } +} + + +/* ---------------------------------------------------------------------------- + * character generation + */ + +static unsigned char font5x8Buf[] = +{ + 0x1e, 0x01, 0x06, 0x01, 0x1e, 0x00, 0x1e, 0x01, 0x06, 0x01, 0x1e, 0x00, + 0x1e, 0x01, 0x1e, 0x01, 0x1e, 0x00, 0x01, 0x00, 0x1f, 0x08, 0x04, 0x08, + 0x1f, 0x00, 0x11, 0x1f, 0x11, 0x00, 0x1f, 0x01, 0x01, 0x00, 0x1f, 0x04, + 0x0a, 0x11, 0x00, 0x01, 0x00, 0x0e, 0x11, 0x11, 0x00, 0x0e, 0x11, 0x11, + 0x0e, 0x00, 0x1f, 0x08, 0x04, 0x08, 0x1f, 0x00, 0x44, 0x41, 0x4e, 0x20, + 0x42, 0x4f, 0x52, 0x4e, 0x53, 0x54, 0x45, 0x49, 0x4e, 0x21, 0x21, 0x00, + 0x66, 0x6e, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00, 0x05, 0x05, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x0f, 0x05, 0x0f, 0x05, 0x05, 0x00, + 0x02, 0x0f, 0x01, 0x0f, 0x08, 0x0f, 0x04, 0x00, 0x0b, 0x0b, 0x08, 0x06, + 0x01, 0x0d, 0x0d, 0x00, 0x03, 0x05, 0x02, 0x05, 0x0d, 0x05, 0x0b, 0x00, + 0x04, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x04, 0x00, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x00, + 0x00, 0x09, 0x06, 0x0f, 0x06, 0x09, 0x00, 0x00, 0x00, 0x02, 0x02, 0x07, + 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x08, 0x08, 0x04, 0x06, 0x02, 0x01, 0x01, 0x00, + 0x0f, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0f, 0x00, 0x06, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x0f, 0x00, 0x0f, 0x09, 0x08, 0x0f, 0x01, 0x09, 0x0f, 0x00, + 0x0f, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x0f, 0x00, 0x09, 0x09, 0x09, 0x0f, + 0x08, 0x08, 0x08, 0x00, 0x0f, 0x09, 0x01, 0x0f, 0x08, 0x09, 0x0f, 0x00, + 0x03, 0x01, 0x01, 0x0f, 0x09, 0x09, 0x0f, 0x00, 0x0f, 0x09, 0x09, 0x0c, + 0x04, 0x04, 0x04, 0x00, 0x0f, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x0f, 0x00, + 0x0f, 0x09, 0x09, 0x0f, 0x08, 0x08, 0x08, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x04, 0x06, 0x00, + 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x00, 0x00, 0x00, 0x0f, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x04, 0x02, 0x01, 0x00, + 0x0f, 0x09, 0x08, 0x0e, 0x02, 0x00, 0x02, 0x00, 0x0f, 0x09, 0x0d, 0x0d, + 0x0d, 0x01, 0x0f, 0x00, 0x0f, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x09, 0x00, + 0x07, 0x09, 0x09, 0x07, 0x09, 0x09, 0x07, 0x00, 0x0f, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x0f, 0x00, 0x07, 0x09, 0x09, 0x09, 0x09, 0x09, 0x07, 0x00, + 0x0f, 0x01, 0x01, 0x0f, 0x01, 0x01, 0x0f, 0x00, 0x0f, 0x01, 0x01, 0x0f, + 0x01, 0x01, 0x01, 0x00, 0x0f, 0x01, 0x01, 0x0d, 0x09, 0x09, 0x0f, 0x00, + 0x09, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x09, 0x00, 0x07, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x07, 0x00, 0x0e, 0x04, 0x04, 0x04, 0x04, 0x05, 0x07, 0x00, + 0x09, 0x09, 0x09, 0x07, 0x09, 0x09, 0x09, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x0f, 0x00, 0x09, 0x0f, 0x0f, 0x0f, 0x09, 0x09, 0x09, 0x00, + 0x09, 0x0b, 0x0d, 0x09, 0x09, 0x09, 0x09, 0x00, 0x0f, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x0f, 0x00, 0x0f, 0x09, 0x09, 0x0f, 0x01, 0x01, 0x01, 0x00, + 0x0f, 0x09, 0x09, 0x09, 0x0b, 0x05, 0x0b, 0x00, 0x07, 0x09, 0x09, 0x07, + 0x09, 0x09, 0x09, 0x00, 0x0f, 0x01, 0x01, 0x0f, 0x08, 0x08, 0x0f, 0x00, + 0x0f, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x0f, 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x05, 0x02, 0x00, + 0x09, 0x09, 0x09, 0x09, 0x0f, 0x0f, 0x09, 0x00, 0x09, 0x09, 0x05, 0x06, + 0x0a, 0x09, 0x09, 0x00, 0x09, 0x09, 0x09, 0x0f, 0x08, 0x08, 0x0f, 0x00, + 0x0f, 0x08, 0x08, 0x06, 0x01, 0x01, 0x0f, 0x00, 0x0e, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x0e, 0x00, 0x01, 0x01, 0x02, 0x06, 0x04, 0x08, 0x08, 0x00, + 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x00, 0x02, 0x05, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, + 0x02, 0x02, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, + 0x0f, 0x09, 0x0f, 0x00, 0x01, 0x01, 0x0f, 0x09, 0x09, 0x09, 0x0f, 0x00, + 0x00, 0x00, 0x0f, 0x01, 0x01, 0x01, 0x0f, 0x00, 0x08, 0x08, 0x0f, 0x09, + 0x09, 0x09, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x09, 0x0f, 0x01, 0x0f, 0x00, + 0x0e, 0x02, 0x0f, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x09, + 0x09, 0x0f, 0x08, 0x0c, 0x01, 0x01, 0x0f, 0x09, 0x09, 0x09, 0x09, 0x00, + 0x02, 0x00, 0x03, 0x02, 0x02, 0x02, 0x07, 0x00, 0x04, 0x00, 0x04, 0x04, + 0x04, 0x04, 0x05, 0x07, 0x01, 0x01, 0x09, 0x05, 0x03, 0x05, 0x09, 0x00, + 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x00, 0x00, 0x09, 0x0f, + 0x0f, 0x09, 0x09, 0x00, 0x00, 0x00, 0x0f, 0x09, 0x09, 0x09, 0x09, 0x00, + 0x00, 0x00, 0x0f, 0x09, 0x09, 0x09, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x09, + 0x09, 0x0f, 0x01, 0x01, 0x00, 0x00, 0x0f, 0x09, 0x09, 0x0f, 0x08, 0x08, + 0x00, 0x00, 0x0f, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x01, + 0x0f, 0x08, 0x0f, 0x00, 0x00, 0x02, 0x0f, 0x02, 0x02, 0x02, 0x0e, 0x00, + 0x00, 0x00, 0x09, 0x09, 0x09, 0x09, 0x0f, 0x00, 0x00, 0x00, 0x09, 0x09, + 0x09, 0x05, 0x02, 0x00, 0x00, 0x00, 0x09, 0x09, 0x0f, 0x0f, 0x09, 0x00, + 0x00, 0x00, 0x09, 0x09, 0x06, 0x09, 0x09, 0x00, 0x00, 0x00, 0x09, 0x09, + 0x09, 0x0f, 0x08, 0x0c, 0x00, 0x00, 0x0f, 0x08, 0x06, 0x01, 0x0f, 0x00, + 0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08, 0x00, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x02, 0x04, 0x02, 0x02, 0x01, 0x00, + 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x00 +}; + +static Bitmap font5x8 = { 8, 1024, 1, (char *) font5x8Buf }; + +/* draw the given 5x8 character at the given coordinates */ +static void bitmapDrawChar5x8 (Bitmap *b, int x, int y, char c) +{ + bitmapCopyRect (b, x, y, &font5x8, 0, c * 8, 5, 8); +} + +/* draw a string of 5x8 characters at the given coordinates */ +static void bitmapDrawString5x8 (Bitmap *b, int x, int y, char *str) +{ + int origx = x; + + while (*str != '\0') + { + char c = *str; + if (c == '\n') + { + x = origx; + y += 8; + } + else + { + if (c < ' ') + { + c = ' '; + } + + bitmapDrawChar5x8 (b, x, y, c); + x += 5; + } + str++; + } +} + + + +/* ---------------------------------------------------------------------------- + * upc/ean symbologies + */ + +/* A quick lesson in UPC and EAN barcodes: + * + * Each digit consists of 2 bars and 2 spaces, taking a total width of 7 + * times the width of the thinnest possible bar or space. There are three + * different possible representations for each digit, used depending on + * what side of a two-sided barcode the digit is used on, and to encode + * checksum or other information in some cases. The three forms are + * related. Taking as the "base" form the pattern as seen on the right-hand + * side of a UPC-A barcode, the other forms are the inverse of the base + * (that is, bar becomes space and vice versa) and the mirror image of the + * base. Still confused? Here's a complete table, where 0 means space and 1 + * means bar: + * + * Left-A Left-B Right + * ------- ------- ------- + * 0 0001101 0100111 1110010 + * 1 0011001 0110011 1100110 + * 2 0010011 0011011 1101100 + * 3 0111101 0100001 1000010 + * 4 0100011 0011101 1011100 + * 5 0110001 0111001 1001110 + * 6 0101111 0000101 1010000 + * 7 0111011 0010001 1000100 + * 8 0110111 0001001 1001000 + * 9 0001011 0010111 1110100 + * + * A UPC-A barcode consists of 6 patterns from Left-A on the left-hand side, + * 6 patterns from Right on the right-hand side, a guard pattern of 01010 + * in the middle, and a guard pattern of 101 on each end. The 12th digit + * checksum is calculated as follows: Take the 1st, 3rd, ... 11th digits, + * sum them and multiplying by 3, and add that to the sum of the other digits. + * Subtract the final digit from 10, and that is the checksum digit. (If + * the last digit of the sum is 0, then the check digit is 0.) + * + * An EAN-13 barcode is just like a UPC-A barcode, except that the characters + * on the left-hand side have a pattern of Left-A and Left-B that encodes + * an extra first digit. Note that an EAN-13 barcode with the first digit + * of 0 is exactly the same as the UPC-A barcode of the rightmost 12 digits. + * The patterns to encode the first digit are as follows: + * + * Left-Hand + * Digit Position + * 1 2 3 4 5 6 + * - - - - - - + * 0 a a a a a a + * 1 a a b a b b + * 2 a a b b a b + * 3 a a b b b a + * 4 a b a a b b + * 5 a b b a a b + * 6 a b b b a a + * 7 a b a b a b + * 8 a b a b b a + * 9 a b b a b a + * + * The checksum for EAN-13 is just like UPC-A, except the 2nd, 4th, ... 12th + * digits are multiplied by 3 instead of the other way around. + * + * An EAN-8 barcode is just like a UPC-A barcode, except there are only 4 + * digits in each half. Unlike EAN-13, there's no nonsense about different + * left-hand side patterns, either. + * + * A UPC-E barcode contains 6 explicit characters between a guard of 101 + * on the left and 010101 on the right. The explicit characters are the + * middle six characters of the code. The first and last characters are + * encoded in the parity pattern of the six characters. There are two + * sets of parity patterns, one to use if the first digit of the number + * is 0, and another if it is 1. (UPC-E barcodes may only start with a 0 + * or 1.) The patterns are as follows: + * + * First digit 0 First digit 1 + * Explicit Digit Explicit Digit + * Position Position + * 1 2 3 4 5 6 1 2 3 4 5 6 + * - - - - - - - - - - - - + * 0 b b b a a a a a a b b b + * 1 b b a b a a a a b a b b + * 2 b b a a b a a a b b a b + * 3 b b a a a b a a b b b a + * 4 b a b b a a a b a a b b + * 5 b a a b b a a b b a a b + * 6 b a a a b b a b b b a a + * 7 b a b a b a a b a b a b + * 8 b a b a a b a b a b b a + * 9 b a a b a b a b b a b a + * + * (Note that the two sets are the complements of each other. Also note + * that the first digit 1 patterns are mostly the same as the EAN-13 + * first digit patterns.) The UPC-E check digit (the final digit encoded in + * the parity pattern) is the same as the UPC-A check digit for the + * expanded form of the UPC-E number. The expanstion is as follows, based + * on the last explicit digit (the second to last digit) in the encoded + * number: + * + * Corresponding + * UPC-E form UPC-A form + * ---------- ------------- + * XABCDE0Y XAB00000CDEY + * XABCDE1Y XAB10000CDEY + * XABCDE2Y XAB20000CDEY + * XABCDE3Y XABC00000DEY + * XABCDE4Y XABCD00000EY + * XABCDE5Y XABCDE00005Y + * XABCDE6Y XABCDE00006Y + * XABCDE7Y XABCDE00007Y + * XABCDE8Y XABCDE00008Y + * XABCDE9Y XABCDE00009Y + * + * All UPC/EAN barcodes may have an additional 2- or 5-digit supplemental + * code just to the right of the main barcode. The supplement starts about + * one digit-length (that is about 7 times the width of the thinnest bar) + * to the right of the main code, beginning with the guard pattern 1011. + * After that comes each digit, with a guard pattern of 01 between each, + * but not at the end. The digits are encoded using the left A and B + * characters to encode a parity pattern. + * + * For 2-digit supplements, the parity pattern is determined by the + * lower two bits of the numeric value of the code (e.g., 42 would use + * pattern 2): + * + * Lower 2 bits Parity Pattern + * ------------ -------------- + * 0 (bin 00) a a + * 1 (bin 01) a b + * 2 (bin 10) b a + * 3 (bin 11) b b + * + * For 5-digit supplements, the parity pattern is calculated in a similar + * manner to check digit calculation: The first, third, and fifth digits + * are summed and multiplied by 3; the second and fourth digits are summed + * and multiplied by nine; the parity digit is the sum of those two numbers, + * modulo 10. The parity pattern is then the last five patterns from the + * UPC-E final digit 0 table for the corresponding digit. + */ + +/* enum to indicate which pattern set to use */ +typedef enum +{ + UPC_LEFT_A, UPC_LEFT_B, UPC_RIGHT +} +UpcSet; + +/* the Left A patterns */ +static unsigned int upcLeftA[] = { + 0x0d, 0x19, 0x13, 0x3d, 0x23, 0x31, 0x2f, 0x3b, 0x37, 0x0b +}; + +/* the Left B patterns */ +static unsigned int upcLeftB[] = { + 0x27, 0x33, 0x1b, 0x21, 0x1d, 0x39, 0x05, 0x11, 0x09, 0x17 +}; + +/* the Right patterns */ +static unsigned int upcRight[] = { + 0x72, 0x66, 0x6c, 0x42, 0x5c, 0x4e, 0x50, 0x44, 0x48, 0x74 +}; + +/* the EAN-13 first-digit patterns */ +static unsigned int ean13FirstDigit[] = { + 0x00, 0x0b, 0x0d, 0x0e, 0x13, 0x19, 0x1c, 0x15, 0x16, 0x1a +}; + +/* the UPC-E last-digit patterns for first digit 0 (complement for + * digit 1); also used for 5-digit supplemental check patterns */ +static unsigned int upcELastDigit[] = { + 0x38, 0x34, 0x32, 0x31, 0x2c, 0x26, 0x23, 0x2a, 0x29, 0x25 +}; + +/* turn a character into an int representing its digit value; return + * 0 for things not in the range '0'-'9' */ +static int charToDigit (char c) +{ + if ((c >= '0') && (c <= '9')) + { + return c - '0'; + } + else + { + return 0; + } +} + +/* draw the given digit character at the given coordinates; a '0' is + * used in place of any non-digit character */ +static void drawDigitChar (struct state *st, Bitmap *b, int x, int y, char c) +{ + if (st->mode != BC_CLOCK24 && + st->mode != BC_CLOCK12) + if ((c < '0') || (c > '9')) + c = '0'; + + bitmapDrawChar5x8 (b, x, y, c); +} + +/* draw a upc/ean digit at the given coordinates */ +static void drawUpcEanDigit (Bitmap *upcBitmap, int x, int y1, int y2, char n, + UpcSet set) +{ + unsigned int bits; + int i; + + n = charToDigit (n); + switch (set) + { + case UPC_LEFT_A: + bits = upcLeftA[(int) n]; + break; + case UPC_LEFT_B: + bits = upcLeftB[(int) n]; + break; + default /* case UPC_RIGHT */: + bits = upcRight[(int) n]; + break; + } + + for (i = 6; i >=0; i--) + { + if (bits & (1 << i)) + { + bitmapVlin (upcBitmap, x, y1, y2); + } + x++; + } +} + +/* report the width of the given supplemental code or 0 if it is a bad + * supplement form */ +static int upcEanSupplementWidth (char *digits) +{ + switch (strlen (digits)) + { + case 2: return 28; /* 8 + 4 + 2*7 + 1*2 */ + case 5: return 55; /* 8 + 4 + 5*7 + 4*2 */ + default: return 0; + } +} + +/* draw the given supplemental barcode, including the textual digits */ +static void drawUpcEanSupplementalBars (struct state *st, + Bitmap *upcBitmap, char *digits, + int x, int y, int y2, int textAbove) +{ + int len = strlen (digits); + int i; + int parity; + int textY; + int textX; + + if (textAbove) + { + textY = y; + y += 8; + } + else + { + y2 -= 8; + textY = y2 + 2; + } + + x += 8; /* skip the space between the main and supplemental */ + + switch (len) + { + case 2: + { + textX = x + 5; + parity = (charToDigit (digits[0]) * 10 + + charToDigit (digits[1])) & 0x3; + break; + } + case 5: + { + textX = x + 10; + parity = + ((charToDigit (digits[0]) + charToDigit (digits[2]) + + charToDigit (digits[4])) * 3 + + (charToDigit (digits[1]) + charToDigit (digits[3])) * 9) + % 10; + parity = upcELastDigit[parity]; + break; + } + default: + { + fprintf (stderr, "%s: bad supplement (%d digits)\n", + progname, len); + exit(1); + break; + } + } + + /* header */ + bitmapVlin (upcBitmap, x, y, y2); + bitmapVlin (upcBitmap, x + 2, y, y2); + bitmapVlin (upcBitmap, x + 3, y, y2); + + for (i = 0; i < len; i++) + { + UpcSet lset = + (parity & (1 << (len - 1 - i))) ? UPC_LEFT_B : UPC_LEFT_A; + int baseX = x + 2 + i * 9; + + /* separator / end of header */ + if (i == 0) + { + bitmapVlin (upcBitmap, baseX, y, y2); + } + bitmapVlin (upcBitmap, baseX + 1, y, y2); + + drawUpcEanDigit (upcBitmap, + baseX + 2, + y, + y2, + digits[i], + lset); + + drawDigitChar (st, upcBitmap, textX + i*6, textY, digits[i]); + } +} + +/* draw the actual barcode part of a UPC-A barcode */ +static void drawUpcABars (Bitmap *upcBitmap, char *digits, int x, int y, + int barY2, int guardY2) +{ + int i; + + /* header */ + bitmapVlin (upcBitmap, x, y, guardY2); + bitmapVlin (upcBitmap, x + 2, y, guardY2); + + /* center marker */ + bitmapVlin (upcBitmap, x + 46, y, guardY2); + bitmapVlin (upcBitmap, x + 48, y, guardY2); + + /* trailer */ + bitmapVlin (upcBitmap, x + 92, y, guardY2); + bitmapVlin (upcBitmap, x + 94, y, guardY2); + + for (i = 0; i < 6; i++) + { + drawUpcEanDigit (upcBitmap, + x + 3 + i*7, + y, + (i == 0) ? guardY2 : barY2, + digits[i], + UPC_LEFT_A); + drawUpcEanDigit (upcBitmap, + x + 50 + i*7, + y, + (i == 5) ? guardY2 : barY2, + digits[i+6], + UPC_RIGHT); + } +} + +/* make and return a full-height UPC-A barcode */ +static int makeUpcAFull (struct state *st, Bitmap *dest, char *digits, int y) +{ + int baseWidth = 108; + int baseHeight = 60; + + int height = baseHeight + y; + int i; + + bitmapClear (dest); + drawUpcABars (dest, digits, 6, y, height - 10, height - 4); + + drawDigitChar (st, dest, 0, height - 14, digits[0]); + + for (i = 0; i < 5; i++) + { + drawDigitChar (st, dest, 18 + i*7, height - 7, digits[i+1]); + drawDigitChar (st, dest, 57 + i*7, height - 7, digits[i+6]); + } + + drawDigitChar (st, dest, 103, height - 14, digits[11]); + + return baseWidth; +} + +/* make and return a UPC-A barcode */ +static int makeUpcA (struct state *st, Bitmap *dest, char *digits, int y) +{ + int i; + unsigned int mul = 3; + unsigned int sum = 0; + + for (i = 0; i < 11; i++) + { + sum += charToDigit (digits[i]) * mul; + mul ^= 2; + } + + if (digits[11] == '?') + { + digits[11] = ((10 - (sum % 10)) % 10) + '0'; + } + + return makeUpcAFull (st, dest, digits, y); +} + +/* draw the actual barcode part of a UPC-E barcode */ +static void drawUpcEBars (struct state *st, + Bitmap *upcBitmap, char *digits, int x, int y, + int barY2, int guardY2) +{ + int i; + int parityPattern = upcELastDigit[charToDigit(digits[7])]; + + int clockp = (st->mode == BC_CLOCK12 || st->mode == BC_CLOCK24); + + if (digits[0] == '1') + { + parityPattern = ~parityPattern; + } + + /* header */ + bitmapVlin (upcBitmap, x, y, guardY2); + bitmapVlin (upcBitmap, x + 2, y, guardY2); + + /* trailer */ + bitmapVlin (upcBitmap, x + 46 + (clockp?8:0), y, guardY2); + bitmapVlin (upcBitmap, x + 48 + (clockp?8:0), y, guardY2); + bitmapVlin (upcBitmap, x + 50 + (clockp?8:0), y, guardY2); + + /* clock kludge -- this draws an extra set of dividers after + digits 2 and 4. This makes this *not* be a valid bar code, + but, it looks pretty for the clock dpy. + */ + if (clockp) + { + bitmapVlin (upcBitmap, x + 18, y, guardY2); + bitmapVlin (upcBitmap, x + 18 + 2, y, guardY2); + + bitmapVlin (upcBitmap, x + 36, y, guardY2); + bitmapVlin (upcBitmap, x + 36 + 2, y, guardY2); + } + + for (i = 0; i < 6; i++) + { + UpcSet lset = + (parityPattern & (1 << (5 - i))) ? UPC_LEFT_B : UPC_LEFT_A; + int off = (clockp + ? (i < 2 ? 0 : + i < 4 ? 4 : /* extra spacing for clock bars */ + 8) + : 0); + drawUpcEanDigit (upcBitmap, + x + 3 + i*7 + off, + y, + barY2, + digits[i + 1], + lset); + } +} + +/* make and return a full-height UPC-E barcode */ +static int makeUpcEFull (struct state *st, Bitmap *dest, char *digits, int y) +{ + int baseWidth = 64; + int baseHeight = 60; + + int height = baseHeight + y; + int i; + + bitmapClear (dest); + drawUpcEBars (st, dest, digits, 6, y, height - 10, height - 4); + + drawDigitChar (st, dest, 0, height - 14, digits[0]); + + for (i = 0; i < 6; i++) + { + drawDigitChar (st, dest, 11 + i*7, height - 7, digits[i+1]); + } + + drawDigitChar (st, dest, 59, height - 14, digits[7]); + + return baseWidth; +} + +/* expand 8 UPC-E digits into a UPC-A number, storing into the given result + * array, or just store '\0' into the first element, if the form factor + * is incorrect; this will also calculate the check digit, if it is + * specified as '?' */ +static void expandToUpcADigits (char *compressed, char *expanded) +{ + int i; + + if ((compressed[0] != '0') && (compressed[0] != '1')) + { + return; + } + + expanded[0] = compressed[0]; + expanded[6] = '0'; + expanded[7] = '0'; + expanded[11] = compressed[7]; + + switch (compressed[6]) + { + case '0': + case '1': + case '2': + { + expanded[1] = compressed[1]; + expanded[2] = compressed[2]; + expanded[3] = compressed[6]; + expanded[4] = '0'; + expanded[5] = '0'; + expanded[8] = compressed[3]; + expanded[9] = compressed[4]; + expanded[10] = compressed[5]; + break; + } + case '3': + { + expanded[1] = compressed[1]; + expanded[2] = compressed[2]; + expanded[3] = compressed[3]; + expanded[4] = '0'; + expanded[5] = '0'; + expanded[8] = '0'; + expanded[9] = compressed[4]; + expanded[10] = compressed[5]; + break; + } + case '4': + { + expanded[1] = compressed[1]; + expanded[2] = compressed[2]; + expanded[3] = compressed[3]; + expanded[4] = compressed[4]; + expanded[5] = '0'; + expanded[8] = '0'; + expanded[9] = '0'; + expanded[10] = compressed[5]; + break; + } + default: + { + expanded[1] = compressed[1]; + expanded[2] = compressed[2]; + expanded[3] = compressed[3]; + expanded[4] = compressed[4]; + expanded[5] = compressed[5]; + expanded[8] = '0'; + expanded[9] = '0'; + expanded[10] = compressed[6]; + break; + } + } + + if (expanded[11] == '?') + { + unsigned int mul = 3; + unsigned int sum = 0; + + for (i = 0; i < 11; i++) + { + sum += charToDigit (expanded[i]) * mul; + mul ^= 2; + } + + expanded[11] = ((10 - (sum % 10)) % 10) + '0'; + } +} + +/* make and return a UPC-E barcode */ +static int makeUpcE (struct state *st, Bitmap *dest, char *digits, int y) +{ + char expandedDigits[13]; + char compressedDigits[9]; + + expandedDigits[0] = '\0'; + compressedDigits[0] = '0'; + strcpy (compressedDigits + 1, digits); + + expandToUpcADigits (compressedDigits, expandedDigits); + if (expandedDigits[0] == '\0') + { + return 0; + } + + compressedDigits[7] = expandedDigits[11]; + + return makeUpcEFull (st, dest, compressedDigits, y); +} + +/* draw the actual barcode part of a EAN-13 barcode */ +static void drawEan13Bars (Bitmap *upcBitmap, char *digits, int x, int y, + int barY2, int guardY2) +{ + int i; + int leftPattern = ean13FirstDigit[charToDigit (digits[0])]; + + /* header */ + bitmapVlin (upcBitmap, x, y, guardY2); + bitmapVlin (upcBitmap, x + 2, y, guardY2); + + /* center marker */ + bitmapVlin (upcBitmap, x + 46, y, guardY2); + bitmapVlin (upcBitmap, x + 48, y, guardY2); + + /* trailer */ + bitmapVlin (upcBitmap, x + 92, y, guardY2); + bitmapVlin (upcBitmap, x + 94, y, guardY2); + + for (i = 0; i < 6; i++) + { + UpcSet lset = (leftPattern & (1 << (5 - i))) ? UPC_LEFT_B : UPC_LEFT_A; + + drawUpcEanDigit (upcBitmap, + x + 3 + i*7, + y, + barY2, + digits[i+1], + lset); + drawUpcEanDigit (upcBitmap, + x + 50 + i*7, + y, + barY2, + digits[i+7], + UPC_RIGHT); + } +} + +/* make and return a full-height EAN-13 barcode */ +static int makeEan13Full (struct state *st, Bitmap *dest, char *digits, int y) +{ + int baseWidth = 102; + int baseHeight = 60; + + int height = baseHeight + y; + int i; + + bitmapClear (dest); + drawEan13Bars (dest, digits, 6, y, height - 10, height - 4); + + drawDigitChar (st, dest, 0, height - 7, digits[0]); + + for (i = 0; i < 6; i++) + { + drawDigitChar (st, dest, 11 + i*7, height - 7, digits[i+1]); + drawDigitChar (st, dest, 57 + i*7, height - 7, digits[i+7]); + } + + return baseWidth; +} + +/* make and return an EAN-13 barcode */ +static int makeEan13 (struct state *st, Bitmap *dest, char *digits, int y) +{ + int i; + unsigned int mul = 1; + unsigned int sum = 0; + + for (i = 0; i < 12; i++) + { + sum += charToDigit (digits[i]) * mul; + mul ^= 2; + } + + if (digits[12] == '?') + { + digits[12] = ((10 - (sum % 10)) % 10) + '0'; + } + + return makeEan13Full (st, dest, digits, y); +} + +/* draw the actual barcode part of an EAN-8 barcode */ +static void drawEan8Bars (Bitmap *upcBitmap, char *digits, int x, int y, + int barY2, int guardY2) +{ + int i; + + /* header */ + bitmapVlin (upcBitmap, x, y, guardY2); + bitmapVlin (upcBitmap, x + 2, y, guardY2); + + /* center marker */ + bitmapVlin (upcBitmap, x + 32, y, guardY2); + bitmapVlin (upcBitmap, x + 34, y, guardY2); + + /* trailer */ + bitmapVlin (upcBitmap, x + 64, y, guardY2); + bitmapVlin (upcBitmap, x + 66, y, guardY2); + + for (i = 0; i < 4; i++) + { + drawUpcEanDigit (upcBitmap, + x + 3 + i*7, + y, + barY2, + digits[i], + UPC_LEFT_A); + drawUpcEanDigit (upcBitmap, + x + 36 + i*7, + y, + barY2, + digits[i+4], + UPC_RIGHT); + } +} + +/* make and return a full-height EAN-8 barcode */ +static int makeEan8Full (struct state *st, Bitmap *dest, char *digits, int y) +{ + int baseWidth = 68; + int baseHeight = 60; + + int height = baseHeight + y; + int i; + + bitmapClear (dest); + drawEan8Bars (dest, digits, 0, y, height - 10, height - 4); + + for (i = 0; i < 4; i++) + { + drawDigitChar (st, dest, 5 + i*7, height - 7, digits[i]); + drawDigitChar (st, dest, 37 + i*7, height - 7, digits[i+4]); + } + + return baseWidth; +} + +/* make and return an EAN-8 barcode */ +static int makeEan8 (struct state *st, Bitmap *dest, char *digits, int y) +{ + int i; + unsigned int mul = 3; + unsigned int sum = 0; + + for (i = 0; i < 7; i++) + { + sum += charToDigit (digits[i]) * mul; + mul ^= 2; + } + + if (digits[7] == '?') + { + digits[7] = ((10 - (sum % 10)) % 10) + '0'; + } + + return makeEan8Full (st, dest, digits, y); +} + +/* Dispatch to the right form factor UPC/EAN barcode generator */ +static void processUpcEan (struct state *st, char *str, Bitmap *dest) +{ + char digits[16]; + int digitCount = 0; + char supDigits[8]; + int supDigitCount = 0; + char *instr = str; + char *banner = NULL; + int supplement = 0; + int vstart = 9; + int width = 0; + + while ((digitCount < 15) && (supDigitCount < 7)) + { + char c = *instr; + if (((c >= '0') && (c <= '9')) || (c == '?')) + { + if (supplement) + { + supDigits[supDigitCount] = *instr; + supDigitCount++; + } + else + { + digits[digitCount] = *instr; + digitCount++; + } + } + else if (c == ',') + { + supplement = 1; + } + else if (c == ':') + { + banner = instr + 1; + break; + } + else if (c == '\0') + { + break; + } + instr++; + } + + digits[digitCount] = '\0'; + supDigits[supDigitCount] = '\0'; + + if (supDigitCount == 0) + { + supplement = 0; + } + else if ((supDigitCount == 2) || (supDigitCount == 5)) + { + supplement = upcEanSupplementWidth (supDigits); + } + else + { + fprintf (stderr, "%s: invalid supplement (must be 2 or 5 digits)\n", + progname); + exit (1); + } + + if (banner == NULL) + { + banner = "barcode"; + } + + switch (digitCount) + { + case 7: + { + width = makeUpcE (st, dest, digits, vstart); + break; + } + case 8: + { + width = makeEan8 (st, dest, digits, vstart); + break; + } + case 12: + { + width = makeUpcA (st, dest, digits, vstart); + break; + } + case 13: + { + width = makeEan13 (st, dest, digits, vstart); + break; + } + default: + { + fprintf (stderr, "%s: bad barcode (%d digits)\n", + progname, digitCount); + exit(1); + } + } + + if (supplement) + { + drawUpcEanSupplementalBars (st, dest, supDigits, + width, + vstart + 1, dest->height - 4, 1); + } + + if (banner != NULL) + { + bitmapDrawString5x8 (dest, + (width + supplement - + ((int) strlen (banner) * 5)) / 2, + 0, + banner); + } +} + + + +/* ---------------------------------------------------------------------------- + * the screenhack + */ + +/* + * overall setup stuff + */ + +/* set up the system */ +static void setup (struct state *st) +{ + XWindowAttributes xgwa; + XGCValues gcv; + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + + st->visual = xgwa.visual; + st->cmap = xgwa.colormap; + st->windowWidth = xgwa.width; + st->windowHeight = xgwa.height; + + gcv.background = get_pixel_resource (st->dpy, xgwa.colormap, + "background", "Background"); + gcv.foreground = get_pixel_resource (st->dpy, xgwa.colormap, + "foreground", "Foreground"); + st->fg_pixel = gcv.foreground; + st->theGC = XCreateGC (st->dpy, st->window, GCForeground|GCBackground, &gcv); + + st->theBitmap = makeBitmap(BARCODE_WIDTH * MAX_MAG, BARCODE_HEIGHT * MAX_MAG); + st->theImage = XCreateImage(st->dpy, st->visual, 1, XYBitmap, 0, st->theBitmap->buf, + st->theBitmap->width, st->theBitmap->height, 8, + st->theBitmap->widthBytes); + st->theImage->bitmap_bit_order = LSBFirst; + st->theImage->byte_order = LSBFirst; +} + + + +/* + * the simulation + */ + +/* set up the model */ +static void setupModel (struct state *st) +{ + int i; + + st->barcode_max = 20; + st->barcode_count = 0; + st->barcodes = malloc (sizeof (Barcode) * st->barcode_max); + + for (i = 0; i < st->barcode_max; i++) + { + st->barcodes[i].bitmap = makeBitmap(BARCODE_WIDTH * MAX_MAG, + BARCODE_HEIGHT * MAX_MAG); + } +} + +/* make a new barcode string */ +static void makeBarcodeString (struct state *st, char *str) +{ + int dig, i; + + switch ((int) (RAND_FLOAT_01 * 4)) + { + case 0: dig = 6; break; + case 1: dig = 7; break; + case 2: dig = 11; break; + default: dig = 12; break; + } + + for (i = 0; i < dig; i++) + { + str[i] = RAND_FLOAT_01 * 10 + '0'; + } + + str[i] = '?'; + i++; + + switch ((int) (RAND_FLOAT_01 * 3)) + { + case 0: dig = 0; break; + case 1: dig = 2; break; + default: dig = 5; break; + } + + if (dig != 0) + { + str[i] = ','; + i++; + while (dig > 0) + { + str[i] = RAND_FLOAT_01 * 10 + '0'; + i++; + dig--; + } + } + + str[i] = ':'; + i++; + + strcpy(&str[i], words[(int) (RAND_FLOAT_01 * WORD_COUNT)]); +} + +/* update the model for one iteration */ +static void scrollModel (struct state *st) +{ + int i; + + for (i = 0; i < st->barcode_count; i++) + { + Barcode *b = &st->barcodes[i]; + b->x--; + if ((b->x + BARCODE_WIDTH * b->mag) < 0) + { + /* fell off the edge */ + if (i != (st->barcode_count - 1)) { + Bitmap *oldb = b->bitmap; + memmove (b, b + 1, (st->barcode_count - i - 1) * sizeof (Barcode)); + st->barcodes[st->barcode_count - 1].bitmap = oldb; + + XFreeColors (st->dpy, st->cmap, &b->pixel, 1, 0); + } + + i--; + st->barcode_count--; + } + } + + while (st->barcode_count < st->barcode_max) + { + Barcode *barcode = &st->barcodes[st->barcode_count]; + barcode->x = (st->barcode_count == 0) ? + 0 : + (st->barcodes[st->barcode_count - 1].x + + st->barcodes[st->barcode_count - 1].mag * BARCODE_WIDTH); + barcode->x += RAND_FLOAT_01 * 100; + barcode->mag = RAND_FLOAT_01 * MAX_MAG; + + if (st->windowWidth < 100 || st->windowHeight < 100) { + barcode->mag *= 0.5; + if (barcode->mag <= 0) barcode->mag = 1; + } + + barcode->y = + RAND_FLOAT_01 * (st->windowHeight - BARCODE_HEIGHT * barcode->mag); + if (barcode->y < 0) + { + barcode->y = 0; + } + makeBarcodeString(st, barcode->code); + processUpcEan (st, barcode->code, st->theBitmap); + bitmapScale (barcode->bitmap, st->theBitmap, barcode->mag); + + { + XColor c; + int ii, ok = 0; + for (ii = 0; ii < 100; ii++) + { + hsv_to_rgb (random() % 360, 1.0, 1.0, &c.red, &c.green, &c.blue); + ok = XAllocColor (st->dpy, st->cmap, &c); + if (ok) break; + } + if (!ok) + { + c.red = c.green = c.blue = 0xFFFF; + if (!XAllocColor (st->dpy, st->cmap, &c)) + abort(); + } + barcode->pixel = c.pixel; + } + + st->barcode_count++; + } +} + +/* update the model for one iteration */ +static void updateGrid (struct state *st) +{ + int i, x, y; + + if (st->grid_w == 0 || st->grid_h == 0 || + (! (random() % 400))) + { + XClearWindow (st->dpy, st->window); + st->grid_w = 1 + (random() % 3); + st->grid_h = 1 + (random() % 4); + } + + if (!st->grid_alloced_p || (! (random() % 100))) + { + XColor c; + hsv_to_rgb (random() % 360, 1.0, 1.0, &c.red, &c.green, &c.blue); + if (st->grid_alloced_p) + XFreeColors (st->dpy, st->cmap, &st->grid_pixel, 1, 0); + XAllocColor (st->dpy, st->cmap, &c); + st->grid_pixel = c.pixel; + st->grid_alloced_p = 1; + } + + st->barcode_count = st->grid_w * st->grid_h; + if (st->barcode_count > st->barcode_max) abort(); + + for (i = 0; i < st->barcode_max; i++) + { + Barcode *b = &st->barcodes[i]; + b->x = b->y = 999999; + } + + i = 0; + for (y = 0; y < st->grid_h; y++) + for (x = 0; x < st->grid_w; x++, i++) + { + Barcode *b = &st->barcodes[i]; + int digits = 12; + + int cell_w = (st->windowWidth / st->grid_w); + int cell_h = (st->windowHeight / st->grid_h); + int mag_x = cell_w / BARCODE_WIDTH; + int mag_y = cell_h / BARCODE_HEIGHT; + int BW = 108 /*BARCODE_WIDTH*/; + int BH = BARCODE_HEIGHT; + + b->mag = (mag_x < mag_y ? mag_x : mag_y); + + b->x = (x * cell_w) + ((cell_w - b->mag * BW) / 2); + b->y = (y * cell_h) + ((cell_h - b->mag * BH) / 2); + b->pixel = st->grid_pixel; + + if (!st->strings[i]) + { + int j; + char *s = malloc (digits + 10); + st->strings[i] = s; + for (j = 0; j < digits; j++) + s[j] = (random() % 10) + '0'; + s[j++] = '?'; + s[j++] = ':'; + s[j] = 0; + } + + /* change one digit in this barcode */ + st->strings[i][random() % digits] = (random() % 10) + '0'; + + strcpy (b->code, st->strings[i]); + processUpcEan (st, b->code, b->bitmap); + } +} + + +/* update the model for one iteration. + This one draws a clock. By jwz. */ +static void updateClock (struct state *st) +{ + Barcode *b = &st->barcodes[0]; + int BW = 76 /* BARCODE_WIDTH */; + int BH = BARCODE_HEIGHT; + int mag_x, mag_y; + int i; + time_t now = time ((time_t *) 0); + struct tm *tm = localtime (&now); + XWindowAttributes xgwa; + int ow = st->windowWidth; + int oh = st->windowHeight; + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->windowWidth = xgwa.width; + st->windowHeight = xgwa.height; + + mag_x = st->windowWidth / BW; + mag_y = st->windowHeight / BH; + + st->barcode_count = 1; + + b->mag = (mag_x < mag_y ? mag_x : mag_y); + + if (b->mag > MAX_MAG) b->mag = MAX_MAG; + if (b->mag < 1) b->mag = 1; + + b->x = (st->windowWidth - (b->mag * BW )) / 2; + b->y = (st->windowHeight - (b->mag * (BH + 9))) / 2; + b->pixel = st->fg_pixel; + + if (!st->button_down_p) + sprintf (b->code, "0%02d%02d%02d?:", + (st->mode == BC_CLOCK24 + ? tm->tm_hour + : (tm->tm_hour > 12 + ? tm->tm_hour - 12 + : (tm->tm_hour == 0 + ? 12 + : tm->tm_hour))), + tm->tm_min, + tm->tm_sec); + else + sprintf (b->code, "0%02d%02d%02d?:", + tm->tm_year % 100, tm->tm_mon+1, tm->tm_mday); + + { + int vstart = 9; + int hh = BH + vstart; + char expandedDigits[13]; + + expandedDigits[0] = '\0'; + + expandToUpcADigits (b->code, expandedDigits); + if (expandedDigits[0] != '\0') + b->code[7] = expandedDigits[11]; + + bitmapClear (st->theBitmap); + drawUpcEBars (st, st->theBitmap, b->code, 6, 9, 59, 65); + for (i = 0; i < 6; i++) + { + int off = (i < 2 ? 0 : + i < 4 ? 4 : + 8); + drawDigitChar (st, st->theBitmap, 11 + i*7 + off, hh - 16, b->code[i+1]); + } + + if (!st->button_down_p) + { +#if 0 + char *days[] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" }; + char *s = days[tm->tm_wday]; + bitmapDrawString5x8 (st->theBitmap, (BW - strlen (s)*5) / 2, 0, s); +#endif + drawDigitChar (st, st->theBitmap, 0, hh - 23, (tm->tm_hour < 12 ? 'A' : 'P')); + drawDigitChar (st, st->theBitmap, 68, hh - 23, 'M'); + } + else + { + char s[20]; + sprintf (s, "%03d", tm->tm_yday); + bitmapDrawString5x8 (st->theBitmap, (BW - strlen (s)*5) / 2, 0, s); + } + } + + bitmapScale (b->bitmap, st->theBitmap, b->mag); + + if (ow != st->windowWidth || oh != st->windowHeight) + XClearWindow (st->dpy, st->window); +} + + + +/* render and dpy the current model */ +static void renderFrame (struct state *st) +{ + int i; + + for (i = 0; i < st->barcode_count; i++) + { + Barcode *barcode = &st->barcodes[i]; + + if (barcode->x > st->windowWidth) { + break; + } + + /* bitmapScale (st->theBitmap, barcode->bitmap, barcode->mag);*/ + st->theImage->data = barcode->bitmap->buf; + + XSetForeground (st->dpy, st->theGC, barcode->pixel); + XPutImage (st->dpy, st->window, st->theGC, st->theImage, + 0, 0, barcode->x, barcode->y, + BARCODE_WIDTH * barcode->mag, + BARCODE_HEIGHT * barcode->mag); + } +} + +/* do one iteration */ +static unsigned long +barcode_draw (Display *dpy, Window win, void *closure) +{ + struct state *st = (struct state *) closure; + if (st->mode == BC_SCROLL) + scrollModel (st); + else if (st->mode == BC_GRID) + updateGrid (st); + else if (st->mode == BC_CLOCK12 || st->mode == BC_CLOCK24) + updateClock (st); + else + abort(); + + renderFrame (st); + + return st->delay; +} + + +static Bool +barcode_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + struct state *st = (struct state *) closure; + int clockp = (st->mode == BC_CLOCK12 || st->mode == BC_CLOCK24); + if (clockp && event->xany.type == ButtonPress) { + st->button_down_p = True; + return True; + } else if (clockp && event->xany.type == ButtonRelease) { + st->button_down_p = False; + return True; + } else + return False; +} + +static void +barcode_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + st->windowWidth = w; + st->windowHeight = h; +} + +static void +barcode_free (Display *dpy, Window window, void *closure) +{ +} + + +/* main and options and stuff */ + +static const char *barcode_defaults [] = { + ".background: black", + ".foreground: green", + ".lowrez: true", + "*fpsSolid: true", + "*delay: 10000", + "*mode: scroll", + 0 +}; + +static XrmOptionDescRec barcode_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-mode", ".mode", XrmoptionSepArg, 0 }, + { "-scroll", ".mode", XrmoptionNoArg, "scroll" }, + { "-grid", ".mode", XrmoptionNoArg, "grid" }, + { "-clock", ".mode", XrmoptionNoArg, "clock" }, + { "-clock12", ".mode", XrmoptionNoArg, "clock12" }, + { "-clock24", ".mode", XrmoptionNoArg, "clock24" }, + { 0, 0, 0, 0 } +}; + +/* initialize the user-specifiable params */ +static void initParams (struct state *st) +{ + int problems = 0; + char *s; + + st->delay = get_integer_resource (st->dpy, "delay", "Delay"); + if (st->delay < 0) + { + fprintf (stderr, "%s: delay must be at least 0\n", progname); + problems = 1; + } + + s = get_string_resource (st->dpy, "mode", "Mode"); + if (!s || !*s || !strcasecmp (s, "scroll")) + st->mode = BC_SCROLL; + else if (!strcasecmp (s, "grid")) + st->mode = BC_GRID; + else if (!strcasecmp (s, "clock") || + !strcasecmp (s, "clock12")) + st->mode = BC_CLOCK12; + else if (!strcasecmp (s, "clock24")) + st->mode = BC_CLOCK24; + else + { + fprintf (stderr, "%s: unknown mode \"%s\"\n", progname, s); + problems = 1; + } + free (s); + + if (st->mode == BC_CLOCK12 || st->mode == BC_CLOCK24) + st->delay = 10000; /* only update every 1/10th second */ + + if (problems) + { + exit (1); + } +} + +static void * +barcode_init (Display *dpy, Window win) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = dpy; + st->window = win; + + initParams (st); + setup (st); + setupModel (st); + return st; +} + + +XSCREENSAVER_MODULE ("Barcode", barcode) diff --git a/hacks/barcode.man b/hacks/barcode.man new file mode 100644 index 0000000..9074e16 --- /dev/null +++ b/hacks/barcode.man @@ -0,0 +1,61 @@ +.TH XScreenSaver 1 "" "X Version 11" +.SH NAME +barcode - draws a random sequence of barcodes for the products you enjoy +.SH SYNOPSIS +.B barcode +[\-display \fIhost:display.screen\fP] +[\-visual \fIvisual\fP] +[\-window] +[\-root] +[\-delay \fInumber\fP] +[\-clock] +[\-clock24] +[\-fps] +.SH DESCRIPTION +This draws a random sequence of colorful barcodes scrolling across your +screen. +.SH OPTIONS +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-delay \fInumber\fP +Per-frame delay, in microseconds. Default: 10000 (0.02 seconds.). +.TP 8 +.B \-clock +Instead of drawing a stream of barcodes, draw a barcode-based digital clock. +.TP 8 +.B \-clock24 +Same as \fI\-clock\fP, but display 24-hour time instead of 12-hour time. +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1) +.SH COPYRIGHT +Copyright \(co 2003 by Dan Bornstein. Permission to use, copy, modify, +distribute, and sell this software and its documentation for any purpose is +hereby granted without fee, provided that the above copyright notice appear +in all copies and that both that copyright notice and this permission notice +appear in supporting documentation. No representations are made about the +suitability of this software for any purpose. It is provided "as is" without +express or implied warranty. +.SH AUTHOR +Dan Bornstein diff --git a/hacks/binaryring.c b/hacks/binaryring.c new file mode 100644 index 0000000..3cbaec2 --- /dev/null +++ b/hacks/binaryring.c @@ -0,0 +1,587 @@ +/* + * Binary Ring + * Copyright (c) 2006-2014 Emilio Del Tessandoro + * + * Directly ported code from complexification.net Binary Ring art + * http://www.complexification.net/gallery/machines/binaryRing/appletm/BinaryRing_m.pde + * + * Binary Ring code: + * j.tarbell June, 2004 + * Albuquerque, New Mexico + * complexification.net + * + * Directly based the hacks of: + * + * xscreensaver, Copyright (c) 1997, 1998, 2002 Jamie Zawinski + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +#include "screenhack.h" +#include "colors.h" +#include "hsv.h" + +#define ANTIALIAS 1 +#define BLACK 0 +#define WHITE 1 + +#define swap(a, b) do { __typeof__(a) tmp; tmp = a; a = b; b = tmp; } while(0) +#define frand1() ((((int) random() ) << 1) * 4.65661287524579692411E-10) +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) + +/* better if signed */ +typedef unsigned long pixel_t; + + +typedef struct { + float x, y; + float xx, yy; + float vx, vy; + float color; + int age; /* age from 0 to ageMax */ +} particle_t; + + +struct state { + int epoch; + int growth_delay; + int ring_radius; + int max_age; + float curliness; + int particles_number; + particle_t* particles; + + + Display *display; /* variables for the X stuff */ + Window window; + GC gc; + XGCValues gcv; + Visual* visual; + int depth; + + int width; + int height; + + Pixmap pix; /* for reshape */ + XImage* buf; /* buffer */ + pixel_t* buffer; + pixel_t colors[2]; + + Bool color; +}; + + + +static void point2rgb(int depth, pixel_t c, int *r, int *g, int *b) +{ + switch(depth) { + case 32: + case 24: +#ifdef HAVE_JWXYZ + /* This program idiotically does not go through a color map, so + we have to hardcode in knowledge of how jwxyz.a packs pixels! + Fix it to go through st->colors[st->ncolors] instead! + */ + *r = (c & 0x00ff0000) >> 16; + *g = (c & 0x0000ffff) >> 8; + *b = (c & 0x000000ff); +#else + *g = (c & 0xff00) >> 8; + *r = (c & 0xff0000) >> 16; + *b = c & 0xff; +#endif + break; + case 16: + *g = ((c >> 5) & 0x3f) << 2; + *r = ((c >> 11) & 0x1f) << 3; + *b = (c & 0x1f) << 3; + break; + case 15: + *g = ((c >> 5) & 0x1f) << 3; + *r = ((c >> 10) & 0x1f) << 3; + *b = (c & 0x1f) << 3; + break; + } +} + +static pixel_t rgb2point(int depth, int r, int g, int b) +{ + pixel_t ret = 0; + + switch(depth) { + case 32: + case 24: +#ifdef HAVE_JWXYZ + /* This program idiotically does not go through a color map, so + we have to hardcode in knowledge of how jwxyz.a packs pixels! + Fix it to go through st->colors[st->ncolors] instead! + */ + ret = 0xFF000000 | (r << 16) | (g << 8) | b; +#else + ret |= (r << 16) | (g << 8) | b; +#endif + break; + case 16: + ret = ((r>>3) << 11) | ((g>>2)<<5) | (b>>3); + break; + case 15: + ret = ((r>>3) << 10) | ((g>>3)<<5) | (b>>3); + break; + } + + return ret; +} + +void print_color ( struct state* st, pixel_t color ); +/* alpha blended point drawing -- this is Not Right and will likely fail on + * non-intel platforms as it is now, needs fixing + */ + +static +void draw_point ( struct state* st, + int x, int y, pixel_t myc, float a ) { + + int or = 0, og = 0, ob = 0; + int r = 0, g = 0, b = 0; + int nr, ng, nb; + register pixel_t c; + + /*or = st->buffer[ 3 * ( y * st->width + x ) + 0 ]; + og = st->buffer[ 3 * ( y * st->width + x ) + 1 ]; + ob = st->buffer[ 3 * ( y * st->width + x ) + 2 ];*/ + + c = st->buffer[ y * st->width + x ]; + point2rgb( st->depth, c, &or, &og, &ob ); + point2rgb( st->depth, myc, &r, &g, &b ); + + nr = or + (r - or) * a; + ng = og + (g - og) * a; + nb = ob + (b - ob) * a; + + /*st->buffer[ 3 * ( y * st->width + x ) + 0 ] = nr; + st->buffer[ 3 * ( y * st->width + x ) + 1 ] = ng; + st->buffer[ 3 * ( y * st->width + x ) + 2 ] = nb;*/ + c = rgb2point(st->depth, nr, ng, nb); + st->buffer[ y * st->width + x ] = c; + + XPutPixel( st->buf, x, y, c ); +} + + + + +void print_color ( struct state* st, pixel_t color ) { + int r=0, g=0, b=0; + point2rgb(st->depth, color, &r, &g, &b); + printf( "%d %d %d\n", r, g, b); +} + + + +#if ANTIALIAS +#define plot_(X,Y,D) do{ \ + _dla_plot(st, (X), (Y), color, (D) * alpha); }while(0) + +static +void _dla_plot(struct state* st, int x, int y, pixel_t col, float br) +{ + if ( ( x >= 0 && x < st->width ) && ( y >= 0 && y < st->height ) ) { + if ( br > 1.0f ) br = 1.0f; + draw_point( st, x, y, col, br ); + } +} + +#define ipart_(X) ((int)(X)) +#define round_(X) ((int)(((float)(X))+0.5)) +#define fpart_(X) (((float)(X))-(float)ipart_(X)) +#define rfpart_(X) (1.0-fpart_(X)) + +static +void draw_line_antialias( + struct state* st, + int x1, int y1, + int x2, int y2, + pixel_t color, float alpha ) +{ + float dx = (float)x2 - (float)x1; + float dy = (float)y2 - (float)y1; + float gradient; + float xend; + float yend; + float xgap; + float ygap; + int xpxl1; + int ypxl1; + float intery; + float interx; + int xpxl2; + int ypxl2; + int x; + int y; + + /* hard clipping, because this routine has some problems with negative coordinates */ + /* TODO: fix the alpha for that boundary cases. Using fabs() could solve? */ + if ( ( x1 < 0 || x1 > st->width ) || + ( x2 < 0 || x2 > st->width ) || + ( y1 < 0 || y1 > st->height ) || + ( y2 < 0 || y2 > st->height ) ) + return; + + if ( fabs(dx) > fabs(dy) ) { + if ( x2 < x1 ) { + swap(x1, x2); + swap(y1, y2); + } + gradient = dy / dx; + xend = round_(x1); + yend = y1 + gradient*(xend - x1); + xgap = rfpart_(x1 + 0.5); + xpxl1 = xend; + ypxl1 = ipart_(yend); + plot_(xpxl1, ypxl1, rfpart_(yend)*xgap); + plot_(xpxl1, ypxl1+1, fpart_(yend)*xgap); + intery = yend + gradient; + + xend = round_(x2); + yend = y2 + gradient*(xend - x2); + xgap = fpart_(x2+0.5); + xpxl2 = xend; + ypxl2 = ipart_(yend); + plot_(xpxl2, ypxl2, rfpart_(yend) * xgap); + plot_(xpxl2, ypxl2 + 1, fpart_(yend) * xgap); + + /*if ( rfpart_(yend) * xgap < 0 || fpart_(yend) * xgap < 0) + printf("%f %f\n", rfpart_(yend) * xgap, fpart_(yend) * xgap);*/ + for(x=xpxl1+1; x <= (xpxl2-1); x++) { + plot_(x, ipart_(intery), rfpart_(intery)); + plot_(x, ipart_(intery) + 1, fpart_(intery)); + /*if ( rfpart_(intery) < 0 || fpart_(intery) < 0) + printf("%f %f\n", rfpart_(intery), fpart_(intery));*/ + intery += gradient; + } + } else { + if ( y2 < y1 ) { + swap(x1, x2); + swap(y1, y2); + } + gradient = dx / dy; + yend = round_(y1); + xend = x1 + gradient*(yend - y1); + ygap = rfpart_(y1 + 0.5); + ypxl1 = yend; + xpxl1 = ipart_(xend); + plot_(xpxl1, ypxl1, rfpart_(xend)*ygap); + plot_(xpxl1, ypxl1+1, fpart_(xend)*ygap); + interx = xend + gradient; + + yend = round_(y2); + xend = x2 + gradient*(yend - y2); + ygap = fpart_(y2+0.5); + ypxl2 = yend; + xpxl2 = ipart_(xend); + plot_(xpxl2, ypxl2, rfpart_(xend) * ygap); + plot_(xpxl2, ypxl2 + 1, fpart_(xend) * ygap); + + for(y=ypxl1+1; y <= (ypxl2-1); y++) { + plot_(ipart_(interx), y, rfpart_(interx)); + plot_(ipart_(interx) + 1, y, fpart_(interx)); + interx += gradient; + } + } +} +#undef plot_ +#undef ipart_ +#undef fpart_ +#undef round_ +#undef rfpart_ + +#else + +static +void draw_line ( struct state* st, int x0, int y0, int x1, int y1, int color, float a ) { + register int steep; + register int deltax; + register int deltay; + register int error; + register int ystep; + register int y; + register int x; + + + steep = abs ( y1 - y0 ) > abs ( x1 - x0 ); + if ( steep ) { swap(x0,y0); swap(x1,y1); } + if ( x0 > x1 ) { swap(x0,x1); swap(y0,y1); } + deltax = x1 - x0; + deltay = abs(y1-y0); + error = 0; + y = y0; + ystep = y0 < y1 ? 1 : -1; + if ( a > 1.0f ) a = 1.0f; + + for ( x = x0; x < x1; x++ ) { + if ( steep ) { + if ( ( y >= 0 && y < st->width ) && ( x >= 0 && x < st->height ) ) + draw_point( st, y, x, color, a ); + } else { + if ( ( x >= 0 && x < st->width ) && ( y >= 0 && y < st->height ) ) + draw_point( st, x, y, color, a ); + } + error += deltay; + if ( ( error << 1 ) > deltax ) { + y += ystep; + error -= deltax; + } + } +} +#endif + +static void create_buffers ( struct state* st, Display* display, Screen* screen, Window window, GC gc ) { + + XWindowAttributes xgwa; + XGetWindowAttributes( display, window, &xgwa ); + + /* Initialize the pixmap */ + if ( st->buf != NULL ) XFreePixmap( display, st->pix ); + + XSetForeground( display, gc, st->colors[BLACK] ); + st->pix = XCreatePixmap( display, window, st->width, st->height, + xgwa.depth ); + XFillRectangle( display, st->pix, gc, 0, 0, st->width, st->height); + + /* Initialize the bitmap */ + if ( st->buf != NULL ) XDestroyImage ( st->buf ); + st->buf = XGetImage( display, st->pix, 0, 0, st->width, st->height, visual_depth(screen, st->visual), ZPixmap ); + st->buffer = (pixel_t*) calloc(sizeof(pixel_t), st->width * st->height); + /*int i; + for ( i = 0; i < st->width * st->height; ++i ) st->buffer[i] = st->colors[BLACK];*/ +} + +static void init_particle ( particle_t* p, float dx, float dy, float direction, int color, int max_age ) { + float max_initial_velocity = 2.0f; + p->x = -dx; + p->y = -dy; + p->xx = 0; + p->yy = 0; + p->vx = max_initial_velocity * cos(direction); + p->vy = max_initial_velocity * sin(direction); + + p->age = random() % max_age; + + p->color = color; +} + +static void clamp ( int* value, int l, int h ) { + if ( *value < l ) *value = l; + if ( *value > h ) *value = h; +} + +static pixel_t next_color ( struct state* st, pixel_t current ) { + int r=0, g=0, b=0; + + point2rgb(st->depth, current, &r, &g, &b); + r += random() % 5 - 2; + g += random() % 5 - 2; + b += random() % 5 - 2; + clamp(&r, 0, 255); + clamp(&g, 0, 255); + clamp(&b, 0, 255); + + return rgb2point( st->depth, r, g, b ); +} + + +static void create_particles ( struct state* st ) { + int i; + float emitx, emity; + float direction; + + for ( i = 0; i < st->particles_number; i++ ) { + emitx = ( st->ring_radius * sinf( M_PI * 2 * ( (float) i / st->particles_number ) ) ); + emity = ( st->ring_radius * cosf( M_PI * 2 * ( (float) i / st->particles_number ) ) ); + direction = (M_PI * i) / st->particles_number; + + if ( st->epoch == WHITE && st->color ) + st->colors[WHITE] = next_color(st, st->colors[WHITE]); + + init_particle(st->particles + i, emitx, emity, direction, st->colors[WHITE], st->max_age); + } +} + + +/* randomly move one particle and draw it */ +static void move ( particle_t* p, struct state * st ) { + int w = st->width / 2; + int h = st->height / 2; + float max_dv = 1.0f; + + p->xx = p->x; + p->yy = p->y; + p->x += p->vx; + p->y += p->vy; + p->vx += frand1() * st->curliness * max_dv; + p->vy += frand1() * st->curliness * max_dv; + + +#if ANTIALIAS + draw_line_antialias( st, + w+p->xx, h+p->yy, w+p->x, h+p->y, p->color, 0.15 ); + draw_line_antialias( st, + w-p->xx, h+p->yy, w-p->x, h+p->y, p->color, 0.15 ); +#else + draw_line( st, w+p->xx, h+p->yy, w+p->x, h+p->y, p->color, 0.15 ); + draw_line( st, w-p->xx, h+p->yy, w-p->x, h+p->y, p->color, 0.15 ); +#endif + + p->age++; + /* if this is too old, die and reborn */ + if ( p->age > st->max_age ) { + float dir = frand1() * 2 * M_PI; + p->x = st->ring_radius * sin(dir); + p->y = st->ring_radius * cos(dir); + p->xx = p->yy = p->vx = p->vy = 0; + p->age = 0; + + if ( st->epoch == WHITE && st->color ) + st->colors[WHITE] = next_color(st, st->colors[WHITE] ); + + p->color = st->colors[st->epoch]; + } +} + + + + +/* Initialize Everything */ +static void* binaryring_init ( Display* display, Window window ) { + XWindowAttributes xgwa; + + struct state *st = ( struct state* ) calloc ( 1, sizeof( *st ) ); + + XGetWindowAttributes( display, window, &xgwa ); + + st->epoch = WHITE; + st->display = display; + st->window = window; + st->particles_number = (get_integer_resource(st->display, "particles_number", "Integer")); + st->growth_delay = (get_integer_resource(st->display, "growth_delay", "Integer")); + st->ring_radius = (get_integer_resource(st->display, "ring_radius", "Integer")); + st->max_age = (get_integer_resource(st->display, "max_age", "Integer")); + st->color = get_boolean_resource(st->display, "color", "Boolean"); + st->height = xgwa.height; + st->width = xgwa.width; + st->visual = xgwa.visual; + st->curliness = 0.5; + + + st->depth = visual_depth(xgwa.screen, st->visual); + st->colors[0] = rgb2point(st->depth, 0, 0, 0); + st->colors[1] = rgb2point(st->depth, 255, 255, 255); + + /*describe_visual (stdout, xgwa.screen, xgwa.visual, False);*/ + + st->particles = malloc (st->particles_number * sizeof( particle_t ) ); + create_particles ( st ); + + st->gc = XCreateGC( st->display, st->window, 0, &st->gcv ); + create_buffers ( st, display, xgwa.screen, window, st->gc ); + + + return st; +} + + +static unsigned long binaryring_draw ( Display* display, Window win, void *closure ) { + struct state *st = (struct state *) closure; + int i; + + for ( i = 0; i < st->particles_number; i++ ) + move( &(st->particles[i]), st ); + + /* draw the XImage in the Pixmap and the put the Pixmap on the screen */ + XPutImage( display, st->pix, st->gc, st->buf, 0, 0, 0, 0, st->width, st->height); + XCopyArea( display, st->pix, win, st->gc, 0, 0, st->width, st->height, 0, 0 ); + + /* randomly switch ageColor periods */ + if ( random() % 10000 > 9950 ) + st->epoch = (st->epoch == WHITE) ? BLACK : WHITE; + + return st->growth_delay; +} + + + +static void binaryring_reshape ( Display* display, Window win, void *closure, unsigned int w, unsigned int h ) { + struct state *st = (struct state *) closure; + + XWindowAttributes tmp; + XGetWindowAttributes(display, win, &tmp); + + if ( tmp.height != st->height || tmp.width != st->width ) { + st->height = tmp.height; + st->width = tmp.width; + + + st->epoch = WHITE; + create_particles ( st ); + + create_buffers ( st, display, tmp.screen, win, st->gc ); + } +} + + +/* if someone press a key switch the color */ +static Bool binaryring_event ( Display* display, Window win, void *closure, XEvent* event ) { + struct state *st = (struct state *) closure; + + if ( (*event).xany.type == KeyPress ) { + st->epoch = (st->epoch == WHITE) ? BLACK : WHITE; + } + + return False; +} + + +/* delete everything */ +static void binaryring_free ( Display* display, Window win, void *closure ) { + struct state *st = (struct state *) closure; + XWindowAttributes tmp; + XGetWindowAttributes(display, win, &tmp); + + free( st->buffer ); + free( st->particles ); + + free ( st ); +} + + +/* Default resources of the program */ +static const char* binaryring_defaults [] = { + ".background: black", + ".foreground: white", + "*growth_delay: 10000", + "*particles_number: 5000", + "*ring_radius: 40", + "*max_age: 400", + "*color: True", + "*ignoreRotation: True", + 0 +}; + +static XrmOptionDescRec binaryring_options [] = { + { "-particles-number", ".particles_number", XrmoptionSepArg, 0 }, + { "-growth-delay", ".growth_delay", XrmoptionSepArg, 0 }, + { "-ring-radius", ".ring_radius", XrmoptionSepArg, 0 }, + { "-max-age", ".max_age", XrmoptionSepArg, 0 }, + { "-color", ".color", XrmoptionNoArg, "True" }, + { "-no-color", ".color", XrmoptionNoArg, "False" }, + { 0, 0, 0, 0} +}; + +XSCREENSAVER_MODULE("BinaryRing", binaryring) diff --git a/hacks/binaryring.man b/hacks/binaryring.man new file mode 100644 index 0000000..2d44496 --- /dev/null +++ b/hacks/binaryring.man @@ -0,0 +1,88 @@ +.TH "Binary Ring" 1 "02-Sep-14" "X Version 11" +.SH NAME +binaryring - A system of path tracing particles evolves continuously from an initial creation. +.SH SYNOPSIS +.B binaryring +[\-fps] +[\-install] +[\-noinstall] +[\-mono] +[\-root] +[\-visual \fIvisual\fP] +[\-window] +[\-window\-id \fIwindow\-id\fP] +[\-color] +[\-no\-color] +[\-growth\-delay \fIdelayms\fP] +[\-particle\-number \fIparticles\fP] +[\-ring\-radius \fIradius\fP] +.SH DESCRIPTION +A system of path tracing particles evolves continuously from an initial circular creation. +Ages of darkness play arbitrarily with ages of light. + +Ported (with some extensions) from the code by J. Tarbell at http://complexification.net +.SH OPTIONS +.I binaryring +accepts the following options: +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.TP 8 +.B \-install +Install a private colormap for the window. +.TP 8 +.B \-mono +If on a color display, pretend we're on a monochrome display. +.TP 8 +.B \-noinstall +Don't install a private colormap for the window. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual +class or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-window\-id \fIwindow\-id\fP +Specify which window id to use. +.TP 8 +.B \-color (Default) +Particles have random generated colors that gradually change over time. +.TP 8 +.B \-no\-color +Use the original black and white visualization. +.TP 8 +.B \-growth\-delay \fIdelayms\fP (Default: \fI10000\fP) +Delay in ms between growth cycles. More delay, slower (but less CPU intensive). +.TP 8 +.B \-particles\-number \fIparticles\fP (Default: \fI5000\fP) +The number of particles in the system. With more particles the fps +can also be affected. +.TP 8 +.B \-ring\-radius \fIradius\fP (Default: \fI40\fP) +The radius of the ring where the particles are born, in pixels. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global +resources stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1) +.SH COPYRIGHT +Copyright \(co 2003 by J. Tarbell +(complex@complexification.net, http://www.complexification.net). + +Ported to XScreensaver by Emilio Del Tessandoro (emilio.deltessa@gmail.com) +.SH AUTHOR +J. Tarbell , Jun-03 + +Emilio Del Tessandoro , Aug-14 diff --git a/hacks/blaster.c b/hacks/blaster.c new file mode 100644 index 0000000..a60351a --- /dev/null +++ b/hacks/blaster.c @@ -0,0 +1,1191 @@ +/* -*- mode: C; tab-width: 2 -*- + * blaster, Copyright (c) 1999 Jonathan H. Lin + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * Robots that move randomly and shoot lasers at each other. If the + * mothership is active, it will fly back and forth horizontally, + * firing 8 lasers in the 8 cardinal directions. The explosions are + * a 20 frame animation. Robots regenerate after the explosion is finished + * and all of its lasers have left the screen. + */ + +#include +#include +#include +#include "screenhack.h" + +struct laser_state { + int active; + int start_x,start_y; + int end_x, end_y; +}; + +struct robot_state { + int alive; + int death; + + int move_style; + int target; + + int old_x, old_y; + int new_x, new_y; + + int radius; + GC robot_color; + GC laser_color; + struct laser_state *lasers; +}; + +struct mother_ship_state { + int active; + int death; + int old_x,new_x; + int y; + GC ship_color; + GC laser_color; + struct laser_state *lasers; +}; + + + + +struct state { + Display *dpy; + Window window; + + GC r_color0, r_color1, r_color2, r_color3, r_color4, r_color5, l_color0, l_color1; + GC s_color; + GC black; + + int delay; + + int NUM_ROBOTS; + int NUM_LASERS; + + int MOTHER_SHIP; + int MOTHER_SHIP_WIDTH; + int MOTHER_SHIP_HEIGHT; + int MOTHER_SHIP_LASER; + int MOTHER_SHIP_PERIOD; + int MOTHER_SHIP_HITS; + + int LINE_MOVE_STYLE; + int RANDOM_MOVE_STYLE; + int NUM_MOVE_STYLES; + + int EXPLODE_SIZE_1; + int EXPLODE_SIZE_2; + int EXPLODE_SIZE_3; + GC EXPLODE_COLOR_1; + GC EXPLODE_COLOR_2; + + XArc *stars; + int NUM_STARS; + int MOVE_STARS; + int MOVE_STARS_X; + int MOVE_STARS_Y; + int MOVE_STARS_RANDOM; + + struct mother_ship_state *mother; + + struct robot_state *robots; + + XWindowAttributes xgwa; + + int initted; + + int draw_x; + int draw_y; + int draw_z; +}; + + +/* creates a new robot. It starts out on one of the edges somewhere and + has no initial velocity. A target is randomly picked. */ +static void make_new_robot(struct state *st, int index) +{ + int laser_check = 0; + int x=0; + + for(x=0;xNUM_LASERS;x++) { + if(st->robots[index].lasers[x].active) { + x=st->NUM_LASERS; + laser_check = 1; + } + } + if(laser_check==0) { + st->robots[index].alive=1; + + st->robots[index].radius = 7+(random()%7); + + st->robots[index].move_style = random()%st->NUM_MOVE_STYLES; + if(random()%2==0) { + st->robots[index].new_x=random()%(st->xgwa.width-st->robots[index].radius); + st->robots[index].old_x=st->robots[index].new_x; + if(random()%2==0) { + st->robots[index].new_y=0; + st->robots[index].old_y=0; + } + else { + st->robots[index].new_y=st->xgwa.height-st->robots[index].radius; + st->robots[index].old_y = st->robots[index].new_y; + } + } + else { + st->robots[index].new_y=random()%(st->xgwa.height-st->robots[index].radius); + st->robots[index].old_y = st->robots[index].new_y; + if(random()%2) { + st->robots[index].new_x=0; + st->robots[index].old_x=0; + } + else { + st->robots[index].new_x=st->xgwa.width-st->robots[index].radius; + st->robots[index].old_x=st->robots[index].new_x; + } + } + + x=random()%6; + if(x==0) { + st->robots[index].robot_color = st->r_color0; + } + else if(x==1) { + st->robots[index].robot_color = st->r_color1; + } + else if(x==2) { + st->robots[index].robot_color = st->r_color2; + } + else if(x==3) { + st->robots[index].robot_color = st->r_color3; + } + else if(x==4) { + st->robots[index].robot_color = st->r_color4; + } + else if(x==5) { + st->robots[index].robot_color = st->r_color5; + } + + if(random()%2==0) { + st->robots[index].laser_color = st->l_color0; + } + else { + st->robots[index].laser_color = st->l_color1; + } + + if(st->NUM_ROBOTS>1) { + st->robots[index].target = random()%st->NUM_ROBOTS; + while(st->robots[index].target==index) { + st->robots[index].target = random()%st->NUM_ROBOTS; + } + } + } +} + +/* moves each robot, randomly changing its direction and velocity. + At random a laser is shot toward that robot's target. Also at random + the target can change. */ +static void move_robots(struct state *st) +{ + int x=0; + int y=0; + int dx=0; + int dy=0; + int target_x = 0; + int target_y = 0; + double slope = 0; + + for(x=0;xNUM_ROBOTS;x++) { + if(st->robots[x].alive) { + if((st->robots[x].new_x == st->robots[x].old_x) && (st->robots[x].new_y == st->robots[x].old_y)) { + if(st->robots[x].new_x==0) { + st->robots[x].old_x = -((random()%3)+1); + } + else { + st->robots[x].old_x = st->robots[x].old_x + (random()%3)+1; + } + if(st->robots[x].new_y==0) { + st->robots[x].old_y = -((random()%3)+1); + } + else { + st->robots[x].old_y = st->robots[x].old_y + (random()%3)+1; + } + } + if(st->robots[x].move_style==st->LINE_MOVE_STYLE) { + dx = st->robots[x].new_x - st->robots[x].old_x; + dy = st->robots[x].new_y - st->robots[x].old_y; + if(dx > 3) { + dx = 3; + } + else if(dx < -3) { + dx = -3; + } + if(dy > 3) { + dy = 3; + } + else if(dy < -3) { + dy = -3; + } + st->robots[x].old_x = st->robots[x].new_x; + st->robots[x].old_y = st->robots[x].new_y; + + st->robots[x].new_x = st->robots[x].new_x + dx; + st->robots[x].new_y = st->robots[x].new_y + dy; + } + else if(st->robots[x].move_style==st->RANDOM_MOVE_STYLE) { + dx = st->robots[x].new_x - st->robots[x].old_x; + dy = st->robots[x].new_y - st->robots[x].old_y; + y=random()%3; + if(y==0) { + dx = dx - ((random()%7)+1); + } + else if(y==1){ + dx = dx + ((random()%7)+1); + } + else { + dx = (-1)*dx; + } + if(dx > 3) { + dx = 3; + } + else if(dx < -3) { + dx = -3; + } + + y = random()%3; + if(y==0) { + dy = dy - ((random()%7)+1); + } + else if(y==1){ + dy = dy + ((random()%7)+1); + } + else { + dx = (-1)*dx; + } + if(dy > 3) { + dy = 3; + } + else if(dy < -3) { + dy = -3; + } + st->robots[x].old_x = st->robots[x].new_x; + st->robots[x].old_y = st->robots[x].new_y; + + st->robots[x].new_x = st->robots[x].new_x + dx; + st->robots[x].new_y = st->robots[x].new_y + dy; + } + + /* bounds corrections */ + if(st->robots[x].new_x >= st->xgwa.width-st->robots[x].radius) { + st->robots[x].new_x = st->xgwa.width - st->robots[x].radius; + } + else if(st->robots[x].new_x < 0) { + st->robots[x].new_x = 0; + } + if(st->robots[x].new_y >= st->xgwa.height-st->robots[x].radius) { + st->robots[x].new_y = st->xgwa.height - st->robots[x].radius; + } + else if(st->robots[x].new_y < 0) { + st->robots[x].new_y = 0; + } + + if(random()%10==0) { + st->robots[x].move_style = 1; + } + else { + st->robots[x].move_style = 0; + } + + if(st->NUM_ROBOTS>1) { + if(random()%2==0) { + if(random()%200==0) { + st->robots[x].target = random()%st->NUM_ROBOTS; + while(st->robots[x].target==x) { + st->robots[x].target = random()%st->NUM_ROBOTS; + } + for(y=0;yNUM_LASERS;y++) { + if(st->robots[x].lasers[y].active == 0) { + st->robots[x].lasers[y].active = 1; + if(random()%2==0) { + if(random()%2==0) { + st->robots[x].lasers[y].start_x = st->robots[x].new_x+st->robots[x].radius; + st->robots[x].lasers[y].start_y = st->robots[x].new_y+st->robots[x].radius; + st->robots[x].lasers[y].end_x = st->robots[x].lasers[y].start_x+7; + st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y+7; + } + else { + st->robots[x].lasers[y].start_x = st->robots[x].new_x-st->robots[x].radius; + st->robots[x].lasers[y].start_y = st->robots[x].new_y+st->robots[x].radius; + st->robots[x].lasers[y].end_x = st->robots[x].lasers[y].start_x-7; + st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y+7; + } + } + else { + if(random()%2==0) { + st->robots[x].lasers[y].start_x = st->robots[x].new_x-st->robots[x].radius; + st->robots[x].lasers[y].start_y = st->robots[x].new_y-st->robots[x].radius; + st->robots[x].lasers[y].end_x = st->robots[x].lasers[y].start_x-7; + st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y-7; + } + else { + st->robots[x].lasers[y].start_x = st->robots[x].new_x+st->robots[x].radius; + st->robots[x].lasers[y].start_y = st->robots[x].new_y-st->robots[x].radius; + st->robots[x].lasers[y].end_x = st->robots[x].lasers[y].start_x+7; + st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y-7; + } + } + y = st->NUM_LASERS; + } + } + } + else { + for(y=0;yNUM_LASERS;y++) { + if(st->robots[x].lasers[y].active==0) { + target_x = st->robots[st->robots[x].target].new_x; + target_y = st->robots[st->robots[x].target].new_y; + if((target_x-st->robots[x].new_x)!=0) { + slope = ((double)target_y-st->robots[x].new_y)/((double)(target_x-st->robots[x].new_x)); + + if((slope<1) && (slope>-1)) { + if(target_x>st->robots[x].new_x) { + st->robots[x].lasers[y].start_x = st->robots[x].radius; + st->robots[x].lasers[y].end_x = st->robots[x].lasers[y].start_x + 7; + } + else { + st->robots[x].lasers[y].start_x = -st->robots[x].radius; + st->robots[x].lasers[y].end_x = st->robots[x].lasers[y].start_x - 7; + } + st->robots[x].lasers[y].start_y = (int)(st->robots[x].lasers[y].start_x * slope); + st->robots[x].lasers[y].end_y = (int)(st->robots[x].lasers[y].end_x * slope); + } + else { + slope = (target_x-st->robots[x].new_x)/(target_y-st->robots[x].new_y); + if(target_y>st->robots[x].new_y) { + st->robots[x].lasers[y].start_y = st->robots[x].radius; + st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y + 7; + } + else { + st->robots[x].lasers[y].start_y = -st->robots[x].radius; + st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y - 7; + } + st->robots[x].lasers[y].start_x = (int)(st->robots[x].lasers[y].start_y * slope);; + st->robots[x].lasers[y].end_x = (int)(st->robots[x].lasers[y].end_y * slope); + } + st->robots[x].lasers[y].start_x = st->robots[x].lasers[y].start_x + st->robots[x].new_x; + st->robots[x].lasers[y].start_y = st->robots[x].lasers[y].start_y + st->robots[x].new_y; + st->robots[x].lasers[y].end_x = st->robots[x].lasers[y].end_x + st->robots[x].new_x; + st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].end_y + st->robots[x].new_y; + } + else { + if(target_y > st->robots[x].new_y) { + st->robots[x].lasers[y].start_x = st->robots[x].new_x; + st->robots[x].lasers[y].start_y = st->robots[x].new_y+st->robots[x].radius; + st->robots[x].lasers[y].end_x = st->robots[x].new_x; + st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y+7; + } + else { + st->robots[x].lasers[y].start_x = st->robots[x].new_x; + st->robots[x].lasers[y].start_y = st->robots[x].new_y-st->robots[x].radius; + st->robots[x].lasers[y].end_x = st->robots[x].new_x; + st->robots[x].lasers[y].end_y = st->robots[x].lasers[y].start_y-7; + } + } + + if((((st->robots[x].lasers[y].start_x - st->robots[x].lasers[y].end_x) > 7) || + ((st->robots[x].lasers[y].end_x - st->robots[x].lasers[y].start_x) > 7)) && + (((st->robots[x].lasers[y].start_y - st->robots[x].lasers[y].end_y) > 7) || + ((st->robots[x].lasers[y].end_y - st->robots[x].lasers[y].start_y) > 7))) { + } + else { + st->robots[x].lasers[y].active = 1; + y = st->NUM_LASERS; + } + } + } + } + } + } + } + else { + if(st->robots[x].death==0) { + make_new_robot(st,x); + } + } + } + +} + +/* This moves a single laser one frame. collisions with other robots or + the mothership is checked. */ +static void move_laser(struct state *st, int rindex, int index) +{ + int x=0; + int y=0; + int z=0; + int dx=0; + int dy=0; + struct laser_state *laser; + if(rindex>=0) { + laser = st->robots[rindex].lasers; + } + else { + laser = st->mother->lasers; + } + if(laser[index].active) { + /* collision with other robots are checked here */ + for(x=0;xNUM_ROBOTS;x++) { + if(x!=rindex) { + if(st->robots[x].alive) { + y = laser[index].start_x-st->robots[x].new_x; + if(y<0) { + y = st->robots[x].new_x-laser[index].start_x; + } + z = laser[index].start_y-st->robots[x].new_y; + if(z<0) { + z = st->robots[x].new_y-laser[index].start_y; + } + if((zrobots[x].radius-1)&&(yrobots[x].radius-1)) { + st->robots[x].alive = 0; + st->robots[x].death = 20; + if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].old_x, st->robots[x].old_y, st->robots[x].radius, st->robots[x].radius, 0, 360*64); + if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x, st->robots[x].new_y, st->robots[x].radius, st->robots[x].radius, 0, 360*64); + laser[index].active = 0; + x = st->NUM_ROBOTS; + } + else { + y = laser[index].end_x-st->robots[x].new_x; + if(y<0) { + y = st->robots[x].new_x-laser[index].end_x; + } + z = laser[index].end_y-st->robots[x].new_y; + if(z<0) { + z = st->robots[x].new_y-laser[index].end_y; + } + if((zrobots[x].radius-1)&&(yrobots[x].radius-1)) { + st->robots[x].alive = 0; + st->robots[x].death = 20; + if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].old_x, st->robots[x].old_y, st->robots[x].radius, st->robots[x].radius, 0, 360*64); + if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x, st->robots[x].new_y, st->robots[x].radius, st->robots[x].radius, 0, 360*64); + laser[index].active = 0; + x = st->NUM_ROBOTS; + } + } + } + } + } + if((st->MOTHER_SHIP)&&(rindex!=-1)) { + if(laser[index].active) { + if(st->mother->active) { + y = laser[index].start_x-st->mother->new_x; + if(y<0) { + y = st->mother->new_x-laser[index].start_x; + } + z = laser[index].start_y-st->mother->y; + if(z<0) { + z = st->mother->y-laser[index].start_y; + } + if((zMOTHER_SHIP_HEIGHT-1)&&(yMOTHER_SHIP_WIDTH-1)) { + laser[index].active = 0; + st->mother->active--; + } + else { + y = laser[index].end_x-st->mother->new_x; + if(y<0) { + y = st->mother->new_x-laser[index].end_x; + } + z = laser[index].end_y-st->mother->y; + if(z<0) { + z = st->mother->y-laser[index].end_y; + } + if((zMOTHER_SHIP_HEIGHT-1)&&(yMOTHER_SHIP_WIDTH-1)) { + laser[index].active = 0; + st->mother->active--; + } + } + + if(st->mother->active==0) { + st->mother->death=20; + } + } + } + } + + if(laser[index].active) { + dx = laser[index].start_x - laser[index].end_x; + dy = laser[index].start_y - laser[index].end_y; + + laser[index].start_x = laser[index].end_x; + laser[index].start_y = laser[index].end_y; + laser[index].end_x = laser[index].end_x-dx; + laser[index].end_y = laser[index].end_y-dy; + + if((laser[index].end_x < 0) || (laser[index].end_x >= st->xgwa.width) || + (laser[index].end_y < 0) || (laser[index].end_y >= st->xgwa.height)) { + laser[index].active = 0; + } + } + } +} + +/* All the robots are drawn, including the mother ship and the explosions. + After all the robots have been drawn, their laser banks are check and + the active lasers are drawn. */ +static void draw_robots(struct state *st) +{ + int x=0; + int y=0; + + for(x=0;xNUM_ROBOTS;x++) { + if(st->robots[x].alive) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].old_x, st->robots[x].old_y, st->robots[x].radius, st->robots[x].radius, 0, 360*64); + XFillArc(st->dpy, st->window, st->robots[x].robot_color, st->robots[x].new_x, st->robots[x].new_y, st->robots[x].radius, st->robots[x].radius, 0, 360*64); + } + else { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].old_x, st->robots[x].old_y, st->robots[x].radius, st->robots[x].radius, 0, 360*64); + if(st->robots[x].death) { + if(st->robots[x].death==20) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->robots[x].death==18) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->robots[x].death==17) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->robots[x].death==15) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->robots[x].death==14) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->robots[x].death==13) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->robots[x].death==12) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->robots[x].death==11) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->robots[x].death==10) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->robots[x].death==9) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->robots[x].death==8) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->robots[x].death==7) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->robots[x].death==6) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64); + } + else if(st->robots[x].death==4) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64); + } + else if(st->robots[x].death==3) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64); + } + else if(st->robots[x].death==2) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(st->robots[x].radius/3), st->robots[x].new_y+(st->robots[x].radius/3), st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64); + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->robots[x].new_x+(1.7*st->robots[x].radius/2), st->robots[x].new_y+(1.7*st->robots[x].radius/2), st->EXPLODE_SIZE_3, st->EXPLODE_SIZE_3, 0, 360*64); + } + else if(st->robots[x].death==1) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->robots[x].new_x+(1.7*st->robots[x].radius/2), st->robots[x].new_y+(1.7*st->robots[x].radius/2), st->EXPLODE_SIZE_3, st->EXPLODE_SIZE_3, 0, 360*64); + } + st->robots[x].death--; + } + } + } + + for(x=0;xNUM_ROBOTS;x++) { + for(y=0;yNUM_LASERS;y++) { + if(st->robots[x].lasers[y].active) { + if (st->black) XDrawLine(st->dpy, st->window, st->black, st->robots[x].lasers[y].start_x, + st->robots[x].lasers[y].start_y, + st->robots[x].lasers[y].end_x, + st->robots[x].lasers[y].end_y); + move_laser(st, x, y); + if(st->robots[x].lasers[y].active) { + XDrawLine(st->dpy, st->window, st->robots[x].laser_color, st->robots[x].lasers[y].start_x, + st->robots[x].lasers[y].start_y, + st->robots[x].lasers[y].end_x, + st->robots[x].lasers[y].end_y); + } + else { + if (st->black) XDrawLine(st->dpy, st->window, st->black, st->robots[x].lasers[y].start_x, + st->robots[x].lasers[y].start_y, + st->robots[x].lasers[y].end_x, + st->robots[x].lasers[y].end_y); + } + } + } + } + + if(st->MOTHER_SHIP) { + if(st->mother->active) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->old_x, st->mother->y, st->MOTHER_SHIP_WIDTH, st->MOTHER_SHIP_HEIGHT, 0 , 360*64); + XFillArc(st->dpy, st->window, st->mother->ship_color, st->mother->new_x, st->mother->y, st->MOTHER_SHIP_WIDTH, st->MOTHER_SHIP_HEIGHT, 0 , 360*64); + } + else { + if(st->mother->death) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->old_x, st->mother->y, st->MOTHER_SHIP_WIDTH, st->MOTHER_SHIP_HEIGHT, 0 , 360*64); + if(st->mother->death==20) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->mother->death==18) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->mother->death==17) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->mother->death==15) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->mother->death==14) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->mother->death==13) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->mother->death==12) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->mother->death==11) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->mother->death==10) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->mother->death==9) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->mother->death==8) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->mother->death==7) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_1, st->EXPLODE_SIZE_1, 0, 360*64); + } + else if(st->mother->death==6) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64); + } + else if(st->mother->death==4) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64); + } + else if(st->mother->death==3) { + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_1, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64); + } + else if(st->mother->death==2) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+1, st->mother->y+1, st->EXPLODE_SIZE_2, st->EXPLODE_SIZE_2, 0, 360*64); + XFillArc(st->dpy, st->window, st->EXPLODE_COLOR_2, st->mother->new_x+(1.7*st->MOTHER_SHIP_WIDTH/2), st->mother->y+(1.7*st->MOTHER_SHIP_HEIGHT/2), st->EXPLODE_SIZE_3, st->EXPLODE_SIZE_3, 0, 360*64); + } + else if(st->mother->death==1) { + if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x+(1.7*st->MOTHER_SHIP_WIDTH/2), st->mother->y+(1.7*st->MOTHER_SHIP_HEIGHT/2), st->EXPLODE_SIZE_3, st->EXPLODE_SIZE_3, 0, 360*64); + } + st->mother->death--; + } + } + for(y=0;y<8;y++) { + if(st->mother->lasers[y].active) { + if (st->black) XDrawLine(st->dpy, st->window, st->black, st->mother->lasers[y].start_x, + st->mother->lasers[y].start_y, + st->mother->lasers[y].end_x, + st->mother->lasers[y].end_y); + move_laser(st, -1,y); + if(st->mother->lasers[y].active) { + XDrawLine(st->dpy, st->window, st->mother->laser_color, st->mother->lasers[y].start_x, + st->mother->lasers[y].start_y, + st->mother->lasers[y].end_x, + st->mother->lasers[y].end_y); + } + else { + if (st->black) XDrawLine(st->dpy, st->window, st->black, st->mother->lasers[y].start_x, + st->mother->lasers[y].start_y, + st->mother->lasers[y].end_x, + st->mother->lasers[y].end_y); + } + } + } + } +} + +static void +init_stars(struct state *st) +{ + if(st->NUM_STARS) { + if (! st->stars) + st->stars = (XArc *) malloc (st->NUM_STARS * sizeof(XArc)); + for(st->draw_x=0;st->draw_xNUM_STARS;st->draw_x++) { + st->stars[st->draw_x].x = random()%st->xgwa.width; + st->stars[st->draw_x].y = random()%st->xgwa.height; + st->stars[st->draw_x].width = random()%4 + 1; + st->stars[st->draw_x].height = st->stars[st->draw_x].width; + st->stars[st->draw_x].angle1 = 0; + st->stars[st->draw_x].angle2 = 360 * 64; + } + } +} + + +static unsigned long +blaster_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + +#ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */ + XClearWindow (dpy, window); +#endif + + if (!st->initted) + { + st->initted = 1; + + st->robots = (struct robot_state *) malloc(st->NUM_ROBOTS * sizeof (struct robot_state)); + for(st->draw_x=0;st->draw_xNUM_ROBOTS;st->draw_x++) { + st->robots[st->draw_x].alive = 0; + st->robots[st->draw_x].death = 0; + st->robots[st->draw_x].lasers = (struct laser_state *) malloc (st->NUM_LASERS * sizeof(struct laser_state)); + for(st->draw_y=0;st->draw_yNUM_LASERS;st->draw_y++) { + st->robots[st->draw_x].lasers[st->draw_y].active = 0; + } + } + + init_stars(st); + } + + if(st->NUM_STARS) { + if(st->MOVE_STARS) { + if (st->black) XFillArcs(st->dpy,st->window,st->black,st->stars,st->NUM_STARS); + if(st->MOVE_STARS_RANDOM) { + st->draw_y = st->MOVE_STARS_X; + st->draw_z = st->MOVE_STARS_Y; + if(random()%167==0) { + st->draw_y = (-1)*st->draw_y; + } + if(random()%173==0) { + st->draw_z = (-1)*st->draw_z; + } + if(random()%50==0) { + if(random()%2) { + st->draw_y++; + if(st->draw_y>st->MOVE_STARS_RANDOM) { + st->draw_y = st->MOVE_STARS_RANDOM; + } + } + else { + st->draw_y--; + if(st->draw_y < -(st->MOVE_STARS_RANDOM)) { + st->draw_y = -(st->MOVE_STARS_RANDOM); + } + } + } + if(random()%50==0) { + if(random()%2) { + st->draw_z++; + if(st->draw_z>st->MOVE_STARS_RANDOM) { + st->draw_z = st->MOVE_STARS_RANDOM; + } + } + else { + st->draw_z--; + if(st->draw_z < -st->MOVE_STARS_RANDOM) { + st->draw_z = -st->MOVE_STARS_RANDOM; + } + } + } + st->MOVE_STARS_X = st->draw_y; + st->MOVE_STARS_Y = st->draw_z; + for(st->draw_x=0;st->draw_xNUM_STARS;st->draw_x++) { + st->stars[st->draw_x].x = st->stars[st->draw_x].x + st->draw_y; + st->stars[st->draw_x].y = st->stars[st->draw_x].y + st->draw_z; + if(st->stars[st->draw_x].x<0) { + st->stars[st->draw_x].x = st->stars[st->draw_x].x + st->xgwa.width; + } + else if(st->stars[st->draw_x].x>st->xgwa.width) { + st->stars[st->draw_x].x = st->stars[st->draw_x].x - st->xgwa.width; + } + if(st->stars[st->draw_x].y<0) { + st->stars[st->draw_x].y = st->stars[st->draw_x].y + st->xgwa.height; + } + else if(st->stars[st->draw_x].y>st->xgwa.height) { + st->stars[st->draw_x].y = st->stars[st->draw_x].y - st->xgwa.height; + } + } + } + else { + for(st->draw_x=0;st->draw_xNUM_STARS;st->draw_x++) { + st->stars[st->draw_x].x = st->stars[st->draw_x].x + st->MOVE_STARS_X; + st->stars[st->draw_x].y = st->stars[st->draw_x].y + st->MOVE_STARS_Y; + if(st->stars[st->draw_x].x<0) { + st->stars[st->draw_x].x = st->stars[st->draw_x].x + st->xgwa.width; + } + else if(st->stars[st->draw_x].x>st->xgwa.width) { + st->stars[st->draw_x].x = st->stars[st->draw_x].x - st->xgwa.width; + } + if(st->stars[st->draw_x].y<0) { + st->stars[st->draw_x].y = st->stars[st->draw_x].y + st->xgwa.height; + } + else if(st->stars[st->draw_x].y>st->xgwa.height) { + st->stars[st->draw_x].y = st->stars[st->draw_x].y - st->xgwa.height; + } + } + } + XFillArcs(st->dpy,st->window,st->s_color,st->stars,st->NUM_STARS); + } + else { + XFillArcs(st->dpy,st->window,st->s_color,st->stars,st->NUM_STARS); + } + } + + if(st->MOTHER_SHIP) { + if(random()%st->MOTHER_SHIP_PERIOD==0) { + if((st->mother->active==0)&&(st->mother->death==0)) { + st->mother->active = st->MOTHER_SHIP_HITS; + st->mother->y = random()%(st->xgwa.height-7); + if(random()%2==0) { + st->mother->old_x=0; + st->mother->new_x=0; + } + else { + st->mother->old_x=st->xgwa.width-25; + st->mother->new_x=st->xgwa.width-25; + } + } + } + } + move_robots(st); + if(st->MOTHER_SHIP) { + if(st->mother->active) { + if(st->mother->old_x==st->mother->new_x) { + if(st->mother->old_x==0) { + st->mother->new_x=3; + } + else { + st->mother->new_x=st->mother->new_x-3; + } + } + else { + if(st->mother->old_x>st->mother->new_x) { + st->mother->old_x = st->mother->new_x; + st->mother->new_x = st->mother->new_x-3; + if(st->mother->new_x<0) { + st->mother->active=0; + if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->old_x, st->mother->y, st->MOTHER_SHIP_WIDTH, st->MOTHER_SHIP_HEIGHT, 0 , 360*64); + if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x, st->mother->y, st->MOTHER_SHIP_WIDTH, st->MOTHER_SHIP_HEIGHT, 0 , 360*64); + } + } + else { + st->mother->old_x = st->mother->new_x; + st->mother->new_x = st->mother->new_x+3; + if(st->mother->new_x>st->xgwa.width) { + st->mother->active=0; + if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->old_x, st->mother->y, st->MOTHER_SHIP_WIDTH, st->MOTHER_SHIP_HEIGHT, 0 , 360*64); + if (st->black) XFillArc(st->dpy, st->window, st->black, st->mother->new_x, st->mother->y, st->MOTHER_SHIP_WIDTH, st->MOTHER_SHIP_HEIGHT, 0 , 360*64); + } + } + } + st->draw_y=0; + for(st->draw_x=0;st->draw_x<8;st->draw_x++) { + if(st->mother->lasers[st->draw_x].active) { + st->draw_y=1; + st->draw_x=8; + } + } + if(st->draw_y==0) { + for(st->draw_x=0;st->draw_x<8;st->draw_x++) { + st->mother->lasers[st->draw_x].active = 1; + st->mother->lasers[st->draw_x].start_x=st->mother->new_x+(st->MOTHER_SHIP_WIDTH/2); + st->mother->lasers[st->draw_x].start_y=st->mother->y+(st->MOTHER_SHIP_HEIGHT/2); + } + st->draw_y = (int)(st->MOTHER_SHIP_LASER/1.5); + st->mother->lasers[0].end_x=st->mother->lasers[0].start_x-st->MOTHER_SHIP_LASER; + st->mother->lasers[0].end_y=st->mother->lasers[0].start_y; + st->mother->lasers[1].end_x=st->mother->lasers[1].start_x-st->draw_y; + st->mother->lasers[1].end_y=st->mother->lasers[1].start_y-st->draw_y; + st->mother->lasers[2].end_x=st->mother->lasers[2].start_x; + st->mother->lasers[2].end_y=st->mother->lasers[2].start_y-st->MOTHER_SHIP_LASER; + st->mother->lasers[3].end_x=st->mother->lasers[3].start_x+st->draw_y; + st->mother->lasers[3].end_y=st->mother->lasers[3].start_y-st->draw_y; + st->mother->lasers[4].end_x=st->mother->lasers[4].start_x+st->MOTHER_SHIP_LASER; + st->mother->lasers[4].end_y=st->mother->lasers[4].start_y; + st->mother->lasers[5].end_x=st->mother->lasers[5].start_x+st->draw_y; + st->mother->lasers[5].end_y=st->mother->lasers[5].start_y+st->draw_y; + st->mother->lasers[6].end_x=st->mother->lasers[6].start_x; + st->mother->lasers[6].end_y=st->mother->lasers[6].start_y+st->MOTHER_SHIP_LASER; + st->mother->lasers[7].end_x=st->mother->lasers[7].start_x-st->draw_y; + st->mother->lasers[7].end_y=st->mother->lasers[7].start_y+st->draw_y; + } + } + } + draw_robots(st); + + return st->delay; +} + +static void * +blaster_init (Display *d, Window w) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + Colormap cmap; + unsigned long bg; + + st->dpy = d; + st->window = w; + XGetWindowAttributes(st->dpy, st->window, &st->xgwa); + cmap = st->xgwa.colormap; + + st->NUM_ROBOTS=5; + st->NUM_LASERS=3; + + st->MOTHER_SHIP_WIDTH=25; + st->MOTHER_SHIP_HEIGHT=7; + st->MOTHER_SHIP_LASER=15; + st->MOTHER_SHIP_PERIOD=150; + st->MOTHER_SHIP_HITS=10; + + st->RANDOM_MOVE_STYLE=1; + st->NUM_MOVE_STYLES=2; + + st->EXPLODE_SIZE_1=27; + st->EXPLODE_SIZE_2=19; + st->EXPLODE_SIZE_3=7; + + + st->delay = get_integer_resource(st->dpy, "delay", "Integer"); + if(st->delay==0) { + st->delay=10000; + } + st->NUM_ROBOTS = get_integer_resource(st->dpy, "num_robots","Integer"); + if(st->NUM_ROBOTS==0) { + st->NUM_ROBOTS=5; + } + st->NUM_LASERS = get_integer_resource(st->dpy, "num_lasers","Integer"); + st->EXPLODE_SIZE_1 = get_integer_resource(st->dpy, "explode_size_1","Integer"); + st->EXPLODE_SIZE_2 = get_integer_resource(st->dpy, "explode_size_2","Integer"); + st->EXPLODE_SIZE_3 = get_integer_resource(st->dpy, "explode_size_3","Integer"); + + st->NUM_STARS = get_integer_resource(st->dpy, "num_stars","Integer"); + if(get_boolean_resource(st->dpy, "move_stars","Boolean")) { + st->MOVE_STARS = 1; + st->MOVE_STARS_X = get_integer_resource(st->dpy, "move_stars_x","Integer"); + st->MOVE_STARS_Y = get_integer_resource(st->dpy, "move_stars_y","Integer"); + st->MOVE_STARS_RANDOM = get_integer_resource(st->dpy, "move_stars_random","Integer"); + } + else { + st->MOVE_STARS = 0; + } + + + bg = get_pixel_resource(st->dpy, cmap, "background","Background"); + gcv.function = GXcopy; + +#define make_gc(color,name) \ + gcv.foreground = get_pixel_resource (st->dpy, cmap, (name), "Foreground"); \ + color = XCreateGC (st->dpy, st->window, GCForeground|GCFunction, &gcv) + + if(mono_p) { + gcv.foreground = bg; + st->black = XCreateGC(st->dpy, st->window, GCForeground|GCFunction, &gcv); + gcv.foreground = get_pixel_resource(st->dpy, cmap, "foreground", "Foreground"); + st->r_color0 = st->r_color1 = st->r_color2 = st->r_color3 = st->r_color4 = st->r_color5 = st->l_color0 = st->l_color1 = st->s_color= + XCreateGC(st->dpy, st->window, GCForeground|GCFunction, &gcv); + if(get_boolean_resource(st->dpy, "mother_ship","Boolean")) { + st->MOTHER_SHIP_WIDTH=get_integer_resource(st->dpy, "mother_ship_width","Integer"); + st->MOTHER_SHIP_HEIGHT=get_integer_resource(st->dpy, "mother_ship_height","Integer"); + st->MOTHER_SHIP_LASER=get_integer_resource(st->dpy, "mother_ship_laser","Integer"); + st->MOTHER_SHIP_PERIOD=get_integer_resource(st->dpy, "mother_ship_period","Integer"); + st->MOTHER_SHIP_HITS=get_integer_resource(st->dpy, "mother_ship_hits","Integer"); + st->MOTHER_SHIP=1; + st->mother = (struct mother_ship_state *) malloc(sizeof(struct mother_ship_state)); + st->mother->lasers = (struct laser_state *) malloc(8*sizeof(struct laser_state)); + st->mother->active = 0; + st->mother->death = 0; + st->mother->ship_color = st->r_color0; + st->mother->laser_color = st->r_color0; + } + } + else { + if(get_boolean_resource(st->dpy, "mother_ship","Boolean")) { + st->MOTHER_SHIP_WIDTH=get_integer_resource(st->dpy, "mother_ship_width","Integer"); + st->MOTHER_SHIP_HEIGHT=get_integer_resource(st->dpy, "mother_ship_height","Integer"); + st->MOTHER_SHIP_LASER=get_integer_resource(st->dpy, "mother_ship_laser","Integer"); + st->MOTHER_SHIP_PERIOD=get_integer_resource(st->dpy, "mother_ship_period","Integer"); + st->MOTHER_SHIP_HITS=get_integer_resource(st->dpy, "mother_ship_hits","Integer"); + st->MOTHER_SHIP=1; + st->mother = (struct mother_ship_state *) malloc(sizeof(struct mother_ship_state)); + st->mother->lasers = (struct laser_state *) malloc(8*sizeof(struct laser_state)); + st->mother->active = 0; + st->mother->death = 0; + make_gc(st->mother->ship_color,"mother_ship_color0"); + make_gc(st->mother->laser_color,"mother_ship_color1"); + } + + make_gc (st->s_color,"star_color"); + + make_gc (st->EXPLODE_COLOR_1,"explode_color_1"); + make_gc (st->EXPLODE_COLOR_2,"explode_color_2"); + + make_gc (st->r_color0,"r_color0"); + make_gc (st->r_color1,"r_color1"); + make_gc (st->r_color2,"r_color2"); + make_gc (st->r_color3,"r_color3"); + make_gc (st->r_color4,"r_color4"); + make_gc (st->r_color5,"r_color5"); + make_gc (st->l_color0,"l_color0"); + make_gc (st->l_color1,"l_color1"); +#ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */ + st->black = 0; +#else + make_gc (st->black,"background"); +#endif + } + + return st; +} + + +static void +blaster_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + XGetWindowAttributes (dpy, window, &st->xgwa); + XClearWindow (dpy, window); + init_stars (st); +} + +static Bool +blaster_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +blaster_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int i; + if (st->r_color0) XFreeGC (dpy, st->r_color0); + if (st->r_color1) XFreeGC (dpy, st->r_color1); + if (st->r_color2) XFreeGC (dpy, st->r_color2); + if (st->r_color3) XFreeGC (dpy, st->r_color3); + if (st->r_color4) XFreeGC (dpy, st->r_color4); + if (st->r_color5) XFreeGC (dpy, st->r_color5); + if (st->l_color0) XFreeGC (dpy, st->l_color0); + if (st->l_color1) XFreeGC (dpy, st->l_color1); + if (st->s_color) XFreeGC (dpy, st->s_color); + if (st->black) XFreeGC (dpy, st->black); + if (st->stars) free (st->stars); + if (st->mother) { + free (st->mother->lasers); + free (st->mother); + } + for (i = 0; i < st->NUM_ROBOTS; i++) + free (st->robots[i].lasers); + free (st->robots); + free (st); +} + + +static const char *blaster_defaults [] = { + ".lowrez: true", + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*r_color0: #FF00FF", + "*r_color1: #FFA500", + "*r_color2: #FFFF00", + "*r_color3: #FFFFFF", + "*r_color4: #0000FF", + "*r_color5: #00FFFF", + "*l_color0: #00FF00", + "*l_color1: #FF0000", + "*mother_ship_color0: #00008B", + "*mother_ship_color1: #FFFFFF", + "*explode_color_1: #FFFF00", + "*explode_color_2: #FFA500", + "*delay: 10000", + "*num_robots: 5", + "*num_lasers: 3", + "*mother_ship: false", + "*mother_ship_width: 25", + "*mother_ship_height: 7", + "*mother_ship_laser: 15", + "*mother_ship_period: 150", + "*mother_ship_hits: 10", + "*explode_size_1: 27", + "*explode_size_2: 19", + "*explode_size_3: 7", + "*num_stars: 50", + "*star_color: white", + "*move_stars: true", + "*move_stars_x: 2", + "*move_stars_y: 1", + "*move_stars_random: 0", +#ifdef HAVE_MOBILE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec blaster_options [] = { + /* These are the 6 robot colors */ + { "-r_color0", ".r_color0", XrmoptionSepArg, 0 }, + { "-r_color1", ".r_color1", XrmoptionSepArg, 0 }, + { "-r_color2", ".r_color2", XrmoptionSepArg, 0 }, + { "-r_color3", ".r_color3", XrmoptionSepArg, 0 }, + { "-r_color4", ".r_color4", XrmoptionSepArg, 0 }, + { "-r_color5", ".r_color5", XrmoptionSepArg, 0 }, + /* These are the 2 laser colors that robots have */ + { "-l_color0", ".l_color0", XrmoptionSepArg, 0 }, + { "-l_color1", ".l_color1", XrmoptionSepArg, 0 }, + /* These are the colors for the mothership and the mothership lasers */ + { "-mother_ship_color0", ".mother_ship_color0", XrmoptionSepArg, 0}, + { "-mother_ship_color1", ".mother_ship_color1", XrmoptionSepArg, 0}, + /* These are the two colors of the animated explosion */ + { "-explode_color_1", ".explode_color_1", XrmoptionSepArg, 0 }, + { "-explode_color_2", ".explode_color_2", XrmoptionSepArg, 0 }, + /* This is the delay in the main loop */ + { "-delay", ".delay", XrmoptionSepArg, 0 }, + /* The number of robots and the number of lasers each robot has */ + { "-num_robots", ".num_robots", XrmoptionSepArg, 0}, + { "-num_lasers", ".num_lasers", XrmoptionSepArg, 0}, + /* If this is set, a mothership will appear, otherwise no mothership */ + { "-mother_ship", ".mother_ship", XrmoptionNoArg, "true"}, + { "-no_mother_ship", ".mother_ship", XrmoptionNoArg, "false"}, + /* This is the width, height, and laser length of the mothership */ + { "-mother_ship_width", ".mother_ship_width", XrmoptionSepArg, 0}, + { "-mother_ship_height", ".mother_ship_height", XrmoptionSepArg, 0}, + { "-mother_ship_laser", ".mother_ship_laser", XrmoptionSepArg, 0}, + /* This is the period which the mothership comes out, higher period==less often */ + { "-mother_ship_period", ".mother_ship_period", XrmoptionSepArg, 0}, + /* This is the number of hits it takes to destroy the mothership */ + { "-mother_ship_hits", ".mother_ship_hits", XrmoptionSepArg, 0}, + /* These are the size of the radius of the animated explosions */ + { "-explode_size_1", ".explode_size_1", XrmoptionSepArg, 0}, + { "-explode_size_2", ".explode_size_2", XrmoptionSepArg, 0}, + { "-explode_size_3", ".explode_size_3", XrmoptionSepArg, 0}, + /* This sets the number of stars in the star field, if this is set to 0, there will be no stars */ + { "-num_stars", ".num_stars", XrmoptionSepArg, 0}, + /* This is the color of the stars */ + { "-star_color", ".star_color", XrmoptionSepArg, 0}, + /* If this is true, the stars will move */ + { "-move_stars", ".move_stars", XrmoptionNoArg, "true"}, + /* This is the amount the stars will move in the x and y direction */ + { "-move_stars_x", ".move_stars_x", XrmoptionSepArg, 0}, + { "-move_stars_y", ".move_stars_y", XrmoptionSepArg, 0}, + /* If this is non-zero, the stars will move randomly, but will not move more than this number in + either the x or y direction */ + { "-move_stars_random", ".move_stars_random", XrmoptionSepArg, 0}, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Blaster", blaster) diff --git a/hacks/blaster.man b/hacks/blaster.man new file mode 100644 index 0000000..6ac369f --- /dev/null +++ b/hacks/blaster.man @@ -0,0 +1,65 @@ +.TH XScreenSaver 1 "" "X Version 11" +.SH NAME +blaster - simulation of space combat +.SH SYNOPSIS +.B blaster +[\-display \fIhost:display.screen\fP] +[\-visual \fIvisual\fP] +[\-window] +[\-root] +[\-num_robots \fInumber\fP] +[\-num_lasers \fInumber\fP] +[\-num_stars \fInumber\fP] +[\-delay \fInumber\fP] +[\-fps] +.SH DESCRIPTION +Draws a simulation of flying space-combat robots (cleverly disguised as +colored circles) doing battle in front of a moving star field. +.SH OPTIONS +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-num_robots \fInumber\fP +Robots. 2 - 50. Default: 5. +.TP 8 +.B \-num_lasers \fInumber\fP +Lasers. 1 - 100. Default: 3. +.TP 8 +.B \-num_stars \fInumber\fP +Stars. 5 - 200. Default: 50. +.TP 8 +.B \-delay \fInumber\fP +Per-frame delay, in microseconds. Default: 10000 (0.01 seconds.). +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1) +.SH COPYRIGHT +Copyright \(co 2002 by Jonathan Lin. Permission to use, copy, modify, +distribute, and sell this software and its documentation for any purpose is +hereby granted without fee, provided that the above copyright notice appear +in all copies and that both that copyright notice and this permission notice +appear in supporting documentation. No representations are made about the +suitability of this software for any purpose. It is provided "as is" without +express or implied warranty. +.SH AUTHOR +Jonathan Lin. diff --git a/hacks/blitspin.c b/hacks/blitspin.c new file mode 100644 index 0000000..d27271d --- /dev/null +++ b/hacks/blitspin.c @@ -0,0 +1,451 @@ +/* xscreensaver, Copyright (c) 1992-2018 Jamie Zawinski + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +/* Rotate a bitmap using using bitblts. + The bitmap must be square, and must be a power of 2 in size. + This was translated from SmallTalk code which appeared in the + August 1981 issue of Byte magazine. + + The input bitmap may be non-square, it is padded and centered + with the background color. Another way would be to subdivide + the bitmap into square components and rotate them independently + (and preferably in parallel), but I don't think that would be as + interesting looking. + + It's too bad almost nothing uses blitter hardware these days, + or this might actually win. + */ + +#include "screenhack.h" +#include "pow2.h" +#include "ximage-loader.h" +#include +#include + +#include "images/gen/som_png.h" + +/* Implementing this using XCopyArea doesn't work with color images on OSX. + This means that the Cocoa implementation of XCopyArea in jwxyz.m is + broken with the GXor, GXand, and/or the GXxor GC operations. This + probably means that (e.g.) "kCGBlendModeDarken" is not close enough + to being "GXand" to use for that. (It works with monochrome images, + just not color ones). + + So, on OSX, we implement the blitter by hand. It is correct, but + orders of magnitude slower. + */ +#ifndef HAVE_JWXYZ +# define USE_XCOPYAREA +#endif + +struct state { + Display *dpy; + Window window; + XWindowAttributes xgwa; + int width, height, size; + Bool scale_up; + Pixmap self, temp, mask; +# ifdef USE_XCOPYAREA + GC gc_set, gc_clear, gc_copy, gc_and, gc_or, gc_xor; +# endif + GC gc; + int delay, delay2; + int duration; + Pixmap bitmap; + unsigned int fg, bg; + + int qwad; /* fuckin' C, man... who needs namespaces? */ + int first_time; + int last_w, last_h; + + time_t start_time; + Bool loaded_p; + Bool load_ext_p; + async_load_state *img_loader; +}; + +static void display (struct state *, Pixmap); +static void blitspin_init_2 (struct state *); + +#define copy_to(from, xoff, yoff, to, op) \ + bitblt (st, st->from, st->to, op, 0, 0, \ + st->size-(xoff), st->size-(yoff), (xoff), (yoff)) + +#define copy_from(to, xoff, yoff, from, op) \ + bitblt (st, st->from, st->to, op, (xoff), (yoff), \ + st->size-(xoff), st->size-(yoff), 0, 0) + + +#ifdef USE_XCOPYAREA +# define bitblt(st, from, to, op, src_x, src_y, w, h, dst_x, dst_y) \ + XCopyArea((st)->dpy, (from), (to), (st)->gc_##op, \ + (src_x), (src_y), (w), (h), (dst_x), (dst_y)) +#else /* !USE_XCOPYAREA */ + +# define bitblt(st, from, to, op, src_x, src_y, w, h, dst_x, dst_y) \ + do_bitblt((st)->dpy, (from), (to), st->gc, GX##op, \ + (src_x), (src_y), (w), (h), (dst_x), (dst_y)) + +static void +do_bitblt (Display *dpy, Drawable src, Drawable dst, GC gc, int op, + int src_x, int src_y, + unsigned int width, unsigned int height, + int dst_x, int dst_y) +{ + if (op == GXclear) + { + XSetForeground (dpy, gc, 0xFF000000); /* ARGB black for Cocoa */ + XFillRectangle (dpy, dst, gc, dst_x, dst_y, width, height); + } + else if (op == GXset) + { + XSetForeground (dpy, gc, ~0L); + XFillRectangle (dpy, dst, gc, dst_x, dst_y, width, height); + } + else if (op == GXcopy) + { + XCopyArea (dpy, src, dst, gc, src_x, src_y, width, height, dst_x, dst_y); + } + else + { + XImage *srci = XGetImage (dpy, src, src_x, src_y, width, height, + ~0L, ZPixmap); + XImage *dsti = XGetImage (dpy, dst, dst_x, dst_y, width, height, + ~0L, ZPixmap); + unsigned long *out = (unsigned long *) dsti->data; + unsigned long *in = (unsigned long *) srci->data; + unsigned long *end = (in + (height * srci->bytes_per_line + / sizeof(unsigned long))); + switch (op) + { + case GXor: while (in < end) { *out++ |= *in++; } break; + case GXand: while (in < end) { *out++ &= *in++; } break; + case GXxor: while (in < end) { *out++ ^= *in++; } break; + default: abort(); + } + XPutImage (dpy, dst, gc, dsti, 0, 0, dst_x, dst_y, width, height); + XDestroyImage (srci); + XDestroyImage (dsti); + } +} + +#endif /* !USE_XCOPYAREA */ + + + +static unsigned long +blitspin_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int this_delay = st->delay; + int qwad; + + if (st->img_loader) /* still loading */ + { + st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0); + + if (!st->img_loader) { /* just finished */ + st->first_time = 0; + st->loaded_p = True; + st->qwad = -1; + st->start_time = time ((time_t *) 0); + blitspin_init_2 (st); + } + + /* Rotate nothing if the very first image is not yet loaded */ + if (! st->loaded_p) + return this_delay; + } + + if (!st->img_loader && + st->load_ext_p && + st->start_time + st->duration < time ((time_t *) 0)) { + /* Start a new image loading, but keep rotating the old image + until the new one arrives. */ + st->img_loader = load_image_async_simple (0, st->xgwa.screen, st->window, + st->bitmap, 0, 0); + } + + if (st->qwad == -1) + { + bitblt(st, st->mask, st->mask, clear,0,0, st->size, st->size, 0,0); + bitblt(st, st->mask, st->mask, set, 0,0, st->size>>1, st->size>>1, 0,0); + st->qwad = st->size>>1; + } + + if (st->first_time) + { + st->first_time = 0; + display (st, st->self); + return st->delay2; + } + + /* for (st->qwad = st->size>>1; st->qwad > 0; st->qwad>>=1) */ + + qwad = st->qwad; + + copy_to (mask, 0, 0, temp, copy); /* 1 */ + copy_to (mask, 0, qwad, temp, or); /* 2 */ + copy_to (self, 0, 0, temp, and); /* 3 */ + copy_to (temp, 0, 0, self, xor); /* 4 */ + copy_from (temp, qwad, 0, self, xor); /* 5 */ + copy_from (self, qwad, 0, self, or); /* 6 */ + copy_to (temp, qwad, 0, self, xor); /* 7 */ + copy_to (self, 0, 0, temp, copy); /* 8 */ + copy_from (temp, qwad, qwad, self, xor); /* 9 */ + copy_to (mask, 0, 0, temp, and); /* A */ + copy_to (temp, 0, 0, self, xor); /* B */ + copy_to (temp, qwad, qwad, self, xor); /* C */ + copy_from (mask, qwad>>1, qwad>>1, mask, and); /* D */ + copy_to (mask, qwad, 0, mask, or); /* E */ + copy_to (mask, 0, qwad, mask, or); /* F */ + display (st, st->self); + + st->qwad >>= 1; + if (st->qwad == 0) /* done with this round */ + { + st->qwad = -1; + this_delay = st->delay2; + } + + return this_delay; +} + + +static int +blitspin_to_pow2(int n, Bool up) +{ + int pow2 = to_pow2 (n); + if (n == pow2) + return n; + else + return up ? pow2 : pow2 >> 1; +} + +static void * +blitspin_init (Display *d_arg, Window w_arg) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + char *bitmap_name; + + st->dpy = d_arg; + st->window = w_arg; + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + + st->fg = get_pixel_resource (st->dpy, st->xgwa.colormap, + "foreground", "Foreground"); + st->bg = get_pixel_resource (st->dpy, st->xgwa.colormap, + "background", "Background"); + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer"); + st->duration = get_integer_resource (st->dpy, "duration", "Seconds"); + if (st->delay < 0) st->delay = 0; + if (st->delay2 < 0) st->delay2 = 0; + if (st->duration < 1) st->duration = 1; + + st->start_time = time ((time_t *) 0); + + bitmap_name = get_string_resource (st->dpy, "bitmap", "Bitmap"); + if (! bitmap_name || !*bitmap_name) + bitmap_name = "(default)"; + + if (!strcasecmp (bitmap_name, "(default)") || + !strcasecmp (bitmap_name, "default")) + bitmap_name = "(screen)"; + + if (!strcasecmp (bitmap_name, "(builtin)") || + !strcasecmp (bitmap_name, "builtin")) + { + Pixmap mask = 0; + Pixmap pixmap = image_data_to_pixmap (st->dpy, st->window, + som_png, sizeof(som_png), + &st->width, &st->height, &mask); + XGCValues gcv; + GC gc; + gcv.foreground = st->bg; + gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + st->bitmap = XCreatePixmap (st->dpy, st->window, + st->xgwa.width, st->xgwa.height, + st->xgwa.depth); + XFillRectangle (st->dpy, st->bitmap, gc, 0, 0, st->width, st->height); + XSetClipMask (st->dpy, gc, mask); + XCopyArea (st->dpy, pixmap, st->bitmap, gc, 0, 0, st->width, st->height, + 0, 0); + XFreeGC (st->dpy, gc); + XFreePixmap (st->dpy, pixmap); + XFreePixmap (st->dpy, mask); + + st->scale_up = True; /* definitely. */ + st->loaded_p = True; + blitspin_init_2 (st); + } + else if (!strcasecmp (bitmap_name, "(screen)") || + !strcasecmp (bitmap_name, "screen")) + { + st->bitmap = XCreatePixmap (st->dpy, st->window, + st->xgwa.width, st->xgwa.height, + st->xgwa.depth); + st->width = st->xgwa.width; + st->height = st->xgwa.height; + st->scale_up = True; /* maybe? */ + st->load_ext_p = True; + st->img_loader = load_image_async_simple (0, st->xgwa.screen, st->window, + st->bitmap, 0, 0); + } + else + { + st->bitmap = file_to_pixmap (st->dpy, st->window, bitmap_name, + &st->width, &st->height, 0); + st->scale_up = True; /* probably? */ + blitspin_init_2 (st); + } + + return st; +} + + +static void +blitspin_init_2 (struct state *st) +{ + XGCValues gcv; + + /* make it square */ + st->size = (st->width < st->height) ? st->height : st->width; + /* round up to power of 2 */ + st->size = blitspin_to_pow2(st->size, st->scale_up); + { /* don't exceed screen size */ + int s = XScreenNumberOfScreen(st->xgwa.screen); + int w = blitspin_to_pow2(XDisplayWidth(st->dpy, s), False); + int h = blitspin_to_pow2(XDisplayHeight(st->dpy, s), False); + if (st->size > w) st->size = w; + if (st->size > h) st->size = h; + } + + if (st->self) XFreePixmap (st->dpy, st->self); + if (st->temp) XFreePixmap (st->dpy, st->temp); + if (st->mask) XFreePixmap (st->dpy, st->mask); + + st->self = XCreatePixmap (st->dpy, st->window, st->size, st->size, + st->xgwa.depth); + st->temp = XCreatePixmap (st->dpy, st->window, st->size, st->size, + st->xgwa.depth); + st->mask = XCreatePixmap (st->dpy, st->window, st->size, st->size, + st->xgwa.depth); + gcv.foreground = (st->xgwa.depth == 1 ? 1 : (~0)); + +# ifdef USE_XCOPYAREA +# define make_gc(op) \ + gcv.function=GX##op; \ + if (st->gc_##op) XFreeGC (st->dpy, st->gc_##op); \ + st->gc_##op = XCreateGC (st->dpy, st->self, GCFunction|GCForeground, &gcv) + make_gc(set); + make_gc(clear); + make_gc(copy); + make_gc(and); + make_gc(or); + make_gc(xor); +# endif /* USE_XCOPYAREA */ + + gcv.foreground = gcv.background = st->bg; + if (st->gc) XFreeGC (st->dpy, st->gc); + st->gc = XCreateGC (st->dpy, st->window, GCForeground|GCBackground, &gcv); + /* Clear st->self to the background color (not to 0, which 'clear' does.) */ + XFillRectangle (st->dpy, st->self, st->gc, 0, 0, st->size, st->size); + XSetForeground (st->dpy, st->gc, st->fg); + + XCopyArea (st->dpy, st->bitmap, st->self, st->gc, 0, 0, + st->width, st->height, + (st->size - st->width) >> 1, + (st->size - st->height) >> 1); + + st->qwad = -1; + st->first_time = 1; +} + +static void +display (struct state *st, Pixmap pixmap) +{ + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + + if (st->xgwa.width != st->last_w || + st->xgwa.height != st->last_h) + { + XClearWindow (st->dpy, st->window); + st->last_w = st->xgwa.width; + st->last_h = st->xgwa.height; + } + if (st->xgwa.depth != 1) + XCopyArea (st->dpy, pixmap, st->window, st->gc, 0, 0, st->size, st->size, + (st->xgwa.width - st->size) >> 1, + (st->xgwa.height - st->size) >> 1); + else + XCopyPlane (st->dpy, pixmap, st->window, st->gc, 0, 0, st->size, st->size, + (st->xgwa.width - st->size) >> 1, + (st->xgwa.height - st->size) >> 1, + 1); +/* + XDrawRectangle (st->dpy, st->window, st->gc, + ((st->xgwa.width - st->size) >> 1) - 1, + ((st->xgwa.height - st->size) >> 1) - 1, + st->size+2, st->size+2); +*/ +} + +static void +blitspin_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +static Bool +blitspin_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + struct state *st = (struct state *) closure; + if (screenhack_event_helper (dpy, window, event)) + { + st->start_time = 0; + return True; + } + return False; +} + +static void +blitspin_free (Display *dpy, Window window, void *closure) +{ +} + + +static const char *blitspin_defaults [] = { + ".background: black", + ".foreground: white", + ".fpsSolid: true", + "*delay: 500000", + "*delay2: 500000", + "*duration: 120", + "*bitmap: (default)", + "*geometry: 1080x1080", +#ifdef HAVE_MOBILE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec blitspin_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-delay2", ".delay2", XrmoptionSepArg, 0 }, + { "-duration", ".duration", XrmoptionSepArg, 0 }, + { "-bitmap", ".bitmap", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("BlitSpin", blitspin) diff --git a/hacks/blitspin.man b/hacks/blitspin.man new file mode 100644 index 0000000..4a221da --- /dev/null +++ b/hacks/blitspin.man @@ -0,0 +1,96 @@ +.TH XScreenSaver 1 "24-Nov-97" "X Version 11" +.SH NAME +blitspin - rotate a bitmap in an interesting way +.SH SYNOPSIS +.B blitspin +[\-display \fIhost:display.screen\fP] +[\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] +[\-mono] [\-install] [\-visual \fIvisual\fP] [\-bitmap \fIfilename\fP] +[\-delay \fIusecs\fP] [\-delay2 \fIusecs\fP] [\-duration \fIsecs\fP] +.SH DESCRIPTION +The \fIblitspin\fP program repeatedly rotates a bitmap by 90 degrees by +using logical operations: the bitmap is divided into quadrants, and the +quadrants are shifted clockwise. Then the same thing is done again with +progressively smaller quadrants, except that all sub-quadrants of a +given size are rotated in parallel. So this takes \fBO(16*log2(N))\fP +blits of size NxN, with the limitation that the image must be square, +and the size must be a power of 2. +.SH OPTIONS +.I blitspin +accepts the following options: +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-mono +If on a color display, pretend we're on a monochrome display. +.TP 8 +.B \-install +Install a private colormap for the window. +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-bitmap \fIfilename\fP +The file name of a bitmap to rotate. It need not be square: it +will be padded with the background color. If unspecified or the +string \fI(default)\fP, a builtin bitmap is used. + +If support for the \fIXPM\fP library was enabled at compile-time, +the specified file may be in \fIXPM\fP format as well as \fIXBM\fP, and +thus may be a color image. + +The \fB*bitmapFilePath\fP resource will be searched if the bitmap +name is not a fully-qualified pathname. +.TP 8 +.B \-grab\-screen +If this option is specified, then the image which is spun will be grabbed +from the portion of the screen underlying the blitspin window, or from +the system's video input, or from a random file on disk, as indicated by +the \fIgrabDesktopImages\fP, \fIgrabVideoFrames\fP, +and \fIchooseRandomImages\fP options in the \fI~/.xscreensaver\fP file; +see +.BR xscreensaver-demo (1) +for more details. +.TP 8 +.B \-delay \fImicroseconds\fP +How long to delay between steps of the rotation process, in microseconds. +Default is 500000, one-half second. +.TP 8 +.B \-duration \fIseconds\fP +How long to run before loading a new image. Default 120 seconds. +.TP 8 +.B \-delay2 \fImicroseconds\fP +How long to delay between each 90-degree rotation, in microseconds. +Default is 500000, one-half second. +.B DISPLAY +to get the default host and display number. +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1), +.BR xscreensaver-demo (1), +.BR xscreensaver-getimage (1) +.SH COPYRIGHT +Copyright \(co 1992, 1993, 1997, 2001 by Jamie Zawinski. +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that copyright +notice and this permission notice appear in supporting documentation. No +representations are made about the suitability of this software for any +purpose. It is provided "as is" without express or implied warranty. +.SH AUTHOR +Jamie Zawinski , 17-aug-92. + +Based on SmallTalk code which appeared in the August 1981 issue of Byte +magazine. diff --git a/hacks/bouboule.c b/hacks/bouboule.c new file mode 100644 index 0000000..1ac0425 --- /dev/null +++ b/hacks/bouboule.c @@ -0,0 +1,858 @@ +/* -*- Mode: C; tab-width: 4 -*- + Ported from xlockmore 4.03a12 to be a standalone program and thus usable + with xscreensaver by Jamie Zawinski on 15-May-97. + + Original copyright notice from xlock.c: + + * Copyright (c) 1988-91 by Patrick J. Naughton. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation. + * + * This file is provided AS IS with no warranties of any kind. The author + * shall have no liability with respect to the infringement of copyrights, + * trade secrets or any patents by this file or any part thereof. In no + * event will the author be liable for any lost revenue or profits or + * other special, indirect and consequential damages. + */ + +#if 0 +static const char sccsid[] = "@(#)bouboule.c 4.00 97/01/01 xlockmore"; +#endif + +/*- + * bouboule.c (bouboule mode for xlockmore) + * + * Sort of starfield for xlockmore. I found that making a starfield for + * a 3D engine and thought it could be a nice lock mode. For a real starfield, + * I only scale the sort of sphere you see to the whole sky and clip the stars + * to the camera screen. + * + * Code Copyright 1996 by Jeremie PETIT (jeremie_petit@geocities.com) + * + * Use: batchcount is the number of stars. + * cycles is the maximum size for a star + * + * 15-May-97: jwz@jwz.org: turned into a standalone program. + * 04-Sep-96: Added 3d support (Henrik Theiling, theiling@coli-uni-sb.de) + * 20-Feb-96: Added tests so that already malloced objects are not + * malloced twice, thanks to the report from + * 01-Feb-96: Patched by Jouk Jansen for VMS + * Patched by for TrueColor displays + * 30-Jan-96: Wrote all that I wanted to. + * + * DONE: Build up a XArc list and Draw everything once with XFillArcs + * That idea came from looking at swarm code. + * DONE: Add an old arcs list for erasing. + * DONE: Make center of starfield SinVariable. + * DONE: Add some random in the sinvary() function. + * DONE: check time for erasing the stars with the two methods and use the + * better one. Note that sometimes the time difference between + * beginning of erasing and its end is negative! I check this, and + * do not use this result when it occurs. If all values are negative, + * the erasing will continue being done in the currently tested mode. + * DONE: Allow stars size customization. + * DONE: Make sizey be no less than half sizex or no bigger than twice sizex. + * + * IDEA: A simple check can be performed to know which stars are "behind" + * and which are "in front". So is possible to very simply change + * the drawing mode for these two sorts of stars. BUT: this would lead + * to a rewrite of the XArc list code because drawing should be done + * in two steps: "behind" stars then "in front" stars. Also, what could + * be the difference between the rendering of these two types of stars? + * IDEA: Calculate the distance of each star to the "viewer" and render the + * star accordingly to this distance. Same remarks as for previous + * ideas can be pointed out. This would even lead to reget the old stars + * drawing code, that has been replaced by the XFillArcs. On another + * hand, this would allow particular stars (own color, shape...), as + * far as they would be individually drawn. One should be careful to + * draw them according to their distance, that is not drawing a far + * star after a close one. + */ + +#ifdef STANDALONE +# define DEFAULTS "*count: 100 \n" \ + "*size: 15 \n" \ + "*delay: 20000 \n" \ + "*ncolors: 64 \n" \ + "*use3d: True \n" \ + "*delta3d: 1.5 \n" \ + "*right3d: red \n" \ + "*left3d: blue \n" \ + "*both3d: magenta \n" \ + "*none3d: black \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True \n" + +# define SMOOTH_COLORS +# define release_bouboule 0 +# define bouboule_handle_event 0 +# include "xlockmore.h" /* from the xscreensaver distribution */ +#else /* !STANDALONE */ +# include "xlock.h" /* from the xlockmore distribution */ +# define ENTRYPOINT /**/ +#endif /* !STANDALONE */ + +ENTRYPOINT ModeSpecOpt bouboule_opts = { + 0, NULL, 0, NULL, NULL }; + +#define USEOLDXARCS 1 /* If 1, we use old xarcs list for erasing. + * else we just roughly erase the window. + * This mainly depends on the number of stars, + * because when they are many, it is faster to + * erase the whole window than to erase each star + */ + +#if HAVE_GETTIMEOFDAY +#define ADAPT_ERASE 1 /* If 1, then we try ADAPT_CHECKS black XFillArcs, + * and after, ADAPT_CHECKS XFillRectangle. + * We check which method seems better, knowing that + * XFillArcs is generally visually better. So we + * consider that XFillArcs is still better if its time + * is about XFillRectangle * ADAPT_ARC_PREFERED + * We need gettimeofday + * for this... Does it exist on other systems ? Do we + * have to use another function for others ? + * This value overrides USEOLDXARCS. + */ + +#ifdef USE_XVMSUTILS +# if 0 +# include "../xvmsutils/unix_time.h" +# else +# include +# endif +#endif + +#include + +#define ADAPT_CHECKS 50 +#define ADAPT_ARC_PREFERED 150 /* Maybe the value that is the most important + * for adapting to a system */ +#endif + +#define dtor(x) (((x) * M_PI) / 180.0) /* Degrees to radians */ + +#define MINSTARS 1 +#define MINSIZE 1 +/* jwz: I think slower color changes look better */ +#define COLOR_CHANGES 50 /* How often we change colors (1 = always) + * This value should be tuned accordingly to + * the number of stars */ +#define MAX_SIZEX_SIZEY 2. /* This controls whether the sphere can be very + * very large and have a small height (or the + * opposite) or no. */ + +#define THETACANRAND 80 /* percentage of changes for the speed of + * change of the 3 theta values */ +#define SIZECANRAND 80 /* percentage of changes for the speed of + * change of the sizex and sizey values */ +#define POSCANRAND 80 /* percentage of changes for the speed of + * change of the x and y values */ +/* Note that these XXXCANRAND values can be 0, that is no rand acceleration * + variation. */ + +#define VARRANDALPHA (NRAND((int) (M_PI * 1000.0))/1000.0) +#define VARRANDSTEP (M_PI/(NRAND(100)+100.0)) +#define VARRANDMIN (-70.0) +#define VARRANDMAX 70.0 + +#define MINZVAL 100 /* stars can come this close */ +#define SCREENZ 2000 /* this is where the screen is */ +#define MAXZVAL 10000 /* stars can go this far away */ + +#define GETZDIFF(z) ((MI_DELTA3D(mi))*20.0*(1.0-(SCREENZ)/(z+1000))) +#define MAXDIFF MAX(-GETZDIFF(MINZVAL),GETZDIFF(MAXZVAL)) + +/* These values are the variation parameters of the acceleration variation * + of the SinVariables that are randomized. */ + +/******************************/ +typedef struct SinVariableStruct +/******************************/ +{ + double alpha; /* + * Alpha is the current state of the sinvariable + * alpha should be initialized to a value between + * 0.0 and 2 * M_PI + */ + double step; /* + * Speed of evolution of alpha. It should be a reasonable + * fraction of 2 * M_PI. This value directly influence + * the variable speed of variation. + */ + double minimum; /* Minimum value for the variable */ + double maximum; /* Maximum value for the variable */ + double value; /* Current value */ + int mayrand; /* Flag for knowing whether some randomization can be + * applied to the variable */ + struct SinVariableStruct *varrand; /* Evolving Variable: the variation of + * alpha */ +} SinVariable; + +/***********************/ +typedef struct StarStruct +/***********************/ +{ + double x, y, z; /* Position of the star */ + short size; /* Try to guess */ +} Star; + +/****************************/ +typedef struct StarFieldStruct +/****************************/ +{ + short width, height; /* width and height of the starfield window */ + short max_star_size; /* Maximum radius for stars. stars radius will + * vary from 1 to MAX_STAR_SIZE */ + SinVariable x; /* Evolving variables: */ + SinVariable y; /* Center of the field on the screen */ + SinVariable z; + SinVariable sizex; /* Evolving variable: half width of the field */ + SinVariable sizey; /* Evolving variable: half height of the field */ + SinVariable thetax; /* Evolving Variables: */ + SinVariable thetay; /* rotation angles of the starfield */ + SinVariable thetaz; /* around x, y and z local axis */ + Star *star; /* List of stars */ + XArc *xarc; /* Current List of arcs */ + XArc *xarcleft; /* additional list for the left arcs */ +#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) + XArc *oldxarc; /* Old list of arcs */ + XArc *oldxarcleft; +#endif + unsigned long color; /* Current color of the starfield */ + int colorp; /* Pointer to color of the starfield */ + int NbStars; /* Number of stars */ + short colorchange; /* Counter for the color change */ +#if (ADAPT_ERASE == 1) + short hasbeenchecked; + long rect_time; + long xarc_time; +#endif +} StarField; + +static StarField *starfield = NULL; + +/*********/ +static void +sinvary(SinVariable * v) +/*********/ + +{ + v->value = v->minimum + + (v->maximum - v->minimum) * (sin(v->alpha) + 1.0) / 2.0; + + if (v->mayrand == 0) + v->alpha += v->step; + else { + int vaval = NRAND(100); + + if (vaval <= v->mayrand) + sinvary(v->varrand); + v->alpha += (100.0 + (v->varrand->value)) * v->step / 100.0; + } + + if (v->alpha > 2 * M_PI) + v->alpha -= 2 * M_PI; +} + +/*************************************************/ +static void +sininit(SinVariable * v, + double alpha, double step, double minimum, double maximum, + short int mayrand) +{ + v->alpha = alpha; + v->step = step; + v->minimum = minimum; + v->maximum = maximum; + v->mayrand = mayrand; + if (mayrand != 0) { + if (v->varrand == NULL) + v->varrand = (SinVariable *) calloc(1, sizeof (SinVariable)); + sininit(v->varrand, + VARRANDALPHA, + VARRANDSTEP, + VARRANDMIN, + VARRANDMAX, + 0); + sinvary(v->varrand); + } + /* We calculate the values at least once for initialization */ + sinvary(v); +} + +static void +sinfree(SinVariable * point) +{ + SinVariable *temp, *next; + + next = point->varrand; + while (next) { + temp = next; + next = temp->varrand; + (void) free((void *) temp); + } +} + + +/***************/ +ENTRYPOINT void +init_bouboule(ModeInfo * mi) +/***************/ + +/*- + * The stars init part was first inspirated from the net3d game starfield + * code. But net3d starfield is not really 3d starfield, and I needed real 3d, + * so only remains the net3d starfield initialization main idea, that is + * the stars distribution on a sphere (theta and omega computing) + */ +{ + StarField *sp; + int size = MI_SIZE(mi); + int i; + double theta, omega; + + if (MI_WIDTH(mi) > 2560) size *= 2; /* Retina displays */ + + MI_INIT (mi, starfield); + sp = &starfield[MI_SCREEN(mi)]; + + sp->width = MI_WIN_WIDTH(mi); + sp->height = MI_WIN_HEIGHT(mi); + + /* use the right `black' pixel values: */ + if (MI_WIN_IS_INSTALL(mi) && MI_WIN_IS_USE3D(mi)) { + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_NONE_COLOR(mi)); + XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + 0, 0, sp->width, sp->height); + } else + XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); + + if (size < -MINSIZE) + sp->max_star_size = NRAND(-size - MINSIZE + 1) + MINSIZE; + else if (size < MINSIZE) + sp->max_star_size = MINSIZE; + else + sp->max_star_size = size; + + sp->NbStars = MI_BATCHCOUNT(mi); + if (sp->NbStars < -MINSTARS) { + if (sp->star) { + (void) free((void *) sp->star); + sp->star = NULL; + } + if (sp->xarc) { + (void) free((void *) sp->xarc); + sp->xarc = NULL; + } + if (sp->xarcleft) { + (void) free((void *) sp->xarcleft); + sp->xarcleft = NULL; + } +#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) + if (sp->oldxarc) { + (void) free((void *) sp->oldxarc); + sp->oldxarc = NULL; + } + if (sp->oldxarcleft) { + (void) free((void *) sp->oldxarcleft); + sp->oldxarcleft = NULL; + } +#endif + sp->NbStars = NRAND(-sp->NbStars - MINSTARS + 1) + MINSTARS; + } else if (sp->NbStars < MINSTARS) + sp->NbStars = MINSTARS; + + /* We get memory for lists of objects */ + if (sp->star == NULL) + sp->star = (Star *) malloc(sp->NbStars * sizeof (Star)); + if (sp->xarc == NULL) + sp->xarc = (XArc *) malloc(sp->NbStars * sizeof (XArc)); + if (MI_WIN_IS_USE3D(mi) && sp->xarcleft == NULL) + sp->xarcleft = (XArc *) malloc(sp->NbStars * sizeof (XArc)); +#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) + if (sp->oldxarc == NULL) + sp->oldxarc = (XArc *) malloc(sp->NbStars * sizeof (XArc)); + if (MI_WIN_IS_USE3D(mi) && sp->oldxarcleft == NULL) + sp->oldxarcleft = (XArc *) malloc(sp->NbStars * sizeof (XArc)); +#endif + + { + /* We initialize evolving variables */ + sininit(&sp->x, + NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0), + ((double) sp->width) / 4.0, + 3.0 * ((double) sp->width) / 4.0, + POSCANRAND); + sininit(&sp->y, + NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0), + ((double) sp->height) / 4.0, + 3.0 * ((double) sp->height) / 4.0, + POSCANRAND); + + /* for z, we have to ensure that the bouboule does not get behind */ + /* the eyes of the viewer. His/Her eyes are at 0. Because the */ + /* bouboule uses the x-radius for the z-radius, too, we have to */ + /* use the x-values. */ + sininit(&sp->z, + NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0), + ((double) sp->width / 2.0 + MINZVAL), + ((double) sp->width / 2.0 + MAXZVAL), + POSCANRAND); + + + sininit(&sp->sizex, + NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0), + MIN(((double) sp->width) - sp->x.value, + sp->x.value) / 5.0, + MIN(((double) sp->width) - sp->x.value, + sp->x.value), + SIZECANRAND); + + sininit(&sp->sizey, + NRAND(3142) / 1000.0, M_PI / (NRAND(100) + 100.0), + MAX(sp->sizex.value / MAX_SIZEX_SIZEY, + sp->sizey.maximum / 5.0), + MIN(sp->sizex.value * MAX_SIZEX_SIZEY, + MIN(((double) sp->height) - + sp->y.value, + sp->y.value)), + SIZECANRAND); + + sininit(&sp->thetax, + NRAND(3142) / 1000.0, M_PI / (NRAND(200) + 200.0), + -M_PI, M_PI, + THETACANRAND); + sininit(&sp->thetay, + NRAND(3142) / 1000.0, M_PI / (NRAND(200) + 200.0), + -M_PI, M_PI, + THETACANRAND); + sininit(&sp->thetaz, + NRAND(3142) / 1000.0, M_PI / (NRAND(400) + 400.0), + -M_PI, M_PI, + THETACANRAND); + } + for (i = 0; i < sp->NbStars; i++) { + Star *star; + XArc *arc = NULL, *arcleft = NULL; +#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) + XArc *oarc = NULL, *oarcleft = NULL; +#endif + + star = &(sp->star[i]); + arc = &(sp->xarc[i]); + if (MI_WIN_IS_USE3D(mi)) + arcleft = &(sp->xarcleft[i]); +#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) + oarc = &(sp->oldxarc[i]); + if (MI_WIN_IS_USE3D(mi)) + oarcleft = &(sp->oldxarcleft[i]); +#endif + /* Elevation and bearing of the star */ + theta = dtor((NRAND(1800)) / 10.0 - 90.0); + omega = dtor((NRAND(3600)) / 10.0 - 180.0); + + /* Stars coordinates in a 3D space */ + star->x = cos(theta) * sin(omega); + star->y = sin(omega) * sin(theta); + star->z = cos(omega); + + /* We set the stars size */ + star->size = NRAND(2 * sp->max_star_size); + if (star->size < sp->max_star_size) + star->size = 0; + else + star->size -= sp->max_star_size; + + /* We set default values for the XArc lists elements */ + arc->x = arc->y = 0; + if (MI_WIN_IS_USE3D(mi)) { + arcleft->x = arcleft->y = 0; + } +#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) + oarc->x = oarc->y = 0; + if (MI_WIN_IS_USE3D(mi)) { + oarcleft->x = oarcleft->y = 0; + } +#endif + arc->width = 2 + star->size; + arc->height = 2 + star->size; + if (MI_WIN_IS_USE3D(mi)) { + arcleft->width = 2 + star->size; + arcleft->height = 2 + star->size; + } +#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) + oarc->width = 2 + star->size; + oarc->height = 2 + star->size; + if (MI_WIN_IS_USE3D(mi)) { + oarcleft->width = 2 + star->size; + oarcleft->height = 2 + star->size; + } +#endif + + arc->angle1 = 0; + arc->angle2 = 360 * 64; + if (MI_WIN_IS_USE3D(mi)) { + arcleft->angle1 = 0; + arcleft->angle2 = 360 * 64; + } +#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) + oarc->angle1 = 0; + oarc->angle2 = 360 * 64; /* ie. we draw whole disks: + * from 0 to 360 degrees */ + if (MI_WIN_IS_USE3D(mi)) { + oarcleft->angle1 = 0; + oarcleft->angle2 = 360 * 64; + } +#endif + } + + if (MI_NPIXELS(mi) > 2) + sp->colorp = NRAND(MI_NPIXELS(mi)); + /* We set up the starfield color */ + if (!MI_WIN_IS_USE3D(mi) && MI_NPIXELS(mi) > 2) + sp->color = MI_PIXEL(mi, sp->colorp); + else + sp->color = MI_WIN_WHITE_PIXEL(mi); + +#if (ADAPT_ERASE == 1) + /* We initialize the adaptation code for screen erasing */ + sp->hasbeenchecked = ADAPT_CHECKS * 2; + sp->rect_time = 0; + sp->xarc_time = 0; +#endif +} + +/****************/ +ENTRYPOINT void +draw_bouboule(ModeInfo * mi) +/****************/ + +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + StarField *sp = &starfield[MI_SCREEN(mi)]; + int i, diff = 0; + double CX, CY, CZ, SX, SY, SZ; + Star *star; + XArc *arc = NULL, *arcleft = NULL; + +#ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */ + XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); +#endif + +#if (ADAPT_ERASE == 1) + struct timeval tv1; + struct timeval tv2; + +#endif + +#if ((USEOLDXARCS == 0) || (ADAPT_ERASE == 1)) + short x_1, y_1, x_2, y_2; + + /* bounding rectangle around the old starfield, + * for erasing with the smallest rectangle + * instead of filling the whole screen */ + int maxdiff = 0; /* maximal distance between left and right */ + + /* star in 3d mode, otherwise 0 */ +#endif + +#if ((USEOLDXARCS == 0) || (ADAPT_ERASE == 1)) + if (MI_WIN_IS_USE3D(mi)) { + maxdiff = (int) MAXDIFF; + } + x_1 = (int) sp->x.value - (int) sp->sizex.value - + sp->max_star_size - maxdiff; + y_1 = (int) sp->y.value - (int) sp->sizey.value - + sp->max_star_size; + x_2 = 2 * ((int) sp->sizex.value + sp->max_star_size + maxdiff); + y_2 = 2 * ((int) sp->sizey.value + sp->max_star_size); +#endif + /* We make variables vary. */ + sinvary(&sp->thetax); + sinvary(&sp->thetay); + sinvary(&sp->thetaz); + + sinvary(&sp->x); + sinvary(&sp->y); + if (MI_WIN_IS_USE3D(mi)) + sinvary(&sp->z); + + /* A little trick to prevent the bouboule from being + * bigger than the screen */ + sp->sizex.maximum = + MIN(((double) sp->width) - sp->x.value, + sp->x.value); + sp->sizex.minimum = sp->sizex.maximum / 3.0; + + /* Another trick to make the ball not too flat */ + sp->sizey.minimum = + MAX(sp->sizex.value / MAX_SIZEX_SIZEY, + sp->sizey.maximum / 3.0); + sp->sizey.maximum = + MIN(sp->sizex.value * MAX_SIZEX_SIZEY, + MIN(((double) sp->height) - sp->y.value, + sp->y.value)); + + sinvary(&sp->sizex); + sinvary(&sp->sizey); + + /* + * We calculate the rotation matrix values. We just make the + * rotation on the fly, without using a matrix. + * Star positions are recorded as unit vectors pointing in various + * directions. We just make them all rotate. + */ + CX = cos(sp->thetax.value); + SX = sin(sp->thetax.value); + CY = cos(sp->thetay.value); + SY = sin(sp->thetay.value); + CZ = cos(sp->thetaz.value); + SZ = sin(sp->thetaz.value); + + for (i = 0; i < sp->NbStars; i++) { + star = &(sp->star[i]); + arc = &(sp->xarc[i]); + if (MI_WIN_IS_USE3D(mi)) { + arcleft = &(sp->xarcleft[i]); + /* to help the eyes, the starfield is always as wide as */ + /* deep, so .sizex.value can be used. */ + diff = (int) GETZDIFF(sp->sizex.value * + ((SY * CX) * star->x + (SX) * star->y + + (CX * CY) * star->z) + sp->z.value); + } + arc->x = (short) ((sp->sizex.value * + ((CY * CZ - SX * SY * SZ) * star->x + + (-CX * SZ) * star->y + + (SY * CZ + SZ * SX * CY) * star->z) + + sp->x.value)); + arc->y = (short) ((sp->sizey.value * + ((CY * SZ + SX * SY * CZ) * star->x + + (CX * CZ) * star->y + + (SY * SZ - SX * CY * CZ) * star->z) + + sp->y.value)); + + if (MI_WIN_IS_USE3D(mi)) { + arcleft->x = (short) ((sp->sizex.value * + ((CY * CZ - SX * SY * SZ) * star->x + + (-CX * SZ) * star->y + + (SY * CZ + SZ * SX * CY) * star->z) + + sp->x.value)); + arcleft->y = (short) ((sp->sizey.value * + ((CY * SZ + SX * SY * CZ) * star->x + + (CX * CZ) * star->y + + (SY * SZ - SX * CY * CZ) * star->z) + + sp->y.value)); + arc->x += diff; + arcleft->x -= diff; + } + if (star->size != 0) { + arc->x -= star->size; + arc->y -= star->size; + if (MI_WIN_IS_USE3D(mi)) { + arcleft->x -= star->size; + arcleft->y -= star->size; + } + } + } + + /* First, we erase the previous starfield */ + if (MI_WIN_IS_INSTALL(mi) && MI_WIN_IS_USE3D(mi)) + XSetForeground(display, gc, MI_NONE_COLOR(mi)); + else + XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi)); + +#if (ADAPT_ERASE == 1) + if (sp->hasbeenchecked == 0) { + /* We just calculate which method is the faster and eventually free + * the oldxarc list */ + if (sp->xarc_time > + ADAPT_ARC_PREFERED * sp->rect_time) { + sp->hasbeenchecked = -2; /* XFillRectangle mode */ + (void) free((void *) sp->oldxarc); + sp->oldxarc = NULL; + if (MI_WIN_IS_USE3D(mi)) { + (void) free((void *) sp->oldxarcleft); + sp->oldxarcleft = NULL; + } + } else { + sp->hasbeenchecked = -1; /* XFillArcs mode */ + } + } + if (sp->hasbeenchecked == -2) { + /* Erasing is done with XFillRectangle */ + XFillRectangle(display, window, gc, + x_1, y_1, x_2, y_2); + } else if (sp->hasbeenchecked == -1) { + /* Erasing is done with XFillArcs */ + XFillArcs(display, window, gc, + sp->oldxarc, sp->NbStars); + if (MI_WIN_IS_USE3D(mi)) + XFillArcs(display, window, gc, + sp->oldxarcleft, sp->NbStars); + } else { + long usec; + + if (sp->hasbeenchecked > ADAPT_CHECKS) { +#ifdef GETTIMEOFDAY_TWO_ARGS + (void) gettimeofday(&tv1, NULL); +#else + (void) gettimeofday(&tv1); +#endif + XFillRectangle(display, window, gc, + x_1, y_1, x_2, y_2); +#ifdef GETTIMEOFDAY_TWO_ARGS + (void) gettimeofday(&tv2, NULL); +#else + (void) gettimeofday(&tv2); +#endif + usec = (tv2.tv_sec - tv1.tv_sec) * 1000000; + if (usec + tv2.tv_usec - tv1.tv_usec > 0) { + sp->rect_time += usec + tv2.tv_usec - tv1.tv_usec; + sp->hasbeenchecked--; + } + } else { +#ifdef GETTIMEOFDAY_TWO_ARGS + (void) gettimeofday(&tv1, NULL); +#else + (void) gettimeofday(&tv1); +#endif + XFillArcs(display, window, gc, + sp->oldxarc, sp->NbStars); + if (MI_WIN_IS_USE3D(mi)) + XFillArcs(display, window, gc, + sp->oldxarcleft, sp->NbStars); +#ifdef GETTIMEOFDAY_TWO_ARGS + (void) gettimeofday(&tv2, NULL); +#else + (void) gettimeofday(&tv2); +#endif + usec = (tv2.tv_sec - tv1.tv_sec) * 1000000; + if (usec + tv2.tv_usec - tv1.tv_usec > 0) { + sp->xarc_time += usec + tv2.tv_usec - tv1.tv_usec; + sp->hasbeenchecked--; + } + } + } +#else +#if (USEOLDXARCS == 1) + XFillArcs(display, window, gc, + sp->oldxarc, sp->NbStars); + if (MI_WIN_IS_USE3D(mi)) + XFillArcs(display, window, gc, + sp->oldxarcleft, sp->NbStars); +#else + XFillRectangle(display, window, gc, + x_1, y_1, x_2, y_2); +#endif +#endif + + /* Then we draw the new one */ + if (MI_WIN_IS_USE3D(mi)) { + if (MI_WIN_IS_INSTALL(mi)) + XSetFunction(display, gc, GXor); + XSetForeground(display, gc, MI_RIGHT_COLOR(mi)); + XFillArcs(display, window, gc, sp->xarc, sp->NbStars); + XSetForeground(display, gc, MI_LEFT_COLOR(mi)); + XFillArcs(display, window, gc, sp->xarcleft, sp->NbStars); + if (MI_WIN_IS_INSTALL(mi)) + XSetFunction(display, gc, GXcopy); + } else { + XSetForeground(display, gc, sp->color); + XFillArcs(display, window, gc, sp->xarc, sp->NbStars); + } + +#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) +#if (ADAPT_ERASE == 1) + if (sp->hasbeenchecked >= -1) { + arc = sp->xarc; + sp->xarc = sp->oldxarc; + sp->oldxarc = arc; + if (MI_WIN_IS_USE3D(mi)) { + arcleft = sp->xarcleft; + sp->xarcleft = sp->oldxarcleft; + sp->oldxarcleft = arcleft; + } + } +#else + arc = sp->xarc; + sp->xarc = sp->oldxarc; + sp->oldxarc = arc; + if (MI_WIN_IS_USE3D(mi)) { + arcleft = sp->xarcleft; + sp->xarcleft = sp->oldxarcleft; + sp->oldxarcleft = arcleft; + } +#endif +#endif + + /* We set up the color for the next drawing */ + if (!MI_WIN_IS_USE3D(mi) && MI_NPIXELS(mi) > 2 && + (++sp->colorchange >= COLOR_CHANGES)) { + sp->colorchange = 0; + if (++sp->colorp >= MI_NPIXELS(mi)) + sp->colorp = 0; + sp->color = MI_PIXEL(mi, sp->colorp); + } +} + +ENTRYPOINT void +free_bouboule(ModeInfo * mi) +{ + StarField *sp = &starfield[MI_SCREEN(mi)]; + + if (sp->star) + (void) free((void *) sp->star); + if (sp->xarc) + (void) free((void *) sp->xarc); + if (sp->xarcleft) + (void) free((void *) sp->xarcleft); +#if ((USEOLDXARCS == 1) || (ADAPT_ERASE == 1)) + if (sp->oldxarc) + (void) free((void *) sp->oldxarc); + if (sp->oldxarcleft) + (void) free((void *) sp->oldxarcleft); +#endif + sinfree(&(sp->x)); + sinfree(&(sp->y)); + sinfree(&(sp->z)); + sinfree(&(sp->sizex)); + sinfree(&(sp->sizey)); + sinfree(&(sp->thetax)); + sinfree(&(sp->thetay)); + sinfree(&(sp->thetaz)); +} + +ENTRYPOINT void +reshape_bouboule(ModeInfo * mi, int width, int height) +{ + StarField *sp = &starfield[MI_SCREEN(mi)]; + sp->width = width; + sp->height = height; + sininit(&sp->x, + sp->x.alpha, sp->x.step, + ((double) sp->width) / 4.0, + 3.0 * ((double) sp->width) / 4.0, + POSCANRAND); + sininit(&sp->y, + sp->y.alpha, sp->y.step, + ((double) sp->height) / 4.0, + 3.0 * ((double) sp->height) / 4.0, + POSCANRAND); +} + +#ifndef STANDALONE +ENTRYPOINT void +refresh_bouboule(ModeInfo * mi) +{ + /* Do nothing, it will refresh by itself */ +} +#endif + +XSCREENSAVER_MODULE ("Bouboule", bouboule) diff --git a/hacks/bouboule.man b/hacks/bouboule.man new file mode 100644 index 0000000..259490f --- /dev/null +++ b/hacks/bouboule.man @@ -0,0 +1,80 @@ +.TH XScreenSaver 1 "15-May-97" "X Version 11" +.SH NAME +bouboule - draws spinning 3D blobs +.SH SYNOPSIS +.B bouboule +[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install] [\-visual \fIvisual\fP] [\-ncolors \fIinteger\fP] [\-delay \fImicroseconds\fP] [\-cycles \fIinteger\fP] [\-count \fIinteger\fP] [\-3d] + +[\-fps] +.SH DESCRIPTION +The \fIbouboule\fP program draws spinning 3D blobs. +.SH OPTIONS +.I bouboule +accepts the following options: +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-mono +If on a color display, pretend we're on a monochrome display. +.TP 8 +.B \-install +Install a private colormap for the window. +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-ncolors \fIinteger\fP +How many colors should be used (if possible). Default 64. +The colors used cycle through the hue, making N stops around +the color wheel. +.TP 8 +.B \-cycles \fIinteger\fP + +.TP 8 +.B \-count \fIinteger\fP + +.TP 8 +.B \-3d +Do red/blue 3d separations (for 3d glasses.) + +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1), +.BR xlock (1) +.SH COPYRIGHT +Copyright \(co 1996 by Jeremie Petit. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. + +.SH AUTHOR +Jeremie Petit , 1996. + +3D support by Henrik Theiling , 04-Sep-96. + +VMS support by Jouk Jansen , 01-Feb-96. + +TrueColor support by David Bagley , 01-Feb-96. + +Ability to run standalone or with \fIxscreensaver\fP added by +Jamie Zawinski , 15-May-97. diff --git a/hacks/boxfit.c b/hacks/boxfit.c new file mode 100644 index 0000000..1b1d0d7 --- /dev/null +++ b/hacks/boxfit.c @@ -0,0 +1,561 @@ +/* xscreensaver, Copyright (c) 2005-2014 Jamie Zawinski + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * Boxfit -- fills space with a gradient of growing boxes or circles. + * + * Written by jwz, 21-Feb-2005. + * + * Inspired by http://www.levitated.net/daily/levBoxFitting.html + */ + +#include "screenhack.h" +#include +#include "ximage-loader.h" + +#define ALIVE 1 +#define CHANGED 2 +#define UNDEAD 4 + +typedef struct { + unsigned long fill_color; + short x, y, w, h; + char flags; +} box; + +typedef struct { + Display *dpy; + Window window; + XWindowAttributes xgwa; + GC gc; + unsigned long fg_color, bg_color; + int border_size; + int spacing; + int inc; + + int mode; + Bool circles_p; + Bool growing_p; + Bool color_horiz_p; + + int box_count; + int boxes_size; + int nboxes; + box *boxes; + + XImage *image; + int ncolors; + XColor *colors; + int delay; + int countdown; + + Bool done_once; + async_load_state *img_loader; + Pixmap loading_pixmap; + +} state; + + +static void +reset_boxes (state *st) +{ + st->nboxes = 0; + st->growing_p = True; + st->color_horiz_p = random() & 1; + + if (st->done_once && st->colors) + free_colors (st->xgwa.screen, st->xgwa.colormap, st->colors, st->ncolors); + + if (!st->done_once) + { + char *s = get_string_resource (st->dpy, "mode", "Mode"); + if (!s || !*s || !strcasecmp (s, "random")) + st->mode = -1; + else if (!strcasecmp (s, "squares") || !strcasecmp (s, "square")) + st->mode = 0; + else if (!strcasecmp (s, "circles") || !strcasecmp (s, "circle")) + st->mode = 1; + else + { + fprintf (stderr, + "%s: mode must be random, squares, or circles, not '%s'\n", + progname, s); + exit (1); + } + } + + if (st->mode == -1) + st->circles_p = random() & 1; + else + st->circles_p = (st->mode == 1); + + st->done_once = True; + + if (st->image || get_boolean_resource (st->dpy, "grab", "Boolean")) + { + if (st->image) XDestroyImage (st->image); + st->image = 0; + + if (st->loading_pixmap) abort(); + if (st->img_loader) abort(); + if (!get_boolean_resource (st->dpy, "peek", "Boolean")) + st->loading_pixmap = XCreatePixmap (st->dpy, st->window, + st->xgwa.width, st->xgwa.height, + st->xgwa.depth); + + XClearWindow (st->dpy, st->window); + st->img_loader = load_image_async_simple (0, st->xgwa.screen, + st->window, + (st->loading_pixmap + ? st->loading_pixmap + : st->window), + 0, 0); + } + else + { + st->ncolors = get_integer_resource (st->dpy, "colors", "Colors"); /* re-get */ + if (st->ncolors < 1) st->ncolors = 1; + make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + st->colors, &st->ncolors, True, 0, False); + if (st->ncolors < 1) abort(); + XClearWindow (st->dpy, st->window); + } +} + + +static void +reshape_boxes (state *st) +{ + int i; + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + for (i = 0; i < st->nboxes; i++) + { + box *b = &st->boxes[i]; + b->flags |= CHANGED; + } +} + +static void * +boxfit_init (Display *dpy, Window window) +{ + XGCValues gcv; + state *st = (state *) calloc (1, sizeof (*st)); + + st->dpy = dpy; + st->window = window; + st->delay = get_integer_resource (dpy, "delay", "Integer"); + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); +/* XSelectInput (dpy, window, st->xgwa.your_event_mask | ExposureMask);*/ + + if (! get_boolean_resource (dpy, "grab", "Boolean")) + { + st->ncolors = get_integer_resource (dpy, "colors", "Colors"); + if (st->ncolors < 1) st->ncolors = 1; + st->colors = (XColor *) malloc (sizeof(XColor) * st->ncolors); + } + + st->inc = get_integer_resource (dpy, "growBy", "GrowBy"); + st->spacing = get_integer_resource (dpy, "spacing", "Spacing"); + st->border_size = get_integer_resource (dpy, "borderSize", "BorderSize"); + st->fg_color = get_pixel_resource (st->dpy, st->xgwa.colormap, + "foreground", "Foreground"); + st->bg_color = get_pixel_resource (st->dpy, st->xgwa.colormap, + "background", "Background"); + if (st->inc < 1) st->inc = 1; + if (st->border_size < 0) st->border_size = 0; + + gcv.line_width = st->border_size; + gcv.background = st->bg_color; + st->gc = XCreateGC (st->dpy, st->window, GCBackground|GCLineWidth, &gcv); + + st->box_count = get_integer_resource (dpy, "boxCount", "BoxCount"); + if (st->box_count < 1) st->box_count = 1; + + st->nboxes = 0; + st->boxes_size = st->box_count * 2; + st->boxes = (box *) calloc (st->boxes_size, sizeof(*st->boxes)); + + reset_boxes (st); + + reshape_boxes (st); + return st; +} + + + +static Bool +boxes_overlap_p (box *a, box *b, int pad) +{ + /* Two rectangles overlap if the max of the tops is less than the + min of the bottoms and the max of the lefts is less than the min + of the rights. + */ +# undef MAX +# undef MIN +# define MAX(A,B) ((A)>(B)?(A):(B)) +# define MIN(A,B) ((A)<(B)?(A):(B)) + + int maxleft = MAX(a->x - pad, b->x); + int maxtop = MAX(a->y - pad, b->y); + int minright = MIN(a->x + a->w + pad + pad - 1, b->x + b->w); + int minbot = MIN(a->y + a->h + pad + pad - 1, b->y + b->h); + return (maxtop < minbot && maxleft < minright); +} + + +static Bool +circles_overlap_p (box *a, box *b, int pad) +{ + int ar = a->w/2; /* radius */ + int br = b->w/2; + int ax = a->x + ar; /* center */ + int ay = a->y + ar; + int bx = b->x + br; + int by = b->y + br; + int d2 = (((bx - ax) * (bx - ax)) + /* distance between centers squared */ + ((by - ay) * (by - ay))); + int r2 = ((ar + br + pad) * /* sum of radii squared */ + (ar + br + pad)); + return (d2 < r2); +} + + +static Bool +box_collides_p (state *st, box *a, int pad) +{ + int i; + + /* collide with wall */ + if (a->x - pad < 0 || + a->y - pad < 0 || + a->x + a->w + pad + pad >= st->xgwa.width || + a->y + a->h + pad + pad >= st->xgwa.height) + return True; + + /* collide with another box */ + for (i = 0; i < st->nboxes; i++) + { + box *b = &st->boxes[i]; + if (a != b && + (st->circles_p + ? circles_overlap_p (a, b, pad) + : boxes_overlap_p (a, b, pad))) + return True; + } + + return False; +} + + +static unsigned int +grow_boxes (state *st) +{ + int inc2 = st->inc + st->spacing + st->border_size; + int i; + int live_count = 0; + + /* check box collisions, and grow if none. + */ + for (i = 0; i < st->nboxes; i++) + { + box *a = &st->boxes[i]; + if (!(a->flags & ALIVE)) continue; + + if (box_collides_p (st, a, inc2)) + { + a->flags &= ~ALIVE; + continue; + } + + live_count++; + a->x -= st->inc; + a->y -= st->inc; + a->w += st->inc + st->inc; + a->h += st->inc + st->inc; + a->flags |= CHANGED; + } + + /* Add more boxes. + */ + while (live_count < st->box_count) + { + box *a; + st->nboxes++; + if (st->boxes_size <= st->nboxes) + { + st->boxes_size = (st->boxes_size * 1.2) + st->nboxes; + st->boxes = (box *) + realloc (st->boxes, st->boxes_size * sizeof(*st->boxes)); + if (! st->boxes) + { + fprintf (stderr, "%s: out of memory (%d boxes)\n", + progname, st->boxes_size); + exit (1); + } + } + + a = &st->boxes[st->nboxes-1]; + a->flags = CHANGED; + + for (i = 0; i < 100; i++) + { + a->x = inc2 + (random() % (st->xgwa.width - inc2)); + a->y = inc2 + (random() % (st->xgwa.height - inc2)); + a->w = 0; + a->h = 0; + + if (! box_collides_p (st, a, inc2)) + { + a->flags |= ALIVE; + live_count++; + break; + } + } + + if (! (a->flags & ALIVE) || /* too many retries; */ + st->nboxes > 65535) /* that's about 1MB of box structs. */ + { + st->nboxes--; /* go into "fade out" mode now. */ + st->growing_p = False; + return 2000000; /* make customizable... */ + } + + /* Pick colors for this box */ + if (st->image) + { + int w = st->image->width; + int h = st->image->height; + a->fill_color = XGetPixel (st->image, a->x % w, a->y % h); + } + else + { + int n = (st->color_horiz_p + ? (a->x * st->ncolors / st->xgwa.width) + : (a->y * st->ncolors / st->xgwa.height)); + a->fill_color = st->colors [n % st->ncolors].pixel; + } + } + + return st->delay; +} + + +static unsigned int +shrink_boxes (state *st) +{ + int i; + int remaining = 0; + + for (i = 0; i < st->nboxes; i++) + { + box *a = &st->boxes[i]; + + if (a->w <= 0 || a->h <= 0) continue; + + a->x += st->inc; + a->y += st->inc; + a->w -= st->inc + st->inc; + a->h -= st->inc + st->inc; + a->flags |= CHANGED; + if (a->w < 0) a->w = 0; + if (a->h < 0) a->h = 0; + + if (a->w > 0 && a->h > 0) + remaining++; + } + + if (remaining == 0) { + reset_boxes (st); + return 1000000; + } else { + return st->delay; + } +} + + +static void +draw_boxes (state *st) +{ + int i; + for (i = 0; i < st->nboxes; i++) + { + box *b = &st->boxes[i]; + + if (b->flags & UNDEAD) continue; + if (! (b->flags & CHANGED)) continue; + b->flags &= ~CHANGED; + + if (!st->growing_p) + { + /* When shrinking, black out an area outside of the border + before re-drawing the box. + */ + int margin = st->inc + st->border_size; + + XSetForeground (st->dpy, st->gc, st->bg_color); + if (st->circles_p) + XFillArc (st->dpy, st->window, st->gc, + b->x - margin, b->y - margin, + b->w + (margin*2), b->h + (margin*2), + 0, 360*64); + else + XFillRectangle (st->dpy, st->window, st->gc, + b->x - margin, b->y - margin, + b->w + (margin*2), b->h + (margin*2)); + + if (b->w <= 0 || b->h <= 0) + b->flags |= UNDEAD; /* really very dead now */ + } + + if (b->w <= 0 || b->h <= 0) continue; + + XSetForeground (st->dpy, st->gc, b->fill_color); + + if (st->circles_p) + XFillArc (st->dpy, st->window, st->gc, b->x, b->y, b->w, b->h, + 0, 360*64); + else + XFillRectangle (st->dpy, st->window, st->gc, b->x, b->y, b->w, b->h); + + if (st->border_size > 0) + { + unsigned int bd = (st->image + ? st->fg_color + : st->colors [(b->fill_color + st->ncolors/2) + % st->ncolors].pixel); + XSetForeground (st->dpy, st->gc, bd); + if (st->circles_p) + XDrawArc (st->dpy, st->window, st->gc, b->x, b->y, b->w, b->h, + 0, 360*64); + else + XDrawRectangle (st->dpy, st->window, st->gc, + b->x, b->y, b->w, b->h); + } + } +} + + +static unsigned long +boxfit_draw (Display *dpy, Window window, void *closure) +{ + state *st = (state *) closure; + int delay; + + if (st->img_loader) /* still loading */ + { + st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0); + if (! st->img_loader) /* just finished */ + { + st->image = XGetImage (st->dpy, + (st->loading_pixmap ? st->loading_pixmap : + st->window), + 0, 0, + st->xgwa.width, st->xgwa.height, ~0L, + ZPixmap); + if (st->loading_pixmap) XFreePixmap (st->dpy, st->loading_pixmap); + XSetWindowBackground (st->dpy, st->window, st->bg_color); + if (st->loading_pixmap) + XClearWindow (st->dpy, st->window); + else + st->countdown = 2000000; + st->loading_pixmap = 0; + } + return st->delay; + } + + if (st->countdown > 0) + { + st->countdown -= st->delay; + if (st->countdown <= 0) + { + st->countdown = 0; + XClearWindow (st->dpy, st->window); + } + return st->delay; + } + + if (st->growing_p) { + draw_boxes (st); + delay = grow_boxes (st); + } else { + delay = shrink_boxes (st); + draw_boxes (st); + } + return delay; +} + +static void +boxfit_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + state *st = (state *) closure; + reshape_boxes (st); +} + +static Bool +boxfit_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + state *st = (state *) closure; + if (screenhack_event_helper (dpy, window, event)) + { + st->growing_p = !st->growing_p; + return True; + } + return False; +} + +static void +boxfit_free (Display *dpy, Window window, void *closure) +{ +} + + +static const char *boxfit_defaults [] = { + ".background: black", + ".foreground: #444444", + "*fpsSolid: true", + "*delay: 20000", + "*mode: random", + "*colors: 64", + "*boxCount: 50", + "*growBy: 1", + "*spacing: 1", + "*borderSize: 1", + "*grab: False", + "*peek: False", + "*grabDesktopImages: False", /* HAVE_JWXYZ */ + "*chooseRandomImages: True", /* HAVE_JWXYZ */ +#ifdef HAVE_MOBILE + "*ignoreRotation: True", + "*rotateImages: True", +#endif + 0 +}; + +static XrmOptionDescRec boxfit_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-colors", ".colors", XrmoptionSepArg, 0 }, + { "-count", ".boxCount", XrmoptionSepArg, 0 }, + { "-growby", ".growBy", XrmoptionSepArg, 0 }, + { "-spacing", ".spacing", XrmoptionSepArg, 0 }, + { "-border", ".borderSize", XrmoptionSepArg, 0 }, + { "-mode", ".mode", XrmoptionSepArg, 0 }, + { "-circles", ".mode", XrmoptionNoArg, "circles" }, + { "-squares", ".mode", XrmoptionNoArg, "squares" }, + { "-random", ".mode", XrmoptionNoArg, "random" }, + { "-grab", ".grab", XrmoptionNoArg, "True" }, + { "-no-grab", ".grab", XrmoptionNoArg, "False" }, + { "-peek", ".peek", XrmoptionNoArg, "True" }, + { "-no-peek", ".peek", XrmoptionNoArg, "False" }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("BoxFit", boxfit) diff --git a/hacks/boxfit.man b/hacks/boxfit.man new file mode 100644 index 0000000..ec157e3 --- /dev/null +++ b/hacks/boxfit.man @@ -0,0 +1,102 @@ +.TH XScreenSaver 1 "" "X Version 11" +.SH NAME +boxfit - fills space with a gradient of growing boxes or circles. +.SH SYNOPSIS +.B boxfit +[\-display \fIhost:display.screen\fP] +[\-visual \fIvisual\fP] +[\-window] +[\-root] +[\-delay \fIusecs\fP] +[\-count \fIint\fP] +[\-growby \fIint\fP] +[\-spacing \fIint\fP] +[\-border \fIint\fP] +[\-circles | \-squares | \-random] +[\-grab] +[\-peek] +[\-fps] +.SH DESCRIPTION +Packs the screen with growing boxes or circles, colored according to a +horizontal or vertical gradient. The objects grow until they touch, +then stop. When the screen is full, they shrink away and the process +restarts. +.SH OPTIONS +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-delay \fImicroseconds\fP +How much of a delay should be introduced between steps of the animation. +Default 20000, or about 0.02 seconds. +.TP 8 +.B \-count \fIint\fP +How many boxes or circles to animate simultaneously; default 50. +Smaller numbers yield larger boxes/circles. +.TP 8 +.B \-growby \fIint\fP +How many pixels the objects should grow by, each frame. Default 1. +.TP 8 +.B \-spacing \fIint\fP +How many pixels of space should be left between the objects. Default 1. +.TP 8 +.B \-border \fIint\fP +Thickness of the colored border around each object. Default 1. +.TP 8 +.B \-circles\fB | \-squares\fP | \-random\fP +Draw circles, squares, or choose randomly (the default). +.TP 8 +.B \-grab +Normally it colors the boxes with a horizontal or vertical gradient. +If \fI\-grab\fP is specified, it will instead load a random image, +and color the boxes according to the colors in that image. +As the picture fills in, some features of the underlying image +may become recognisable. + +When grabbing images, the image will be grabbed from the portion of +the screen underlying the window, or from the system's video input, +or from a random file on disk, as indicated by +the \fIgrabDesktopImages\fP, \fIgrabVideoFrames\fP, +and \fIchooseRandomImages\fP options in the \fI~/.xscreensaver\fP +file; see +.BR xscreensaver-demo (1) +for more details. +.TP 8 +.B \-peek +This option says to briefly show you the underlying image before +beginning. The default is not to show the unadulterated image at all. +(This only has an effect when \fI\-grab\fP is used.) +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1) +.BR xscreensaver\-demo (1), +.BR xscreensaver\-getimage (1) +.SH COPYRIGHT +Copyright \(co 2005 by Jamie Zawinski. Permission to use, copy, modify, +distribute, and sell this software and its documentation for any purpose is +hereby granted without fee, provided that the above copyright notice appear +in all copies and that both that copyright notice and this permission notice +appear in supporting documentation. No representations are made about the +suitability of this software for any purpose. It is provided "as is" without +express or implied warranty. +.SH AUTHOR +Jamie Zawinski diff --git a/hacks/braid.c b/hacks/braid.c new file mode 100644 index 0000000..4f5a77c --- /dev/null +++ b/hacks/braid.c @@ -0,0 +1,443 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/*- + * braid --- random braids around a circle and then changes the color in + * a rotational pattern + */ + +#if 0 +static const char sccsid[] = "@(#)braid.c 5.00 2000/11/01 xlockmore"; +#endif + +/*- + * Copyright (c) 1995 by John Neil. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation. + * + * This file is provided AS IS with no warranties of any kind. The author + * shall have no liability with respect to the infringement of copyrights, + * trade secrets or any patents by this file or any part thereof. In no + * event will the author be liable for any lost revenue or profits or + * other special, indirect and consequential damages. + * + * Revision History: + * 01-Nov-2000: Allocation checks + * 10-May-1997: Jamie Zawinski compatible with xscreensaver + * 01-Sep-1995: color knotted components differently, J. Neil. + * 29-Aug-1995: Written. John Neil + */ + +#ifdef STANDALONE +# define MODE_braid +# define DEFAULTS "*delay: 1000 \n" \ + "*count: 15 \n" \ + "*cycles: 100 \n" \ + "*size: -7 \n" \ + "*ncolors: 64 \n" \ + "*fpsSolid: true \n" \ + "*ignoreRotation: True" \ + +# define UNIFORM_COLORS +# define free_braid 0 +# define release_braid 0 +# define reshape_braid 0 +# define braid_handle_event 0 +# include "xlockmore.h" +#else /* STANDALONE */ +# include "xlock.h" +# define ENTRYPOINT /**/ +#endif /* STANDALONE */ + +#ifdef MODE_braid + +ENTRYPOINT ModeSpecOpt braid_opts = {0, NULL, 0, NULL, NULL}; + +#ifdef USE_MODULES +ModStruct braid_description = +{"braid", "init_braid", "draw_braid", (char *) NULL, + "refresh_braid", "init_braid", (char *) NULL, &braid_opts, + 1000, 15, 100, 1, 64, 1.0, "", + "Shows random braids and knots", 0, NULL}; + +#endif + +#if defined( COLORROUND ) && defined( COLORCOMP ) +#undef COLORROUND +#undef COLORCOMP +#endif + +#if !defined( COLORROUND ) && !defined( COLORCOMP ) +#if 0 +/* to color in a circular pattern use COLORROUND */ +#define COLORROUND +#else +/* to color by component use COLORCOMP */ +#define COLORCOMP +#endif +#endif + +#define MAXLENGTH 50 /* the maximum length of a braid word */ +#define MINLENGTH 8 /* the minimum length of a braid word */ +#define MAXSTRANDS 15 /* the maximum number of strands in the braid */ +#define MINSTRANDS 3 /* the minimum number of strands in the braid */ +#define SPINRATE 12.0 /* the rate at which the colors spin */ + +#define INTRAND(min,max) (NRAND((max+1)-(min))+(min)) +#define FLOATRAND(min,max) ((min)+((double) LRAND()/((double) MAXRAND))*((max)-(min))) + +typedef struct { + int linewidth; + int braidword[MAXLENGTH]; + int components[MAXSTRANDS]; + int startcomp[MAXLENGTH][MAXSTRANDS]; + int nstrands; + int braidlength; + float startcolor; + int center_x; + int center_y; + float min_radius; + float max_radius; + float top, bottom, left, right; + int age; + int color_direction; +} braidtype; + +static braidtype *braids = (braidtype *) NULL; + +static int +applyword(braidtype * braid, int string, int position) +{ + int i, c; + + c = string; + for (i = position; i < braid->braidlength; i++) { + if (c == ABS(braid->braidword[i])) + c--; + else if (c == ABS(braid->braidword[i]) - 1) + c++; + } + for (i = 0; i < position; i++) { + if (c == ABS(braid->braidword[i])) + c--; + else if (c == ABS(braid->braidword[i]) - 1) + c++; + } + return c; +} + +#if 0 +static int +applywordto(braidtype * braid, int string, int position) +{ + int i, c; + + c = string; + for (i = 0; i < position; i++) { + if (c == ABS(braid->braidword[i])) { + c--; + } else if (c == ABS(braid->braidword[i]) - 1) { + c++; + } + } + return c; +} +#endif + +static int +applywordbackto(braidtype * braid, int string, int position) +{ + int i, c; + + c = string; + for (i = position - 1; i >= 0; i--) { + if (c == ABS(braid->braidword[i])) { + c--; + } else if (c == ABS(braid->braidword[i]) - 1) { + c++; + } + } + return c; +} + +ENTRYPOINT void +init_braid(ModeInfo * mi) +{ + braidtype *braid; + int used[MAXSTRANDS]; + int i, count, comp, c; + float min_length; + + MI_INIT (mi, braids); + braid = &braids[MI_SCREEN(mi)]; + + braid->center_x = MI_WIDTH(mi) / 2; + braid->center_y = MI_HEIGHT(mi) / 2; + braid->age = 0; + + /* jwz: go in the other direction sometimes. */ + braid->color_direction = ((LRAND() & 1) ? 1 : -1); + + MI_CLEARWINDOW(mi); + + min_length = (braid->center_x > braid->center_y) ? + braid->center_y : braid->center_x; + braid->min_radius = min_length * 0.30; + braid->max_radius = min_length * 0.90; + + if (MI_COUNT(mi) < MINSTRANDS) + braid->nstrands = MINSTRANDS; + else + braid->nstrands = INTRAND(MINSTRANDS, + MAX(MIN(MIN(MAXSTRANDS, MI_COUNT(mi)), + (int) ((braid->max_radius - braid->min_radius) / 5.0)), MINSTRANDS)); + braid->braidlength = INTRAND(MINLENGTH, MIN(MAXLENGTH -1, braid->nstrands * 6)); + + for (i = 0; i < braid->braidlength; i++) { + braid->braidword[i] = + INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3); + if (i > 0) + while (braid->braidword[i] == -braid->braidword[i - 1]) + braid->braidword[i] = INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3); + } + + while (braid->braidword[0] == -braid->braidword[braid->braidlength - 1]) + braid->braidword[braid->braidlength - 1] = + INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3); + + do { + (void) memset((char *) used, 0, sizeof (used)); + count = 0; + for (i = 0; i < braid->braidlength; i++) + used[ABS(braid->braidword[i])]++; + for (i = 0; i < braid->nstrands; i++) + count += (used[i] > 0) ? 1 : 0; + if (count < braid->nstrands - 1) { + braid->braidword[braid->braidlength] = + INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3); + while (braid->braidword[braid->braidlength] == + -braid->braidword[braid->braidlength - 1] && + braid->braidword[0] == -braid->braidword[braid->braidlength]) + braid->braidword[braid->braidlength] = + INTRAND(1, braid->nstrands - 1) * (INTRAND(1, 2) * 2 - 3); + braid->braidlength++; + } + } while (count < braid->nstrands - 1 && braid->braidlength < MAXLENGTH); + + braid->startcolor = (MI_NPIXELS(mi) > 2) ? + (float) NRAND(MI_NPIXELS(mi)) : 0.0; + /* XSetLineAttributes (display, MI_GC(mi), 2, LineSolid, CapRound, + JoinRound); */ + + (void) memset((char *) braid->components, 0, sizeof (braid->components)); + c = 1; + comp = 0; + braid->components[0] = 1; + do { + i = comp; + do { + i = applyword(braid, i, 0); + braid->components[i] = braid->components[comp]; + } while (i != comp); + count = 0; + for (i = 0; i < braid->nstrands; i++) + if (braid->components[i] == 0) + count++; + if (count > 0) { + for (comp = 0; braid->components[comp] != 0; comp++); + braid->components[comp] = ++c; + } + } while (count > 0); + + braid->linewidth = MI_SIZE(mi); + + if (braid->linewidth < 0) + braid->linewidth = NRAND(-braid->linewidth) + 1; + if (braid->linewidth * braid->linewidth * 8 > MIN(MI_WIDTH(mi), MI_HEIGHT(mi))) + braid->linewidth = MIN(1, (int) sqrt((double) MIN(MI_WIDTH(mi), MI_HEIGHT(mi)) / 8)); + for (i = 0; i < braid->nstrands; i++) + if (!(braid->components[i] & 1)) + braid->components[i] *= -1; +} + +ENTRYPOINT void +draw_braid(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + int num_points = 500; + float t_inc; + float theta, psi; + float t, r_diff; + int i, s; + float x_1, y_1, x_2, y_2, r1, r2; + float color, color_use = 0.0, color_inc; + braidtype *braid; + + if (braids == NULL) + return; + braid = &braids[MI_SCREEN(mi)]; + + MI_IS_DRAWN(mi) = True; + XSetLineAttributes(display, MI_GC(mi), braid->linewidth, + LineSolid, + (braid->linewidth <= 3 ? CapButt : CapRound), + JoinMiter); + + theta = (2.0 * M_PI) / (float) (braid->braidlength); + t_inc = (2.0 * M_PI) / (float) num_points; + color_inc = (float) MI_NPIXELS(mi) * braid->color_direction / + (float) num_points; + braid->startcolor += SPINRATE * color_inc; + if (((int) braid->startcolor) >= MI_NPIXELS(mi)) + braid->startcolor = 0.0; + + r_diff = (braid->max_radius - braid->min_radius) / (float) (braid->nstrands); + + color = braid->startcolor; + psi = 0.0; + for (i = 0; i < braid->braidlength; i++) { + psi += theta; + for (t = 0.0; t < theta; t += t_inc) { +#ifdef COLORROUND + color += color_inc; + if (((int) color) >= MI_NPIXELS(mi)) + color = 0.0; + color_use = color; +#endif + for (s = 0; s < braid->nstrands; s++) { + if (ABS(braid->braidword[i]) == s) + continue; + if (ABS(braid->braidword[i]) - 1 == s) { + /* crosSINFg */ +#ifdef COLORCOMP + if (MI_NPIXELS(mi) > 2) { + color_use = color + SPINRATE * + braid->components[applywordbackto(braid, s, i)] + + (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi); + while (((int) color_use) >= MI_NPIXELS(mi)) + color_use -= (float) MI_NPIXELS(mi); + while (((int) color_use) < 0) + color_use += (float) MI_NPIXELS(mi); + } +#endif +#ifdef COLORROUND + if (MI_NPIXELS(mi) > 2) { + color_use += SPINRATE * color_inc; + while (((int) color_use) >= MI_NPIXELS(mi)) + color_use -= (float) MI_NPIXELS(mi); + } +#endif + r1 = braid->min_radius + r_diff * (float) (s); + r2 = braid->min_radius + r_diff * (float) (s + 1); + if (braid->braidword[i] > 0 || + (FABSF(t - theta / 2.0) > theta / 7.0)) { + x_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r2 + + 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r1)) * + COSF(t + psi) + braid->center_x; + y_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r2 + + 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r1)) * + SINF(t + psi) + braid->center_y; + x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r2 + + 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r1)) * + COSF(t + t_inc + psi) + braid->center_x; + y_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r2 + + 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r1)) * + SINF(t + t_inc + psi) + braid->center_y; + if (MI_NPIXELS(mi) > 2) + XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use)); + else + XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi)); + + XDrawLine(display, window, MI_GC(mi), + (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2)); + } +#ifdef COLORCOMP + if (MI_NPIXELS(mi) > 2) { + color_use = color + SPINRATE * + braid->components[applywordbackto(braid, s + 1, i)] + + (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi); + while (((int) color_use) >= MI_NPIXELS(mi)) + color_use -= (float) MI_NPIXELS(mi); + while (((int) color_use) < 0) + color_use += (float) MI_NPIXELS(mi); + } +#endif + if (braid->braidword[i] < 0 || + (FABSF(t - theta / 2.0) > theta / 7.0)) { + x_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r1 + + 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r2)) * + COSF(t + psi) + braid->center_x; + y_1 = ((0.5 * (1.0 + SINF(t / theta * M_PI - M_PI_2)) * r1 + + 0.5 * (1.0 + SINF((theta - t) / theta * M_PI - M_PI_2)) * r2)) * + SINF(t + psi) + braid->center_y; + x_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r1 + + 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r2)) * + COSF(t + t_inc + psi) + braid->center_x; + y_2 = ((0.5 * (1.0 + SINF((t + t_inc) / theta * M_PI - M_PI_2)) * r1 + + 0.5 * (1.0 + SINF((theta - t - t_inc) / theta * M_PI - M_PI_2)) * r2)) * + SINF(t + t_inc + psi) + braid->center_y; + if (MI_NPIXELS(mi) > 2) + XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use)); + else + XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi)); + + XDrawLine(display, window, MI_GC(mi), + (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2)); + } + } else { + /* no crosSINFg */ +#ifdef COLORCOMP + if (MI_NPIXELS(mi) > 2) { + color_use = color + SPINRATE * + braid->components[applywordbackto(braid, s, i)] + + (psi + t) / 2.0 / M_PI * (float) MI_NPIXELS(mi); + while (((int) color_use) >= MI_NPIXELS(mi)) + color_use -= (float) MI_NPIXELS(mi); + while (((int) color_use) < 0) + color_use += (float) MI_NPIXELS(mi); + } +#endif +#ifdef COLORROUND + if (MI_NPIXELS(mi) > 2) { + color_use += SPINRATE * color_inc; + while (((int) color_use) >= MI_NPIXELS(mi)) + color_use -= (float) MI_NPIXELS(mi); + } +#endif + r1 = braid->min_radius + r_diff * (float) (s); + x_1 = r1 * COSF(t + psi) + braid->center_x; + y_1 = r1 * SINF(t + psi) + braid->center_y; + x_2 = r1 * COSF(t + t_inc + psi) + braid->center_x; + y_2 = r1 * SINF(t + t_inc + psi) + braid->center_y; + if (MI_NPIXELS(mi) > 2) + XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, (int) color_use)); + else + XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi)); + + XDrawLine(display, window, MI_GC(mi), + (int) (x_1), (int) (y_1), (int) (x_2), (int) (y_2)); + } + } + } + } + XSetLineAttributes(display, MI_GC(mi), 1, LineSolid, CapNotLast, JoinRound); + + if (++braid->age > MI_CYCLES(mi)) { + init_braid(mi); + } +} + +#ifndef STANDALONE +ENTRYPOINT void +refresh_braid(ModeInfo * mi) +{ + MI_CLEARWINDOW(mi); +} +#endif + +XSCREENSAVER_MODULE ("Braid", braid) + +#endif /* MODE_braid */ diff --git a/hacks/braid.man b/hacks/braid.man new file mode 100644 index 0000000..28f0c4d --- /dev/null +++ b/hacks/braid.man @@ -0,0 +1,69 @@ +.TH XScreenSaver 1 "10-May-97" "X Version 11" +.SH NAME +braid - draws random color-cycling braids around a circle +.SH SYNOPSIS +.B braid +[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install] [\-visual \fIvisual\fP] [\-ncolors \fIinteger\fP] [\-delay \fImicroseconds\fP] [\-cycles \fIinteger\fP] [\-count \fIinteger\fP] + +[\-fps] +.SH DESCRIPTION +The \fIbraid\fP program draws random color-cycling braids around a circle. +.SH OPTIONS +.I braid +accepts the following options: +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-mono +If on a color display, pretend we're on a monochrome display. +.TP 8 +.B \-install +Install a private colormap for the window. +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-ncolors \fIinteger\fP +How many colors should be used (if possible). Default 64. +The colors used cycle through the hue, making N stops around +the color wheel. +.TP 8 +.B \-cycles \fIinteger\fP + +.TP 8 +.B \-count \fIinteger\fP + +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1), +.BR xlock (1) +.SH COPYRIGHT +Copyright \(co 1995 by John Neil. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. +.SH AUTHOR +John Neil , 29-Aug-95. + +Ability to run standalone or with \fIxscreensaver\fP added by +Jamie Zawinski , 10-May-97. diff --git a/hacks/bsod.c b/hacks/bsod.c new file mode 100644 index 0000000..ff6c359 --- /dev/null +++ b/hacks/bsod.c @@ -0,0 +1,6008 @@ +/* xscreensaver, Copyright (c) 1998-2018 Jamie Zawinski + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * Blue Screen of Death: the finest in personal computer emulation. + * Concept cribbed from Stephen Martin ; + * this version written by jwz, 4-Jun-98. + * Mostly rewritten by jwz, 20-Feb-2006. + */ + + +/* To add a new mode: + + - Define a function `new_os(dpy,win)' that returns a `bsod_state' struct. + - Draw on the window to set up its frame-zero state. This must be fast: + no sleeping or long loops! + - Populate the bsod_state structure with additional actions to take by + using the various BSOD_ macros. Note that you can control the delays + when printing text on a per-character or per-line basis. + - Insert your function in the `all_modes' table. + - Add a `doXXX' entry to `bsod_defaults'. + - Add fonts or colors to `bsod_defaults' if necessary. + + Look at windows_31() for a simple example. + + Look at linux_fsck() for a more complicated example with random behavior. + + Or, you can bypass all that: look at nvidia() for a really hairy example. + */ + + +#include "screenhack.h" +#include "ximage-loader.h" +#include "apple2.h" + +#include +#include + +#ifdef HAVE_XSHM_EXTENSION +#include "xshm.h" +#endif + +#ifdef HAVE_UNAME +# include +#endif /* HAVE_UNAME */ + +#include "images/gen/amiga_png.h" +#include "images/gen/hmac_png.h" +#include "images/gen/osx_10_2_png.h" +#include "images/gen/osx_10_3_png.h" +#include "images/gen/android_png.h" +#include "images/gen/ransomware_png.h" +#include "images/gen/atari_png.h" +#include "images/gen/mac_png.h" +#include "images/gen/macbomb_png.h" +#include "images/gen/apple_png.h" +#include "images/gen/atm_png.h" + +#undef countof +#define countof(x) (sizeof((x))/sizeof((*x))) + +# undef MIN +# undef MAX +# define MIN(A,B) ((A)<(B)?(A):(B)) +# define MAX(A,B) ((A)>(B)?(A):(B)) + +#undef EOF +typedef enum { EOF=0, + LEFT, CENTER, RIGHT, + LEFT_FULL, CENTER_FULL, RIGHT_FULL, + COLOR, INVERT, MOVETO, MARGINS, + CURSOR_BLOCK, CURSOR_LINE, RECT, LINE, COPY, PIXMAP, IMG, FONT, + PAUSE, CHAR_DELAY, LINE_DELAY, + LOOP, RESET, VERT_MARGINS, CROP, + WRAP, WORD_WRAP, TRUNCATE +} bsod_event_type; + +struct bsod_event { + bsod_event_type type; + void *arg1, *arg2, *arg3, *arg4, *arg5, *arg6; +}; + +struct bsod_state { + Display *dpy; + Window window; + XWindowAttributes xgwa; + XFontStruct *font, *fontA, *fontB, *fontC; + unsigned long fg, bg; + GC gc; + int left_margin, right_margin; /* for text wrapping */ + int top_margin, bottom_margin; /* for text scrolling and cropping */ + int xoff, yoff; + Bool wrap_p, word_wrap_p; + char word_buf[80]; + Bool scroll_p; + Bool crop_p; /* If True, chops off extra text vertically */ + + Pixmap pixmap, mask; /* Source image used by BSOD_PIXMAP */ + + int x, y; /* current text-drawing position */ + int current_left; /* don't use this */ + int last_nonwhite; + + int pos; /* position in queue */ + int queue_size; + struct bsod_event *queue; + + unsigned long char_delay; /* delay between printing characters */ + unsigned long line_delay; /* delay between printing lines */ + + Bool macx_eol_kludge; + + void *closure; + int (*draw_cb) (struct bsod_state *); + void (*free_cb) (struct bsod_state *); + + async_load_state *img_loader; +}; + + +# if !defined(__GNUC__) && !defined(__extension__) + /* don't warn about "string length is greater than the length ISO C89 + compilers are required to support" in these string constants... */ +# define __extension__ /**/ +# endif + + +/* Draw text at the current position; align is LEFT, CENTER, RIGHT, or *_FULL + (meaning to clear the whole line margin to margin). + */ +#define BSOD_TEXT(bst,align,string) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = (align); \ + (bst)->queue[(bst)->pos].arg1 = (void *) strdup (__extension__ (string)); \ + (bst)->queue[(bst)->pos].arg2 = (bst)->queue[(bst)->pos].arg1; \ + (bst)->queue[(bst)->pos].arg3 = (void *) 0; \ + (bst)->pos++; \ + } while (0) + +/* Flip the foreground and background colors + */ +#define BSOD_INVERT(bst) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = INVERT; \ + (bst)->pos++; \ + } while (0) + +/* Set the foreground and background colors to the given pixels + */ +#define BSOD_COLOR(bst,fg,bg) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = COLOR; \ + (bst)->queue[(bst)->pos].arg1 = (void *) fg; \ + (bst)->queue[(bst)->pos].arg2 = (void *) bg; \ + (bst)->pos++; \ + } while (0) + +/* Set the position of the next text. + Note that this is the baseline: lower left corner of next char printed. + */ +#define BSOD_MOVETO(bst,x,y) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = MOVETO; \ + (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (x)); \ + (bst)->queue[(bst)->pos].arg2 = (void *) ((long) (y)); \ + (bst)->pos++; \ + } while (0) + +/* Delay for at least the given number of microseconds. + */ +#define BSOD_PAUSE(bst,usec) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = PAUSE; \ + (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (usec)); \ + (bst)->pos++; \ + } while (0) + +/* Set the delay after each character is printed. + */ +#define BSOD_CHAR_DELAY(bst,usec) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = CHAR_DELAY; \ + (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (usec)); \ + (bst)->pos++; \ + } while (0) + +/* Set the delay after each newline. + */ +#define BSOD_LINE_DELAY(bst,usec) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = LINE_DELAY; \ + (bst)->queue[(bst)->pos].arg1 = (void *) (usec); \ + (bst)->pos++; \ + } while (0) + +/* Set the prevailing left/right margins (used when strings have + embedded newlines, and when centering or right-justifying text.) + */ +#define BSOD_MARGINS(bst,left,right) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = MARGINS; \ + (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (left)); \ + (bst)->queue[(bst)->pos].arg2 = (void *) ((long) (right)); \ + (bst)->pos++; \ + } while (0) + +/* Set the prevailing top/bottom margins (used when scrolling and cropping text) + */ +#define BSOD_VERT_MARGINS(bst,top,bottom) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = VERT_MARGINS; \ + (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (top)); \ + (bst)->queue[(bst)->pos].arg2 = (void *) ((long) (bottom)); \ + (bst)->pos++; \ + } while (0) + +/* Draw a blinking cursor; type is CURSOR_BLOCK or CURSOR_LINE. + usec is how long 1/2 of a cycle is. count is how many times to blink. + (You can pass a gigantic number if this is the last thing in your mode.) + */ +#define BSOD_CURSOR(bst,ctype,usec,count) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = (ctype); \ + (bst)->queue[(bst)->pos].arg1 = (void *) (usec); \ + (bst)->queue[(bst)->pos].arg2 = (void *) (count); \ + (bst)->pos++; \ + } while (0) + +/* Draw or fill a rectangle. You can set line-width in the GC. + */ +#define BSOD_RECT(bst,fill,x,y,w,h) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = RECT; \ + (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (fill)); \ + (bst)->queue[(bst)->pos].arg2 = (void *) ((long) (x)); \ + (bst)->queue[(bst)->pos].arg3 = (void *) ((long) (y)); \ + (bst)->queue[(bst)->pos].arg4 = (void *) ((long) (w)); \ + (bst)->queue[(bst)->pos].arg5 = (void *) ((long) (h)); \ + (bst)->pos++; \ + } while (0) + +/* Draw a line. + */ +#define BSOD_LINE(bst,x,y,x2,y2,thick) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = LINE; \ + (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (x)); \ + (bst)->queue[(bst)->pos].arg2 = (void *) ((long) (y)); \ + (bst)->queue[(bst)->pos].arg3 = (void *) ((long) (x2)); \ + (bst)->queue[(bst)->pos].arg4 = (void *) ((long) (y2)); \ + (bst)->queue[(bst)->pos].arg5 = (void *) ((long) (thick)); \ + (bst)->pos++; \ + } while (0) + +/* Copy a rect from the window, to the window. + */ +#define BSOD_COPY(bst,srcx,srcy,w,h,tox,toy) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = COPY; \ + (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (srcx)); \ + (bst)->queue[(bst)->pos].arg2 = (void *) ((long) (srcy)); \ + (bst)->queue[(bst)->pos].arg3 = (void *) ((long) (w)); \ + (bst)->queue[(bst)->pos].arg4 = (void *) ((long) (h)); \ + (bst)->queue[(bst)->pos].arg5 = (void *) ((long) (tox)); \ + (bst)->queue[(bst)->pos].arg6 = (void *) ((long) (toy)); \ + (bst)->pos++; \ + } while (0) + +/* Copy a rect from bst->pixmap to the window. + */ +#define BSOD_PIXMAP(bst,srcx,srcy,w,h,tox,toy) do { \ + BSOD_COPY(bst,srcx,srcy,w,h,tox,toy); \ + (bst)->queue[(bst)->pos-1].type = PIXMAP; \ + } while (0) + +/* Load a random image (or the desktop) onto the window. + */ +#define BSOD_IMG(bst) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = IMG; \ + (bst)->pos++; \ + } while (0) + +/* Switch between fonts A, B and C. + */ +#define BSOD_FONT(bst,n) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = FONT; \ + (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (n)); \ + (bst)->pos++; \ + } while (0) + +/* Jump around in the state table. You can use this as the last thing + in your state table to repeat the last N elements forever. + */ +#define BSOD_LOOP(bst,off) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = LOOP; \ + (bst)->queue[(bst)->pos].arg1 = (void *) (off); \ + (bst)->pos++; \ + } while (0) + +/* Restart the whole thing from the beginning. + */ +#define BSOD_RESET(bst) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = RESET; \ + (bst)->pos++; \ + } while (0) + +/* Sets the crop state, if True, will not write text below the bottom_margin + */ +#define BSOD_CROP(bst, state) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = CROP; \ + (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (state)); \ + (bst)->pos++; \ + } while (0) + +#define BSOD_WRAP(bst) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = WRAP; \ + (bst)->pos++; \ + } while (0) + +#define BSOD_WORD_WRAP(bst) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = WORD_WRAP; \ + (bst)->pos++; \ + } while (0) + +#define BSOD_TRUNCATE(bst) do { \ + ensure_queue (bst); \ + (bst)->queue[(bst)->pos].type = TRUNCATE; \ + (bst)->pos++; \ + } while (0) + + +static void +ensure_queue (struct bsod_state *bst) +{ + int n; + if (bst->pos + 1 < bst->queue_size) + return; + + n = bst->queue_size + 10; + if (n < 100) n *= 2; + n *= 1.2; + + bst->queue = (struct bsod_event *) + realloc (bst->queue, n * sizeof(*bst->queue)); + if (!bst->queue) abort(); + memset (bst->queue + bst->queue_size, 0, + (n - bst->queue_size) * sizeof(*bst->queue)); + bst->queue_size = n; +} + + +static void +position_for_text (struct bsod_state *bst, const char *line) +{ + int max_width = 0; + + const char *start = line; + + if (bst->queue[bst->pos].type != LEFT && + bst->queue[bst->pos].type != LEFT_FULL) + while (*start) + { + int dir, ascent, descent; + XCharStruct ov; + const char *end = start; + while (*end && *end != '\r' && *end != '\n') + end++; + + XTextExtents (bst->font, start, end-start, + &dir, &ascent, &descent, &ov); + if (ov.width > max_width) + max_width = ov.width; + if (!*end) break; + start = end+1; + } + + switch (bst->queue[bst->pos].type) { + case LEFT: + case LEFT_FULL: + bst->current_left = bst->left_margin + bst->xoff; + break; + case RIGHT: + case RIGHT_FULL: + bst->x = max_width - bst->right_margin - bst->xoff; + bst->current_left = bst->x; + break; + case CENTER: + case CENTER_FULL: + { + int w = (bst->xgwa.width - bst->left_margin - bst->right_margin - + max_width); + if (w < 0) w = 0; + bst->x = bst->left_margin + bst->xoff + (w / 2); + bst->current_left = bst->x; + break; + } + default: + abort(); + } +} + + +static void +bst_crlf (struct bsod_state *bst) +{ + int lh = bst->font->ascent + bst->font->descent; + bst->x = bst->current_left; + if (!bst->scroll_p || + bst->y + lh < bst->xgwa.height - bst->bottom_margin - bst->yoff) + bst->y += lh; + else + { + int w = bst->xgwa.width - bst->right_margin - bst->left_margin; + int h = bst->xgwa.height - bst->top_margin - bst->bottom_margin; + XCopyArea (bst->dpy, bst->window, bst->window, bst->gc, + bst->left_margin + bst->xoff, + bst->top_margin + bst->yoff + lh, + w, h - lh, + bst->left_margin + bst->xoff, + bst->top_margin + bst->yoff); + XClearArea (bst->dpy, bst->window, + bst->left_margin + bst->xoff, + bst->top_margin + bst->yoff + h - lh, w, lh, False); + } +} + + +static void +draw_char (struct bsod_state *bst, char c) +{ + if (!c) + abort(); + else if (bst->crop_p && bst->y >= + (bst->xgwa.height - bst->bottom_margin - bst->yoff)) + { + /* reached the bottom of the drawing area, and crop_p = True */ + return; + } + else if (c == '\r') + { + bst->x = bst->current_left; + bst->last_nonwhite = bst->x; + } + else if (c == '\n') + { + if (bst->macx_eol_kludge) + { + /* Special case for the weird way OSX crashes print newlines... */ + XDrawImageString (bst->dpy, bst->window, bst->gc, + bst->x, bst->y, " ", 1); + XDrawImageString (bst->dpy, bst->window, bst->gc, + bst->x, + bst->y + bst->font->ascent + bst->font->descent, + " ", 1); + } + bst_crlf (bst); + } + else if (c == '\b') /* backspace */ + { + int cw = (bst->font->per_char + ? bst->font->per_char['n'-bst->font->min_char_or_byte2].width + : bst->font->min_bounds.width); + bst->x -= cw; + if (bst->x < bst->left_margin + bst->xoff) + bst->x = bst->left_margin + bst->xoff; + } + else + { + int dir, ascent, descent; + XCharStruct ov; + XTextExtents (bst->font, &c, 1, &dir, &ascent, &descent, &ov); + + if ((bst->wrap_p || bst->word_wrap_p) && + bst->x + ov.width > bst->xgwa.width - bst->right_margin - bst->xoff) + { + XCharStruct ov2; + int L = 0; + + if (bst->word_wrap_p && *bst->word_buf) + { + L = strlen(bst->word_buf); + XTextExtents (bst->font, bst->word_buf, L, + &dir, &ascent, &descent, &ov2); + } + + if (L) /* Erase the truncated wrapped word */ + { + XSetForeground (bst->dpy, bst->gc, bst->bg); + XFillRectangle (bst->dpy, bst->window, bst->gc, + bst->last_nonwhite, + bst->y - bst->font->ascent, + ov2.width, + bst->font->ascent + bst->font->descent); + XSetForeground (bst->dpy, bst->gc, bst->fg); + } + + bst_crlf (bst); + + if (L) /* Draw wrapped partial word on the next line, no delay */ + { + XDrawImageString (bst->dpy, bst->window, bst->gc, + bst->x, bst->y, bst->word_buf, L); + bst->x += ov2.width; + bst->last_nonwhite = bst->x; + } + } + + XDrawImageString (bst->dpy, bst->window, bst->gc, + bst->x, bst->y, &c, 1); + bst->x += ov.width; + + if (bst->word_wrap_p) + { + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') + { + bst->word_buf[0] = 0; + bst->last_nonwhite = bst->x; + } + else + { + int L = strlen (bst->word_buf); + if (L >= sizeof(bst->word_buf)-1) abort(); + bst->word_buf[L] = c; + bst->word_buf[L+1] = 0; + } + } + } +} + + +static long +bsod_pop (struct bsod_state *bst) +{ + bsod_event_type type = bst->queue[bst->pos].type; + + if (bst->draw_cb) + return bst->draw_cb (bst); + + if (bst->pos < 0) /* already done */ + abort(); + + switch (type) { + + case LEFT: case LEFT_FULL: + case CENTER: case CENTER_FULL: + case RIGHT: case RIGHT_FULL: + { + const char *s = (const char *) bst->queue[bst->pos].arg2; + char c; + + if (! *s) + { + long delay = bst->line_delay; + /* Reset the string back to the beginning, in case we loop. */ + bst->queue[bst->pos].arg2 = bst->queue[bst->pos].arg1; + bst->queue[bst->pos].arg3 = 0; + bst->queue[bst->pos].type = (bsod_event_type) + bst->queue[bst->pos].arg4; + bst->pos++; + bst->current_left = bst->left_margin + bst->xoff; + return delay; + } + + if (! bst->queue[bst->pos].arg3) /* "done once" */ + { + position_for_text (bst, s); + bst->queue[bst->pos].arg4 = (void *) bst->queue[bst->pos].type; + bst->queue[bst->pos].type = LEFT; + bst->word_buf[0] = 0; + bst->last_nonwhite = bst->x; + + if (type == CENTER_FULL || + type == LEFT_FULL || + type == RIGHT_FULL) + { + XSetForeground (bst->dpy, bst->gc, bst->bg); + XFillRectangle (bst->dpy, bst->window, bst->gc, + 0, + bst->y - bst->font->ascent, + bst->xgwa.width, + bst->font->ascent + bst->font->descent); + XSetForeground (bst->dpy, bst->gc, bst->fg); + } + } + + c = *s++; + draw_char (bst, c); + bst->queue[bst->pos].arg2 = (void *) s; + bst->queue[bst->pos].arg3 = (void *) 1; /* "done once" */ + + return (c == '\r' || c == '\n' + ? bst->line_delay + : bst->char_delay); + } + case INVERT: + { + unsigned long swap = bst->fg; + bst->fg = bst->bg; + bst->bg = swap; + XSetForeground (bst->dpy, bst->gc, bst->fg); + XSetBackground (bst->dpy, bst->gc, bst->bg); + bst->pos++; + return 0; + } + case COLOR: + { + bst->fg = (unsigned long) bst->queue[bst->pos].arg1; + bst->bg = (unsigned long) bst->queue[bst->pos].arg2; + XSetForeground (bst->dpy, bst->gc, bst->fg); + XSetBackground (bst->dpy, bst->gc, bst->bg); + bst->pos++; + return 0; + } + case MOVETO: + { + bst->x = (long) bst->queue[bst->pos].arg1; + bst->y = (long) bst->queue[bst->pos].arg2; + bst->word_buf[0] = 0; + bst->last_nonwhite = bst->x; + bst->pos++; + return 0; + } + case RECT: + { + int f = (long) bst->queue[bst->pos].arg1; + int x = (long) bst->queue[bst->pos].arg2; + int y = (long) bst->queue[bst->pos].arg3; + int w = (long) bst->queue[bst->pos].arg4; + int h = (long) bst->queue[bst->pos].arg5; + if (f) + XFillRectangle (bst->dpy, bst->window, bst->gc, x, y, w, h); + else + XDrawRectangle (bst->dpy, bst->window, bst->gc, x, y, w, h); + bst->pos++; + return 0; + } + case LINE: + { + int x1 = (long) bst->queue[bst->pos].arg1; + int y1 = (long) bst->queue[bst->pos].arg2; + int x2 = (long) bst->queue[bst->pos].arg3; + int y2 = (long) bst->queue[bst->pos].arg4; + int t = (long) bst->queue[bst->pos].arg5; + XGCValues gcv; + gcv.line_width = t; + XChangeGC (bst->dpy, bst->gc, GCLineWidth, &gcv); + XDrawLine (bst->dpy, bst->window, bst->gc, x1, y1, x2, y2); + bst->pos++; + return 0; + } + case COPY: + case PIXMAP: + { + int srcx = (long) bst->queue[bst->pos].arg1; + int srcy = (long) bst->queue[bst->pos].arg2; + int w = (long) bst->queue[bst->pos].arg3; + int h = (long) bst->queue[bst->pos].arg4; + int tox = (long) bst->queue[bst->pos].arg5; + int toy = (long) bst->queue[bst->pos].arg6; + if (type == PIXMAP && bst->mask) + { + XSetClipMask (bst->dpy, bst->gc, bst->mask); + XSetClipOrigin (bst->dpy, bst->gc, tox, toy); + } + XCopyArea (bst->dpy, + (type == PIXMAP ? bst->pixmap : bst->window), + bst->window, bst->gc, + srcx, srcy, w, h, tox, toy); + if (type == PIXMAP && bst->mask) + XSetClipMask (bst->dpy, bst->gc, None); + bst->pos++; + return 0; + } + case IMG: + { + if (bst->img_loader) abort(); + bst->img_loader = load_image_async_simple (0, bst->xgwa.screen, + bst->window, bst->window, + 0, 0); + bst->pos++; + return 0; + } + case FONT: + { + switch ((long) bst->queue[bst->pos].arg1) { + case 0: bst->font = bst->fontA; break; + case 1: bst->font = bst->fontB; break; + case 2: bst->font = bst->fontC; break; + default: abort(); break; + } + XSetFont (bst->dpy, bst->gc, bst->font->fid); + bst->pos++; + return 0; + } + case PAUSE: + { + long delay = (long) bst->queue[bst->pos].arg1; + bst->pos++; + return delay; + } + case CHAR_DELAY: + { + bst->char_delay = (long) bst->queue[bst->pos].arg1; + bst->pos++; + return 0; + } + case LINE_DELAY: + { + bst->line_delay = (long) bst->queue[bst->pos].arg1; + bst->pos++; + return 0; + } + case MARGINS: + { + bst->left_margin = (long) bst->queue[bst->pos].arg1; + bst->right_margin = (long) bst->queue[bst->pos].arg2; + bst->pos++; + return 0; + } + case VERT_MARGINS: + { + bst->top_margin = (long) bst->queue[bst->pos].arg1; + bst->bottom_margin = (long) bst->queue[bst->pos].arg2; + bst->pos++; + return 0; + } + case CURSOR_BLOCK: + case CURSOR_LINE: + { + long delay = (long) bst->queue[bst->pos].arg1; + long count = (long) bst->queue[bst->pos].arg2; + int ox = bst->x; + + if (type == CURSOR_BLOCK) + { + unsigned long swap = bst->fg; + bst->fg = bst->bg; + bst->bg = swap; + XSetForeground (bst->dpy, bst->gc, bst->fg); + XSetBackground (bst->dpy, bst->gc, bst->bg); + draw_char (bst, ' '); + } + else + { + draw_char (bst, (count & 1 ? ' ' : '_')); + draw_char (bst, ' '); + } + + bst->x = ox; + + count--; + bst->queue[bst->pos].arg2 = (void *) count; + if (count <= 0) + bst->pos++; + + return delay; + } + case WRAP: + bst->wrap_p = 1; + bst->word_wrap_p = 0; + bst->pos++; + return 0; + + case WORD_WRAP: + bst->wrap_p = 0; + bst->word_wrap_p = 1; + bst->pos++; + return 0; + + case TRUNCATE: + bst->wrap_p = 0; + bst->word_wrap_p = 0; + bst->pos++; + return 0; + + case LOOP: + { + long off = (long) bst->queue[bst->pos].arg1; + bst->pos += off; + if (bst->pos < 0 || bst->pos >= bst->queue_size) + abort(); + return 0; + } + case RESET: + { + int i; + for (i = 0; i < bst->queue_size; i++) + switch (bst->queue[i].type) { + case LEFT: case LEFT_FULL: + case CENTER: case CENTER_FULL: + case RIGHT: case RIGHT_FULL: + bst->queue[i].arg2 = bst->queue[i].arg1; + bst->queue[i].arg3 = 0; + bst->queue[i].type = (bsod_event_type) bst->queue[i].arg4; + break; + default: break; + } + bst->pos = 0; + return 0; + } + case CROP: + { + bst->crop_p = (long) bst->queue[bst->pos].arg1; + bst->pos++; + return 0; + } + case EOF: + { + bst->pos = -1; + return -1; + } + default: + break; + } + abort(); +} + + +static struct bsod_state * +make_bsod_state (Display *dpy, Window window, + const char *name, const char *class) +{ + XGCValues gcv; + struct bsod_state *bst; + char buf1[1024], buf2[1024]; + char buf5[1024], buf6[1024]; + char buf7[1024], buf8[1024]; + const char *font1, *font3, *font4; + + bst = (struct bsod_state *) calloc (1, sizeof (*bst)); + bst->queue_size = 10; + bst->queue = (struct bsod_event *) calloc (bst->queue_size, + sizeof (*bst->queue)); + bst->dpy = dpy; + bst->window = window; + XGetWindowAttributes (dpy, window, &bst->xgwa); + + /* If the window is small, use ".font"; if big, ".bigFont". */ + if ( +# ifdef HAVE_MOBILE + 1 +# else + bst->xgwa.height < 640 +# endif + ) + { + sprintf (buf1, "%.100s.font", name); + sprintf (buf2, "%.100s.font", class); + } + else + { + sprintf (buf1, "%.100s.bigFont", name); + sprintf (buf2, "%.100s.bigFont", class); + } + sprintf (buf5, "%.100s.fontB", name); + sprintf (buf6, "%.100s.fontB", class); + sprintf (buf7, "%.100s.fontC", name); + sprintf (buf8, "%.100s.fontC", class); + + font1 = get_string_resource (dpy, buf1, buf2); + font3 = get_string_resource (dpy, buf5, buf6); + font4 = get_string_resource (dpy, buf7, buf8); + + /* If there was no ".mode.font" resource also look for ".font". + Under real X11, the wildcard does this, so this is redundant, + but jwxyz needs it because it doesn't implement wildcards. + */ +# define RES2(VAR, BUF1, BUF2) do { \ + if (! VAR) { \ + VAR = get_string_resource (dpy, \ + strchr (BUF1, '.') + 1, \ + strchr (BUF2, '.') + 1); \ + }} while(0) + RES2 (font1, buf1, buf2); + RES2 (font3, buf5, buf6); + RES2 (font4, buf7, buf8); +#undef RES2 + + if (font1 && *font1) + bst->font = load_font_retry (dpy, font1); + + if (! bst->font) + abort(); + + if (font3 && *font3) + bst->fontB = load_font_retry (dpy, font3); + if (font4 && *font4) + bst->fontC = load_font_retry (dpy, font4); + + if (! bst->fontB) bst->fontB = bst->font; + if (! bst->fontC) bst->fontC = bst->font; + + bst->fontA = bst->font; + + + gcv.font = bst->font->fid; + + sprintf (buf1, "%.100s.foreground", name); + sprintf (buf2, "%.100s.Foreground", class); + bst->fg = gcv.foreground = get_pixel_resource (dpy, bst->xgwa.colormap, + buf1, buf2); + sprintf (buf1, "%.100s.background", name); + sprintf (buf2, "%.100s.Background", class); + bst->bg = gcv.background = get_pixel_resource (dpy, bst->xgwa.colormap, + buf1, buf2); + bst->gc = XCreateGC (dpy, window, GCFont|GCForeground|GCBackground, &gcv); + +#ifdef HAVE_JWXYZ + jwxyz_XSetAntiAliasing (dpy, bst->gc, True); +#endif + +# ifdef USE_IPHONE + /* Stupid iPhone X bezel. + #### This is the worst of all possible ways to do this! + */ + if (bst->xgwa.width == 2436 || bst->xgwa.height == 2436) { + if (bst->xgwa.width > bst->xgwa.height) + bst->xoff = 96; + else + bst->yoff = 96; + } +# endif + + bst->left_margin = bst->right_margin = 10; + bst->x = bst->left_margin + bst->xoff; + bst->y = bst->font->ascent + bst->left_margin + bst->yoff; + + XSetWindowBackground (dpy, window, gcv.background); + return bst; +} + + +static void +free_bsod_state (struct bsod_state *bst) +{ + int i; + + if (bst->free_cb) + bst->free_cb (bst); + if (bst->pixmap) + XFreePixmap(bst->dpy, bst->pixmap); + if (bst->mask) + XFreePixmap(bst->dpy, bst->mask); + + XFreeFont (bst->dpy, bst->font); + XFreeGC (bst->dpy, bst->gc); + + for (i = 0; i < bst->queue_size; i++) + switch (bst->queue[i].type) { + case LEFT: case LEFT_FULL: + case RIGHT: case RIGHT_FULL: + case CENTER: case CENTER_FULL: + free ((char *) bst->queue[i].arg1); + break; + default: + break; + } + + free (bst->queue); + free (bst); +} + + +static Pixmap +double_pixmap (Display *dpy, Visual *visual, int depth, Pixmap pixmap, + int pix_w, int pix_h) +{ + int x, y; + Pixmap p2 = XCreatePixmap(dpy, pixmap, pix_w*2, pix_h*2, depth); + XImage *i1 = XGetImage (dpy, pixmap, 0, 0, pix_w, pix_h, ~0L, + (depth == 1 ? XYPixmap : ZPixmap)); + XImage *i2 = XCreateImage (dpy, visual, depth, + (depth == 1 ? XYPixmap : ZPixmap), 0, 0, + pix_w*2, pix_h*2, 8, 0); + XGCValues gcv; + GC gc = XCreateGC (dpy, p2, 0, &gcv); + i2->data = (char *) calloc(i2->height, i2->bytes_per_line); + for (y = 0; y < pix_h; y++) + for (x = 0; x < pix_w; x++) + { + unsigned long p = XGetPixel(i1, x, y); + XPutPixel(i2, x*2, y*2, p); + XPutPixel(i2, x*2+1, y*2, p); + XPutPixel(i2, x*2, y*2+1, p); + XPutPixel(i2, x*2+1, y*2+1, p); + } + free(i1->data); i1->data = 0; + XDestroyImage(i1); + XPutImage(dpy, p2, gc, i2, 0, 0, 0, 0, i2->width, i2->height); + XFreeGC (dpy, gc); + free(i2->data); i2->data = 0; + XDestroyImage(i2); + XFreePixmap(dpy, pixmap); + return p2; +} + + +/***************************************************************************** + *****************************************************************************/ + +static struct bsod_state * +windows_31 (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "windows", "Windows"); + + bst->xoff = bst->left_margin = bst->right_margin = 0; + + BSOD_INVERT (bst); + BSOD_TEXT (bst, CENTER, "Windows\n"); + BSOD_INVERT (bst); + BSOD_TEXT (bst, CENTER, + "A fatal exception 0E has occured at F0AD:42494C4C\n" + "the current application will be terminated.\n" + "\n" + "* Press any key to terminate the current application.\n" + "* Press CTRL+ALT+DELETE again to restart your computer.\n" + " You will lose any unsaved information in all applications.\n" + "\n" + "\n"); + BSOD_TEXT (bst, CENTER, "Press any key to continue"); + + bst->y = ((bst->xgwa.height - bst->yoff - + ((bst->font->ascent + bst->font->descent) * 9)) + / 2); + + XClearWindow (dpy, window); + return bst; +} + +static struct bsod_state * +vmware (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "vmware", "VMware"); + + unsigned long fg = bst->fg; + unsigned long bg = bst->bg; + unsigned long fg2 = get_pixel_resource (dpy, bst->xgwa.colormap, + "vmware.foreground2", + "vmware.foreground"); + BSOD_COLOR (bst, fg2, bg); + BSOD_TEXT (bst, LEFT, + "VMware ESX Server [Releasebuild-98103]\n"); + BSOD_COLOR (bst, fg, bg); + BSOD_TEXT (bst, LEFT, + "PCPU 1 locked up. Failed to ack TLB invalidate.\n" + "frame=0x3a37d98 ip=0x625e94 cr2=0x0 cr3=0x40c66000 cr4=0x16c\n" + "es=0xffffffff ds=0xffffffff fs=0xffffffff gs=0xffffffff\n" + "eax=0xffffffff ebx=0xffffffff ecx=0xffffffff edx=0xffffffff\n" + "ebp=0x3a37ef4 esi=0xffffffff edi=0xffffffff err=-1 eflags=0xffffffff\n" + "*0:1037/helper1-4 1:1107/vmm0:Fagi 2:1121/vmware-vm 3:1122/mks:Franc\n" + "0x3a37ef4:[0x625e94]Panic+0x17 stack: 0x833ab4, 0x3a37f10, 0x3a37f48\n" + "0x3a37f04:[0x625e94]Panic+0x17 stack: 0x833ab4, 0x1, 0x14a03a0\n" + "0x3a37f48:[0x64bfa4]TLBDoInvalidate+0x38f stack: 0x3a37f54, 0x40, 0x2\n" + "0x3a37f70:[0x66da4d]XMapForceFlush+0x64 stack: 0x0, 0x4d3a, 0x0\n" + "0x3a37fac:[0x652b8b]helpFunc+0x2d2 stack: 0x1, 0x14a4580, 0x0\n" + "0x3a37ffc:[0x750902]CpuSched_StartWorld+0x109 stack: 0x0, 0x0, 0x0\n" + "0x3a38000:[0x0]blk_dev+0xfd76461f stack: 0x0, 0x0, 0x0\n" + "VMK uptime: 7:05:43:45.014 TSC: 1751259712918392\n" + "Starting coredump to disk\n"); + BSOD_CHAR_DELAY (bst, 10000); + BSOD_TEXT (bst, LEFT, "using slot 1 of 1... "); + BSOD_CHAR_DELAY (bst, 300000); + BSOD_TEXT (bst, LEFT, "9876"); + BSOD_CHAR_DELAY (bst, 3000000); + BSOD_TEXT (bst, LEFT, "66665"); + BSOD_CHAR_DELAY (bst, 100000); + BSOD_TEXT (bst, LEFT, "4321"); + BSOD_CHAR_DELAY (bst, 0); + BSOD_TEXT (bst, LEFT, "Disk dump successfull.\n" + "Waiting for Debugger (world 1037)\n" + "Debugger is listening on serial port ...\n"); + BSOD_CHAR_DELAY (bst, 10000); + BSOD_TEXT (bst, LEFT, "Press Escape to enter local debugger\n"); + BSOD_CHAR_DELAY (bst, 10000); + BSOD_TEXT (bst, LEFT, "Remote debugger activated. Local debugger no longer available.\n"); + +/* BSOD_CURSOR (bst, CURSOR_LINE, 240000, 999999);*/ + +/* bst->y = ((bst->xgwa.height - bst->yoff - + ((bst->font->ascent + bst->font->descent) * 9)) + / 2);*/ + + XClearWindow (dpy, window); + return bst; +} + + + +static struct bsod_state * +windows_nt (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "nt", "NT"); + + BSOD_TEXT (bst, LEFT, + "*** STOP: 0x0000001E (0x80000003,0x80106fc0,0x8025ea21,0xfd6829e8)\n" + "Unhandled Kernel exception c0000047 from fa8418b4 (8025ea21,fd6829e8)\n" + "\n" + "Dll Base Date Stamp - Name Dll Base Date Stamp - Name\n" + "80100000 2be154c9 - ntoskrnl.exe 80400000 2bc153b0 - hal.dll\n" + "80258000 2bd49628 - ncrc710.sys 8025c000 2bd49688 - SCSIPORT.SYS \n" + "80267000 2bd49683 - scsidisk.sys 802a6000 2bd496b9 - Fastfat.sys\n" + "fa800000 2bd49666 - Floppy.SYS fa810000 2bd496db - Hpfs_Rec.SYS\n" + "fa820000 2bd49676 - Null.SYS fa830000 2bd4965a - Beep.SYS\n" + "fa840000 2bdaab00 - i8042prt.SYS fa850000 2bd5a020 - SERMOUSE.SYS\n" + "fa860000 2bd4966f - kbdclass.SYS fa870000 2bd49671 - MOUCLASS.SYS\n" + "fa880000 2bd9c0be - Videoprt.SYS fa890000 2bd49638 - NCC1701E.SYS\n" + "fa8a0000 2bd4a4ce - Vga.SYS fa8b0000 2bd496d0 - Msfs.SYS\n" + "fa8c0000 2bd496c3 - Npfs.SYS fa8e0000 2bd496c9 - Ntfs.SYS\n" + "fa940000 2bd496df - NDIS.SYS fa930000 2bd49707 - wdlan.sys\n" + "fa970000 2bd49712 - TDI.SYS fa950000 2bd5a7fb - nbf.sys\n" + "fa980000 2bd72406 - streams.sys fa9b0000 2bd4975f - ubnb.sys\n" + "fa9c0000 2bd5bfd7 - usbser.sys fa9d0000 2bd4971d - netbios.sys\n" + "fa9e0000 2bd49678 - Parallel.sys fa9f0000 2bd4969f - serial.SYS\n" + "faa00000 2bd49739 - mup.sys faa40000 2bd4971f - SMBTRSUP.SYS\n" + "faa10000 2bd6f2a2 - srv.sys faa50000 2bd4971a - afd.sys\n" + "faa60000 2bd6fd80 - rdr.sys faaa0000 2bd49735 - bowser.sys\n" + "\n" + "Address dword dump Dll Base - Name\n" + "801afc20 80106fc0 80106fc0 00000000 00000000 80149905 : " + "fa840000 - i8042prt.SYS\n" + "801afc24 80149905 80149905 ff8e6b8c 80129c2c ff8e6b94 : " + "8025c000 - SCSIPORT.SYS\n" + "801afc2c 80129c2c 80129c2c ff8e6b94 00000000 ff8e6b94 : " + "80100000 - ntoskrnl.exe\n" + "801afc34 801240f2 80124f02 ff8e6df4 ff8e6f60 ff8e6c58 : " + "80100000 - ntoskrnl.exe\n" + "801afc54 80124f16 80124f16 ff8e6f60 ff8e6c3c 8015ac7e : " + "80100000 - ntoskrnl.exe\n" + "801afc64 8015ac7e 8015ac7e ff8e6df4 ff8e6f60 ff8e6c58 : " + "80100000 - ntoskrnl.exe\n" + "801afc70 80129bda 80129bda 00000000 80088000 80106fc0 : " + "80100000 - ntoskrnl.exe\n" + "\n" + "Kernel Debugger Using: COM2 (Port 0x2f8, Baud Rate 19200)\n" + "Restart and set the recovery options in the system control panel\n" + "or the /CRASHDEBUG system start option. If this message reappears,\n" + "contact your system administrator or technical support group." + ); + + bst->line_delay = 750; + + XClearWindow (dpy, window); + return bst; +} + + +static struct bsod_state * +windows_2k (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "windows", "Windows"); + + BSOD_TEXT (bst, LEFT, + "*** STOP: 0x000000D1 (0xE1D38000,0x0000001C,0x00000000,0xF09D42DA)\n" + "DRIVER_IRQL_NOT_LESS_OR_EQUAL \n" + "\n" + "*** Address F09D42DA base at F09D4000, DateStamp 39f459ff - CRASHDD.SYS\n" + "\n" + "Beginning dump of physical memory\n"); + BSOD_PAUSE (bst, 4000000); + BSOD_TEXT (bst, LEFT, + "Physical memory dump complete. Contact your system administrator or\n" + "technical support group.\n"); + + bst->left_margin = 40; + bst->y = (bst->font->ascent + bst->font->descent) * 10; + bst->line_delay = 750; + + XClearWindow (dpy, window); + return bst; +} + + +static struct bsod_state * +windows_me (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "windows", "Windows"); + + BSOD_TEXT (bst, LEFT, + "Windows protection error. You need to restart your computer.\n\n" + "System halted."); + BSOD_CURSOR (bst, CURSOR_LINE, 120000, 999999); + + bst->left_margin = 40; + bst->y = ((bst->xgwa.height - bst->yoff - + ((bst->font->ascent + bst->font->descent) * 3)) + / 2); + + XClearWindow (dpy, window); + return bst; +} + + +static struct bsod_state * +windows_xp (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "windows", "Windows"); + + BSOD_TEXT (bst, LEFT, /* From Wm. Rhodes */ + "A problem has been detected and windows has been shut down to prevent " + "damage\n" + "to your computer.\n" + "\n" + "If this is the first time you've seen this Stop error screen,\n" + "restart your computer. If this screen appears again, follow\n" + "these steps:\n" + "\n" + "Check to be sure you have adequate disk space. If a driver is\n" + "identified in the Stop message, disable the driver or check\n" + "with the manufacturer for driver updates. Try changing video\n" + "adapters.\n" + "\n" + "Check with your hardware vendor for any BIOS updates. Disable\n" + "BIOS memory options such as caching or shadowing. If you need\n" + "to use Safe Mode to remove or disable components, restart your\n" + "computer, press F8 to select Advanced Startup Options, and then\n" + "select Safe Mode.\n" + "\n" + "Technical information:\n" + "\n" + "*** STOP: 0x0000007E (0xC0000005,0xF88FF190,0x0xF8975BA0,0xF89758A0)\n" + "\n" + "\n" + "*** EPUSBDSK.sys - Address F88FF190 base at FF88FE000, datestamp " + "3b9f3248\n" + "\n" + "Beginning dump of physical memory\n"); + BSOD_PAUSE (bst, 4000000); + BSOD_TEXT (bst, LEFT, + "Physical memory dump complete.\n" + "Contact your system administrator or technical support group for " + "further\n" + "assistance.\n"); + + XClearWindow (dpy, window); + return bst; +} + + +static struct bsod_state * +windows_lh (Display *dpy, Window window) +{ + struct bsod_state *bst = + make_bsod_state (dpy, window, "windowslh", "WindowsLH"); + + unsigned long fg = bst->fg; + unsigned long bg = bst->bg; + unsigned long bg2 = get_pixel_resource (dpy, bst->xgwa.colormap, + "windowslh.background2", + "WindowsLH.Background"); + + /* The "RSOD" that appeared with "Windows Longhorn 5048.050401-0536_x86fre" + As reported by http://joi.ito.com/RedScreen.jpg + */ + BSOD_COLOR (bst, bg, bg2); + BSOD_TEXT (bst, CENTER_FULL, "Windows Boot Error\n"); + BSOD_COLOR (bst, fg, bg); + BSOD_TEXT (bst, CENTER, + "\n" + "Windows Boot Manager has experienced a problem.\n" + "\n" + "\n" + " Status: 0xc000000f\n" + "\n" + "\n" + "\n" + " Info: An error occurred transferring exectuion." /* (sic) */ + "\n" + "\n" + "\n" + "You can try to recover the system with the Microsoft Windows " + "System Recovery\n" + "Tools. (You might need to restart the system manually.)\n" + "\n" + "If the problem continues, please contact your system administrator " + "or computer\n" + "manufacturer.\n" + ); + BSOD_MOVETO (bst, bst->left_margin + bst->xoff, + bst->xgwa.height - bst->yoff - bst->font->descent); + BSOD_COLOR (bst, bg, bg2); + BSOD_TEXT (bst, LEFT_FULL, " SPACE=Continue\n"); + + bst->y = bst->font->ascent; + + XClearWindow (dpy, window); + return bst; +} + + +static struct bsod_state * +windows_10_update (Display *dpy, Window window) +{ + struct bsod_state *bst = + make_bsod_state (dpy, window, "win10", "Win10"); + const char *fmt = "Working on updates %d%%"; + char line1[255]; + const char *line2 = "Don't turn off your PC. This will take a while."; + const char *line3 = "Your PC will restart several times."; + int line_height = bst->fontA->ascent + bst->fontA->descent; + int y1 = bst->xgwa.height / 2 - line_height * 4; + int y2 = bst->xgwa.height - bst->yoff - line_height * 3; + int pct; + + /* TODO: win10_spinner.gif goes at (y - line_height * 2 - 64). */ + + for (pct = 0; pct < 98; pct++) + { + BSOD_MOVETO (bst, 0, y1); + sprintf (line1, fmt, pct); + BSOD_TEXT (bst, CENTER, line1); + BSOD_MOVETO (bst, 0, y1 + line_height); + BSOD_TEXT (bst, CENTER, line2); + BSOD_MOVETO (bst, 0, y2); + BSOD_TEXT (bst, CENTER, line3); + BSOD_PAUSE (bst, 200000 + (random() % 3000000) + (random() % 3000000)); + } + + XClearWindow (dpy, window); + return bst; +} + + +static struct bsod_state * +windows_10 (Display *dpy, Window window) +{ + struct bsod_state *bst = + make_bsod_state (dpy, window, "win10", "Win10"); + + int qr_width = 41; + int qr_height = 41; + static const unsigned char qr_bits[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0x01, + 0x03,0x9A,0x70,0xEE,0x80,0x01,0xFB,0x22,0xAA,0xA6,0xBE,0x01, + 0x8B,0x8E,0x74,0xE7,0xA2,0x01,0x8B,0xEE,0x42,0xC4,0xA2,0x01, + 0x8B,0x42,0x6E,0xED,0xA2,0x01,0xFB,0xDA,0x63,0xA6,0xBE,0x01, + 0x03,0xAA,0xAA,0xAA,0x80,0x01,0xFF,0x8B,0xD8,0x9D,0xFF,0x01, + 0x63,0x62,0xDA,0x1B,0x98,0x01,0x6F,0x67,0x98,0x9F,0xBC,0x01, + 0x4F,0xCC,0x55,0x81,0x83,0x01,0xB7,0x6D,0xFF,0x68,0xB2,0x01, + 0xC3,0x10,0x87,0x8B,0x96,0x01,0x6F,0xB1,0x91,0x58,0x94,0x01, + 0xE3,0x36,0x88,0x84,0xB8,0x01,0x83,0x9B,0xFE,0x59,0xD7,0x01, + 0x3B,0x74,0x98,0x5C,0xB4,0x01,0x37,0x75,0xDC,0x91,0xA6,0x01, + 0x77,0xDE,0x01,0x54,0xBA,0x01,0xBB,0x6D,0x8B,0xB9,0xB5,0x01, + 0x1F,0x06,0xBD,0x9B,0xB4,0x01,0xD3,0xBD,0x91,0x19,0x84,0x01, + 0x0B,0x20,0xD8,0x91,0xB4,0x01,0x33,0x95,0xBC,0x0A,0xD5,0x01, + 0xB3,0x60,0xDC,0xD9,0xB6,0x01,0xEF,0x77,0x18,0x09,0xA4,0x01, + 0xA3,0xC2,0x95,0x51,0xB2,0x01,0xDF,0x63,0xDB,0xBE,0xB3,0x01, + 0x03,0x08,0xC9,0x09,0xF0,0x01,0xFF,0xA3,0x19,0xBD,0xFB,0x01, + 0x03,0x2E,0x84,0xA5,0xAA,0x01,0xFB,0x9A,0xFC,0x9B,0xBB,0x01, + 0x8B,0x7E,0x9C,0x1D,0xB0,0x01,0x8B,0x6E,0x58,0xA1,0xDB,0x01, + 0x8B,0xDA,0xD5,0x65,0xA2,0x01,0xFB,0x72,0xFB,0xE9,0xF0,0x01, + 0x03,0x02,0x99,0x3B,0xB3,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0x01, + 0xFF,0xFF,0xFF,0xFF,0xFF,0x01}; + Pixmap pixmap; + + const char *lines[] = { + ":(\n", + "\n", + "Your PC ran into a problem and needs to restart. We're just\n", + "collecting some error info, and then we'll restart for you.\n", + "\n", + "\n", + "\n", + "For more information about this issue and\n", + "possible fixes, visit\n", +/* "https://www.jwz.org/xscreensaver\n",*/ + "http://youtu.be/-RjmN9RZyr4\n", + "\n", + "If you call a support person, give them this info:\n", + "Stop code CRITICAL_PROCESS_DIED", + }; + int i, y = 0, y0 = 0; + int line_height0 = bst->fontB->ascent; + int line_height1 = bst->fontA->ascent + bst->fontA->descent; + int line_height2 = bst->fontC->ascent + bst->fontC->descent; + int line_height = line_height0; + int top, left0, left; + int stop = 60 + (random() % 39); + + if (!(random() % 7)) + return windows_10_update (dpy, window); + + + line_height1 *= 1.3; + line_height2 *= 1.5; + + top = ((bst->xgwa.height - bst->yoff + - (line_height0 * 1 + + line_height1 * 6 + + line_height2 * 6)) + / 2); + + { + int dir, ascent, descent; + XCharStruct ov; + const char *s = lines[2]; + XTextExtents (bst->fontA, s, strlen(s), + &dir, &ascent, &descent, &ov); + left = left0 = (bst->xgwa.width - ov.width) / 2; + } + + pixmap = XCreatePixmapFromBitmapData (dpy, window, (char *) qr_bits, + qr_width, qr_height, + bst->fg, bst->bg, bst->xgwa.depth); + { + int n = 2; + if (bst->xgwa.width > 2560) n++; /* Retina displays */ + for (i = 0; i < n; i++) + { + pixmap = double_pixmap (dpy, bst->xgwa.visual, bst->xgwa.depth, + pixmap, qr_width, qr_height); + qr_width *= 2; + qr_height *= 2; + } + } + bst->pixmap = pixmap; + + y = top; + line_height = line_height0; + BSOD_FONT (bst, 1); + for (i = 0; i < countof(lines); i++) + { + BSOD_MOVETO (bst, left, y); + BSOD_TEXT (bst, LEFT, lines[i]); + y += line_height; + if (i == 0) + { + BSOD_FONT (bst, 0); + line_height = line_height1; + } + else if (i == 4) + { + y0 = y; + y += line_height / 2; + BSOD_PIXMAP (bst, 0, 0, qr_width, qr_height, left, y + line_height1); + BSOD_FONT (bst, 2); + line_height = line_height2; + left += qr_width + line_height2 / 2; +# ifdef HAVE_MOBILE + y -= 14; +# endif + } + } + + left = left0; + BSOD_FONT (bst, 0); + for (i = 0; i <= stop; i++) + { + char buf[100]; + sprintf (buf, "%d%% complete", i); + BSOD_MOVETO (bst, left, y0); + BSOD_TEXT (bst, LEFT, buf); + BSOD_PAUSE (bst, 85000); + } + BSOD_PAUSE (bst, 3000000); + + XClearWindow (dpy, window); + return bst; +} + + +static struct bsod_state * +windows_other (Display *dpy, Window window) +{ + /* Lump all of the 2K-ish crashes together and select them randomly... + */ + int which = (random() % 4); + switch (which) { + case 0: return windows_2k (dpy, window); break; + case 1: return windows_me (dpy, window); break; + case 2: return windows_xp (dpy, window); break; + case 3: return windows_lh (dpy, window); break; + default: abort(); break; + } +} + +/* Windows and Apple2 ransomware. + */ +static struct bsod_state *apple2ransomware (Display *, Window); + +static struct bsod_state * +windows_ransomware (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, + "ransomware", "Ransomware"); + char buf[1024]; + + int pix_w = 0, pix_h = 0; + Pixmap mask = 0; + Pixmap pixmap = image_data_to_pixmap (dpy, window, + ransomware_png, sizeof(ransomware_png), + &pix_w, &pix_h, &mask); + int i, n = 0; + + /* Don't start the countdown from the start, advance the deadline by 3 - 30 + hours */ + int advance_deadline = (random() % 97200) + 10800; + + time_t now = time(NULL); + const time_t stage1_deadline = now + 259200 - advance_deadline; /* 3 days */ + const time_t stage2_deadline = now + 604800 - advance_deadline; /* 7 days */ + char stage1_deadline_str[25], stage2_deadline_str[25]; + char countdown_str[16]; + int countdown_d, countdown_h, countdown_m, countdown_s, countdown_r; + int line_height = bst->font->ascent + bst->font->descent; + int line_height1 = bst->fontA->ascent + bst->fontA->descent; + + const char *currencies[] = { + "Blitcoin", + "Bitcorn", + "Buttcorn", + "clicks", + "clicks", + "Ass Pennies", + "Ass Pennies", + "Dollary-doos", + "Dunning-Krugerrands", + "Dunning-Krugerrands", + "Dunning-Krugerrands", + "Dunning-Krugerrands", + "Dunning-Krugerrands", + "Dunning-Krugerrands", + "gift certificates", + "Creepto-Currency", + "secret sauce", + "Tribbles", + }; + + const char *currency = currencies[random() % countof(currencies)]; + + const char *header_quips[] = { + "Oops, your screens have been encrypted!", + "Oops, your screens have been encrypted!", + "Oops, your screens have been encrypted!", + "Oops, your screens have been encrypted!", + "Oops, your screen have encrypted!", + "Oops, you're screens have been encrypted!", + "Oops, your screens have been encrupted!", + "Oops, your screens have been encrumpet!", + "Oops, your screens have been encrusted!", + "If you don't pay this ransom, then you are a theif!", + "Your screen was subject to the laws of mathomatics!", + "Oops, your screen was shaved by Occam's Razor!", + "Oops, your screen was perturbated by Langford's Basilisk!", + "Your screen is now stored as Snapchat messages!", + "Oops, your screen is now stored on Betamax!", + "Oops, your screen is now in the clown!", + "Oops, your screen has been deprecated!", + "Oops, you're screen was seized by the FBI!", + "All your screen was shared with your coworkers!", + "All your screen are belong to us.", + "Well actually, your screen isn't needed anymore.", + "u just got popped with some 0day shit!!", + "M'lady,", + }; + + const char *header_quip = header_quips[random() % countof(header_quips)]; + + /* You got this because... */ + const char *excuse_quips[] = { + "all human actions are equivalent and all are on principle doomed " + "to failure", + "you hold a diverse portfolio of cryptocurrencies", + "you need to get in on ransomware futures at the ground floor", + "your flight was overbooked", + "you did not apply the security update for bugs NSA keys secret from " + "Microsoft in your Windows(R) operating system", + "you are bad and you should feel bad", + "you used the wifi at defcon", + "you lack official Clown Strike[TM] threaty threat technology", + }; + + const char *excuse_quip = excuse_quips[random() % countof(excuse_quips)]; + + /* WELL ACTUALLY, screensavers aren't really nescessary anymore because... */ + const char *screensaver_quips[] = { + "I read it on hacker news", + "that's official Debian policy now", + "that is the official policy of United Airlines", + "they cause global warming", + "they lack an eternal struggle", + "they lack a vapid dichotomy", + "those electrons could be used for gold farming instead", + "you can make more money in art exhibitions", + }; + + const char *screensaver_quip = + screensaver_quips[random() % countof(screensaver_quips)]; + + const char *lines[] = { + "*What Happened To My Computer?\n", + "Your important pixels are paintcrypted. All of your documents, photos, ", + "videos, databases, icons, dick pics are not accessible because they ", + "have been bitblted. Maybe you are looking for a way to get them back, ", + "but don't waste your time. Nobody can recover your pixels without our ", + "pointer motion clicker services.\n", + "\n", + "*Can I Recover My Important Dick Pix?\n", + "Yes. We guarantee that you can recover them safely and easily. But you ", + "not have much time.\n", + "You can expose some files for free. Try it now by pressing .\n", + "But if you want to unsave all your screens, then you need to pay. ", + "You have only 3 days to click. After that the clicks will double. ", + "After 7 days your pixels will be gone forever.\n", + "We will have free events for cheapskates who can't pay in 6 months, ", + "long after all the pixels are xored.\n", + "\n", + "*How do I pay?\n", + "Payment is accepted in ", "[C]", + " only. For more information, press .", + " Please check the current price of ", "[C]", " and buy some ", "[C]", + ". For more information, press .\n", + "And send the correct amount to the address specified below. After your ", + "payment, press . Best time to check: 4-6am, Mon-Fri.\n", + "\n", + "*Why Did I Get This?\n", + "You got this because ", "[Q]", + ". Also you didn't click hard enough and now Tinkerbelle is dead.\n", + "\n", + "*But Aren't Screensavers Are Necessary?\n", + "WELL ACTUALLY, screensavers aren't really nescessary anymore because ", + "[S]", ".\n", + "\n", + "Please file complaints to @POTUS on Twitter.\n", + "\n" + "\n" + "\n" + "\n", + "*GREETZ TO CRASH OVERRIDE AND ALSO JOEY\n", + }; + + /* Positions of UI elements. Layout: + + +---------+-+---------------------------------------+ + | LOGO | | HEADER | + | | |---------------------------------------| + | | | NOTE TEXT | + | DEAD | | | + | LINE | | | + | TIMERS | | | + | | | | + | | | | + | | | | + | | | | + | | | | + +---------+ | | + | LINKS | +---------------------------------------+ + | LINKS | | FOOTER | + +---------+-+---------------------------------------+ + + The right side of the UI maximises to available width. + The note text maximises to available height. + The logo, header and timers are anchored to the top left of the window. + The links and footer are anchored to the bottom left of the window. + The entire window is a fixed 4:3 scale, with a minimum margin around it. + */ + + /* main window text */ + unsigned long fg = bst->fg; + unsigned long bg = bst->bg; + /* ransom note */ + unsigned long fg2 = get_pixel_resource (dpy, bst->xgwa.colormap, + "ransomware.foreground2", + "Ransomware.Foreground"); + unsigned long bg2 = get_pixel_resource (dpy, bst->xgwa.colormap, + "ransomware.background2", + "Ransomware.Background"); + /* buttons */ + unsigned long fg3 = get_pixel_resource (dpy, bst->xgwa.colormap, + "ransomware.foreground3", + "Ransomware.Foreground"); + unsigned long bg3 = get_pixel_resource (dpy, bst->xgwa.colormap, + "ransomware.background3", + "Ransomware.Background"); + /* links */ + unsigned long link = get_pixel_resource (dpy, bst->xgwa.colormap, + "ransomware.link", + "Ransomware.Foreground"); + /* headers */ + unsigned long theader = get_pixel_resource (dpy, bst->xgwa.colormap, + "ransomware.timerheader", + "Ransomware.Foreground"); + int left_column_width; + int right_column_width; + int right_column_height; + int stage1_countdown_y, stage2_countdown_y; + int margin; + int top_height, bottom_height; + int x, y; + + if (bst->xgwa.width > 2560) n++; /* Retina displays */ + for (i = 0; i < n; i++) + { + pixmap = double_pixmap (dpy, bst->xgwa.visual, bst->xgwa.depth, + pixmap, pix_w, pix_h); + mask = double_pixmap (dpy, bst->xgwa.visual, 1, + mask, pix_w, pix_h); + pix_w *= 2; + pix_h *= 2; + } + + margin = line_height; + left_column_width = MAX (pix_w, line_height1 * 8); + right_column_width = MIN (line_height * 40, + MAX (line_height * 8, + bst->xgwa.width - left_column_width + - margin*2)); + top_height = line_height * 2.5; + bottom_height = line_height * 6; + right_column_height = MIN (line_height * 36, + bst->xgwa.height - bottom_height - top_height + - line_height); + + if ((bst->xgwa.width / 4) * 3 > bst->xgwa.height) + /* Wide screen: keep the big text box at 4:3, centered. */ + right_column_height = MIN (right_column_height, + right_column_width * 4 / 3); + else if (right_column_width < line_height * 30) + /* Tall but narrow screen: make the text box be full height. */ + right_column_height = (bst->xgwa.height - bottom_height - top_height + - line_height); + + x = (bst->xgwa.width - left_column_width - right_column_width - margin) / 2; + y = (bst->xgwa.height - right_column_height - bottom_height) / 2; + + bst->xoff = bst->left_margin = bst->right_margin = 0; + + if (!(random() % 8)) + return apple2ransomware (dpy, window); + + /* Draw the main red window */ + BSOD_INVERT (bst); + BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height); + + if (pixmap) { + bst->pixmap = pixmap; + bst->mask = mask; + BSOD_PIXMAP (bst, 0, 0, pix_w, pix_h, + x + (left_column_width - pix_w) / 2, + y); + } + + /* Setup deadlines */ + strftime (stage1_deadline_str, sizeof(stage1_deadline_str), + "%m/%d/%Y %H:%M:%S", localtime(&stage1_deadline)); + strftime (stage2_deadline_str, sizeof(stage1_deadline_str), + "%m/%d/%Y %H:%M:%S", localtime(&stage2_deadline)); + + BSOD_INVERT (bst); + /* Draw header pane */ + BSOD_FONT (bst, 0); + + BSOD_MARGINS (bst, + x + left_column_width + margin, + bst->xgwa.width - + (x + left_column_width + margin + right_column_width)); + BSOD_MOVETO (bst, x + left_column_width + margin, + y + bst->fontA->ascent); + BSOD_COLOR (bst, fg, bg); + BSOD_WORD_WRAP (bst); + BSOD_TEXT (bst, CENTER, header_quip); + BSOD_TRUNCATE (bst); + + /* Draw left-side timers */ + BSOD_MARGINS (bst, x, bst->xgwa.width - (x + left_column_width)); + BSOD_MOVETO (bst, x, y + pix_h + line_height); + BSOD_FONT (bst, 1); + + BSOD_COLOR (bst, theader, bg); + BSOD_TEXT (bst, CENTER, "Payment will be raised on\n"); + BSOD_COLOR (bst, fg, bg); + BSOD_TEXT (bst, CENTER, stage1_deadline_str); + + stage1_countdown_y = y + pix_h + line_height + line_height1 * 3; + BSOD_MOVETO (bst, x, stage1_countdown_y - line_height); + BSOD_TEXT (bst, CENTER, "Time Left"); + + BSOD_COLOR (bst, theader, bg); + BSOD_WORD_WRAP (bst); + BSOD_TEXT (bst, CENTER, "\n\n\n\nYour pixels will be lost on\n"); + BSOD_TRUNCATE (bst); + BSOD_COLOR (bst, fg, bg); + BSOD_TEXT (bst, CENTER, stage2_deadline_str); + + stage2_countdown_y = stage1_countdown_y + line_height1 * 5; + BSOD_MOVETO (bst, x, stage2_countdown_y - line_height); + BSOD_TEXT (bst, CENTER, "Time Left"); + + BSOD_FONT (bst, 1); + + /* Draw links, but skip on small screens */ + if (right_column_height > 425) { + BSOD_MOVETO (bst, x, + y + right_column_height + top_height + bottom_height + - line_height1 * 5); + BSOD_COLOR (bst, link, bg); + BSOD_TEXT (bst, LEFT, "\n"); + BSOD_TEXT (bst, LEFT, "About "); + BSOD_TEXT (bst, LEFT, currency); + BSOD_TEXT (bst, LEFT, "\n\n" + "How to buy "); + BSOD_TEXT (bst, LEFT, currency); + BSOD_TEXT (bst, LEFT, "\n\n" + "Contact us\n"); + } + + /* Ransom note text area */ + BSOD_COLOR (bst, bg2, fg2); + BSOD_RECT (bst, True, + x + left_column_width + margin, + y + top_height, + right_column_width, + right_column_height); + BSOD_MOVETO (bst, + x + left_column_width + margin + line_height / 2, + y + top_height + line_height + line_height / 2); + BSOD_MARGINS (bst, + x + left_column_width + margin + line_height / 2, + bst->xgwa.width - + (x + left_column_width + margin + right_column_width)); + BSOD_VERT_MARGINS (bst, + y + top_height + line_height / 2, + bottom_height - line_height); + BSOD_INVERT (bst); + + /* Write out the ransom note itself */ + BSOD_CROP (bst, True); + BSOD_WORD_WRAP (bst); + for (i = 0; i < countof(lines); i++) + { + const char *s = lines[i]; + if (!strcmp(s, "[C]")) s = currency; + else if (!strcmp(s, "[Q]")) s = excuse_quip; + else if (!strcmp(s, "[S]")) s = screensaver_quip; + + if (*s == '*') + { + s++; + BSOD_FONT (bst, 2); + } + else + BSOD_FONT (bst, 0); + + BSOD_TEXT (bst, LEFT, s); + } + BSOD_TRUNCATE (bst); + BSOD_CROP (bst, False); + BSOD_FONT (bst, 0); + + /* Draw over any overflowing ransom text. */ + BSOD_COLOR (bst, bg, fg); + BSOD_RECT (bst, True, + x + left_column_width + margin, + y + top_height + right_column_height, + bst->xgwa.width, bst->xgwa.height); + BSOD_RECT (bst, True, + x + left_column_width + margin + right_column_width, + y + top_height, + bst->xgwa.width, bst->xgwa.height); + + /* Draw the footer */ + BSOD_COLOR (bst, theader, bg); + BSOD_MOVETO (bst, + x + left_column_width + margin, + y + top_height + right_column_height + line_height * 2); + + sprintf(buf, "Send $%.2f of %s to this address:\n", 101+frand(888), currency); + BSOD_TEXT (bst, LEFT, buf); + BSOD_COLOR (bst, fg2, bg2); + + /* address, has some extra slashes in there because it's a fake address */ + for (i = 0; i < 40; i++) { + const char *s = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123459789"; + buf[i] = s[random() % strlen(s)]; + } + strncpy (buf, " //", 3); + buf[10] = '/'; + buf[17] = '/'; + buf[24] = '/'; + strcpy (buf+33, " "); + BSOD_TEXT (bst, LEFT, buf); + + BSOD_COLOR (bst, fg, bg); + BSOD_TEXT (bst, LEFT, " "); + BSOD_COLOR (bst, fg3, bg3); + BSOD_TEXT (bst, LEFT, " Copy "); + BSOD_COLOR (bst, fg, bg); + BSOD_TEXT (bst, LEFT, "\n\n"); + + BSOD_COLOR (bst, fg3, bg3); + BSOD_TEXT (bst, LEFT, " Demogrify Screen "); + BSOD_COLOR (bst, fg, bg); + BSOD_TEXT (bst, LEFT, " "); + BSOD_COLOR (bst, fg3, bg3); + BSOD_TEXT (bst, LEFT, " Check Payment "); + + + /* Draw countdown timers */ + BSOD_COLOR (bst, fg, bg); + BSOD_FONT (bst, 0); + do { + /* First timer */ + BSOD_MOVETO (bst, x, stage1_countdown_y); + BSOD_MARGINS (bst, x, bst->xgwa.width - (x + left_column_width)); + + countdown_r = stage1_deadline - now; + countdown_s = countdown_r % 60; + countdown_m = (countdown_r / 60) % 60; + countdown_h = (countdown_r / 3600) % 24; + countdown_d = (countdown_r / 86400); + + sprintf (countdown_str, "%02d:%02d:%02d:%02d\n", + countdown_d, countdown_h, countdown_m, countdown_s); + + BSOD_TEXT (bst, CENTER, countdown_str); + + /* Second timer */ + BSOD_MOVETO (bst, x, stage2_countdown_y); + + countdown_r = stage2_deadline - now; + countdown_s = countdown_r % 60; + countdown_m = (countdown_r / 60) % 60; + countdown_h = (countdown_r / 3600) % 24; + countdown_d = (countdown_r / 86400); + + sprintf (countdown_str, "%02d:%02d:%02d:%02d\n", + countdown_d, countdown_h, countdown_m, countdown_s); + + BSOD_TEXT (bst, CENTER, countdown_str); + + BSOD_PAUSE (bst, 1000000); + now++; + + /* While the "correct" thing to do is create enough of a script to fill the + * stage2_deadline, this would be 7 days of "frames", which is quite a bit + * of memory. Instead, only fill the buffer with 1 hour of frames, which is + * enough to make the point before xscreensaver cycles us. + */ + } while (stage1_deadline - now > 3600); + + XClearWindow (dpy, window); + return bst; +} + + +/* As seen in Portal 2. By jwz. + */ +static struct bsod_state * +glados (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "glaDOS", "GlaDOS"); + const char * panicstr[] = { + "\n", + "MOLTEN CORE WARNING\n", + "\n", + "An operator error exception has occurred at FISSREAC0020093:09\n", + "FISSREAC0020077:14 FISSREAC0020023:17 FISSREAC0020088:22\n", + "neutron multiplication rate at spikevalue 99999999\n", + "\n", + "* Press any key to vent radiological emissions into atmosphere.\n", + "* Consult reactor core manual for instructions on proper reactor core\n", + "maintenance and repair.\n", + "\n", + "Press any key to continue\n", + }; + + int i; + + bst->xoff = bst->left_margin = bst->right_margin = 0; + + bst->y = ((bst->xgwa.height - bst->yoff - + ((bst->font->ascent + bst->font->descent) * countof(panicstr))) + / 2); + + BSOD_MOVETO (bst, 0, bst->y); + BSOD_INVERT (bst); + BSOD_TEXT (bst, CENTER, "OPERATOR ERROR\n"); + BSOD_INVERT (bst); + for (i = 0; i < countof(panicstr); i++) + BSOD_TEXT (bst, CENTER, panicstr[i]); + BSOD_PAUSE (bst, 1000000); + BSOD_INVERT (bst); + BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height); + BSOD_INVERT (bst); + BSOD_PAUSE (bst, 250000); + BSOD_RESET (bst); + + XClearWindow (dpy, window); + return bst; +} + + + +/* SCO OpenServer 5 panic, by Tom Kelly + */ +static struct bsod_state * +sco (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "sco", "SCO"); + + BSOD_TEXT (bst, LEFT, + "Unexpected trap in kernel mode:\n" + "\n" + "cr0 0x80010013 cr2 0x00000014 cr3 0x00000000 tlb 0x00000000\n" + "ss 0x00071054 uesp 0x00012055 efl 0x00080888 ipl 0x00000005\n" + "cs 0x00092585 eip 0x00544a4b err 0x004d4a47 trap 0x0000000E\n" + "eax 0x0045474b ecx 0x0042544b edx 0x57687920 ebx 0x61726520\n" + "esp 0x796f7520 ebp 0x72656164 esi 0x696e6720 edi 0x74686973\n" + "ds 0x3f000000 es 0x43494c48 fs 0x43525343 gs 0x4f4d4b53\n" + "\n" + "PANIC: k_trap - kernel mode trap type 0x0000000E\n" + "Trying to dump 5023 pages to dumpdev hd (1/41), 63 pages per '.'\n" + ); + BSOD_CHAR_DELAY (bst, 100000); + BSOD_TEXT (bst, LEFT, + "................................................................." + "..............\n" + ); + BSOD_CHAR_DELAY (bst, 0); + BSOD_TEXT (bst, LEFT, + "5023 pages dumped\n" + "\n" + "\n" + ); + BSOD_PAUSE (bst, 2000000); + BSOD_TEXT (bst, LEFT, + "** Safe to Power Off **\n" + " - or -\n" + "** Press Any Key to Reboot **\n" + ); + + bst->y = ((bst->xgwa.height - bst->yoff - + ((bst->font->ascent + bst->font->descent) * 18))); + + XClearWindow (dpy, window); + return bst; +} + + +/* Linux (sparc) panic, by Tom Kelly + */ +static struct bsod_state * +sparc_linux (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, + "sparclinux", "SparcLinux"); + bst->scroll_p = True; + bst->y = bst->xgwa.height - bst->yoff + - bst->font->ascent - bst->font->descent; + + BSOD_TEXT (bst, LEFT, + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "Unable to handle kernel paging request at virtual address f0d4a000\n" + "tsk->mm->context = 00000014\n" + "tsk->mm->pgd = f26b0000\n" + " \\|/ ____ \\|/\n" + " \"@'/ ,. \\`@\"\n" + " /_| \\__/ |_\\\n" + " \\__U_/\n" + "gawk(22827): Oops\n" + "PSR: 044010c1 PC: f001c2cc NPC: f001c2d0 Y: 00000000\n" + "g0: 00001000 g1: fffffff7 g2: 04401086 g3: 0001eaa0\n" + "g4: 000207dc g5: f0130400 g6: f0d4a018 g7: 00000001\n" + "o0: 00000000 o1: f0d4a298 o2: 00000040 o3: f1380718\n" + "o4: f1380718 o5: 00000200 sp: f1b13f08 ret_pc: f001c2a0\n" + "l0: efffd880 l1: 00000001 l2: f0d4a230 l3: 00000014\n" + "l4: 0000ffff l5: f0131550 l6: f012c000 l7: f0130400\n" + "i0: f1b13fb0 i1: 00000001 i2: 00000002 i3: 0007c000\n" + "i4: f01457c0 i5: 00000004 i6: f1b13f70 i7: f0015360\n" + "Instruction DUMP:\n" + ); + + XClearWindow (dpy, window); + return bst; +} + + +/* BSD Panic by greywolf@starwolf.com - modeled after the Linux panic above. + By Grey Wolf + */ +static struct bsod_state * +bsd (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "bsd", "BSD"); + + const char * const panicstr[] = { + "panic: ifree: freeing free inode\n", + "panic: blkfree: freeing free block\n", + "panic: improbability coefficient below zero\n", + "panic: cgsixmmap\n", + "panic: crazy interrupts\n", + "panic: nmi\n", + "panic: attempted windows install\n", + "panic: don't\n", + "panic: free inode isn't\n", + "panic: cpu_fork: curproc\n", + "panic: malloc: out of space in kmem_map\n", + "panic: vogon starship detected\n", + "panic: teleport chamber: out of order\n", + "panic: Brain fried - core dumped\n" + }; + int i, n, b; + char syncing[80], bbuf[5]; + + for (i = 0; i < sizeof(syncing); i++) + syncing[i] = 0; + + i = (random() % (sizeof(panicstr) / sizeof(*panicstr))); + BSOD_TEXT (bst, LEFT, panicstr[i]); + BSOD_TEXT (bst, LEFT, "Syncing disks: "); + + b = (random() % 40); + for (n = 0; (n < 20) && (b > 0); n++) + { + if (i) + { + i = (random() & 0x7); + b -= (random() & 0xff) % 20; + if (b < 0) + b = 0; + } + sprintf (bbuf, "%d ", b); + BSOD_TEXT (bst, LEFT, bbuf); + BSOD_PAUSE (bst, 1000000); + } + + BSOD_TEXT (bst, LEFT, "\n"); + BSOD_TEXT (bst, LEFT, (b ? "damn!" : "sunk!")); + BSOD_TEXT (bst, LEFT, "\nRebooting\n"); + + bst->y = ((bst->xgwa.height - bst->yoff - + ((bst->font->ascent + bst->font->descent) * 4))); + + XClearWindow (dpy, window); + return bst; +} + + +static struct bsod_state * +amiga (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "amiga", "Amiga"); + + const char *guru1 ="Software failure. Press left mouse button to continue."; + const char *guru2 ="Guru Meditation #00000003.00C01570"; + Pixmap pixmap = 0; + Pixmap mask = 0; + int pix_w = 0, pix_h = 0; + int height; + int lw = bst->font->ascent + bst->font->descent; + unsigned long fg = bst->fg; + unsigned long bg = bst->bg; + + unsigned long bg2 = get_pixel_resource (dpy, bst->xgwa.colormap, + "amiga.background2", + "Amiga.Background"); + + bst->yoff = 0; + bst->top_margin = bst->bottom_margin = 0; + + pixmap = image_data_to_pixmap (dpy, window, + amiga_png, sizeof(amiga_png), + &pix_w, &pix_h, &mask); + + if (pixmap) + { + int i, n = 0; + if (MIN (bst->xgwa.width, bst->xgwa.height) > 600) n++; + if (bst->xgwa.width > 2560) n++; /* Retina displays */ + for (i = 0; i < n; i++) + { + pixmap = double_pixmap (dpy, bst->xgwa.visual, bst->xgwa.depth, + pixmap, pix_w, pix_h); + mask = double_pixmap (dpy, bst->xgwa.visual, 1, mask, pix_w, pix_h); + pix_w *= 2; + pix_h *= 2; + } + } + + XSetLineAttributes (dpy, bst->gc, lw, LineSolid, CapButt, JoinMiter); + + height = lw * 5; + + bst->char_delay = bst->line_delay = 0; + + BSOD_PAUSE (bst, 2000000); + BSOD_COPY (bst, 0, 0, bst->xgwa.width, bst->xgwa.height - height, 0, height); + + BSOD_COLOR (bst, fg, bg); + BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, height); /* red */ + BSOD_COLOR (bst, bg, fg); + BSOD_RECT (bst, True, lw/2, lw/2, bst->xgwa.width-lw, height-lw); /* black */ + BSOD_COLOR (bst, fg, bg); + BSOD_MOVETO (bst, 0, lw*2); + BSOD_TEXT (bst, CENTER, guru1); + BSOD_MOVETO (bst, 0, lw*3.5); + BSOD_TEXT (bst, CENTER, guru2); + BSOD_PAUSE (bst, 1000000); + + BSOD_COLOR (bst, bg, fg); + BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, height); /* black */ + BSOD_COLOR (bst, fg, bg); + BSOD_MOVETO (bst, 0, lw*2); + BSOD_TEXT (bst, CENTER, guru1); + BSOD_MOVETO (bst, 0, lw*3.5); + BSOD_TEXT (bst, CENTER, guru2); + BSOD_PAUSE (bst, 1000000); + + BSOD_LOOP (bst, -17); + + XSetWindowBackground (dpy, window, bg2); + XClearWindow (dpy, window); + XSetWindowBackground (dpy, window, bst->bg); + + if (pixmap) + { + int x = (bst->xgwa.width - pix_w) / 2; + int y = ((bst->xgwa.height - pix_h) / 2); + XSetClipMask (dpy, bst->gc, mask); + XSetClipOrigin (dpy, bst->gc, x, y); + XCopyArea (dpy, pixmap, bst->window, bst->gc, 0, 0, pix_w, pix_h, x, y); + XSetClipMask (dpy, bst->gc, None); + XFreePixmap (dpy, pixmap); + XFreePixmap (dpy, mask); + } + + bst->y += lw; + + return bst; +} + + + +/* Atari ST, by Marcus Herbert + Marcus had this to say: + + Though I still have my Atari somewhere, I hardly remember + the meaning of the bombs. I think 9 bombs was "bus error" or + something like that. And you often had a few bombs displayed + quickly and then the next few ones coming up step by step. + Perhaps somebody else can tell you more about it.. its just + a quick hack :-} + */ +static struct bsod_state * +atari (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "atari", "Atari"); + + int pix_w, pix_h; + int offset; + int i, x, y; + Pixmap mask = 0; + Pixmap pixmap = image_data_to_pixmap (dpy, window, + atari_png, sizeof(atari_png), + &pix_w, &pix_h, &mask); + + pixmap = double_pixmap (dpy, bst->xgwa.visual, bst->xgwa.depth, + pixmap, pix_w, pix_h); + mask = double_pixmap (dpy, bst->xgwa.visual, 1, mask, pix_w, pix_h); + pix_w *= 2; + pix_h *= 2; + + offset = pix_w; + x = 0; + y = bst->xgwa.height/2; + if (y < 0) y = 0; + + for (i = 1; i< 7; i++) + BSOD_COPY (bst, x, y, pix_w, pix_h, (x + (i*offset)), y); + + for (; i< 10; i++) + { + BSOD_PAUSE (bst, 1000000); + BSOD_COPY (bst, x, y, pix_w, pix_h, (x + (i*offset)), y); + } + + XClearWindow (dpy, window); + XSetClipMask (dpy, bst->gc, mask); + XSetClipOrigin (dpy, bst->gc, x, y); + XCopyArea (dpy, pixmap, window, bst->gc, 0, 0, pix_w, pix_h, x, y); + XSetClipMask (dpy, bst->gc, None); + XFreePixmap (dpy, pixmap); + XFreePixmap (dpy, mask); + + return bst; +} + + +static struct bsod_state * +mac (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "mac", "Mac"); + + int pix_w, pix_h; + int i; + + const char *string = ("0 0 0 0 0 0 0 F\n" + "0 0 0 0 0 0 0 3"); + + Pixmap mask = 0; + Pixmap pixmap = image_data_to_pixmap (dpy, window, + mac_png, sizeof(mac_png), + &pix_w, &pix_h, &mask); + int offset = pix_h * 4; + + bst->xoff = bst->left_margin = bst->right_margin = 0; + + for (i = 0; i < 2; i++) + { + pixmap = double_pixmap (dpy, bst->xgwa.visual, bst->xgwa.depth, + pixmap, pix_w, pix_h); + mask = double_pixmap (dpy, bst->xgwa.visual, 1, mask, pix_w, pix_h); + pix_w *= 2; pix_h *= 2; + } + + bst->x = (bst->xgwa.width - pix_w) / 2; + bst->y = (((bst->xgwa.height + offset) / 2) - + pix_h - + (bst->font->ascent + bst->font->descent) * 2); + if (bst->y < 0) bst->y = 0; + + XClearWindow (dpy, window); + XSetClipMask (dpy, bst->gc, mask); + XSetClipOrigin (dpy, bst->gc, bst->x, bst->y); + XCopyArea (dpy, pixmap, window, bst->gc, 0, 0, pix_w, pix_h, bst->x, bst->y); + XSetClipMask (dpy, bst->gc, None); + XFreePixmap (dpy, pixmap); + XFreePixmap (dpy, mask); + + bst->y += offset + bst->font->ascent + bst->font->descent; + BSOD_TEXT (bst, CENTER, string); + + return bst; +} + + +static struct bsod_state * +macsbug (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "macsbug", "MacsBug"); + + __extension__ + const char *left = (" SP \n" + " 04EB0A58 \n" + "58 00010000\n" + "5C 00010000\n" + " ........\n" + "60 00000000\n" + "64 000004EB\n" + " ........\n" + "68 0000027F\n" + "6C 2D980035\n" + " ....-..5\n" + "70 00000054\n" + "74 0173003E\n" + " ...T.s.>\n" + "78 04EBDA76\n" + "7C 04EBDA8E\n" + " .S.L.a.U\n" + "80 00000000\n" + "84 000004EB\n" + " ........\n" + "88 00010000\n" + "8C 00010000\n" + " ...{3..S\n" + "\n" + "\n" + " CurApName \n" + " Finder \n" + "\n" + " 32-bit VM \n" + "SR Smxnzvc0\n" + "D0 04EC0062\n" + "D1 00000053\n" + "D2 FFFF0100\n" + "D3 00010000\n" + "D4 00010000\n" + "D5 04EBDA76\n" + "D6 04EBDA8E\n" + "D7 00000001\n" + "\n" + "A0 04EBDA76\n" + "A1 04EBDA8E\n" + "A2 A0A00060\n" + "A3 027F2D98\n" + "A4 027F2E58\n" + "A5 04EC04F0\n" + "A6 04EB0A86\n" + "A7 04EB0A58"); + const char *bottom = (" _A09D\n" + " +00884 40843714 #$0700,SR " + " ; A973 | A973\n" + " +00886 40843765 *+$0400 " + " | 4A1F\n" + " +00888 40843718 $0004(A7),([0,A7[)" + " ; 04E8D0AE | 66B8"); + __extension__ + const char * body = ("PowerPC unmapped memory exception at 003AFDAC " + "BowelsOfTheMemoryMgr+04F9C\n" + " Calling chain using A6/R1 links\n" + " Back chain ISA Caller\n" + " 00000000 PPC 28C5353C __start+00054\n" + " 24DB03C0 PPC 28B9258C main+0039C\n" + " 24DB0350 PPC 28B9210C MainEvent+00494\n" + " 24DB02B0 PPC 28B91B40 HandleEvent+00278\n" + " 24DB0250 PPC 28B83DAC DoAppleEvent+00020\n" + " 24DB0210 PPC FFD3E5D0 " + "AEProcessAppleEvent+00020\n" + " 24DB0132 68K 00589468\n" + " 24DAFF8C 68K 00589582\n" + " 24DAFF26 68K 00588F70\n" + " 24DAFEB3 PPC 00307098 " + "EmToNatEndMoveParams+00014\n" + " 24DAFE40 PPC 28B9D0B0 DoScript+001C4\n" + " 24DAFDD0 PPC 28B9C35C RunScript+00390\n" + " 24DAFC60 PPC 28BA36D4 run_perl+000E0\n" + " 24DAFC10 PPC 28BC2904 perl_run+002CC\n" + " 24DAFA80 PPC 28C18490 Perl_runops+00068\n" + " 24DAFA30 PPC 28BE6CC0 Perl_pp_backtick+000FC\n" + " 24DAF9D0 PPC 28BA48B8 Perl_my_popen+00158\n" + " 24DAF980 PPC 28C5395C sfclose+00378\n" + " 24DAF930 PPC 28BA568C free+0000C\n" + " 24DAF8F0 PPC 28BA6254 pool_free+001D0\n" + " 24DAF8A0 PPC FFD48F14 DisposePtr+00028\n" + " 24DAF7C9 PPC 00307098 " + "EmToNatEndMoveParams+00014\n" + " 24DAF780 PPC 003AA180 __DisposePtr+00010"); + + const char *s; + int body_lines = 1; + + int char_width, line_height; + int col_right, row_top, row_bottom, page_right, page_bottom, body_top; + int xoff, yoff; + + unsigned long fg = bst->fg; + unsigned long bg = bst->bg; + unsigned long bc = get_pixel_resource (dpy, bst->xgwa.colormap, + "macsbug.borderColor", + "MacsBug.BorderColor"); + + bst->xoff = bst->left_margin = bst->right_margin = 0; + + for (s = body; *s; s++) if (*s == '\n') body_lines++; + + char_width = (bst->font->per_char + ? bst->font->per_char['n'-bst->font->min_char_or_byte2].width + : bst->font->min_bounds.width); + line_height = bst->font->ascent + bst->font->descent; + + col_right = char_width * 12; /* number of columns in `left' */ + page_bottom = line_height * 47; /* number of lines in `left' */ + + if (page_bottom > bst->xgwa.height - bst->yoff) + page_bottom = bst->xgwa.height - bst->yoff; + + row_bottom = page_bottom - line_height; + row_top = row_bottom - (line_height * 4); + page_right = col_right + (char_width * 88); + body_top = row_top - (line_height * body_lines); + + page_bottom += 2; + row_bottom += 2; + body_top -= 4; + + if (body_top > 4) + body_top = 4; + + xoff = (bst->xgwa.width - page_right) / 2; + yoff = (bst->xgwa.height - page_bottom) / 2; + + if (xoff < 0) xoff = 0; + if (yoff < 0) yoff = 0; + + BSOD_MARGINS (bst, xoff, yoff); + + BSOD_COLOR (bst, bc, bg); + BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height); + BSOD_COLOR (bst, bg, bg); + BSOD_RECT (bst, True, xoff-2, yoff, page_right+4, page_bottom); + BSOD_COLOR (bst, fg, bg); + + BSOD_MOVETO (bst, xoff, yoff + line_height); + BSOD_TEXT (bst, LEFT, left); + BSOD_MOVETO (bst, xoff+col_right, yoff + row_top + line_height); + BSOD_TEXT (bst, LEFT, bottom); + + BSOD_RECT (bst, True, xoff + col_right, yoff, 2, page_bottom); + BSOD_RECT (bst, True, xoff + col_right, yoff + row_top, + page_right - col_right, 1); + BSOD_RECT (bst, True, xoff + col_right, yoff + row_bottom, + page_right - col_right, 1); + BSOD_RECT (bst, False, xoff-2, yoff, page_right+4, page_bottom); + + BSOD_LINE_DELAY (bst, 500); + BSOD_MOVETO (bst, + xoff + col_right + char_width, + yoff + body_top + line_height); + BSOD_MARGINS (bst, xoff + col_right + char_width, yoff); + BSOD_TEXT (bst, LEFT, body); + + BSOD_RECT (bst, False, xoff-2, yoff, page_right+4, page_bottom); /* again */ + + BSOD_RECT (bst, False, + xoff + col_right + (char_width/2)+2, + yoff + row_bottom + 2, + 0, + page_bottom - row_bottom - 4); + + BSOD_PAUSE (bst, 666666); + BSOD_INVERT (bst); + BSOD_LOOP (bst, -3); + + XClearWindow (dpy, window); + return bst; +} + + +static struct bsod_state * +mac1 (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "mac1", "Mac1"); + + int pix_w, pix_h; + int x, y; + Pixmap mask = 0; + Pixmap pixmap = image_data_to_pixmap (dpy, window, + macbomb_png, sizeof(macbomb_png), + &pix_w, &pix_h, &mask); + + if (pixmap && + pix_w < bst->xgwa.width / 2 && + pix_h < bst->xgwa.height / 2) + { + int i, n = 1; + if (bst->xgwa.width > 2560) n++; /* Retina displays */ + for (i = 0; i < n; i++) + { + pixmap = double_pixmap (dpy, bst->xgwa.visual, + bst->xgwa.depth, pixmap, pix_w, pix_h); + mask = double_pixmap (dpy, bst->xgwa.visual, 1, mask, pix_w, pix_h); + pix_w *= 2; + pix_h *= 2; + } + } + + x = (bst->xgwa.width - pix_w) / 2; + y = (bst->xgwa.height - pix_h) / 2; + if (y < 0) y = 0; + + XClearWindow (dpy, window); + XSetClipMask (dpy, bst->gc, mask); + XSetClipOrigin (dpy, bst->gc, x, y); + XCopyArea (dpy, pixmap, window, bst->gc, 0, 0, pix_w, pix_h, x, y); + XSetClipMask (dpy, bst->gc, None); + XFreePixmap (dpy, mask); + + return bst; +} + + +/* This is what kernel panics looked like on MacOS X 10.0 through 10.1.5. + In later releases, it's a graphic of a power button with text in + English, French, German, and Japanese overlayed transparently. + */ +static struct bsod_state * +macx_10_0 (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "macx", "MacX"); + + XClearWindow (dpy, window); + XSetForeground (dpy, bst->gc, + get_pixel_resource (dpy, bst->xgwa.colormap, + "macx.textForeground", + "MacX.TextForeground")); + XSetBackground (dpy, bst->gc, + get_pixel_resource (dpy, bst->xgwa.colormap, + "macx.textBackground", + "MacX.TextBackground")); + + { + Pixmap pixmap = 0; + Pixmap mask = 0; + int x, y, pix_w, pix_h; + pixmap = image_data_to_pixmap (dpy, window, + hmac_png, sizeof(hmac_png), + &pix_w, &pix_h, &mask); + +# ifdef HAVE_MOBILE + if (pixmap) + { + pixmap = double_pixmap (dpy, bst->xgwa.visual, + bst->xgwa.depth, pixmap, pix_w, pix_h); + mask = double_pixmap (dpy, bst->xgwa.visual, + 1, mask, pix_w, pix_h); + pix_w *= 2; + pix_h *= 2; + } +# endif + + x = (bst->xgwa.width - pix_w) / 2; + y = (bst->xgwa.height - pix_h) / 2; + if (y < 0) y = 0; + XSetClipMask (dpy, bst->gc, mask); + XSetClipOrigin (dpy, bst->gc, x, y); + XCopyArea (dpy, pixmap, window, bst->gc, 0, 0, pix_w, pix_h, x, y); + XSetClipMask (dpy, bst->gc, None); + XFreePixmap (dpy, pixmap); + XFreePixmap (dpy, mask); + } + + bst->left_margin = 0; + bst->right_margin = 0; + bst->y = bst->font->ascent; + bst->macx_eol_kludge = True; + bst->wrap_p = True; + + BSOD_PAUSE (bst, 3000000); + BSOD_TEXT (bst, LEFT, + "panic(cpu 0): Unable to find driver for this platform: " + "\"PowerMac 3,5\".\n" + "\n" + "backtrace: 0x0008c2f4 0x0002a7a0 0x001f0204 0x001d4e4c 0x001d4c5c " + "0x001a56cc 0x01d5dbc 0x001c621c 0x00037430 0x00037364\n" + "\n" + "\n" + "\n" + "No debugger configured - dumping debug information\n" + "\n" + "version string : Darwin Kernel Version 1.3:\n" + "Thu Mar 1 06:56:40 PST 2001; root:xnu/xnu-123.5.obj~1/RELEASE_PPC\n" + "\n" + "\n" + "\n" + "\n" + "DBAT0: 00000000 00000000\n" + "DBAT1: 00000000 00000000\n" + "DBAT2: 80001FFE 8000003A\n" + "DBAT3: 90001FFE 9000003A\n" + "MSR=00001030\n" + "backtrace: 0x0008c2f4 0x0002a7a0 0x001f0204 0x001d4e4c 0x001d4c5c " + "0x001a56cc 0x01d5dbc 0x001c621c 0x00037430 0x00037364\n" + "\n" + "panic: We are hanging here...\n"); + + return bst; +} + + +static struct bsod_state * +macx_10_2 (Display *dpy, Window window, Bool v10_3_p) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "macx", "MacX"); + + Pixmap mask = 0; + Pixmap pixmap = 0; + int pix_w = 0, pix_h = 0; + int x, y; + + if (v10_3_p) + pixmap = image_data_to_pixmap (dpy, window, + osx_10_3_png, sizeof(osx_10_3_png), + &pix_w, &pix_h, &mask); + else + pixmap = image_data_to_pixmap (dpy, window, + osx_10_2_png, sizeof(osx_10_2_png), + &pix_w, &pix_h, &mask); + if (! pixmap) abort(); + if (! mask) abort(); + +#if 0 + if (bst->xgwa.height > 600) /* scale up the bitmap */ + { + pixmap = double_pixmap (dpy, bst->xgwa.visual, bst->xgwa.depth, + pixmap, pix_w, pix_h); + mask = double_pixmap (dpy, bst->xgwa.visual, 1, mask, pix_w, pix_h); + if (! pixmap) abort(); + if (! mask) abort(); + pix_w *= 2; + pix_h *= 2; + } +#endif + + BSOD_IMG (bst); + BSOD_PAUSE (bst, 2000000); + + bst->pixmap = pixmap; + bst->mask = mask; + + x = (bst->xgwa.width - pix_w) / 2; + y = ((bst->xgwa.height - pix_h) / 2); + BSOD_PIXMAP (bst, 0, 0, pix_w, pix_h, x, y); + + return bst; +} + + +/* 2006 Mac Mini with MacOS 10.6 failing with a bad boot drive. By jwz. + */ +static struct bsod_state * +mac_diskfail (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "macdisk", "Mac"); + int cw = (bst->font->per_char + ? bst->font->per_char['n'-bst->font->min_char_or_byte2].width + : bst->font->min_bounds.width); + int h = bst->font->ascent + bst->font->descent; + int L = (bst->xgwa.width - (cw * 80)) / 2; + int T = (bst->xgwa.height - (h * 10)) / 2; + + unsigned long fg = bst->fg; + unsigned long bg = bst->bg; + unsigned long bg2 = get_pixel_resource (dpy, bst->xgwa.colormap, + "macx.background", + "Mac.Background"); + if (L < 0) L = 0; + if (T < 0) T = 0; + + bst->wrap_p = True; + bst->scroll_p = True; + + BSOD_COLOR(bst, bg2, bg); + BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height); + BSOD_PAUSE (bst, 3000000); + + BSOD_COLOR(bst, bg, fg); + BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height); + BSOD_COLOR(bst, fg, bg); + + BSOD_MARGINS (bst, L, L); + BSOD_MOVETO (bst, L, T); + + BSOD_TEXT (bst, LEFT, + "efiboot loaded from device: Acpi(PNP0A03,0)/Pci*1F|2)/Ata" + "(Primary,Slave)/HD(Part\n" + "2,Sig8997E427-064E-4FE7-8CB9-F27A784B232C)\n" + "boot file path: \\System\\Library\\CoreServices\\boot.efi\n" + ".Loading kernel cache file 'System\\Library\\Caches\\" + "com.apple.kext.caches\\Startup\\\n" + "kernelcache_i386.2A14EC2C'\n" + "Loading 'mach_kernel'...\n" + ); + BSOD_CHAR_DELAY (bst, 7000); + BSOD_TEXT (bst, LEFT, + ".....................\n" + ); + BSOD_CHAR_DELAY (bst, 0); + BSOD_TEXT (bst, LEFT, + "root device uuid is 'B62181B4-6755-3C27-BFA1-49A0E053DBD6\n" + "Loading drivers...\n" + "Loading System\\Library\\Caches\\com.apple.kext.caches\\" + "Startup\\Extensions.mkext....\n" + ); + BSOD_CHAR_DELAY (bst, 7000); + BSOD_TEXT (bst, LEFT, + "..............................................................." + ".................\n" + "..............................................................." + ".................\n" + "..............\n" + ); + BSOD_INVERT (bst); + BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height); + BSOD_INVERT (bst); + + BSOD_MARGINS (bst, 0, 0); + BSOD_MOVETO (bst, 0, h); + + BSOD_CHAR_DELAY (bst, 0); + BSOD_LINE_DELAY (bst, 5000); + BSOD_TEXT (bst, LEFT, + "npvhash=4095\n" + "PRE enabled\n" + "Darwin Kernel Version 10.8.9: Tue Jun 7 16:33:36 PDT 2011;" + " root:xnu-1504.15.3~1/RELEASE_I386\n" + "vm_page_bootstrap: 508036 free pages and 16252 wired pages\n" + "standard timeslicing quantum is 10000 us\n" + "mig_table_max_displ = 73\n" + "AppleACPICPU: ProcessorId=0 LocalApicId=0 Enabled\n" + "AppleACPICPU: ProcessorId=1 LocalApicId=1 Enabled\n" + "calling npo_policy_init for Quarantine\n" + "Security policy loaded: Quaantine policy (Quarantine)\n" + "calling npo_policy_init for Sandbox\n" + "Security policy loaded: Seatbelt sandbox policy (Sandbox)\n" + "calling npo_policy_init for TMSafetyNet\n" + "Security policy loaded: Safety net for Time Machine " + "(TMSafetyNet)\n" + "Copyright (c) 1982, 1986, 1989, 1991, 1993\n" + "The Regents of the University of California. All rights " + "reserved.\n" + "\n" + "MAC Framework successfully initialized\n" + "using 10485 buffer headers and 4096 cluster IO buffer headers\n" + "IOAPIC: Version 0x20 Vectors 64:87\n" + "ACPI: System State [S0 S3 S4 S5] (S3)\n" + "PFM64 0x10000000, 0xf0000000\n" + "[ PCI configuration begin ]\n" + "PCI configuration changed (bridge=1 device=1 cardbus=0)\n" + "[ PCI configuration end, bridges 4 devices 17 ]\n" + "nbinit: done (64 MB memory set for nbuf pool)\n" + "rooting via boot-uuid from /chosen: " + "B62181B4-6755-3C27-BFA1-49A0E053DBD6\n" + "Waiting on IOProviderClass" + "IOResourcesIOResourceMatch" + "boot-uuid-nedia\n" + "com.apple.AppleFSCCompressionTypeZlib kmod start\n" + "com.apple.AppleFSCCompressionTypeZlib kmod succeeded\n" + "AppleIntelCPUPowerManagementClient: ready\n" + "FireWire (OHCI) Lucent ID 5811 built-in now active, GUID " + "0019e3fffe97f8b4; max speed s400.\n" + "Got boot device = IOService:/AppleACPIPlatformExpert/PCI000/" + "AppleACPIPCI/SATA@1F,2/AppleAHCI/PRI202/IOAHCIDevice@0/" + "AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/" + "IOBlockStorageDriver/ST96812AS Media/IOGUIDPartitionScheme/" + "Customer02\n" + ); + BSOD_PAUSE (bst, 1000000); + BSOD_TEXT (bst, LEFT, + "BSD root: Disk0s, major 14, minor 2\n" + "[Bluetooth::CSRHIDTransition] switchtoHCIMode (legacy)\n" + "[Bluetooth::CSRHIDTransition] transition complete.\n" + "CSRUSBBluetoothHCIController::setupHardware super returned 0\n" + ); + BSOD_PAUSE (bst, 3000000); + BSOD_TEXT (bst, LEFT, + "disk0s2: I/O error.\n" + "0 [Level 3] [ReadUID 0] [Facility com.apple.system.fs] " + "[ErrType IO] [ErrNo 5] [IOType Read] [PBlkNum 48424] " + "[LBlkNum 1362] [FSLogMsgID 2009724291] [FSLogMsgOrder First]\n" + "0 [Level 3] [ReadUID 0] [Facility com.apple.system.fs] " + "[DevNode root_device] [MountPt /] [FSLogMsgID 2009724291] " + "[FSLogMsgOrder Last]\n" + "panic(cpu 0 caller 0x47f5ad): \"Process 1 exec of /sbin/launchd" + " failed, errno 5\\n\"0/SourceCache/xnu/xnu-1504.15.3/bsd/kern/" + "kern_exec.c:3145\n" + "Debugger called: \n" + "Backtrace (CPU 0), Frame : Return Address (4 potential args " + "on stack)\n" + "0x34bf3e48 : 0x21b837 (0x5dd7fc 0x34bf3e7c 0x223ce1 0x0)\n" + "0x34bf3e98 : 0x47f5ad (0x5cf950 0x831c08 0x5 0x0)\n" + "0x34bf3ef8 : 0x4696d2 (0x4800d20 0x1fe 0x45a69a0 0x80000001)\n" + "0x34bf3f38 : 0x48fee5 (0x46077a8 0x84baa0 0x34bf3f88 " + "0x34bf3f94)\n" + "0x34bf3f68 : 0x219432 (0x46077a8 0xffffff7f 0x0 0x227c4b)\n" + "0x34bf3fa8 : 0x2aacb4 (0xffffffff 0x1 0x22f8f5 0x227c4b)\n" + "0x34bf3fc8 : 0x2a1976 (0x0 0x0 0x2a17ab 0x4023ef0)\n" + "\n" + "BSD process name corresponding to current thread: init\n" + "\n" + "Mac OS version:\n" + "Not yet set\n" + "\n" + "Kernel version:\n" + "Darwin Kernel version 10.8.0: Tue Jun 7 16:33:36 PDT 2011; " + "root:xnu-1504.15-3~1/RELEASE_I386\n" + "System model name: Macmini1,1 (Mac-F4208EC0)\n" + "\n" + "System uptime in nanoseconds: 13239332027\n" + ); + BSOD_CURSOR (bst, CURSOR_BLOCK, 500000, 999999); + + XClearWindow (dpy, window); + + return bst; +} + + +/* 2017 MacOS 10.12 interminable software update, by jwz. + */ +static struct bsod_state * +macx_install (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "macinstall", "MacX"); + + int pix_w, pix_h; + int x, y; + int bw1, bh1; + int bw2, bh2; + + unsigned long fg = get_pixel_resource (dpy, bst->xgwa.colormap, + "macinstall.foreground", + "Mac.Foreground"); + unsigned long bg = get_pixel_resource (dpy, bst->xgwa.colormap, + "macinstall.background", + "Mac.Background"); + unsigned long fg2 = get_pixel_resource (dpy, bst->xgwa.colormap, + "macinstall.barForeground", + "Mac.Foreground"); + unsigned long bg2 = get_pixel_resource (dpy, bst->xgwa.colormap, + "macinstall.barBackground", + "Mac.Background"); + char buf[1024]; + int lh = bst->font->ascent + bst->font->descent; + int i, min; + double pct; + + Pixmap mask = 0; + Pixmap pixmap = image_data_to_pixmap (dpy, window, + apple_png, sizeof(apple_png), + &pix_w, &pix_h, &mask); + + bst->xoff = bst->left_margin = bst->right_margin = 0; + + if (pixmap) + { + int i, n = 0; + if (bst->xgwa.width > 2560) n++; /* Retina displays */ + for (i = 0; i < n; i++) + { + pixmap = double_pixmap (dpy, bst->xgwa.visual, bst->xgwa.depth, + pixmap, pix_w, pix_h); + mask = double_pixmap (dpy, bst->xgwa.visual, 1, mask, pix_w, pix_h); + pix_w *= 2; + pix_h *= 2; + } + } + + bst->pixmap = pixmap; + bst->mask = mask; + + x = (bst->xgwa.width - pix_w) / 2; + y = (bst->xgwa.height) / 2 - pix_h; + if (y < 0) y = 0; + + XSetLineAttributes (dpy, bst->gc, 1, LineSolid, CapRound, JoinMiter); + + BSOD_COLOR(bst, bg, bg); + BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height); + BSOD_COLOR(bst, fg, bg); + BSOD_PIXMAP (bst, 0, 0, pix_w, pix_h, x, y); + y += pix_h * 2 - lh; + + /* progress bar */ + bw1 = pix_w * 2.5; + bh1 = lh * 0.66; + if (bh1 < 8) bh1 = 8; + + x = (bst->xgwa.width - bw1) / 2; + BSOD_COLOR(bst, fg2, bg); + BSOD_LINE (bst, x, y, x + bw1, y, bh1); + + bw2 = bw1 - 1; + bh2 = bh1 - 4; + BSOD_COLOR(bst, bg2, bg); + BSOD_LINE (bst, x+1, y, x + bw2, y, bh2); + + BSOD_COLOR(bst, fg, bg); + BSOD_LINE (bst, x, y, x + 1, y, bh1); + + pct = 5 + (random() % 40); + min = 5 + (random() % 40); + + for (i = 0; i < 100; i++) { + pct += frand(0.3); + min += (random() % 3) - 1; /* sometimes down, mostly up */ + + if (pct > 90) pct = 90; + BSOD_RECT (bst, True, x, y - bh1/2, bw1 * pct / 100, bh1); + + sprintf (buf, " Installing Software Update: about %d minutes. ", min); + bst->y = y + lh * 3; + BSOD_TEXT (bst, CENTER, buf); + BSOD_PAUSE (bst, 1000000); + } + + return bst; +} + + +static struct bsod_state * +macx (Display *dpy, Window window) +{ + switch (1?4:random() % 5) { + case 0: return macx_10_0 (dpy, window); break; + case 1: return macx_10_2 (dpy, window, False); break; + case 2: return macx_10_2 (dpy, window, True); break; + case 3: return mac_diskfail (dpy, window); break; + case 4: return macx_install (dpy, window); break; + default: abort(); + } +} + + +#ifndef HAVE_JWXYZ /* #### I have no idea how to implement this without + real plane-masks. I don't think it would look + right if done with alpha-transparency... */ +/* blit damage + * + * by Martin Pool , Feb 2000. + * + * This is meant to look like the preferred failure mode of NCD + * Xterms. The parameters for choosing what to copy where might not + * be quite right, but it looks about ugly enough. + */ +static struct bsod_state * +blitdamage (Display *dpy, Window window) +{ + struct bsod_state *bst = + make_bsod_state (dpy, window, "blitdamage", "BlitDamage"); + + int i; + int delta_x = 0, delta_y = 0; + int w, h; + int chunk_h, chunk_w; + int steps; + int src_x, src_y; + int x, y; + + w = bst->xgwa.width; + h = bst->xgwa.height; + + XSetPlaneMask (dpy, bst->gc, random()); + + steps = 50; + chunk_w = w / (random() % 1 + 1); + chunk_h = h / (random() % 1 + 1); + if (random() & 0x1000) + delta_y = random() % 600; + if (!delta_y || (random() & 0x2000)) + delta_x = random() % 600; + src_x = 0; + src_y = 0; + x = 0; + y = 0; + + BSOD_IMG (bst); + for (i = 0; i < steps; i++) { + if (x + chunk_w > w) + x -= w; + else + x += delta_x; + + if (y + chunk_h > h) + y -= h; + else + y += delta_y; + + BSOD_COPY (bst, src_x, src_y, chunk_w, chunk_h, x, y); + BSOD_PAUSE (bst, 1000); + } + + return bst; +} +#endif /* !HAVE_JWXYZ */ + + +/* + * OS/2 panics, by Knut St. Osmundsen + * + * All but one messages are real ones, some are from my test machines + * and system dumps, others are reconstructed from google results. + * Please, don't be to hard if the formatting of the earlier systems + * aren't 100% correct. + */ +static struct bsod_state * +os2 (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "os2", "OS2"); + + __extension__ + static const char * const os2_panics[] = + { /* OS/2 2.0 trap - details are bogus (CR0++). */ + "TRAP 0002 ERRCD=0000 ERACC=**** ERLIM=********\n" + "EAX=7d240a58 EBX=ff202fdc ECX=00064423 EDX=00003624\n" + "ESI=fff3272c EDI=7d240004 EBP=00004a44 FLG=00003202\n" + "CS:EIP=0160:fff702a6 CSACC=c09d CSLIM=ffffffff\n" + "SS:ESP=0030:00004a38 SSACC=1097 SSLIM=00003fff\n" + "DS=0158 DSACC=c0f3 DSLIM=ffffffff CR0=fffffffb\n" + "ES=0158 ESACC=c0f3 ESLIM=ffffffff CR2=1a060014\n" + "FS=0000 FSACC=**** FSLIM=********\n" + "GS=0000 GSACC=**** GSLIM=********\n" + "\n" + "The system detected an internal processing error\n" + "at location ##0160:fff6453f - 000d:a53f\n" + "60000, 9084\n" + "\n" + "038600d1\n" + "Internal revision 6.307, 92/03/01\n" + "\n", + + /* warp 3 (early) */ + "TRAP 000e ERRCD=0000 ERACC=**** ERLIM=********\n" + "EAX=ff050c20 EBX=000000bb ECX=ffff00c1 EDx=fff379b8\n" + "ESI=ffe55a3c EDI=00000000 EBP=00004eb8 FLG=00013282\n" + "CS:EIP=0160:fff8dbb8 CSACC=c09b CSLIM=ffffffff\n" + "SS:EIP=0030:00004eb4 SSACC=1097 SSLIM=00003fff\n" + "DS=0158 DSACC=c0f3 DSLIM=ffffffff CR0=8001001b\n" + "ES=0158 DSACC=c0f3 DSLIM=ffffffff CR2=000000c7\n" + "FS=0000 FSACC=**** FSLIM=********\n" + "GS=0000 GSACC=**** GSLIM=********\n" + "\n" + "The system detected an internal processing error\n" + "at location ##0160:fff66bf0 - 000d:9bf0.\n" + "60000, 9084\n" + "\n" + "048600b4\n" + "Internal revision 8.125, 94/02/16\n" + "\n" + "The system is stopped. Record the location number of the error\n" + "and contact your service representative.\n", + + /* warp 3 */ + "TRAP 000e ERRCD=0002 ERACC=**** ERLIM=********\n" + "EAX=00000000 EBX=fdef1e0c ECX=00003824 EDX=0000edf9\n" + "ESI=fdf30e80 EDI=fc8b0000 EBP=00005658 FLG=00012246\n" + "CS:EIP=0160:fff8ada3 CSACC=c09b CSLIM=ffffffff\n" + "SS:ESP=0030:000055d4 SSACC=1097 SSLIM=0000480f\n" + "DS=0158 DSACC=c093 DSLIM=ffffffff CR0=8001001b\n" + "ES=0158 ESACC=c093 ESLIM=ffffffff CR2=fc8b0000\n" + "FS=03b8 FSACC=0093 FSLIM=00000023\n" + "GS=0000 GSACC=**** GSLIM=********\n" + "\n" + "The system detected an internal processing error\n" + "at location ##0160:fff5c364 - 000d:a364.\n" + "60000, 9084\n" + "\n" + "05860526\n" + "Internal revision 8200,94/11/07\n" + "\n" + "The system is stopped. Record all of the above information and\n" + "contact your service representative.\n", + + /* warp 3 (late) */ + "TRAP 000d ERRCD=2200 ERACC=1092 ERLIM=00010fff\n" + "EAX=0000802e EBX=fff001c8 ECX=9bd80000 EDX=00000000\n" + "ESI=fff09bd8 EDI=fdeb001b EBP=00000000 FLG=00012012\n" + "CS:EIP=0168:fff480a2 CSACC=c09b CSLIM=ffffffff\n" + "SS:ESP=00e8:00001f32 SSACC=0093 SSLIM=00001fff\n" + "DS=0940 DSACC=0093 DSLIM=00000397 CR0=8001001b\n" + "ES=00e8 ESACC=0093 ESLIM=00001fff CR2=15760008\n" + "FS=0000 FSACC=**** FSLIM=****\n" + "GS=0000 GSACC=**** GSLIM=****\n" + "\n" + "The system detected an internal processing error\n" + "at location ##0168:fff4b06e - 000e:c06e\n" + "60000, 9084\n" + "\n" + "06860652\n" + "Internal revision 8.259_uni,98/01/07\n" + "\n" + "The system is stopped. Record all of the above information and\n" + "contact your service representative.\n", + + /* Warp 4.52+ - the official r0trap.exe from the debugging classes */ + "Exception in module: OS2KRNL\n" + "TRAP 000e ERRCD=0002 ERACC=**** ERLIM=********\n" + "EAX=00000001 EBX=80010002 ECX=ffed4638 EDX=0003f17b\n" + "ESI=00000001 EDI=00000002 EBP=00005408 FLG=00012202\n" + "CS:EIP=0168:fff3cd2e CSACC=c09b CSLIM=ffffffff\n" + "SS:ESP=0030:000053ec SSACC=1097 SSLIM=000044ff\n" + "DS=0160 DSACC=c093 DSLIM=ffffffff CR0=8001001b\n" + "ES=0160 ESACC=c093 ESLIM=ffffffff CR2=00000001\n" + "FS=0000 FSACC=**** FSLIM=********\n" + "GS=0000 GSACC=**** GSLIM=********\n" + "\n" + "The system detected an internal processing error at\n" + "location ##0168:fff1e3f3 - 000e:c3f3.\n" + "60000, 9084\n" + "\n" + "068606a0\n" + "Internal revision 14.097_UNI\n" + "\n" + "The system is stopped. Record all of the above information and\n" + "contact your service representative.\n", + + /* Warp 4.52+, typical JFS problem. */ + "Exeption in module: JFS\n" + "TRAP 0003 ERRCD=0000 ERACC=**** ERLIM=********\n" + "EAX=00000000 EBX=ffffff05 ECX=00000001 EDX=f5cd8010\n" + "ESI=000000e6 EDI=000000e7 EBP=f9c7378e FLG=00002296\n" + "CS:EIP=0168:f8df3250 CSACC=c09b CSLIM=ffffffff\n" + "SS:ESP=1550:fdc73778 SSACC=c093 SSLIM=ffffffff\n" + "DS=0160 DSACC=c093 DSLIM=ffffffff CR0=80010016\n" + "ES=0160 ESACC=c093 DSLIM=ffffffff CR2=05318000\n" + "FS=03c0 FSACC=0093 DSLIM=00000023\n" + "GS=0160 GSACC=c093 DSLIM=ffffffff\n" + "\n" + "The system detected an internal processing error\n" + "at location ##0168:fff1e2ab - 000e:c2ab.\n" + "60000, 9084\n" + "\n" + "07860695\n" + "\n" + "Internal revision 14.100c_UNI\n" + "\n" + "The system is stopped. Record all of the above information and\n" + "contact your service representative.\n" + }; + + BSOD_TEXT (bst, LEFT, os2_panics[random() % countof(os2_panics)]); + BSOD_CURSOR (bst, CURSOR_LINE, 240000, 999999); + + XClearWindow (dpy, window); + return bst; +} + + +/* SPARC Solaris panic. Should look pretty authentic on Solaris boxes. + * Anton Solovyev + */ +static struct bsod_state * +sparc_solaris (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "solaris", "Solaris"); + int i; + + bst->scroll_p = True; + bst->wrap_p = True; + bst->left_margin = bst->right_margin = bst->xgwa.width * 0.07; + bst->top_margin = bst->bottom_margin = bst->xgwa.height * 0.07; + bst->y = bst->top_margin + bst->yoff + bst->font->ascent; + + BSOD_IMG (bst); + BSOD_PAUSE (bst, 3000000); + + BSOD_INVERT(bst); + BSOD_RECT (bst, True, + bst->left_margin, bst->top_margin, + bst->xgwa.width - bst->left_margin - bst->right_margin, + bst->xgwa.height - bst->top_margin - bst->bottom_margin); + BSOD_INVERT(bst); + + BSOD_TEXT (bst, LEFT, + "BAD TRAP: cpu=0 type=0x31 rp=0x2a10043b5e0 addr=0xf3880 mmu_fsr=0x0\n" + "BAD TRAP occurred in module \"unix\" due to an illegal access to a" + " user address.\n" + "adb: trap type = 0x31\n" + "addr=0xf3880\n" + "pid=307, pc=0x100306e4, sp=0x2a10043ae81, tstate=0x4480001602," + " context=0x87f\n" + "g1-g7: 1045b000, 32f, 10079440, 180, 300000ebde8, 0, 30000953a20\n" + "Begin traceback... sp = 2a10043ae81\n" + "Called from 100bd060, fp=2a10043af31, args=f3700 300008cc988 f3880 0" + " 1 300000ebde0.\n" + "Called from 101fe1bc, fp=2a10043b011, args=3000045a240 104465a0" + " 300008e47d0 300008e48fa 300008ae350 300008ae410\n" + "Called from 1007c520, fp=2a10043b0c1, args=300008e4878 300003596e8 0" + " 3000045a320 0 3000045a220\n" + "Called from 1007c498, fp=2a10043b171, args=1045a000 300007847f0 20" + " 3000045a240 1 0\n" + "Called from 1007972c, fp=2a10043b221, args=1 300009517c0 30000951e58 1" + " 300007847f0 0\n" + "Called from 10031e10, fp=2a10043b2d1, args=3000095b0c8 0 300009396a8" + " 30000953a20 0 1\n" + "Called from 10000bdd8, fp=ffffffff7ffff1c1, args=0 57 100131480" + " 100131480 10012a6e0 0\n" + "End traceback...\n" + "panic[cpu0]/thread=30000953a20: trap\n" + "syncing file systems..."); + + BSOD_PAUSE (bst, 3000000); + + BSOD_TEXT (bst, LEFT, " 1 done\n"); + BSOD_TEXT (bst, LEFT, "dumping to /dev/dsk/c0t0d0s3, offset 26935296\n"); + BSOD_PAUSE (bst, 2000000); + + + for (i = 1; i <= 100; ++i) + { + char buf[100]; + sprintf (buf, "\b\b\b\b\b\b\b\b\b\b\b%3d%% done", i); + BSOD_TEXT (bst, LEFT, buf); + BSOD_PAUSE (bst, 100000); + } + + BSOD_TEXT (bst, LEFT, + ": 2803 pages dumped, compression ratio 2.88, dump succeeded\n"); + BSOD_PAUSE (bst, 2000000); + + BSOD_TEXT (bst, LEFT, + "rebooting...\n" + "Resetting ..."); + + return bst; +} + + +/* Linux panic and fsck, by jwz + */ +static struct bsod_state * +linux_fsck (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "linux", "Linux"); + + int i; + const char *sysname; + char buf[1024]; +# ifdef HAVE_UNAME + struct utsname uts; +#endif /* UNAME */ + + const char *linux_panic[] = { + " kernel: Unable to handle kernel paging request at virtual " + "address 0000f0ad\n", + " kernel: printing eip:\n", + " kernel: c01becd7\n", + " kernel: *pde = 00000000\n", + " kernel: Oops: 0000\n", + " kernel: CPU: 0\n", + " kernel: EIP: 0010:[] Tainted: P \n", + " kernel: EFLAGS: 00010286\n", + " kernel: eax: 0000ff00 ebx: ca6b7e00 ecx: ce1d7a60 edx: ce1d7a60\n", + " kernel: esi: ca6b7ebc edi: 00030000 ebp: d3655ca0 esp: ca6b7e5c\n", + " kernel: ds: 0018 es: 0018 ss: 0018\n", + " kernel: Process crond (pid: 1189, stackpage=ca6b7000)\n", + " kernel: Stack: d3655ca0 ca6b7ebc 00030054 ca6b7e7c c01c1e5b " + "00000287 00000020 c01c1fbf \n", + "", + " kernel: 00005a36 000000dc 000001f4 00000000 00000000 " + "ce046d40 00000001 00000000 \n", + "", "", "", + " kernel: ffffffff d3655ca0 d3655b80 00030054 c01bef93 " + "d3655ca0 ca6b7ebc 00030054 \n", + "", "", "", + " kernel: Call Trace: [] [] [] " + "[] []\n", + "", "", "", + " kernel: [] [] [] []\n", + " kernel: \n", + " kernel: Code: 2a 00 75 08 8b 44 24 2c 85 c0 74 0c 8b 44 24 58 83 48 18 " + "08 \n", + 0 + }; + + bst->scroll_p = True; + bst->wrap_p = True; + bst->left_margin = bst->right_margin = 10; + bst->top_margin = bst->bottom_margin = 10; + + sysname = "linux"; +# ifdef HAVE_UNAME + { + char *s; + if (uname (&uts) >= 0) + sysname = uts.nodename; + s = strchr (sysname, '.'); + if (s) *s = 0; + } +# endif /* !HAVE_UNAME */ + + + BSOD_TEXT (bst, LEFT, "waiting for X server to shut down "); + BSOD_PAUSE (bst, 100000); + BSOD_TEXT (bst, LEFT, + "XIO: fatal IO error 2 (broken pipe) on X server \":0.0\"\n" + " after 339471 requests (339471 known processed) " + "with 0 events remaining\n"); + BSOD_CHAR_DELAY (bst, 300000); + BSOD_TEXT (bst, LEFT, ".........\n"); + BSOD_CHAR_DELAY (bst, 0); + BSOD_TEXT (bst, LEFT, + "xinit: X server slow to shut down, sending KILL signal.\n" + "waiting for server to die "); + BSOD_CHAR_DELAY (bst, 300000); + BSOD_TEXT (bst, LEFT, "...\n"); + BSOD_CHAR_DELAY (bst, 0); + BSOD_TEXT (bst, LEFT, "xinit: Can't kill server\n"); + BSOD_PAUSE (bst, 2000000); + + sprintf (buf, "\n%s Login: ", sysname); + BSOD_TEXT (bst, LEFT, buf); + BSOD_PAUSE (bst, 1000000); + BSOD_TEXT (bst, LEFT, + "\n\n" + "Parallelizing fsck version 1.22 (22-Jun-2001)\n" + "e2fsck 1.22, 22-Jun-2001 for EXT2 FS 0.5b, 95/08/09\n" + "Warning! /dev/hda1 is mounted.\n" + "/dev/hda1 contains a file system with errors, check forced.\n"); + BSOD_PAUSE (bst, 1000000); + + if (0 == random() % 2) + BSOD_TEXT (bst, LEFT, + "Couldn't find ext2 superblock, trying backup blocks...\n" + "The filesystem size (according to the superblock) is 3644739 blocks\n" + "The physical size of the device is 3636706 blocks\n" + "Either the superblock or the partition table is likely to be corrupt!\n" + "Abort? no\n"); + BSOD_PAUSE (bst, 1000000); + + AGAIN: + + BSOD_TEXT (bst, LEFT, "Pass 1: Checking inodes, blocks, and sizes\n"); + BSOD_PAUSE (bst, 2000000); + + i = (random() % 60) - 20; + while (--i > 0) + { + int b = random() % 0xFFFF; + sprintf (buf, "Deleted inode %d has zero dtime. Fix? yes\n\n", b); + BSOD_TEXT (bst, LEFT, buf); + BSOD_PAUSE (bst, 1000); + } + + i = (random() % 40) - 10; + if (i > 0) + { + int g = random() % 0xFFFF; + int b = random() % 0xFFFFFFF; + + BSOD_PAUSE (bst, 1000000); + + sprintf (buf, "Warning: Group %d's copy of the group descriptors " + "has a bad block (%d).\n", g, b); + BSOD_TEXT (bst, LEFT, buf); + + b = random() % 0x3FFFFF; + while (--i > 0) + { + b += random() % 0xFFFF; + sprintf (buf, + "Error reading block %d (Attempt to read block " + "from filesystem resulted in short read) while doing " + "inode scan. Ignore error?", + b); + BSOD_TEXT (bst, LEFT, buf); + BSOD_PAUSE (bst, 10000); + BSOD_TEXT (bst, LEFT, " yes\n\n"); + } + } + + if (0 == (random() % 10)) + { + BSOD_PAUSE (bst, 1000000); + + i = 3 + (random() % 10); + while (--i > 0) + { + BSOD_TEXT (bst, LEFT, + "Could not allocate 256 block(s) for inode table: " + "No space left on device\n"); + BSOD_PAUSE (bst, 1000); + } + BSOD_TEXT (bst, LEFT, "Restarting e2fsck from the beginning...\n"); + BSOD_PAUSE (bst, 2000000); + + goto AGAIN; + } + + i = (random() % 20) - 5; + + if (i > 0) + BSOD_PAUSE (bst, 1000000); + + while (--i > 0) + { + int j = 5 + (random() % 10); + int w = random() % 4; + + while (--j > 0) + { + int b = random() % 0xFFFFF; + int g = random() % 0xFFF; + + if (0 == (random() % 10)) + b = 0; + else if (0 == (random() % 10)) + b = -1; + + if (w == 0) + sprintf (buf, + "Inode table for group %d not in group. (block %d)\n" + "WARNING: SEVERE DATA LOSS POSSIBLE.\n" + "Relocate?", + g, b); + else if (w == 1) + sprintf (buf, + "Block bitmap for group %d not in group. (block %d)\n" + "Relocate?", + g, b); + else if (w == 2) + sprintf (buf, + "Inode bitmap %d for group %d not in group.\n" + "Continue?", + b, g); + else /* if (w == 3) */ + sprintf (buf, + "Bad block %d in group %d's inode table.\n" + "WARNING: SEVERE DATA LOSS POSSIBLE.\n" + "Relocate?", + b, g); + + BSOD_TEXT (bst, LEFT, buf); + BSOD_TEXT (bst, LEFT, " yes\n\n"); + BSOD_PAUSE (bst, 1000); + } + } + + + if (0 == random() % 10) goto PANIC; + BSOD_TEXT (bst, LEFT, "Pass 2: Checking directory structure\n"); + BSOD_PAUSE (bst, 2000000); + + i = (random() % 20) - 5; + while (--i > 0) + { + int n = random() % 0xFFFFF; + int o = random() % 0xFFF; + sprintf (buf, "Directory inode %d, block 0, offset %d: " + "directory corrupted\n" + "Salvage? ", + n, o); + BSOD_TEXT (bst, LEFT, buf); + BSOD_PAUSE (bst, 1000); + BSOD_TEXT (bst, LEFT, " yes\n\n"); + + if (0 == (random() % 100)) + { + sprintf (buf, "Missing '.' in directory inode %d.\nFix?", n); + BSOD_TEXT (bst, LEFT, buf); + BSOD_PAUSE (bst, 1000); + BSOD_TEXT (bst, LEFT, " yes\n\n"); + } + } + + if (0 == random() % 10) + goto PANIC; + + BSOD_TEXT (bst, LEFT, + "Pass 3: Checking directory connectivity\n" + "/lost+found not found. Create? yes\n"); + BSOD_PAUSE (bst, 2000000); + + /* Unconnected directory inode 4949 (/var/spool/squid/06/???) + Connect to /lost+found? yes + + '..' in /var/spool/squid/06/08 (20351) is (0), should be + /var/spool/squid/06 (20350). + Fix? yes + + Unconnected directory inode 128337 (/var/spool/squid/06/???) + Connect to /lost+found? yes + */ + + + if (0 == random() % 10) goto PANIC; + BSOD_TEXT (bst, LEFT, "Pass 4: Checking reference counts\n"); + BSOD_PAUSE (bst, 2000000); + + /* Inode 2 ref count is 19, should be 20. Fix? yes + + Inode 4949 ref count is 3, should be 2. Fix? yes + + ... + + Inode 128336 ref count is 3, should be 2. Fix? yes + + Inode 128337 ref count is 3, should be 2. Fix? yes + + */ + + + if (0 == random() % 10) goto PANIC; + BSOD_TEXT (bst, LEFT, "Pass 5: Checking group summary information\n"); + BSOD_PAUSE (bst, 2000000); + + i = (random() % 200) - 50; + if (i > 0) + { + BSOD_TEXT (bst, LEFT, "Block bitmap differences: "); + while (--i > 0) + { + sprintf (buf, " %d", -(random() % 0xFFF)); + BSOD_TEXT (bst, LEFT, buf); + BSOD_PAUSE (bst, 1000); + } + BSOD_TEXT (bst, LEFT, "\nFix? yes\n\n"); + } + + + i = (random() % 100) - 50; + if (i > 0) + { + BSOD_TEXT (bst, LEFT, "Inode bitmap differences: "); + while (--i > 0) + { + sprintf (buf, " %d", -(random() % 0xFFF)); + BSOD_TEXT (bst, LEFT, buf); + BSOD_PAUSE (bst, 1000); + } + BSOD_TEXT (bst, LEFT, "\nFix? yes\n\n"); + } + + i = (random() % 20) - 5; + while (--i > 0) + { + int g = random() % 0xFFFF; + int c = random() % 0xFFFF; + sprintf (buf, + "Free blocks count wrong for group #0 (%d, counted=%d).\nFix? ", + g, c); + BSOD_TEXT (bst, LEFT, buf); + BSOD_PAUSE (bst, 1000); + BSOD_TEXT (bst, LEFT, " yes\n\n"); + } + + PANIC: + + i = 0; + BSOD_TEXT (bst, LEFT, "\n\n"); + while (linux_panic[i]) + { + time_t t = time ((time_t *) 0); + struct tm *tm = localtime (&t); + char prefix[100]; + + if (*linux_panic[i]) + { + strftime (prefix, sizeof(prefix)-1, "%b %d %H:%M:%S ", tm); + BSOD_TEXT (bst, LEFT, prefix); + BSOD_TEXT (bst, LEFT, sysname); + BSOD_TEXT (bst, LEFT, linux_panic[i]); + BSOD_PAUSE (bst, 1000); + } + else + BSOD_PAUSE (bst, 300000); + + i++; + } + BSOD_PAUSE (bst, 4000000); + + XClearWindow(dpy, window); + return bst; +} + + +/* + * Linux (hppa) panic, by Stuart Brady + * Output courtesy of M. Grabert + */ +static struct bsod_state * +hppa_linux (Display *dpy, Window window) +{ + struct bsod_state *bst = + make_bsod_state (dpy, window, "hppalinux", "HPPALinux"); + + int i = 0; + const char *release, *sysname, *gccversion, *version; + long int linedelay = 0; + char ss[1024]; +# ifdef HAVE_UNAME + struct utsname uts; +# endif /* UNAME */ + + __extension__ + struct { long int delay; const char *string; } linux_panic[] = + {{ 0, "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "\n\n\n\n\n\n\n\n\n\n\n\n\n" }, + { 0, "Linux version %s (root@%s) (gcc version %s) %s\n" }, + { 4000, "FP[0] enabled: Rev 1 Model 16\n" }, + { 10, "The 32-bit Kernel has started...\n" }, + { -1, "Determining PDC firmware type: System Map.\n" }, + { -1, "model 00005bb0 00000481 00000000 00000002 7778df9f 100000f0 " + "00000008 000000b2 000000b2\n" }, + { -1, "vers 00000203\n" }, + { -1, "CPUID vers 17 rev 7 (0x00000227)\n" }, + { -1, "capabilities 0x3\n" }, + { -1, "model 9000/785/C3000\n" }, + { -1, "Total Memory: 1024 Mb\n" }, + { -1, "On node 0 totalpages: 262144\n" }, + { -1, " DMA zone: 262144 pages, LIFO batch:16\n" }, + { -1, " Normal zone: 0 pages, LIFO batch:1\n" }, + { -1, " HighMem zone: 0 pages, LIFO batch:1\n" }, + { -1, "LCD display at f05d0008,f05d0000 registered\n" }, + { -1, "Building zonelist for node : 0\n" }, + { -1, "Kernel command line: ide=nodma root=/dev/sda3 HOME=/ ip=off " + "console=ttyS0 TERM=vt102 palo_kernel=2/vmlinux-2.6\n" }, + { -1, "ide_setup: ide=nodmaIDE: Prevented DMA\n" }, + { -1, "PID hash table entries: 16 (order 4: 128 bytes)\n" }, + {500, "Console: colour dummy device 160x64\n" }, + { 10, "Memory: 1034036k available\n" }, + { -1, "Calibrating delay loop... 796.67 BogoMIPS\n" }, + { -1, "Dentry cache hash table entries: 131072 (order: 7, 524288 " + "bytes)\n" }, + { -1, "Inode-cache hash table entries: 65536 (order: 6, 262144 " + "bytes)\n" }, + { -1, "Mount-cache hash table entries: 512 (order: 0, 4096 bytes)\n" }, + { -1, "POSIX conformance testing by UNIFIX\n" }, + { -1, "NET: Registered protocol family 16\n" }, + { 100, "Searching for devices...\n" }, + { 25, "Found devices:\n" }, + { 10, "1. Astro BC Runway Port at 0xfed00000 [10] " + "{ 12, 0x0, 0x582, 0x0000b }\n" }, + { -1, "2. Elroy PCI Bridge at 0xfed30000 [10/0] " + "{ 13, 0x0, 0x782, 0x0000a }\n" }, + { -1, "3. Elroy PCI Bridge at 0xfed32000 [10/1] " + "{ 13, 0x0, 0x782, 0x0000a }\n" }, + { -1, "4. Elroy PCI Bridge at 0xfed38000 [10/4] " + "{ 13, 0x0, 0x782, 0x0000a }\n" }, + { -1, "5. Elroy PCI Bridge at 0xfed3c000 [10/6] " + "{ 13, 0x0, 0x782, 0x0000a }\n" }, + { -1, "6. AllegroHigh W at 0xfffa0000 [32] " + "{ 0, 0x0, 0x5bb, 0x00004 }\n" }, + { -1, "7. Memory at 0xfed10200 [49] { 1, 0x0, 0x086, 0x00009 }\n" }, + { -1, "CPU(s): 1 x PA8500 (PCX-W) at 400.000000 MHz\n" }, + { -1, "SBA found Astro 2.1 at 0xfed00000\n" }, + { -1, "lba version TR2.1 (0x2) found at 0xfed30000\n" }, + { -1, "lba version TR2.1 (0x2) found at 0xfed32000\n" }, + { -1, "lba version TR2.1 (0x2) found at 0xfed38000\n" }, + { -1, "lba version TR2.1 (0x2) found at 0xfed3c000\n" }, + { 100, "SCSI subsystem initialized\n" }, + { 10, "drivers/usb/core/usb.c: registered new driver usbfs\n" }, + { -1, "drivers/usb/core/usb.c: registered new driver hub\n" }, + { -1, "ikconfig 0.7 with /proc/config*\n" }, + { -1, "Initializing Cryptographic API\n" }, + { 250, "SuperIO: probe of 0000:00:0e.0 failed with error -1\n" }, + { 20, "SuperIO: Found NS87560 Legacy I/O device at 0000:00:0e.1 " + "(IRQ 64)\n" }, + { -1, "SuperIO: Serial port 1 at 0x3f8\n" }, + { -1, "SuperIO: Serial port 2 at 0x2f8\n" }, + { -1, "SuperIO: Parallel port at 0x378\n" }, + { -1, "SuperIO: Floppy controller at 0x3f0\n" }, + { -1, "SuperIO: ACPI at 0x7e0\n" }, + { -1, "SuperIO: USB regulator enabled\n" }, + { -1, "SuperIO: probe of 0000:00:0e.2 failed with error -1\n" }, + { -1, "Soft power switch enabled, polling @ 0xf0400804.\n" }, + { -1, "pty: 256 Unix98 ptys configured\n" }, + { -1, "Generic RTC Driver v1.07\n" }, + { -1, "Serial: 8250/16550 driver $" "Revision: 1.100 $ 13 ports, " + "IRQ sharing disabled\n" }, + { -1, "ttyS0 at I/O 0x3f8 (irq = 0) is a 16550A\n" }, + { -1, "ttyS1 at I/O 0x2f8 (irq = 0) is a 16550A\n" }, + { -1, "Linux Tulip driver version 1.1.13 (May 11, 2002)\n" }, + { 150, "tulip0: no phy info, aborting mtable build\n" }, + { 10, "tulip0: MII transceiver #1 config 1000 status 782d " + "advertising 01e1.\n" }, + { -1, "eth0: Digital DS21143 Tulip rev 65 at 0xf4008000, " + "00:10:83:F9:B4:34, IRQ 66.\n" }, + { -1, "Uniform Multi-Platform E-IDE driver Revision: 7.00alpha2\n" }, + { -1, "ide: Assuming 33MHz system bus speed for PIO modes; " + "override with idebus=xx\n" }, + { 100, "SiI680: IDE controller at PCI slot 0000:01:06.0\n" }, + { 10, "SiI680: chipset revision 2\n" }, + { -1, "SiI680: BASE CLOCK == 133\n" }, + { -1, "SiI680: 100% native mode on irq 128\n" }, + { -1, " ide0: MMIO-DMA at 0xf4800000-0xf4800007 -- " + "Error, MMIO ports already in use.\n" }, + { -1, " ide1: MMIO-DMA at 0xf4800008-0xf480000f -- " + "Error, MMIO ports already in use.\n" }, + { 5, "hda: TS130220A2, ATA DISK drive\n" }, + { -1, " _______________________________\n" }, + { -1, " < Your System ate a SPARC! Gah! >\n" }, + { -1, " -------------------------------\n" }, + { -1, " \\ ^__^\n" }, + { -1, " \\ (xx)\\_______\n" }, + { -1, " (__)\\ )\\/\\\n" }, + { -1, " U ||----w |\n" }, + { -1, " || ||\n" }, + { -1, "swapper (pid 1): Breakpoint (code 0)\n" }, + { -1, "\n" }, + { -1, " YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\n" }, + { -1, "PSW: 00000000000001001111111100001111 Not tainted\n" }, + { -1, "r00-03 4d6f6f21 1032f010 10208f34 103fc2e0\n" }, + { -1, "r04-07 103fc230 00000001 00000001 0000000f\n" }, + { -1, "r08-11 103454f8 000f41fa 372d3980 103ee404\n" }, + { -1, "r12-15 3ccbf700 10344810 103ee010 f0400004\n" }, + { -1, "r16-19 f00008c4 f000017c f0000174 00000000\n" }, + { -1, "r20-23 fed32840 fed32800 00000000 0000000a\n" }, + { -1, "r24-27 0000ffa0 000000ff 103fc2e0 10326010\n" }, + { -1, "r28-31 00000000 00061a80 4ff98340 10208f34\n" }, + { -1, "sr0-3 00000000 00000000 00000000 00000000\n" }, + { -1, "sr4-7 00000000 00000000 00000000 00000000\n" }, + { -1, "\n" }, + { -1, "IASQ: 00000000 00000000 IAOQ: 00000000 00000004\n" }, + { -1, " IIR: 00000000 ISR: 00000000 IOR: 00000000\n" }, + { -1, " CPU: 0 CR30: 4ff98000 CR31: 1037c000\n" }, + { -1, " ORIG_R28: 55555555\n" }, + { -1, " IAOQ[0]: 0x0\n" }, + { -1, " IAOQ[1]: 0x4\n" }, + { -1, " RP(r2): probe_hwif+0x218/0x44c\n" }, + { -1, "Kernel panic: Attempted to kill init!\n" }, + { 0, NULL }}; + + bst->scroll_p = True; + bst->wrap_p = True; + bst->left_margin = bst->right_margin = 10; + bst->top_margin = bst->bottom_margin = 10; + + release = "2.6.0-test11-pa2"; + sysname = "hppa"; + version = "#2 Mon Dec 8 06:09:27 GMT 2003"; +# ifdef HAVE_UNAME + { + char *s; + if (uname (&uts) >= 0) + { + sysname = uts.nodename; + if (!strcmp (uts.sysname, "Linux")) + { + release = uts.release; + version = uts.version; + } + } + s = strchr (sysname, '.'); + if (s) *s = 0; + } +# endif /* !HAVE_UNAME */ + +# if (defined (__GNUC__) && defined (__VERSION__)) + gccversion = __VERSION__; +# else /* !(defined (__GNUC__) && defined (__VERSION__)) */ + gccversion = "3.3.2 (Debian)"; +# endif /* !(defined (__GNUC__) && defined (__VERSION__)) */ + + /* Insert current host name into banner on line 2 */ + { + snprintf (ss, 1024, linux_panic[1].string, + release, sysname, gccversion, version); + linux_panic[1].string = ss; + } + + BSOD_PAUSE (bst, 100000); + while (linux_panic[i].string) + { + if (linux_panic[i].delay != -1) + linedelay = linux_panic[i].delay * 1000; + BSOD_PAUSE (bst, linedelay); + BSOD_TEXT (bst, LEFT, linux_panic[i].string); + i++; + } + + bst->y = bst->xgwa.height - bst->yoff + - bst->font->ascent - bst->font->descent; + + XClearWindow(dpy, window); + return bst; +} + + +/* VMS by jwz (text sent by Roland Barmettler ) + */ +static struct bsod_state * +vms (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "vms", "VMS"); + + const char *sysname; + int char_delay = 0; + int dot_delay = 40000; + int chunk_delay = 500000; + char *s, *s1; + int i; + int arg_count; +# ifdef HAVE_UNAME + struct utsname uts; +# endif /* UNAME */ + + __extension__ + + const char *lines[] = { + "%CNXMAN, Lost connection to system #\n" + "%SHADOW-I-VOLPROC, DSA0: shadow master has changed. " + "Dump file WILL be written if system crashes.\n" + "\n", + "", + + "%CNXMAN, Quorum lost, blocking activity\n" + "%CNXMAN, Timed-out lost connection to system #\n" + "%CNXMAN, Timed-out lost connection to system #\n" + "%CNXMAN, Timed-out lost connection to system #\n" + "%CNXMAN, Proposing reconfiguration of the VMScluster\n", + "", + + "%CNXMAN, Removed from VMScluster system #\n" + "%CNXMAN, Removed from VMScluster system #\n" + "%CNXMAN, Removed from VMScluster system #\n" + "%CNXMAN, Completing VMScluster state transition\n", + + "\n" + "**** OpenVMS (TM) Alpha Operating system V7.3-1 - BUGCHECK ****\n" + "\n" + "** Bugcheck code = 000005DC: CLUEXIT, Node voluntarily exiting " + "VMScluster\n" + "** Crash CPU: 00 Primary CPU: 00 Active CPUs: 00000001\n" + "** Current Process = NULL\n" + "** Current PSB ID = 00000001\n" + "** Image Name =\n" + "\n" + "** Dumping error log buffers to HBVS unit 0\n" + "**** Unable to dump error log buffers to remaining shadow set members\n" + "** Error log buffers not dumped to HBVS unit 200\n" + "\n" + "** Dumping memory to HBVS unit 0\n" + "**** Starting compressed selective memory dump at #...\n", + + "...", + + "\n" + "**** Memory dump complete - not all processes or global pages saved\n", + + "\n" + "halted CPU 0\n", + "", + + "\n" + "halt code = 5\n" + "HALT instruction executed\n" + "PC = ffffffff800c3884\n", + + "\n" + "CPU 0 booting\n", + + "\n" + "resetting all I/O buses\n" + "\n" + "\n" + }; + char *args[8]; + int ids[3]; + + bst->scroll_p = True; + bst->wrap_p = True; + bst->left_margin = bst->right_margin = 10; + bst->top_margin = bst->bottom_margin = 10; + + sysname = "VMS001"; +# ifdef HAVE_UNAME + { + if (uname (&uts) >= 0) + sysname = uts.nodename; + s = strchr (sysname, '.'); + if (s) *s = 0; + } +# endif /* !HAVE_UNAME */ + + args[0] = malloc (strlen(sysname) + 7); + strcpy (args[0], sysname); + args[0][5] = 0; + + /* Pick three numbers, 1-9, no overlaps. */ + ids[0] = 1 + (random() % 9); + do { ids[1] = 1 + (random() % 9); } while (ids[1]==ids[0]); + do { ids[2] = 1 + (random() % 9); } while (ids[2]==ids[0] || ids[2]==ids[1]); + + i = strlen(args[0])-1; + if (i < 6) i++; + args[0][i] = '0' + ids[0]; + args[0][i+1] = 0; + + for (s = args[0]; *s; s++) + if (isalpha(*s)) *s = toupper (*s); + + args[1] = strdup (args[0]); + args[2] = strdup (args[0]); args[2][i] = '0' + ids[1]; + args[3] = strdup (args[0]); args[3][i] = '0' + ids[2]; + + args[4] = strdup (args[1]); + args[5] = strdup (args[2]); + args[6] = strdup (args[3]); + + { + time_t t = time ((time_t *) 0); + struct tm *tm = localtime (&t); + args[7] = malloc (30); + strftime (args[7], 29, "%d-%b-%Y %H:%M", tm); + for (s = args[7]; *s; s++) + if (isalpha(*s)) *s = toupper (*s); + } + + arg_count = 0; + for (i = 0; i < countof(lines); i++) + { + const char *fmt = lines[i]; + if (! strcmp (fmt, "...")) + { + int steps = 180 + (random() % 60); + while (--steps >= 0) + { + BSOD_TEXT (bst, LEFT, "."); + BSOD_PAUSE (bst, dot_delay); + } + } + else + { + char *fmt2 = malloc (strlen (fmt) * 2 + 1); + for (s = (char *) fmt, s1 = fmt2; *s; s++) + { + if (*s == '#') + { + strcpy (s1, args[arg_count++]); + s1 += strlen(s1); + } + else + *s1++ = *s; + } + *s1 = 0; + BSOD_CHAR_DELAY (bst, char_delay); + BSOD_TEXT (bst, LEFT, fmt2); + free (fmt2); + BSOD_CHAR_DELAY (bst, 0); + BSOD_PAUSE (bst, chunk_delay); + } + } + + for (i = 0; i < countof (args); i++) + free (args[i]); + + XClearWindow(dpy, window); + return bst; +} + + +/* HVX (formerly GCOS6) and TPS6 crash + by Brian Garratt + + GCOS6 is a Unix-like operating system developed by Honeywell in the + 1970s in collaboration with MIT and AT&T (who called their version + UNIX). Both are very much like MULTICS which Honeywell got from GE. + + HVX ("High-performance Virtual System on Unix") is an AIX application + which emulates GCOS6 hardware on RS6000-like machines. + */ +static struct bsod_state * +hvx (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "hvx", "HVX"); + + bst->scroll_p = True; + bst->wrap_p = True; + bst->y = bst->xgwa.height - bst->bottom_margin - bst->yoff + - bst->font->ascent; + + BSOD_CHAR_DELAY (bst, 10000); + BSOD_TEXT (bst, LEFT, + "(TP) Trap no E Effective address 00000000 Instruction D7DE\n" + "(TP) Registers :\n" + "(TP) B1 -> B7 03801B02 00000000 03880D45 038BABDB 0388AFFD" + " 0389B3F8 03972317\n" + "(TP) R1 -> R7 0001 0007 F10F 090F 0020 0106 0272\n" + "(TP) P I Z M1 0388A18B 3232 0000 FF00\n" + "(TP) Program counter is at offset 0028 from string YTPAD\n" + "(TP) User id of task which trapped is LT 626\n" + "(TP)?\n" + ); + BSOD_PAUSE (bst, 1000000); + + BSOD_CHAR_DELAY (bst, 100000); + BSOD_TEXT (bst, LEFT, " TP CLOSE ALL"); + + BSOD_CHAR_DELAY (bst, 10000); + BSOD_TEXT (bst, LEFT, "\n(TP)?\n"); + BSOD_PAUSE (bst, 1000000); + + BSOD_CHAR_DELAY (bst, 100000); + BSOD_TEXT (bst, LEFT, " TP ABORT -LT ALL"); + + BSOD_CHAR_DELAY (bst, 10000); + BSOD_TEXT (bst, LEFT, "\n(TP)?\n"); + BSOD_PAUSE (bst, 1000000); + + BSOD_CHAR_DELAY (bst, 100000); + BSOD_TEXT (bst, LEFT, " TP STOP KILL"); + + BSOD_CHAR_DELAY (bst, 10000); + BSOD_TEXT (bst, LEFT, + "\n" + "(TP)?\n" + "Core dumps initiated for selected HVX processes ...\n" + "Core dumps complete.\n" + "Fri Jul 19 15:53:09 2002\n" + "Live registers for cp 0:\n" + " P = 7de3 IW=0000 I=32 CI=30000000 S=80006013" + " IV=aa0 Level=13\n" + " R1-7 = 1f 913 13 4 8 0 0\n" + " B1-7 = 64e71b a93 50e 64e73c 6c2c 7000 b54\n" + "Memory dump starting to file /var/hvx/dp01/diag/Level2 ...\n" + "Memory dump complete.\n" + ); + + XClearWindow(dpy, window); + return bst; +} + + +/* HPUX panic, by Tobias Klausmann + */ +static struct bsod_state * +hpux (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "hpux", "HPUX"); + const char *sysname; + char buf[2048]; +# ifdef HAVE_UNAME + struct utsname uts; +# endif /* UNAME */ + + bst->scroll_p = True; + bst->y = bst->xgwa.height - bst->bottom_margin - bst->yoff + - bst->font->ascent; + + sysname = "HPUX"; +# ifdef HAVE_UNAME + { + char *s; + if (uname (&uts) >= 0) + sysname = uts.nodename; + s = strchr (sysname, '.'); + if (s) *s = 0; + } +# endif /* !HAVE_UNAME */ + + BSOD_TEXT (bst, LEFT, + " " + " " + " \n"); + sprintf (buf, "%.100s [HP Release B.11.00] (see /etc/issue)\n", sysname); + BSOD_TEXT (bst, LEFT, buf); + BSOD_PAUSE (bst, 1000000); + BSOD_TEXT (bst, LEFT, + "Console Login:\n" + "\n" + " ******* Unexpected HPMC/TOC. Processor HPA FFFFFFFF'" + "FFFA0000 *******\n" + " GENERAL REGISTERS:\n" + "r00/03 00000000'00000000 00000000'00000000 00000000'00000000 00000000'" + "006C76C0\n" + "r04/07 00000000'00000001 00000000'0126E328 00000000'00000000 00000000'" + "0122B640\n" + "r08/11 00000000'00000000 00000000'0198CFC0 00000000'000476FE 00000000'" + "00000001\n" + "r12/15 00000000'40013EE8 00000000'08000080 00000000'4002530C 00000000'" + "4002530C\n" + "r16/19 00000000'7F7F2A00 00000000'00000001 00000000'00000000 00000000'" + "00000000\n" + "r20/23 00000000'006C8048 00000000'00000001 00000000'00000000 00000000'" + "00000000\n" + "r24/27 00000000'00000000 00000000'00000000 00000000'00000000 00000000'" + "00744378\n" + "r28/31 00000000'00000000 00000000'007DD628 00000000'0199F2B0 00000000'" + "00000000\n" + " CONTROL REGISTERS:\n" + "sr0/3 00000000'0F3B4000 00000000'0C2A2000 00000000'016FF800 00000000'" + "00000000\n" + "sr4/7 00000000'00000000 00000000'016FF800 00000000'0DBF1400 00000000'" + "00000000\n" + "pcq = 00000000'00000000.00000000'00104950 00000000'00000000.00000000'" + "00104A14\n" + "isr = 00000000'10240006 ior = 00000000'67D9E220 iir = 08000240 rctr = " + "7FF10BB6\n" + "\n" + "pid reg cr8/cr9 00007700'0000B3A9 00000000'0000C5D8\n" + "pid reg cr12/cr13 00000000'00000000 00000000'00000000\n" + "ipsw = 000000FF'080CFF1F iva = 00000000'0002C000 sar = 3A ccr = C0\n" + "tr0/3 00000000'006C76C0 00000000'00000001 00000000'00000000 00000000'" + "7F7CE000\n" + "tr4/7 00000000'03790000 0000000C'4FB68340 00000000'C07EE13F 00000000'" + "0199F2B0\n" + "eiem = FFFFFFF0'FFFFFFFF eirr = 80000000'00000000 itmr = 0000000C'" + "4FD8EDE1\n" + "cr1/4 00000000'00000000 00000000'00000000 00000000'00000000 00000000'" + "00000000\n" + "cr5/7 00000000'00000000 00000000'00000000 00000000'" + "00000000\n" + " MACHINE CHECK PARAMETERS:\n" + "Check Type = 00000000 CPU STATE = 9E000001 Cache Check = 00000000\n" + "TLB Check = 00000000 Bus Check = 00000000 PIM State = ? SIU " + "Status = ????????\n" + "Assists = 00000000 Processor = 00000000\n" + "Slave Addr = 00000000'00000000 Master Addr = 00000000'00000000\n" + "\n" + "\n" + "TOC, pcsq.pcoq = 0'0.0'104950 , isr.ior = 0'10240006.0'67d9e220\n" + "@(#)B2352B/9245XB HP-UX (B.11.00) #1: Wed Nov 5 22:38:19 PST 1997\n" + "Transfer of control: (display==0xd904, flags==0x0)\n" + "\n" + "\n" + "\n" + "*** A system crash has occurred. (See the above messages for details.)\n" + "*** The system is now preparing to dump physical memory to disk, for use\n" + "*** in debugging the crash.\n" + "\n" + "*** The dump will be a SELECTIVE dump: 40 of 256 megabytes.\n" + "*** To change this dump type, press any key within 10 seconds.\n" + "*** Proceeding with selective dump.\n" + "\n" + "*** The dump may be aborted at any time by pressing ESC.\n"); + + { + int i; + int steps = 11; + int size = 40; + for (i = 0; i <= steps; i++) + { + if (i > steps) i = steps; + sprintf (buf, + "*** Dumping: %3d%% complete (%d of 40 MB) (device 64:0x2)\r", + i * 100 / steps, + i * size / steps); + BSOD_TEXT (bst, LEFT, buf); + BSOD_PAUSE (bst, 1500000); + } + } + + BSOD_TEXT (bst, LEFT, "\n*** System rebooting.\n"); + + XClearWindow(dpy, window); + return bst; +} + + +/* IBM OS/390 aka MVS aka z/OS. + Text from Dan Espen . + Apparently this isn't actually a crash, just a random session... + But who can tell. + */ +static struct bsod_state * +os390 (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "os390", "OS390"); + + bst->scroll_p = True; + bst->y = bst->xgwa.height - bst->bottom_margin - bst->yoff + - bst->font->ascent; + + BSOD_LINE_DELAY (bst, 100000); + BSOD_TEXT (bst, LEFT, + "\n*** System rebooting.\n" + "* ISPF Subtask abend *\n" + "SPF ENDED DUE TO ERROR+\n" + "READY\n" + "\n" + "IEA995I SYMPTOM DUMP OUTPUT\n" + " USER COMPLETION CODE=0222\n" + " TIME=23.00.51 SEQ=03210 CPU=0000 ASID=00AE\n" + " PSW AT TIME OF ERROR 078D1000 859DAF18 ILC 2 INTC 0D\n" + " NO ACTIVE MODULE FOUND\n" + " NAME=UNKNOWN\n" + " DATA AT PSW 059DAF12 - 00181610 0A0D9180 70644710\n" + " AR/GR 0: 00000000/80000000 1: 00000000/800000DE\n" + " 2: 00000000/196504DC 3: 00000000/00037A78\n" + " 4: 00000000/00037B78 5: 00000000/0003351C\n" + " 6: 00000000/0000F0AD 7: 00000000/00012000\n" + " 8: 00000000/059DAF10 9: 00000000/0002D098\n" + " A: 00000000/059D9F10 B: 00000000/059D8F10\n" + " C: 00000000/859D7F10 D: 00000000/00032D60\n" + " E: 00000000/00033005 F: 01000002/00000041\n" + " END OF SYMPTOM DUMP\n" + "ISPS014 - ** Logical screen request failed - abend 0000DE **\n" + "ISPS015 - ** Contact your system programmer or dialog developer.**\n" + "*** ISPF Main task abend ***\n" + "IEA995I SYMPTOM DUMP OUTPUT\n" + " USER COMPLETION CODE=0222\n" + " TIME=23.00.52 SEQ=03211 CPU=0000 ASID=00AE\n" + " PSW AT TIME OF ERROR 078D1000 8585713C ILC 2 INTC 0D\n" + " ACTIVE LOAD MODULE ADDRESS=05855000 OFFSET=0000213C\n" + " NAME=ISPMAIN\n" + " DATA AT PSW 05857136 - 00181610 0A0D9180 D3304770\n" + " GR 0: 80000000 1: 800000DE\n" + " 2: 00015260 3: 00000038\n" + " 4: 00012508 5: 00000000\n" + " 6: 000173AC 7: FFFFFFF8\n" + " 8: 05858000 9: 00012CA0\n" + " A: 05857000 B: 05856000\n" + " C: 85855000 D: 00017020\n" + " E: 85857104 F: 00000000\n" + " END OF SYMPTOM DUMP\n" + "READY\n" + "***"); + BSOD_CURSOR (bst, CURSOR_LINE, 240000, 999999); + + XClearWindow(dpy, window); + return bst; +} + + +/* Compaq Tru64 Unix panic, by jwz as described by + Tobias Klausmann + */ +static struct bsod_state * +tru64 (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "tru64", "Tru64"); + const char *sysname; + char buf[2048]; +# ifdef HAVE_UNAME + struct utsname uts; +#endif /* UNAME */ + + bst->scroll_p = True; + bst->y = bst->xgwa.height - bst->bottom_margin - bst->yoff + - bst->font->ascent; + + sysname = "127.0.0.1"; +# ifdef HAVE_UNAME + { + if (uname (&uts) >= 0) + sysname = uts.nodename; + } +# endif /* !HAVE_UNAME */ + + sprintf (buf, + "Compaq Tru64 UNIX V5.1B (Rev. 2650) (%.100s) console\n" + "\n" + "login: ", + sysname); + BSOD_TEXT (bst, LEFT, buf); + BSOD_PAUSE (bst, 6000000); + + BSOD_TEXT (bst, LEFT, + "panic (cpu 0): trap: illegal instruction\n" + "kernel inst fault=gentrap, ps=0x5, pc=0xfffffc0000593878, inst=0xaa\n" + "kernel inst fault=gentrap, ps=0x5, pc=0xfffffc0000593878, inst=0xaa\n" + " \n" + "DUMP: blocks available: 1571600\n" + "DUMP: blocks wanted: 100802 (partial compressed dump) [OKAY]\n" + "DUMP: Device Disk Blocks Available\n" + "DUMP: ------ ---------------------\n" + "DUMP: 0x1300023 1182795 - 1571597 (of 1571598) [primary swap]\n" + "DUMP.prom: Open: dev 0x5100041, block 2102016: SCSI 0 11 0 2 200 0 0\n" + "DUMP: Writing header... [1024 bytes at dev 0x1300023, block 1571598]\n" + "DUMP: Writing data"); + + { + int i; + int steps = 4 + (random() % 8); + BSOD_CHAR_DELAY (bst, 1000000); + for (i = 0; i < steps; i++) + BSOD_TEXT (bst, LEFT, "."); + BSOD_CHAR_DELAY (bst, 0); + sprintf (buf, "[%dMB]\n", steps); + BSOD_TEXT (bst, LEFT, buf); + } + + BSOD_TEXT (bst, LEFT, + "DUMP: Writing header... [1024 bytes at dev 0x1300023, block 1571598]\n" + "DUMP: crash dump complete.\n" + "kernel inst fault=gentrap, ps=0x5, pc=0xfffffc0000593878, inst=0xaa\n" + " \n" + "DUMP: second crash dump skipped: 'dump_savecnt' enforced.\n"); + BSOD_PAUSE (bst, 4000000); + + BSOD_TEXT (bst, LEFT, + "\n" + "halted CPU 0\n" + "\n" + "halt code = 5\n" + "HALT instruction executed\n" + "PC = fffffc00005863b0\n"); + BSOD_PAUSE (bst, 3000000); + + BSOD_TEXT (bst, LEFT, + "\n" + "CPU 0 booting\n" + "\n" + "\n" + "\n"); + + XClearWindow(dpy, window); + return bst; +} + + +/* MS-DOS, by jwz + */ +static struct bsod_state * +msdos (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "msdos", "MSDOS"); + + BSOD_CHAR_DELAY (bst, 10000); + BSOD_TEXT (bst, LEFT, "C:\\WINDOWS>"); + BSOD_CURSOR (bst, CURSOR_LINE, 200000, 8); + + BSOD_CHAR_DELAY (bst, 200000); + BSOD_TEXT (bst, LEFT, "dir a:"); + BSOD_PAUSE (bst, 1000000); + + BSOD_CHAR_DELAY (bst, 10000); + BSOD_TEXT (bst, LEFT, "\nNot ready reading drive A\nAbort, Retry, Fail?"); + + BSOD_CURSOR (bst, CURSOR_LINE, 200000, 10); + BSOD_CHAR_DELAY (bst, 200000); + BSOD_TEXT (bst, LEFT, "f"); + BSOD_PAUSE (bst, 1000000); + + BSOD_CHAR_DELAY (bst, 10000); + BSOD_TEXT (bst, LEFT, + "\n\n\nNot ready reading drive A\nAbort, Retry, Fail?"); + + BSOD_CURSOR (bst, CURSOR_LINE, 200000, 10); + BSOD_CHAR_DELAY (bst, 200000); + BSOD_TEXT (bst, LEFT, "f"); + BSOD_PAUSE (bst, 1000000); + + BSOD_CHAR_DELAY (bst, 10000); + BSOD_TEXT (bst, LEFT, "\nVolume in drive A has no label\n\n" + "Not ready reading drive A\nAbort, Retry, Fail?"); + + BSOD_CURSOR (bst, CURSOR_LINE, 200000, 12); + BSOD_CHAR_DELAY (bst, 200000); + BSOD_TEXT (bst, LEFT, "a"); + BSOD_PAUSE (bst, 1000000); + + BSOD_CHAR_DELAY (bst, 10000); + BSOD_TEXT (bst, LEFT, "\n\nC:\\WINDOWS>"); + + BSOD_CURSOR (bst, CURSOR_LINE, 200000, 999999); + + XClearWindow(dpy, window); + return bst; +} + + +/* nvidia, by jwz. + * + * This is what happens if an Nvidia card goes into some crazy text mode. + * Most often seen on the second screen of a dual-head system when the + * proper driver isn't loaded. + */ +typedef struct { int fg; int bg; int bit; Bool blink; } nvcell; + +static void +nvspatter (nvcell *grid, int rows, int cols, int ncolors, int nbits, + Bool fill_p) +{ + int max = rows * cols; + int from = fill_p ? 0 : random() % (max - 1); + int len = fill_p ? max : random() % (cols * 4); + int to = from + len; + int i; + Bool noisy = ((random() % 4) == 0); + Bool diag = (noisy || fill_p) ? 0 : ((random() % 4) == 0); + + int fg = random() % ncolors; + int bg = random() % ncolors; + int blink = ((random() % 4) == 0); + int bit = (random() % nbits); + + if (to > max) to = max; + + if (diag) + { + int src = random() % (rows * cols); + int len2 = (cols / 2) - (random() % 5); + int j = src; + for (i = from; i < to; i++, j++) + { + if (j > src + len2 || j >= max) + j = src; + if (i >= max) abort(); + if (j >= max) abort(); + grid[j] = grid[i]; + } + } + else + for (i = from; i < to; i++) + { + nvcell *cell = &grid[i]; + cell->fg = fg; + cell->bg = bg; + cell->bit = bit; + cell->blink = blink; + + if (noisy) + { + fg = random() % ncolors; + bg = random() % ncolors; + blink = ((random() % 8) == 0); + } + } +} + +typedef struct { + struct bsod_state *bst; + GC gc1; + Pixmap bits[5]; + int rows, cols; + int cellw, cellh; + nvcell *grid; + int ncolors; + unsigned long colors[256]; + int tick; +} nvstate; + + +static void +nvidia_free (struct bsod_state *bst) +{ + nvstate *nvs = (nvstate *) bst->closure; + int i; + XFreeColors (bst->dpy, bst->xgwa.colormap, nvs->colors, nvs->ncolors, 0); + for (i = 0; i < countof(nvs->bits); i++) + XFreePixmap (bst->dpy, nvs->bits[i]); + XFreeGC (bst->dpy, nvs->gc1); + free (nvs->grid); + free (nvs); +} + +static int +nvidia_draw (struct bsod_state *bst) +{ + nvstate *nvs = (nvstate *) bst->closure; + int x, y; + + for (y = 0; y < nvs->rows; y++) + for (x = 0; x < nvs->cols; x++) + { + nvcell *cell = &nvs->grid[y * nvs->cols + x]; + unsigned long fg = nvs->colors[cell->fg]; + unsigned long bg = nvs->colors[cell->bg]; + Bool flip = cell->blink && (nvs->tick & 1); + XSetForeground (bst->dpy, bst->gc, flip ? fg : bg); + XSetBackground (bst->dpy, bst->gc, flip ? bg : fg); + XCopyPlane (bst->dpy, nvs->bits[cell->bit], bst->window, bst->gc, + 0, 0, nvs->cellw, nvs->cellh, + x * nvs->cellw, y * nvs->cellh, 1L); + } + + nvs->tick++; + if ((random() % 5) == 0) /* change the display */ + nvspatter (nvs->grid, nvs->rows, nvs->cols, nvs->ncolors, + countof(nvs->bits), False); + + return 250000; +} + + +static struct bsod_state * +nvidia (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "nvidia", "nVidia"); + nvstate *nvs = (nvstate *) calloc (1, sizeof (*nvs)); + + XGCValues gcv; + int i; + + nvs->bst = bst; + bst->closure = nvs; + bst->draw_cb = nvidia_draw; + bst->free_cb = nvidia_free; + + nvs->cols = 80; + nvs->rows = 25; + nvs->cellw = bst->xgwa.width / nvs->cols; + nvs->cellh = bst->xgwa.height / nvs->rows; + if (nvs->cellw < 8 || nvs->cellh < 18) + nvs->cellw = 8, nvs->cellh = 18; + nvs->cols = (bst->xgwa.width / nvs->cellw) + 1; + nvs->rows = (bst->xgwa.height / nvs->cellh) + 1; + + nvs->grid = (nvcell *) calloc (sizeof(*nvs->grid), nvs->rows * nvs->cols); + + /* Allocate colors + */ + nvs->ncolors = 16; + for (i = 0; i < nvs->ncolors; i++) + { + XColor c; + c.red = random() & 0xFFFF; + c.green = random() & 0xFFFF; + c.blue = random() & 0xFFFF; + c.flags = DoRed|DoGreen|DoBlue; + XAllocColor (dpy, bst->xgwa.colormap, &c); + nvs->colors[i] = c.pixel; + } + + /* Construct corrupted character bitmaps + */ + for (i = 0; i < countof(nvs->bits); i++) + { + int j; + + nvs->bits[i] = XCreatePixmap (dpy, window, nvs->cellw, nvs->cellh, 1); + if (!nvs->gc1) nvs->gc1 = XCreateGC (dpy, nvs->bits[i], 0, &gcv); + + XSetForeground (dpy, nvs->gc1, 0); + XFillRectangle (dpy, nvs->bits[i], nvs->gc1, 0, 0, + nvs->cellw, nvs->cellh); + XSetForeground (dpy, nvs->gc1, 1); + + if ((random() % 40) != 0) + for (j = 0; j < ((nvs->cellw * nvs->cellh) / 16); j++) + XFillRectangle (dpy, nvs->bits[i], nvs->gc1, + (random() % (nvs->cellw-2)) & ~1, + (random() % (nvs->cellh-2)) & ~1, + 2, 2); + } + + /* Randomize the grid + */ + nvspatter (nvs->grid, nvs->rows, nvs->cols, nvs->ncolors, + countof(nvs->bits), True); + for (i = 0; i < 20; i++) + nvspatter (nvs->grid, nvs->rows, nvs->cols, nvs->ncolors, + countof(nvs->bits), False); + + return bst; +} + + +/* + * Simulate various Apple ][ crashes. The memory map encouraged many programs + * to use the primary hi-res video page for various storage, and the secondary + * hi-res page for active display. When it crashed into Applesoft or the + * monitor, it would revert to the primary page and you'd see memory garbage on + * the screen. Also, it was common for copy-protected games to use the primary + * text page for important code, because that made it really hard to + * reverse-engineer them. The result often looked like what this generates. + * + * The Apple ][ logic and video hardware is in apple2.c. The TV is emulated by + * analogtv.c for maximum realism + * + * Trevor Blackwell + */ + +static const char * const apple2_basic_errors[]={ + "BREAK", + "NEXT WITHOUT FOR", + "SYNTAX ERROR", + "RETURN WITHOUT GOSUB", + "ILLEGAL QUANTITY", + "OVERFLOW", + "OUT OF MEMORY", + "BAD SUBSCRIPT ERROR", + "DIVISION BY ZERO", + "STRING TOO LONG", + "FORMULA TOO COMPLEX", + "UNDEF'D FUNCTION", + "OUT OF DATA" +#if 0 + , + "DEFAULT ARGUMENTS ARE NOT ALLOWED IN DECLARATION OF FRIEND " + "TEMPLATE SPECIALIZATION" +#endif + +}; +static const char * const apple2_dos_errors[]={ + "VOLUME MISMATCH", + "I/O ERROR", + "DISK FULL", + "NO BUFFERS AVAILABLE", + "PROGRAM TOO LARGE", +}; + +static void a2controller_crash(apple2_sim_t *sim, int *stepno, + double *next_actiontime) +{ + apple2_state_t *st=sim->st; + char *s; + int i; + + struct mydata { + int fillptr; + int fillbyte; + } *mine; + + if (!sim->controller_data) + sim->controller_data = calloc(sizeof(struct mydata),1); + mine=(struct mydata *) sim->controller_data; + + switch(*stepno) { + case 0: + + a2_init_memory_active(sim); + sim->dec->powerup = 1000.0; + + if (random()%3==0) { + st->gr_mode=0; + *next_actiontime+=0.4; + *stepno=100; + } + else if (random()%4==0) { + st->gr_mode=A2_GR_LORES; + if (random()%3==0) st->gr_mode |= A2_GR_FULL; + *next_actiontime+=0.4; + *stepno=100; + } + else if (random()%2==0) { + st->gr_mode=A2_GR_HIRES; + *stepno=300; + } + else { + st->gr_mode=A2_GR_HIRES; + *next_actiontime+=0.4; + *stepno=100; + } + break; + + case 100: + /* An illegal instruction or a reset caused it to drop into the + assembly language monitor, where you could disassemble code & view + data in hex. */ + if (random()%3==0) { + char ibytes[128]; + char itext[128]; + int addr=0xd000+random()%0x3000; + sprintf(ibytes, + "%02X",random()%0xff); + sprintf(itext, + "???"); + sprintf(sim->printing_buf, + "\n\n" + "%04X: %-15s %s\n" + " A=%02X X=%02X Y=%02X S=%02X F=%02X\n" + "*", + addr,ibytes,itext, + random()%0xff, random()%0xff, + random()%0xff, random()%0xff, + random()%0xff); + sim->printing=sim->printing_buf; + a2_goto(st,23,1); + if (st->gr_mode) { + *stepno=180; + } else { + *stepno=200; + } + sim->prompt='*'; + *next_actiontime += 2.0 + (random()%1000)*0.0002; + } + else { + /* Lots of programs had at least their main functionality in + Applesoft Basic, which had a lot of limits (memory, string + length, etc) and would sometimes crash unexpectedly. */ + sprintf(sim->printing_buf, + "\n" + "\n" + "\n" + "?%s IN %d\n" + "\001]", + apple2_basic_errors[random() % + (sizeof(apple2_basic_errors) + /sizeof(char *))], + (1000*(random()%(random()%59+1)) + + 100*(random()%(random()%9+1)) + + 5*(random()%(random()%199+1)) + + 1*(random()%(random()%(random()%2+1)+1)))); + sim->printing=sim->printing_buf; + a2_goto(st,23,1); + *stepno=110; + sim->prompt=']'; + *next_actiontime += 2.0 + (random()%1000)*0.0002; + } + break; + + case 110: + if (random()%3==0) { + /* This was how you reset the Basic interpreter. The sort of + incantation you'd have on a little piece of paper taped to the + side of your machine */ + sim->typing="CALL -1370"; + *stepno=120; + } + else if (random()%2==0) { + sim->typing="CATALOG\n"; + *stepno=170; + } + else { + *next_actiontime+=1.0; + *stepno=999; + } + break; + + case 120: + *stepno=130; + *next_actiontime += 0.5; + break; + + case 130: + st->gr_mode=0; + a2_cls(st); + a2_goto(st,0,16); + for (s="APPLE ]["; *s; s++) a2_printc(st,*s); + a2_goto(st,23,0); + a2_printc(st,']'); + *next_actiontime+=1.0; + *stepno=999; + break; + + case 170: + if (random()%50==0) { + sprintf(sim->printing_buf, + "\nDISK VOLUME 254\n\n" + " A 002 HELLO\n" + "\n" + "]"); + sim->printing=sim->printing_buf; + } + else { + sprintf(sim->printing_buf,"\n?%s\n]", + apple2_dos_errors[random()% + (sizeof(apple2_dos_errors) / + sizeof(char *))]); + sim->printing=sim->printing_buf; + } + *stepno=999; + *next_actiontime+=1.0; + break; + + case 180: + if (random()%2==0) { + /* This was how you went back to text mode in the monitor */ + sim->typing="FB4BG"; + *stepno=190; + } else { + *next_actiontime+=1.0; + *stepno=999; + } + break; + + case 190: + st->gr_mode=0; + a2_invalidate(st); + a2_printc(st,'\n'); + a2_printc(st,'*'); + *stepno=200; + *next_actiontime+=2.0; + break; + + case 200: + /* This reset things into Basic */ + if (random()%2==0) { + sim->typing="FAA6G"; + *stepno=120; + } + else { + *stepno=999; + *next_actiontime+=sim->delay; + } + break; + + case 300: + for (i=0; i<1500; i++) { + a2_poke(st, mine->fillptr, mine->fillbyte); + mine->fillptr++; + mine->fillbyte = (mine->fillbyte+1)&0xff; + } + *next_actiontime += 0.08; + /* When you hit c000, it changed video settings */ + if (mine->fillptr>=0xc000) { + a2_invalidate(st); + st->gr_mode=0; + } + /* And it seemed to reset around here, I dunno why */ + if (mine->fillptr>=0xcf00) *stepno=130; + break; + + case 999: + break; + + case A2CONTROLLER_FREE: + free(mine); + mine = 0; + break; + } +} + +static int +a2_draw (struct bsod_state *bst) +{ + apple2_sim_t *sim = (apple2_sim_t *) bst->closure; + if (! sim) { + sim = apple2_start (bst->dpy, bst->window, 9999999, a2controller_crash); + bst->closure = sim; + } + + if (! apple2_one_frame (sim)) { + bst->closure = 0; + } + + return 10000; +} + +static void +a2_free (struct bsod_state *bst) +{ + apple2_sim_t *sim = (apple2_sim_t *) bst->closure; + if (sim) { + sim->stepno = A2CONTROLLER_DONE; + a2_draw (bst); /* finish up */ + if (bst->closure) abort(); /* should have been freed by now */ + } +} + + +static struct bsod_state * +apple2crash (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "apple2", "Apple2"); + bst->draw_cb = a2_draw; + bst->free_cb = a2_free; + return bst; +} + + +static void +a2controller_ransomware(apple2_sim_t *sim, int *stepno, + double *next_actiontime) +{ + apple2_state_t *st=sim->st; + + struct mydata { + const char *str; + Bool bold_p; + } *mine; + + if (!sim->controller_data) + sim->controller_data = calloc(sizeof(struct mydata),1); + mine=(struct mydata *) sim->controller_data; + + switch(*stepno) { + case 0: + + st->gr_mode |= A2_GR_FULL; + a2_cls(st); + a2_goto(st,0,16); + a2_prints(st, "APPLE ]["); + a2_goto(st,2,0); + *stepno = 10; + *next_actiontime += 2; + break; + + case 10: + a2_prints(st, "READY\n\n"); + *stepno = 11; + *next_actiontime += 1; + break; + + case 11: + a2_goto(st, 1, 0); + *stepno = 12; + mine->str = + ("\n" + " _____________________________________\n" + "/ \\\n" + "! OOPS YOUR FILES HAVE BEEN ENCRYPTED !\n" + "! ________________________ !\n" + "! ! ! !\n" + "! [/--\\] ! [ WHAT HAPPENED TO MY ] ! !\n" + "! [!] [!] ! [ COMPUTER? ] ! !\n" + "! [!] [!] ! ! !\n" + "! [######] ! [ CAN I RECOVER MY ] ! !\n" + "! [######] ! [ FILES? ] ! !\n" + "! [######] ! ! !\n" + "! [######] ! [ HOW DO I PAY? ] ! !\n" + "! ! ! !\n" + "! !________________________! !\n" + "! !\n" + "! BITCOIN ACCEPTED HERE !\n" + "\\_____________________________________/\n" + "\n" + "\n" + "WAITING FOR BLOCKCHAIN..@\n" + "\n" + "PLEASE INSERT NEXT FLOPPY: " + ); + break; + + case 12: + { + char c = *mine->str; + mine->str++; + + if (c == 0) + { + *next_actiontime += 30; + *stepno = 0; + } + else if (c == '[') + mine->bold_p++; + else if (c == ']') + mine->bold_p--; + else + { + if (c == '@') + { + c = '.'; + *next_actiontime += 2; + } + + if (mine->bold_p) + c |= 0xC0; + a2_printc_noscroll(st, c); + if (c == '.') + *next_actiontime += 1; + } + } + break; + + case A2CONTROLLER_FREE: + return; + } +} + + +static int +a2_ransomware_draw (struct bsod_state *bst) +{ + apple2_sim_t *sim = (apple2_sim_t *) bst->closure; + if (! sim) { + sim = apple2_start (bst->dpy, bst->window, 9999999, + a2controller_ransomware); + bst->closure = sim; + } + + if (! apple2_one_frame (sim)) { + bst->closure = 0; + } + + return 10000; +} + +static struct bsod_state * +apple2ransomware (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "apple2", "Apple2"); + bst->draw_cb = a2_ransomware_draw; + bst->free_cb = a2_free; + return bst; +} + + + +/* A crash spotted on a cash machine circa 2006, by jwz. I didn't note + what model it was; probably a Tranax Mini-Bank 1000 or similar vintage. + */ +static struct bsod_state * +atm (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "atm", "ATM"); + + int pix_w, pix_h; + int x, y, i = 0; + float scale = 0.48; + Pixmap mask = 0; + Pixmap pixmap = image_data_to_pixmap (dpy, window, + atm_png, sizeof(atm_png), + &pix_w, &pix_h, &mask); + + XClearWindow (dpy, window); + + while (pix_w <= bst->xgwa.width * scale && + pix_h <= bst->xgwa.height * scale) + { + pixmap = double_pixmap (dpy, bst->xgwa.visual, bst->xgwa.depth, + pixmap, pix_w, pix_h); + mask = double_pixmap (dpy, bst->xgwa.visual, 1, mask, pix_w, pix_h); + pix_w *= 2; + pix_h *= 2; + i++; + } + + x = (bst->xgwa.width - pix_w) / 2; + y = (bst->xgwa.height - pix_h) / 2; + if (y < 0) y = 0; + + if (i > 0) + { + int j; + XSetForeground (dpy, bst->gc, + get_pixel_resource (dpy, bst->xgwa.colormap, + "atm.background", + "ATM.Background")); + for (j = -1; j < pix_w; j += i+1) + XDrawLine (bst->dpy, pixmap, bst->gc, j, 0, j, pix_h); + for (j = -1; j < pix_h; j += i+1) + XDrawLine (bst->dpy, pixmap, bst->gc, 0, j, pix_w, j); + } + + XSetClipMask (dpy, bst->gc, mask); + XSetClipOrigin (dpy, bst->gc, x, y); + XCopyArea (dpy, pixmap, window, bst->gc, 0, 0, pix_w, pix_h, x, y); + + XFreePixmap (dpy, pixmap); + XFreePixmap (dpy, mask); + + return bst; +} + + +/* An Android phone boot loader, by jwz. + */ +static struct bsod_state * +android (Display *dpy, Window window) +{ + struct bsod_state *bst = make_bsod_state (dpy, window, "android", "Android"); + + unsigned long bg = get_pixel_resource (dpy, bst->xgwa.colormap, + "android.background", + "Android.Background"); + unsigned long fg = get_pixel_resource (dpy, bst->xgwa.colormap, + "android.foreground", + "Android.Foreground"); + unsigned long c1 = get_pixel_resource (dpy, bst->xgwa.colormap, + "android.color1", + "Android.Foreground"); + unsigned long c2 = get_pixel_resource (dpy, bst->xgwa.colormap, + "android.color2", + "Android.Foreground"); + unsigned long c3 = get_pixel_resource (dpy, bst->xgwa.colormap, + "android.color3", + "Android.Foreground"); + unsigned long c4 = get_pixel_resource (dpy, bst->xgwa.colormap, + "android.color4", + "Android.Foreground"); + unsigned long c5 = get_pixel_resource (dpy, bst->xgwa.colormap, + "android.color5", + "Android.Foreground"); + unsigned long c6 = get_pixel_resource (dpy, bst->xgwa.colormap, + "android.color6", + "Android.Foreground"); + unsigned long c7 = get_pixel_resource (dpy, bst->xgwa.colormap, + "android.color7", + "Android.Foreground"); + + const char *lines0[] = { + "Calculating... please wait\n", + "osbl: 0x499DF907\n", + "amss: 0x73162409\n", + "hboot: 0xE46C3327\n", + "boot: 0xBA570E7A\n", + "recovery: 0xC8BBA213\n", + "system: 0x87C3B1F0\n", + "\n", + "Press power key to go back.\n", + }; + + const char *lines1[] = { + "Checking SD card update...\n", + "", + " SD Checking...\n", + " Failed to open zipfile\n", + " loading preload_content...\n", + " [Caution] Preload Content Not Found\n", + " loading HTCUpdateZipName image...\n", + "", + " Checking...[PG46IMG.zip]\n", + "Please plug off USB\n", + }; + + const char *lines2[] = { + " SD Checking...\n", + " Loading...[PK76DIAG.zip]\n", + " No image!\n", + " Loading...[PK76DIAG.nbh]\n", + " No image or wrong image!\n", + " Loading...[PK76IMG.zip]\n", + " No image!\n", + " Loading...[PK76IMG.nbh]\n", + " No image or wrong image!\n", + " Loading...[PK76IMG.tar]\n", + " No image!\n", + " Loading...[PK76IMG.aes]\n", + " No image!\n", + " Loading...[PK76IMG.enc]\n", + " No image!\n", + }; + + int cw = (bst->font->per_char + ? bst->font->per_char['n'-bst->font->min_char_or_byte2].width + : bst->font->min_bounds.width); + int line_height = bst->font->ascent + bst->font->descent; + + int state = 0; + + Pixmap pixmap = 0, mask = 0; + int pix_w = 0, pix_h = 0; + + pixmap = image_data_to_pixmap (dpy, window, + android_png, sizeof(android_png), + &pix_w, &pix_h, &mask); + if (! pixmap) abort(); + { + int i, n = 0; + if (bst->xgwa.width > 2560) n++; /* Retina displays */ + for (i = 0; i < n; i++) + { + pixmap = double_pixmap (dpy, bst->xgwa.visual, bst->xgwa.depth, + pixmap, pix_w, pix_h); + mask = double_pixmap (dpy, bst->xgwa.visual, 1, + mask, pix_w, pix_h); + pix_w *= 2; + pix_h *= 2; + } + } + bst->pixmap = pixmap; + bst->mask = mask; + + bst->left_margin = (bst->xgwa.width - (cw * 40)) / 2; + if (bst->left_margin < 0) bst->left_margin = 0; + + while (1) { + unsigned long delay = + ((state == 0 || + state == countof(lines0) || + state == countof(lines0) + countof(lines1) || + state == countof(lines0) + countof(lines1) + countof(lines2)) + ? 10000 : 0); + BSOD_LINE_DELAY (bst, delay); + + if (state <= countof(lines0) + countof(lines1) + countof(lines2)) + { + BSOD_COLOR (bst, bg, bg); + BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height); + BSOD_COLOR (bst, bg, c1); + BSOD_MOVETO (bst, bst->left_margin + bst->xoff, + bst->top_margin + bst->yoff + line_height); + BSOD_TEXT (bst, LEFT, "*** UNLOCKED ***\n"); + BSOD_COLOR (bst, c2, bg); + BSOD_TEXT (bst, LEFT, + "PRIMOU PVT SHIP S-OFF RL\n" + "HBOOT-1.17.0000\n" + "CPLD-None\n" + "MICROP-None\n" + "RADIO-3831.17.00.23_2\n" + "eMMC-bootmode: disabled\n" + "CPU-bootmode : disabled\n" + "HW Secure boot: enabled\n" + "MODEM PATH : OFF\n" + "May 15 2012, 10:28:15\n" + "\n"); + BSOD_COLOR (bst, bg, c3); + + if (pixmap) + { + int x = (bst->xgwa.width - pix_w) / 2; + int y = bst->xgwa.height - bst->yoff - pix_h; + BSOD_PIXMAP (bst, 0, 0, pix_w, pix_h, x, y); + } + } + + if (state == countof(lines0) || + state == countof(lines0) + countof(lines1) || + state == countof(lines0) + countof(lines1) + countof(lines2)) + { + BSOD_TEXT (bst, LEFT, "HBOOT USB\n"); + BSOD_COLOR (bst, c4, bg); + BSOD_TEXT (bst, LEFT, + "\n" + " to previous item\n" + " to next item\n" + " to select item\n" + "\n"); + BSOD_COLOR (bst, c5, bg); BSOD_TEXT (bst, LEFT, "FASTBOOT\n"); + BSOD_COLOR (bst, c6, bg); BSOD_TEXT (bst, LEFT, "RECOVERY\n"); + BSOD_COLOR (bst, c7, bg); BSOD_TEXT (bst, LEFT, "FACTORY RESET\n"); + BSOD_COLOR (bst, c3, bg); BSOD_TEXT (bst, LEFT, "SIMLOCK\n"); + BSOD_COLOR (bst, bg, c3); BSOD_TEXT (bst, LEFT, "HBOOT USB\n"); + BSOD_COLOR (bst, fg, bg); BSOD_TEXT (bst, LEFT, "IMAGE CRC\n"); + BSOD_COLOR (bst, c3, bg); BSOD_TEXT (bst, LEFT, "SHOW BARCODE\n"); + BSOD_PAUSE (bst, 3000000); + } + else if (state < countof(lines0)) + { + BSOD_TEXT (bst, LEFT, "IMAGE CRC\n\n"); + BSOD_COLOR (bst, c5, bg); + { + int i; + for (i = 0; i <= state; i++) { + const char *s = lines0[i]; + BSOD_COLOR (bst, (strchr(s, ':') ? c7 : c3), bg); + BSOD_TEXT (bst, LEFT, s); + } + } + BSOD_PAUSE (bst, 500000); + if (state == countof(lines0)-1) + BSOD_PAUSE (bst, 2000000); + } + else if (state < countof(lines0) + countof(lines1)) + { + BSOD_TEXT (bst, LEFT, "HBOOT\n\n"); + BSOD_COLOR (bst, c5, bg); + { + int i; + for (i = countof(lines0); i <= state; i++) { + const char *s = lines1[i - countof(lines0)]; + BSOD_COLOR (bst, (*s == ' ' ? c6 : c3), bg); + BSOD_TEXT (bst, LEFT, s); + } + } + BSOD_PAUSE (bst, 500000); + if (state == countof(lines0) + countof(lines1) - 1) + BSOD_PAUSE (bst, 2000000); + } + else if (state < countof(lines0) + countof(lines1) + countof(lines2)) + { + BSOD_TEXT (bst, LEFT, "HBOOT USB\n\n"); + BSOD_COLOR (bst, c5, bg); + { + int i; + for (i = countof(lines0) + countof(lines1); i <= state; i++) { + const char *s = lines2[i - countof(lines0) - countof(lines1)]; + BSOD_COLOR (bst, (*s == ' ' ? c6 : c3), bg); + BSOD_TEXT (bst, LEFT, s); + } + } + BSOD_PAUSE (bst, 500000); + if (state == countof(lines0) + countof(lines1) + countof(lines2)-1) + BSOD_PAUSE (bst, 2000000); + } + else + break; + + state++; + } + + XClearWindow (dpy, window); + + return bst; +} + + + + +/***************************************************************************** + *****************************************************************************/ + + +static const struct { + const char *name; + struct bsod_state * (*fn) (Display *, Window); +} all_modes[] = { + { "Windows", windows_31 }, + { "NT", windows_nt }, + { "Win2K", windows_other }, + { "Win10", windows_10 }, + { "Ransomware", windows_ransomware }, + { "Amiga", amiga }, + { "Mac", mac }, + { "MacsBug", macsbug }, + { "Mac1", mac1 }, + { "MacX", macx }, + { "SCO", sco }, + { "HVX", hvx }, + { "HPPALinux", hppa_linux }, + { "SparcLinux", sparc_linux }, + { "BSD", bsd }, + { "Atari", atari }, +#ifndef HAVE_JWXYZ + { "BlitDamage", blitdamage }, +#endif + { "Solaris", sparc_solaris }, + { "Linux", linux_fsck }, + { "HPUX", hpux }, + { "OS390", os390 }, + { "Tru64", tru64 }, + { "VMS", vms }, + { "OS2", os2 }, + { "MSDOS", msdos }, + { "Nvidia", nvidia }, + { "Apple2", apple2crash }, + { "ATM", atm }, + { "GLaDOS", glados }, + { "Android", android }, + { "VMware", vmware }, +}; + + +struct driver_state { + const char *name; + int only, which, next_one; + int mode_duration; + int delay_remaining; + time_t start; + Bool debug_p, cycle_p; + struct bsod_state *bst; +}; + + +static void +hack_title (struct driver_state *dst) +{ +# ifndef HAVE_JWXYZ + char *oname = 0; + XFetchName (dst->bst->dpy, dst->bst->window, &oname); + if (oname && !strncmp (oname, "BSOD: ", 6)) { + char *tail = oname + 4; + char *s = strchr (tail+1, ':'); + char *nname; + if (s) tail = s; + nname = malloc (strlen (tail) + strlen (dst->name) + 20); + sprintf (nname, "BSOD: %s%s", dst->name, tail); + XStoreName (dst->bst->dpy, dst->bst->window, nname); + free (nname); + } +# endif /* !HAVE_JWXYZ */ +} + +static void * +bsod_init (Display *dpy, Window window) +{ + struct driver_state *dst = (struct driver_state *) calloc (1, sizeof(*dst)); + char *s; + + dst->mode_duration = get_integer_resource (dpy, "delay", "Integer"); + if (dst->mode_duration < 3) dst->mode_duration = 3; + + dst->debug_p = get_boolean_resource (dpy, "debug", "Boolean"); + + dst->only = -1; + dst->next_one = -1; + s = get_string_resource(dpy, "doOnly", "DoOnly"); + if (s && !strcasecmp (s, "cycle")) + { + dst->which = -1; + dst->cycle_p = True; + } + else if (s && *s) + { + int count = countof(all_modes); + for (dst->only = 0; dst->only < count; dst->only++) + if (!strcasecmp (s, all_modes[dst->only].name)) + break; + if (dst->only >= count) + { + fprintf (stderr, "%s: unknown -only mode: \"%s\"\n", progname, s); + dst->only = -1; + } + } + if (s) free (s); + + dst->name = "none"; + dst->which = -1; + return dst; +} + + +static unsigned long +bsod_draw (Display *dpy, Window window, void *closure) +{ + struct driver_state *dst = (struct driver_state *) closure; + time_t now; + int time_left; + + AGAIN: + now = time ((time_t *) 0); + time_left = dst->start + dst->mode_duration - now; + + if (dst->bst && dst->bst->img_loader) /* still loading */ + { + dst->bst->img_loader = + load_image_async_simple (dst->bst->img_loader, 0, 0, 0, 0, 0); + return 100000; + } + + DELAY_NOW: + /* Rather than returning a multi-second delay from the draw() routine, + meaning "don't call us again for N seconds", we quantize that down + to 1/10th second intervals so that it's more responsive to + rotate/reshape events. + */ + if (dst->delay_remaining) + { + int inc = 10000; + int this_delay = MIN (dst->delay_remaining, inc); + dst->delay_remaining = MAX (0, dst->delay_remaining - inc); + return this_delay; + } + + if (! dst->bst && time_left > 0) /* run completed; wait out the delay */ + { + if (dst->debug_p) + fprintf (stderr, "%s: %s: %d left\n", progname, dst->name, time_left); + dst->start = 0; + if (time_left > 5) time_left = 5; /* Boooored now */ + dst->delay_remaining = 1000000 * time_left; + } + + else if (dst->bst) /* sub-mode currently running */ + { + int this_delay = -1; + + if (time_left > 0) + this_delay = bsod_pop (dst->bst); + + /* XSync (dpy, False); slows down char drawing too much on HAVE_JWXYZ */ + + if (this_delay == 0) + goto AGAIN; /* no delay, not expired: stay here */ + else if (this_delay >= 0) + { + dst->delay_remaining = this_delay; /* return; time to sleep */ + goto DELAY_NOW; + } + else + { /* sub-mode run completed or expired */ + if (dst->debug_p) + fprintf (stderr, "%s: %s: done\n", progname, dst->name); + free_bsod_state (dst->bst); + dst->bst = 0; + return 0; + } + } + else /* launch a new sub-mode */ + { + if (dst->next_one >= 0) + dst->which = dst->next_one, dst->next_one = -1; + else if (dst->cycle_p) + dst->which = (dst->which + 1) % countof(all_modes); + else if (dst->only >= 0) + dst->which = dst->only; + else + { + int count = countof(all_modes); + int *enabled = (int *) calloc (sizeof(*enabled), count + 1); + int nenabled = 0; + int i; + + for (i = 0; i < count; i++) + { + char name[100], class[100]; + sprintf (name, "do%s", all_modes[i].name); + sprintf (class, "Do%s", all_modes[i].name); + if (get_boolean_resource (dpy, name, class)) + enabled[nenabled++] = i; + } + + if (nenabled == 0) + { + fprintf (stderr, "%s: no display modes enabled?\n", progname); + /* exit (-1); */ + dst->which = dst->only = 0; + } + else if (nenabled == 1) + dst->which = enabled[0]; + else + { + i = dst->which; + while (i == dst->which) + i = enabled[random() % nenabled]; + dst->which = i; + } + free (enabled); + } + + if (dst->debug_p) + fprintf (stderr, "%s: %s: launch\n", progname, + all_modes[dst->which].name); + + /* Run the mode setup routine... + */ + if (dst->bst) abort(); + dst->name = all_modes[dst->which].name; + dst->bst = all_modes[dst->which].fn (dpy, window); + dst->start = (dst->bst ? time ((time_t *) 0) : 0); + + /* Reset the structure run state to the beginning, + and do some sanitization of the cursor position + before the first run. + */ + if (dst->bst) + { + if (dst->debug_p) + fprintf (stderr, "%s: %s: queue size: %d (%d)\n", progname, + dst->name, dst->bst->pos, dst->bst->queue_size); + + hack_title (dst); + dst->bst->pos = 0; + dst->bst->x = dst->bst->current_left = + dst->bst->left_margin + dst->bst->xoff; + + if (dst->bst->y < + dst->bst->top_margin + dst->bst->yoff + dst->bst->font->ascent) + dst->bst->y = + dst->bst->top_margin + dst->bst->yoff + dst->bst->font->ascent; + } + } + + return 0; +} + + +static void +bsod_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct driver_state *dst = (struct driver_state *) closure; + + if (dst->bst && + w == dst->bst->xgwa.width && + h == dst->bst->xgwa.height) + return; + + if (dst->debug_p) + fprintf (stderr, "%s: %s: reshape reset\n", progname, dst->name); + + /* just restart this mode and restart when the window is resized. */ + if (dst->bst) + free_bsod_state (dst->bst); + dst->bst = 0; + dst->start = 0; + dst->delay_remaining = 0; + dst->next_one = dst->which; + dst->name = "none"; + XClearWindow (dpy, window); +} + + +static Bool +bsod_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + struct driver_state *dst = (struct driver_state *) closure; + Bool reset_p = False; + + /* pick a new mode and restart when mouse clicked, or certain keys typed. */ + + if (screenhack_event_helper (dpy, window, event)) + reset_p = True; + + if (reset_p) + { + if (dst->debug_p) + fprintf (stderr, "%s: %s: manual reset\n", progname, dst->name); + if (dst->bst) + free_bsod_state (dst->bst); + dst->bst = 0; + dst->start = 0; + dst->delay_remaining = 0; + dst->name = "none"; + XClearWindow (dpy, window); + return True; + } + else + return False; +} + + +static void +bsod_free (Display *dpy, Window window, void *closure) +{ + struct driver_state *dst = (struct driver_state *) closure; + if (dst->bst) + free_bsod_state (dst->bst); + free (dst); +} + + +static const char *bsod_defaults [] = { + "*delay: 45", + "*debug: False", + + "*doOnly: ", + "*doWindows: True", + "*doNT: True", + "*doWin2K: True", + "*doWin10: True", + "*doRansomware: True", + "*doAmiga: True", + "*doMac: True", + "*doMacsBug: True", + "*doMac1: True", + "*doMacX: True", + "*doSCO: True", + "*doAtari: False", /* boring */ + "*doBSD: False", /* boring */ + "*doLinux: True", + "*doSparcLinux: False", /* boring */ + "*doHPPALinux: True", + "*doBlitDamage: True", + "*doSolaris: True", + "*doHPUX: True", + "*doTru64: True", + "*doApple2: True", + "*doOS390: True", + "*doVMS: True", + "*doHVX: True", + "*doMSDOS: True", + "*doOS2: True", + "*doNvidia: True", + "*doATM: True", + "*doGLaDOS: True", + "*doAndroid: True", + "*doVMware: True", + + ".foreground: White", + ".background: Black", + + ".windows.foreground: White", + ".windows.background: #0000AA", /* EGA color 0x01. */ + + ".nt.foreground: White", + ".nt.background: #0000AA", /* EGA color 0x01. */ + + ".windowslh.foreground: White", + ".windowslh.background: #AA0000", /* EGA color 0x04. */ + ".windowslh.background2: #AAAAAA", /* EGA color 0x07. */ + + ".win10.foreground: White", + ".win10.background: #1070AA", + + ".ransomware.foreground: White", + ".ransomware.background: #841212", + ".ransomware.foreground2: Black", /* ransom note */ + ".ransomware.background2: White", + ".ransomware.foreground3: Black", /* buttons */ + ".ransomware.background3: #AAAAAA", + ".ransomware.link: #7BF9F6", + ".ransomware.timerheader: #BDBE02", + + + ".glaDOS.foreground: White", + ".glaDOS.background: #0000AA", /* EGA color 0x01. */ + + ".amiga.foreground: #FF0000", + ".amiga.background: Black", + ".amiga.background2: White", + + ".mac.foreground: #FFFFFF", + ".mac.background: Black", + + ".atari.foreground: Black", + ".atari.background: White", + + ".macsbug.foreground: Black", + ".macsbug.background: White", + ".macsbug.borderColor: #AAAAAA", + + ".mac1.foreground: Black", + ".mac1.background: White", + + ".macx.foreground: White", + ".macx.textForeground: White", + ".macx.textBackground: Black", + ".macx.background: #888888", + + ".macinstall.barForeground: #C0C0C0", + ".macinstall.barBackground: #888888", + + ".sco.foreground: White", + ".sco.background: Black", + + ".hvx.foreground: White", + ".hvx.background: Black", + + ".linux.foreground: White", + ".linux.background: Black", + + ".hppalinux.foreground: White", + ".hppalinux.background: Black", + + ".sparclinux.foreground: White", + ".sparclinux.background: Black", + + ".bsd.foreground: #c0c0c0", + ".bsd.background: Black", + + ".solaris.foreground: Black", + ".solaris.background: White", + + ".hpux.foreground: White", + ".hpux.background: Black", + + ".os390.background: Black", + ".os390.foreground: Red", + + ".tru64.foreground: White", + ".tru64.background: #0000AA", /* EGA color 0x01. */ + + ".vms.foreground: White", + ".vms.background: Black", + + ".msdos.foreground: White", + ".msdos.background: Black", + + ".os2.foreground: White", + ".os2.background: Black", + + ".atm.foreground: Black", + ".atm.background: #FF6600", + + ".android.foreground: Black", + ".android.background: White", + ".android.color1: #AA00AA", /* violet */ + ".android.color2: #336633", /* green1 */ + ".android.color3: #0000FF", /* blue */ + ".android.color4: #CC7744", /* orange */ + ".android.color5: #99AA55", /* green2 */ + ".android.color6: #66AA33", /* green3 */ + ".android.color7: #FF0000", /* red */ + + ".vmware.foreground: White", + ".vmware.foreground2: Yellow", + ".vmware.background: #a700a8", /* purple */ + + "*dontClearRoot: True", + + ANALOGTV_DEFAULTS + +#ifdef HAVE_XSHM_EXTENSION + "*useSHM: True", +#endif + + "*fontB: ", + "*fontC: ", + +# if defined(USE_IPHONE) + + "*font: PxPlus IBM VGA8 16, Courier-Bold 14", + "*bigFont: ", + + ".mac.font: Courier-Bold 18", + ".macsbug.font: Courier-Bold 8", + ".macx.font: Courier-Bold 14", + ".macdisk.font: Courier-Bold 14", + ".macinstall.font: Helvetica 12, Arial 12", + ".macinstall.bigFont: Helvetica 12, Arial 12", + ".msdos.font: PxPlus IBM VGA8 32, Courier-Bold 28", + ".nt.font: PxPlus IBM VGA8 12, Courier-Bold 10", + ".win10.font: Arial 12, Helvetica 12", + ".win10.bigFont: Arial 12, Helvetica 12", + ".win10.fontB: Arial 50, Helvetica 50", + ".win10.fontC: Arial 9, Helvetica 9", + + /* The real Solaris font is ../OSX/Gallant19.bdf but I don't know how + to convert that to a TTF, so let's use Luxi Mono instead. */ + ".solaris.font: Luxi Mono 12, PxPlus IBM VGA8 12, Courier Bold 12", + + /* "Arial" loads "ArialMT" but "Arial Bold" does not load "Arial-BoldMT"? */ + ".ransomware.font: Arial 11, Helvetica 11", + ".ransomware.fontB: Arial 9, Helvetica 9", + ".ransomware.fontC: Arial Bold 11, Arial-BoldMT 11, Helvetica Bold 11", + +# elif defined(HAVE_ANDROID) + + "*font: PxPlus IBM VGA8 16", + "*bigFont: ", + + ".mac.font: -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*", + ".macsbug.font: -*-courier-bold-r-*-*-*-80-*-*-m-*-*-*", + ".macx.font: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", + ".macdisk.font: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", + ".macinstall.font: -*-helvetica-medium-r-*-*-*-120-*-*-*-*-*-*", + ".macinstall.bigFont: -*-helvetica-medium-r-*-*-*-120-*-*-*-*-*-*", + ".msdos.font: PxPlus IBM VGA8 32", + ".nt.font: PxPlus IBM VGA8 12", + ".solaris.font: Luxi Mono 12, PxPlus IBM VGA8 12, Courier Bold 12", + + ".win10.font: -*-helvetica-medium-r-*-*-*-120-*-*-*-*-*-*", + ".win10.bigFont: -*-helvetica-medium-r-*-*-*-120-*-*-*-*-*-*", + ".win10.fontB: -*-helvetica-medium-r-*-*-*-500-*-*-*-*-*-*", + ".win10.fontC: -*-helvetica-medium-r-*-*-*-90-*-*-*-*-*-*", + + ".ransomware.font: -*-helvetica-medium-r-*-*-*-100-*-*-*-*-*-*", + ".ransomware.fontB: -*-helvetica-medium-r-*-*-*-80-*-*-*-*-*-*", + ".ransomware.fontC: -*-helvetica-bold-r-*-*-*-100-*-*-*-*-*-*", + +# elif defined(HAVE_COCOA) + + "*font: PxPlus IBM VGA8 8, Courier Bold 9", + "*bigFont: PxPlus IBM VGA8 32, Courier Bold 24", + + ".mac.font: Monaco 10, Courier Bold 9", + ".mac.bigFont: Monaco 18, Courier Bold 18", + + ".macsbug.font: Monaco 10, Courier Bold 9", + ".macsbug.bigFont: Monaco 24, Courier Bold 24", + + ".macx.font: Courier Bold 9", + ".macx.bigFont: Courier Bold 14", + ".macdisk.font: Courier Bold 9", + ".macdisk.bigFont: Courier Bold 18", + ".macinstall.font: Helvetica 24, Arial 24", + ".macinstall.bigFont: Helvetica 24, Arial 24", + + ".hvx.bigFont: PxPlus IBM VGA8 16, Courier Bold 14", + ".hppalinux.bigFont: PxPlus IBM VGA8 16, Courier Bold 14", + ".linux.bigFont: PxPlus IBM VGA8 16, Courier Bold 14", + ".hpux.bigFont: PxPlus IBM VGA8 16, Courier Bold 14", + ".msdos.font: PxPlus IBM VGA8 16, Courier Bold 14", + ".solaris.font: Luxi Mono 12, PxPlus IBM VGA8 12, Courier Bold 12", + ".solaris.bigFont: Luxi Mono 16, PxPlus IBM VGA8 16, Courier Bold 14", + + ".win10.font: Arial 24, Helvetica 24", + ".win10.bigFont: Arial 24, Helvetica 24", + ".win10.fontB: Arial 100, Helvetica 100", + ".win10.fontC: Arial 16, Helvetica 16", + + ".ransomware.font: Arial 24, Helvetica 24", + ".ransomware.bigFont: Arial 24, Helvetica 24", + ".ransomware.fontB: Arial 16, Helvetica 16", + ".ransomware.fontC: Arial Bold 24, Helvetica Bold 24", + +# else /* X11 */ + + "*font: 9x15bold", + "*bigFont: -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*", + + ".macsbug.font: -*-courier-medium-r-*-*-*-80-*-*-m-*-*-*", + ".macsbug.bigFont: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", + + ".macdisk.font: -*-courier-bold-r-*-*-*-80-*-*-m-*-*-*", + ".macdisk.bigFont: -*-courier-bold-r-*-*-*-100-*-*-m-*-*-*", + ".macinstall.font: -*-helvetica-medium-r-*-*-*-180-*-*-*-*-*-*", + ".macinstall.bigFont: -*-helvetica-medium-r-*-*-*-180-*-*-*-*-*-*", + + ".sco.font: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", + ".hvx.font: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", + ".hppalinux.bigFont: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", + ".sparclinux.bigFont: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", + + /* Some systems might have this, but I'm not sure where it comes from: */ + /* ".bsd.font: -*-vga-normal-r-*-*-*-120-*-*-c-*-*-*", */ + /* The fonts/misc/vga.pcf that comes with xdosemu has no XLFD name: */ + ".bsd.font: vga", + ".bsd.bigFont: -*-vga-normal-r-*-*-*-220-*-*-c-*-*-*", + + /* The original Solaris console font was: + -sun-gallant-demi-r-normal-*-*-140-*-*-c-*-*-* + Red Hat introduced Luxi Mono as its console font, which is similar + to Gallant. X.Org includes it but Debian and Fedora do not. */ + ".solaris.font: -*-luxi mono-medium-r-normal--*-140-*-*-m-*-*-*", + + ".hpux.bigFont: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", + ".os390.bigFont: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", + ".tru64.bigFont: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", + ".vms.bigFont: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", + ".msdos.bigFont: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", + + ".win10.font: -*-helvetica-medium-r-*-*-*-180-*-*-*-*-*-*", + ".win10.bigFont: -*-helvetica-medium-r-*-*-*-180-*-*-*-*-*-*", + ".win10.fontB: -*-helvetica-medium-r-*-*-*-240-*-*-*-*-*-*", + ".win10.fontC: -*-helvetica-medium-r-*-*-*-140-*-*-*-*-*-*", + + ".ransomware.font: -*-helvetica-medium-r-*-*-*-180-*-*-*-*-*-*", + ".ransomware.bigFont: -*-helvetica-medium-r-*-*-*-180-*-*-*-*-*-*", + ".ransomware.fontB: -*-helvetica-medium-r-*-*-*-140-*-*-*-*-*-*", + ".ransomware.fontC: -*-helvetica-bold-r-*-*-*-180-*-*-*-*-*-*", + + +# endif /* X11 */ + + 0 +}; + +static const XrmOptionDescRec bsod_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-only", ".doOnly", XrmoptionSepArg, 0 }, + { "-debug", ".debug", XrmoptionNoArg, "True" }, + { "-windows", ".doWindows", XrmoptionNoArg, "True" }, + { "-no-windows", ".doWindows", XrmoptionNoArg, "False" }, + { "-nt", ".doNT", XrmoptionNoArg, "True" }, + { "-no-nt", ".doNT", XrmoptionNoArg, "False" }, + { "-2k", ".doWin2K", XrmoptionNoArg, "True" }, + { "-no-2k", ".doWin2K", XrmoptionNoArg, "False" }, + { "-win10", ".doWin10", XrmoptionNoArg, "True" }, + { "-no-win10", ".doWin10", XrmoptionNoArg, "False" }, + { "-ransomware", ".doRansomware", XrmoptionNoArg, "True" }, + { "-no-ransomware", ".doRansomware", XrmoptionNoArg, "False" }, + { "-amiga", ".doAmiga", XrmoptionNoArg, "True" }, + { "-no-amiga", ".doAmiga", XrmoptionNoArg, "False" }, + { "-mac", ".doMac", XrmoptionNoArg, "True" }, + { "-no-mac", ".doMac", XrmoptionNoArg, "False" }, + { "-mac1", ".doMac1", XrmoptionNoArg, "True" }, + { "-no-mac1", ".doMac1", XrmoptionNoArg, "False" }, + { "-macx", ".doMacX", XrmoptionNoArg, "True" }, + { "-no-macx", ".doMacX", XrmoptionNoArg, "False" }, + { "-atari", ".doAtari", XrmoptionNoArg, "True" }, + { "-no-atari", ".doAtari", XrmoptionNoArg, "False" }, + { "-macsbug", ".doMacsBug", XrmoptionNoArg, "True" }, + { "-no-macsbug", ".doMacsBug", XrmoptionNoArg, "False" }, + { "-apple2", ".doApple2", XrmoptionNoArg, "True" }, + { "-no-apple2", ".doApple2", XrmoptionNoArg, "False" }, + { "-sco", ".doSCO", XrmoptionNoArg, "True" }, + { "-no-sco", ".doSCO", XrmoptionNoArg, "False" }, + { "-hvx", ".doHVX", XrmoptionNoArg, "True" }, + { "-no-hvx", ".doHVX", XrmoptionNoArg, "False" }, + { "-bsd", ".doBSD", XrmoptionNoArg, "True" }, + { "-no-bsd", ".doBSD", XrmoptionNoArg, "False" }, + { "-linux", ".doLinux", XrmoptionNoArg, "True" }, + { "-no-linux", ".doLinux", XrmoptionNoArg, "False" }, + { "-hppalinux", ".doHPPALinux", XrmoptionNoArg, "True" }, + { "-no-hppalinux", ".doHPPALinux", XrmoptionNoArg, "False" }, + { "-sparclinux", ".doSparcLinux", XrmoptionNoArg, "True" }, + { "-no-sparclinux", ".doSparcLinux", XrmoptionNoArg, "False" }, + { "-blitdamage", ".doBlitDamage", XrmoptionNoArg, "True" }, + { "-no-blitdamage", ".doBlitDamage", XrmoptionNoArg, "False" }, + { "-nvidia", ".doNvidia", XrmoptionNoArg, "True" }, + { "-no-nvidia", ".doNvidia", XrmoptionNoArg, "False" }, + { "-solaris", ".doSolaris", XrmoptionNoArg, "True" }, + { "-no-solaris", ".doSolaris", XrmoptionNoArg, "False" }, + { "-hpux", ".doHPUX", XrmoptionNoArg, "True" }, + { "-no-hpux", ".doHPUX", XrmoptionNoArg, "False" }, + { "-os390", ".doOS390", XrmoptionNoArg, "True" }, + { "-no-os390", ".doOS390", XrmoptionNoArg, "False" }, + { "-tru64", ".doHPUX", XrmoptionNoArg, "True" }, + { "-no-tru64", ".doTru64", XrmoptionNoArg, "False" }, + { "-vms", ".doVMS", XrmoptionNoArg, "True" }, + { "-no-vms", ".doVMS", XrmoptionNoArg, "False" }, + { "-msdos", ".doMSDOS", XrmoptionNoArg, "True" }, + { "-no-msdos", ".doMSDOS", XrmoptionNoArg, "False" }, + { "-os2", ".doOS2", XrmoptionNoArg, "True" }, + { "-no-os2", ".doOS2", XrmoptionNoArg, "False" }, + { "-atm", ".doATM", XrmoptionNoArg, "True" }, + { "-no-atm", ".doATM", XrmoptionNoArg, "False" }, + { "-glados", ".doGLaDOS", XrmoptionNoArg, "True" }, + { "-no-glados", ".doGLaDOS", XrmoptionNoArg, "False" }, + { "-android", ".doAndroid", XrmoptionNoArg, "True" }, + { "-no-android", ".doAndroid", XrmoptionNoArg, "False" }, + { "-vmware", ".doVMware", XrmoptionNoArg, "True" }, + { "-no-vmware", ".doVMware", XrmoptionNoArg, "False" }, + ANALOGTV_OPTIONS + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("BSOD", bsod) diff --git a/hacks/bsod.man b/hacks/bsod.man new file mode 100644 index 0000000..0043e7f --- /dev/null +++ b/hacks/bsod.man @@ -0,0 +1,149 @@ +.de EX \"Begin example +.ne 5 +.if n .sp 1 +.if t .sp .5 +.nf +.in +.5i +.. +.de EE +.fi +.in -.5i +.if n .sp 1 +.if t .sp .5 +.. +.TH XScreenSaver 1 "5-May-2004" "X Version 11" +.SH NAME +bsod - Blue Screen of Death emulator +.SH SYNOPSIS +.B bsod +[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] +[\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install] +[\-visual \fIvisual\fP] [\-delay \fIseconds\fP] +[\-fps] +.SH DESCRIPTION +The +.I bsod +program is the finest in personal computer emulation. +.PP +.I bsod +steps through a set of screens, each one a recreation of a different failure +mode of an operating system. Systems depicted include +Windows 3.1, Windows 95, Windows NT, MS-DOS, AmigaDOS 1.3, Linux, +SCO UNIX, BSD UNIX, HPUX, Solaris, Tru64, VMS, HVX/GCOS6, IBM OS/390, OS/2, +MacOS (MacsBug, Bomb, Sad Mac, and OSX), Atari ST, Apple ][+, VMware and +NCD X Terminals. +.PP +.SH OPTIONS +.I bsod +accepts the following options: +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-mono +If on a color display, pretend we're on a monochrome display. +.TP 8 +.B \-install +Install a private colormap for the window. +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-delay \fIdelay\fP +The duration each crash-mode is displayed before selecting another. +.TP 8 +.B \-only \fIwhich\fP +Tell it to run only one mode, e.g., \fI\-only HPUX\fP. +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH X RESOURCES +Notable X resources supported include the following, which control which +hacks are displayed and which aren't. +.BR doWindows , +.BR doNT , +.BR doWin2K , +.BR doWin10 , +.BR doRansomware , +.BR doAmiga , +.BR doMac , +.BR doMac1 , +.BR doMacsBug , +.BR doMacX , +.BR doSCO , +.BR doAtari , +.BR doBSD , +.BR doLinux , +.BR doSparcLinux , +.BR doHPPALinux , +.BR doBlitDamage , +.BR doSolaris , +.BR doHPUX , +.BR doApple2 , +.BR doOS390 , +.BR doTru64 , +.BR doVMS , +.BR doMSDOS , +.BR doOS2 , +.BR doHVX , +.BR doVMware , +and +.BR doATM . +Each of these is a Boolean resource, they all default to true, except +for doAtari, doBSD, doSparcLinux, and doHPPALinux, which are turned off +by default, because they're really not all that interesting looking +unless you're a fan of those systems. + +There are command-line options for all of these: +e.g., \fI\-bsd\fP, \fI\-no-bsd\fP. (Also note the \fI\-only\fP option.) +.SH BUGS +Unlike the systems being simulated, \fIbsod\fP does not require a +reboot after running. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1), +.BR http://www.microsoft.com/ , +.BR http://www.apple.com/ , +.BR http://www.sco.com/ , +.BR http://www.kernel.org/ , +and +.BR http://www.amiga.de/ . +.SH TRADEMARKS +Microsoft Windows, Microsoft Windows 95, and Microsoft Windows NT are all +registered trademarks of Microsoft Corporation. Apple Macintosh is a +registered trademark of Apple Computer. Amiga is a registered trademark of +Amiga International, Inc. Solaris is a trademark of Sun Microsystems. HP-UX +is a trademark of HP Hewlett Packard Group LLC. Nvidia is a tradmark of +Nvidia Corporation. VMS is probably a trademark of Digital Equipment +Corporation. Atari ST is probably a trademark, too, but it's hard to tell who +owns it. SCO is probably still a trademark of somebody these days, I guess. +Linux is a registered trademark of Linus Torvalds, but it isn't his +fault. OS/2 is a registered trademark of International Business Machines +Corporation. VMware is a registered trademark of VMware, Inc. Android is a +trademark of Google LLC. GladOS is a trademark of Aperture Science +Incorporated. +.SH COPYRIGHT +Copyright \(co 1998-2018 by Jamie Zawinski. Permission to use, copy, modify, +distribute, and sell this software and its documentation for any purpose is +hereby granted without fee, provided that the above copyright notice appear +in all copies and that both that copyright notice and this permission notice +appear in supporting documentation. No representations are made about the +suitability of this software for any purpose. It is provided "as is" without +express or implied warranty. No animals were harmed during the testing of +these simulations. Always mount a scratch monkey. +.SH AUTHOR +Concept cribbed from Stephen Martin . This version is by +Jamie Zawinski , with contributions from many others. diff --git a/hacks/bubbles-default.c b/hacks/bubbles-default.c new file mode 100644 index 0000000..0e729d5 --- /dev/null +++ b/hacks/bubbles-default.c @@ -0,0 +1,154 @@ +/* bubbles_default.c - pick images for bubbles.c + * By Jamie Zawinski , 20-Jan-98. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include "bubbles.h" +#include "yarandom.h" + +#ifndef NO_DEFAULT_BUBBLE + +# define BLOOD 0 +# include "images/gen/blood1_png.h" +# include "images/gen/blood2_png.h" +# include "images/gen/blood3_png.h" +# include "images/gen/blood4_png.h" +# include "images/gen/blood5_png.h" +# include "images/gen/blood6_png.h" +# include "images/gen/blood7_png.h" +# include "images/gen/blood8_png.h" +# include "images/gen/blood9_png.h" +# include "images/gen/blood10_png.h" +# include "images/gen/blood11_png.h" + +# define BLUE 1 +# include "images/gen/blue1_png.h" +# include "images/gen/blue2_png.h" +# include "images/gen/blue3_png.h" +# include "images/gen/blue4_png.h" +# include "images/gen/blue5_png.h" +# include "images/gen/blue6_png.h" +# include "images/gen/blue7_png.h" +# include "images/gen/blue8_png.h" +# include "images/gen/blue9_png.h" +# include "images/gen/blue10_png.h" +# include "images/gen/blue11_png.h" + +# define GLASS 2 +# include "images/gen/glass1_png.h" +# include "images/gen/glass2_png.h" +# include "images/gen/glass3_png.h" +# include "images/gen/glass4_png.h" +# include "images/gen/glass5_png.h" +# include "images/gen/glass6_png.h" +# include "images/gen/glass7_png.h" +# include "images/gen/glass8_png.h" +# include "images/gen/glass9_png.h" +# include "images/gen/glass10_png.h" +# include "images/gen/glass11_png.h" + +# define JADE 3 +# include "images/gen/jade1_png.h" +# include "images/gen/jade2_png.h" +# include "images/gen/jade3_png.h" +# include "images/gen/jade4_png.h" +# include "images/gen/jade5_png.h" +# include "images/gen/jade6_png.h" +# include "images/gen/jade7_png.h" +# include "images/gen/jade8_png.h" +# include "images/gen/jade9_png.h" +# include "images/gen/jade10_png.h" +# include "images/gen/jade11_png.h" + +# define END 4 + + +bubble_png default_bubbles[50]; +int num_default_bubbles; + +void init_default_bubbles(void) +{ + int i = 0; + switch (random() % END) { + +# define DEF(N,S) default_bubbles[i].png = N; default_bubbles[i].size = S; i++ + + case BLOOD: + DEF(blood1_png, sizeof(blood1_png)); + DEF(blood2_png, sizeof(blood2_png)); + DEF(blood3_png, sizeof(blood3_png)); + DEF(blood4_png, sizeof(blood4_png)); + DEF(blood5_png, sizeof(blood5_png)); + DEF(blood6_png, sizeof(blood6_png)); + DEF(blood7_png, sizeof(blood7_png)); + DEF(blood8_png, sizeof(blood8_png)); + DEF(blood9_png, sizeof(blood9_png)); + DEF(blood10_png, sizeof(blood10_png)); + DEF(blood11_png, sizeof(blood11_png)); + break; + + case BLUE: + DEF(blue1_png, sizeof(blue1_png)); + DEF(blue2_png, sizeof(blue2_png)); + DEF(blue3_png, sizeof(blue3_png)); + DEF(blue4_png, sizeof(blue4_png)); + DEF(blue5_png, sizeof(blue5_png)); + DEF(blue6_png, sizeof(blue6_png)); + DEF(blue7_png, sizeof(blue7_png)); + DEF(blue8_png, sizeof(blue8_png)); + DEF(blue9_png, sizeof(blue9_png)); + DEF(blue10_png, sizeof(blue10_png)); + DEF(blue11_png, sizeof(blue11_png)); + break; + + case GLASS: + DEF(glass1_png, sizeof(glass1_png)); + DEF(glass2_png, sizeof(glass2_png)); + DEF(glass3_png, sizeof(glass3_png)); + DEF(glass4_png, sizeof(glass4_png)); + DEF(glass5_png, sizeof(glass5_png)); + DEF(glass6_png, sizeof(glass6_png)); + DEF(glass7_png, sizeof(glass7_png)); + DEF(glass8_png, sizeof(glass8_png)); + DEF(glass9_png, sizeof(glass9_png)); + DEF(glass10_png, sizeof(glass10_png)); + DEF(glass11_png, sizeof(glass11_png)); + break; + + case JADE: + DEF(jade1_png, sizeof(jade1_png)); + DEF(jade2_png, sizeof(jade2_png)); + DEF(jade3_png, sizeof(jade3_png)); + DEF(jade4_png, sizeof(jade4_png)); + DEF(jade5_png, sizeof(jade5_png)); + DEF(jade6_png, sizeof(jade6_png)); + DEF(jade7_png, sizeof(jade7_png)); + DEF(jade8_png, sizeof(jade8_png)); + DEF(jade9_png, sizeof(jade9_png)); + DEF(jade10_png, sizeof(jade10_png)); + DEF(jade11_png, sizeof(jade11_png)); + break; + + default: + abort(); + break; + } + + default_bubbles[i].png = 0; + num_default_bubbles = i; +} + +#endif /* NO_DEFAULT_BUBBLE */ diff --git a/hacks/bubbles.c b/hacks/bubbles.c new file mode 100644 index 0000000..9cb2678 --- /dev/null +++ b/hacks/bubbles.c @@ -0,0 +1,1437 @@ +/* bubbles.c - frying pan / soft drink in a glass simulation */ + +/*$Id: bubbles.c,v 1.30 2008/07/31 19:27:48 jwz Exp $*/ + +/* + * Copyright (C) 1995-1996 James Macnicol + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +/* + * I got my original inspiration for this by looking at the bottom of a + * frying pan while something was cooking and watching the little bubbles + * coming off the bottom of the pan as the oil was boiling joining together + * to form bigger bubbles and finally to *pop* and disappear. I had some + * time on my hands so I wrote this little xscreensaver module to imitate + * it. Now that it's done it reminds me more of the bubbles you get in + * a glass of fizzy soft drink..... + * + * The problem seemed to be that the position/size etc. of all the bubbles + * on the screen had to be remembered and searched through to find when + * bubbles hit each other and combined. To do this more efficiently, the + * window/screen is divided up into a square mesh of side length mesh_length + * and separate lists of bubbles contained in each cell of the mesh are + * kept. Only the cells in the immediate vicinity of the bubble in question + * are searched. This should make things more efficient although the whole + * thing seems to use up too much CPU, but then I'm using an ancient PC so + * perhaps it's not surprising . + * (Six months after I wrote the above I now have a Pentium with PCI graphics + * and things are _much_ nicer.) + * + * Author: James Macnicol + * Internet E-mail : j-macnicol@adfa.edu.au + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#undef DEBUG /* doesn't compile */ + +#include +#include + +#ifndef VMS +# include +#else /* VMS */ +# if __DECC_VER >= 50200000 +# include +# endif +#endif /* VMS */ + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include "screenhack.h" +#include "yarandom.h" +#include "bubbles.h" +#include "ximage-loader.h" + +#define FANCY_BUBBLES + +/* + * Public variables + */ + +static const char *bubbles_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*simple: false", + "*broken: false", + "*delay: 10000", + "*quiet: false", + "*mode: float", + "*trails: false", + "*3D: false", + 0 +}; + +static XrmOptionDescRec bubbles_options [] = { + { "-simple", ".simple", XrmoptionNoArg, "true" }, +#ifdef FANCY_BUBBLES + { "-broken", ".broken", XrmoptionNoArg, "true" }, +#endif + { "-quiet", ".quiet", XrmoptionNoArg, "true" }, + { "-3D", ".3D", XrmoptionNoArg, "true" }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-mode", ".mode", XrmoptionSepArg, 0 }, + { "-drop", ".mode", XrmoptionNoArg, "drop" }, + { "-rise", ".mode", XrmoptionNoArg, "rise" }, + { "-trails", ".trails", XrmoptionNoArg, "true" }, + { 0, 0, 0, 0 } +}; + +/* + * Private variables + */ + +struct state { + Display *dpy; + Window window; + + Bubble **mesh; + int mesh_length; + int mesh_width; + int mesh_height; + int mesh_cells; + + int **adjacent_list; + + int screen_width; + int screen_height; + int screen_depth; + unsigned int default_fg_pixel, default_bg_pixel; + + int bubble_min_radius; /* For simple mode only */ + int bubble_max_radius; + long *bubble_areas; + int *bubble_droppages; + GC draw_gc, erase_gc; + +#ifdef FANCY_BUBBLES + int num_bubble_pixmaps; + Bubble_Step **step_pixmaps; +#endif + + Bool simple; + Bool broken; + Bool quiet; + Bool threed; + Bool drop; + Bool trails; + int drop_dir; + int delay; +}; + +static int drop_bubble( struct state *st, Bubble *bb ); + +/* + * To prevent forward references, some stuff is up here + */ + +static long +calc_bubble_area(struct state *st, int r) +/* Calculate the area of a bubble of radius r */ +{ +#ifdef DEBUG + printf("%d %g\n", r, + 10.0 * PI * (double)r * (double)r * (double)r); +#endif /* DEBUG */ + if (st->threed) + return (long)(10.0 * PI * (double)r * (double)r * (double)r); + else + return (long)(10.0 * PI * (double)r * (double)r); +} + +static void * +xmalloc(size_t size) +/* Safe malloc */ +{ + void *ret; + + if ((ret = malloc(size)) == NULL) { + fprintf(stderr, "%s: out of memory\n", progname); + exit(1); + } + return ret; +} + +#ifdef DEBUG +static void +die_bad_bubble(Bubble *bb) +/* This is for use with GDB */ +{ + fprintf(stderr, "Bad bubble detected at 0x%x!\n", (int)bb); + exit(1); +} +#endif + +static int +null_bubble(Bubble *bb) +/* Returns true if the pointer passed is NULL. If not then this checks to +see if the bubble is valid (i.e. the (x,y) position is valid and the magic +number is set correctly. This only a sanity check for debugging and is +turned off if DEBUG isn't set. */ +{ + if (bb == (Bubble *)NULL) + return 1; +#ifdef DEBUG + if ((bb->cell_index < 0) || (bb->cell_index > st->mesh_cells)) { + fprintf(stderr, "cell_index = %d\n", bb->cell_index); + die_bad_bubble(bb); + } + if (bb->magic != BUBBLE_MAGIC) { + fprintf(stderr, "Magic = %d\n", bb->magic); + die_bad_bubble(bb); + } + if (st->simple) { + if ((bb->x < 0) || (bb->x > st->screen_width) || + (bb->y < 0) || (bb->y > st->screen_height) || + (bb->radius < st->bubble_min_radius) || (bb->radius > + st->bubble_max_radius)) { + fprintf(stderr, + "radius = %d, x = %d, y = %d, magic = %d, cell index = %d\n", + bb->radius, bb->x, bb->y, bb->magic, bb->cell_index); + die_bad_bubble(bb); + } +#ifdef FANCY_BUBBLES + } else { + if ((bb->x < 0) || (bb->x > st->screen_width) || + (bb->y < 0) || (bb->y > st->screen_height) || + (bb->radius < st->step_pixmaps[0]->radius) || + (bb->radius > st->step_pixmaps[st->num_bubble_pixmaps-1]->radius)) { + fprintf(stderr, + "radius = %d, x = %d, y = %d, magic = %d, cell index = %d\n", + bb->radius, bb->x, bb->y, bb->magic, bb->cell_index); + die_bad_bubble(bb); + } +#endif + } +#endif /* DEBUG */ + return 0; +} + +#ifdef DEBUG +static void +print_bubble_list(Bubble *bb) +/* Print list of where all the bubbles are. For debugging purposes only. */ +{ + if (! null_bubble(bb)) { + printf(" (%d, %d) %d\n", bb->x, bb->y, bb->radius); + print_bubble_list(bb->next); + } +} +#endif /* DEBUG */ + +static void +add_bubble_to_list(Bubble **list, Bubble *bb) +/* Take a pointer to a list of bubbles and stick bb at the head of the + list. */ +{ + Bubble *head = *list; + + if (null_bubble(head)) { + bb->prev = (Bubble *)NULL; + bb->next = (Bubble *)NULL; + } else { + bb->next = head; + bb->prev = (Bubble *)NULL; + head->prev = bb; + } + *list = bb; +} + + +/* + * Mesh stuff + */ + + +static void +init_mesh (struct state *st) +/* Setup the mesh of bubbles */ +{ + int i; + + st->mesh = (Bubble **)xmalloc(st->mesh_cells * sizeof(Bubble *)); + for (i = 0; i < st->mesh_cells; i++) + st->mesh[i] = (Bubble *)NULL; +} + +static int +cell_to_mesh(struct state *st, int x, int y) +/* convert cell coordinates to mesh index */ +{ +#ifdef DEBUG + if ((x < 0) || (y < 0)) { + fprintf(stderr, "cell_to_mesh: x = %d, y = %d\n", x, y); + exit(1); + } +#endif + return ((st->mesh_width * y) + x); +} + +static void +mesh_to_cell(struct state *st, int mi, int *cx, int *cy) +/* convert mesh index into cell coordinates */ +{ + *cx = mi % st->mesh_width; + *cy = mi / st->mesh_width; +} + +static int +pixel_to_mesh(struct state *st, int x, int y) +/* convert screen coordinates into mesh index */ +{ + return cell_to_mesh(st, (x / st->mesh_length), (y / st->mesh_length)); +} + +static int +verify_mesh_index(struct state *st, int x, int y) +/* check to see if (x,y) is in the mesh */ +{ + if ((x < 0) || (y < 0) || (x >= st->mesh_width) || (y >= st->mesh_height)) + return (-1); + return (cell_to_mesh(st, x, y)); +} + +#ifdef DEBUG +static void +print_adjacents(int *adj) +/* Print a list of the cells calculated above. For debugging only. */ +{ + int i; + + printf("("); + for (i = 0; i < 8; i++) + printf("%d ", adj[i]); + printf(")\n"); +} +#endif /* DEBUG */ + +static void +add_to_mesh(struct state *st, Bubble *bb) +/* Add the given bubble to the mesh by sticking it on the front of the +list. bb is already allocated so no need to malloc() anything, just +adjust pointers. */ +{ +#ifdef DEBUG + if (null_bubble(bb)) { + fprintf(stderr, "Bad bubble passed to add_to_mesh()!\n"); + exit(1); + } +#endif /* DEBUG */ + + add_bubble_to_list(&st->mesh[bb->cell_index], bb); +} + +#ifdef DEBUG +static void +print_mesh (struct state *st) +/* Print the contents of the mesh */ +{ + int i; + + for (i = 0; i < st->mesh_cells; i++) { + if (! null_bubble(st->mesh[i])) { + printf("Mesh cell %d\n", i); + print_bubble_list(st->mesh[i]); + } + } +} + +static void +valid_mesh (struct state *st) +/* Check to see if the mesh is Okay. For debugging only. */ +{ + int i; + Bubble *b; + + for (i = 0; i < st->mesh_cells; i++) { + b = st->mesh[i]; + while (! null_bubble(b)) + b = b->next; + } +} + +static int +total_bubbles (struct state *st) +/* Count how many bubbles there are in total. For debugging only. */ +{ + int rv = 0; + int i; + Bubble *b; + + for (i = 0; i < st->mesh_cells; i++) { + b = st->mesh[i]; + while (! null_bubble(b)) { + rv++; + b = b->next; + } + } + + return rv; +} +#endif /* DEBUG */ + +static void +calculate_adjacent_list (struct state *st) +/* Calculate the list of cells adjacent to a particular cell for use + later. */ +{ + int i; + int ix, iy; + + st->adjacent_list = (int **)xmalloc(st->mesh_cells * sizeof(int *)); + for (i = 0; i < st->mesh_cells; i++) { + st->adjacent_list[i] = (int *)xmalloc(9 * sizeof(int)); + mesh_to_cell(st, i, &ix, &iy); + st->adjacent_list[i][0] = verify_mesh_index(st, --ix, --iy); + st->adjacent_list[i][1] = verify_mesh_index(st, ++ix, iy); + st->adjacent_list[i][2] = verify_mesh_index(st, ++ix, iy); + st->adjacent_list[i][3] = verify_mesh_index(st, ix, ++iy); + st->adjacent_list[i][4] = verify_mesh_index(st, ix, ++iy); + st->adjacent_list[i][5] = verify_mesh_index(st, --ix, iy); + st->adjacent_list[i][6] = verify_mesh_index(st, --ix, iy); + st->adjacent_list[i][7] = verify_mesh_index(st, ix, --iy); + st->adjacent_list[i][8] = i; + } +} + +static void +adjust_areas (struct state *st) +/* Adjust areas of bubbles so we don't get overflow in weighted_mean() */ +{ + double maxvalue; + long maxarea; + long factor; + int i; + +#ifdef FANCY_BUBBLES + if (st->simple) + maxarea = st->bubble_areas[st->bubble_max_radius+1]; + else + maxarea = st->step_pixmaps[st->num_bubble_pixmaps]->area; +#else /* !FANCY_BUBBLES */ + maxarea = st->bubble_areas[st->bubble_max_radius+1]; +#endif /* !FANCY_BUBBLES */ + maxvalue = (double)st->screen_width * 2.0 * (double)maxarea; + factor = (long)ceil(maxvalue / (double)LONG_MAX); + if (factor > 1) { + /* Overflow will occur in weighted_mean(). We must divide areas + each by factor so it will never do so. */ +#ifdef FANCY_BUBBLES + if (st->simple) { + for (i = st->bubble_min_radius; i <= st->bubble_max_radius+1; i++) { + st->bubble_areas[i] /= factor; + if (st->bubble_areas[i] == 0) + st->bubble_areas[i] = 1; + } + } else { + for (i = 0; i <= st->num_bubble_pixmaps; i++) { +#ifdef DEBUG + printf("area = %ld", st->step_pixmaps[i]->area); +#endif /* DEBUG */ + st->step_pixmaps[i]->area /= factor; + if (st->step_pixmaps[i]->area == 0) + st->step_pixmaps[i]->area = 1; +#ifdef DEBUG + printf("-> %ld\n", st->step_pixmaps[i]->area); +#endif /* DEBUG */ + } + } +#else /* !FANCY_BUBBLES */ + for (i = st->bubble_min_radius; i <= st->bubble_max_radius+1; i++) { + st->bubble_areas[i] /= factor; + if (st->bubble_areas[i] == 0) + st->bubble_areas[i] = 1; + } +#endif /* !FANCY_BUBBLES */ + } +#ifdef DEBUG + printf("maxarea = %ld\n", maxarea); + printf("maxvalue = %g\n", maxvalue); + printf("LONG_MAX = %ld\n", LONG_MAX); + printf("factor = %ld\n", factor); +#endif /* DEBUG */ +} + +/* + * Bubbles stuff + */ + +static Bubble * +new_bubble (struct state *st) +/* Add a new bubble at some random position on the screen of the smallest +size. */ +{ + Bubble *rv = (Bubble *)xmalloc(sizeof(Bubble)); + + /* Can't use null_bubble() here since magic number hasn't been set */ + if (rv == (Bubble *)NULL) { + fprintf(stderr, "Ran out of memory!\n"); + exit(1); + } + + if (st->simple) { + rv->radius = st->bubble_min_radius; + rv->area = st->bubble_areas[st->bubble_min_radius]; +#ifdef FANCY_BUBBLES + } else { + rv->step = 0; + rv->radius = st->step_pixmaps[0]->radius; + rv->area = st->step_pixmaps[0]->area; +#endif /* FANCY_BUBBLES */ + } + rv->visible = 0; + rv->magic = BUBBLE_MAGIC; + rv->x = random() % st->screen_width; + rv->y = random() % st->screen_height; + rv->cell_index = pixel_to_mesh(st, rv->x, rv->y); + + return rv; +} + +static void +show_bubble(struct state *st, Bubble *bb) +/* paint the bubble on the screen */ +{ + if (null_bubble(bb)) { + fprintf(stderr, "NULL bubble passed to show_bubble\n"); + exit(1); + } + + if (! bb->visible) { + bb->visible = 1; + + if (st->simple) { + XDrawArc(st->dpy, st->window, st->draw_gc, (bb->x - bb->radius), + (bb->y - bb->radius), bb->radius*2, bb->radius*2, 0, + 360*64); + } else { +#ifdef FANCY_BUBBLES + XSetClipOrigin(st->dpy, st->step_pixmaps[bb->step]->draw_gc, + (bb->x - bb->radius), + (bb->y - bb->radius)); + + XCopyArea(st->dpy, st->step_pixmaps[bb->step]->ball, st->window, + st->step_pixmaps[bb->step]->draw_gc, + 0, 0, (bb->radius * 2), + (bb->radius * 2), + (bb->x - bb->radius), + (bb->y - bb->radius)); +#endif /* FANCY_BUBBLES */ + } + } +} + +static void +hide_bubble(struct state *st, Bubble *bb) +/* erase the bubble */ +{ + if (null_bubble(bb)) { + fprintf(stderr, "NULL bubble passed to hide_bubble\n"); + exit(1); + } + + if (bb->visible) { + bb->visible = 0; + + if (st->simple) { + XDrawArc(st->dpy, st->window, st->erase_gc, (bb->x - bb->radius), + (bb->y - bb->radius), bb->radius*2, bb->radius*2, 0, + 360*64); + } else { +#ifdef FANCY_BUBBLES + if (! st->broken) { + XSetClipOrigin(st->dpy, st->step_pixmaps[bb->step]->erase_gc, + (bb->x - bb->radius), (bb->y - bb->radius)); + + XFillRectangle(st->dpy, st->window, st->step_pixmaps[bb->step]->erase_gc, + (bb->x - bb->radius), + (bb->y - bb->radius), + (bb->radius * 2), + (bb->radius * 2)); + } +#endif /* FANCY_BUBBLES */ + } + } +} + +static void +delete_bubble_in_mesh(struct state *st, Bubble *bb, int keep_bubble) +/* Delete an individual bubble, adjusting list of bubbles around it. + If keep_bubble is true then the bubble isn't actually deleted. We + use this to allow bubbles to change mesh cells without reallocating, + (it needs this when two bubbles collide and the centre position is + recalculated, and this may stray over a mesh boundary). */ +{ + if ((!null_bubble(bb->prev)) && (!null_bubble(bb->next))) { + bb->prev->next = bb->next; + bb->next->prev = bb->prev; + } else if ((!null_bubble(bb->prev)) && + (null_bubble(bb->next))) { + bb->prev->next = (Bubble *)NULL; + bb->next = st->mesh[bb->cell_index]; + } else if ((null_bubble(bb->prev)) && + (!null_bubble(bb->next))) { + bb->next->prev = (Bubble *)NULL; + st->mesh[bb->cell_index] = bb->next; + bb->next = st->mesh[bb->cell_index]; + } else { + /* Only item on list */ + st->mesh[bb->cell_index] = (Bubble *)NULL; + } + if (! keep_bubble) + free(bb); +} + +static unsigned long +ulongsqrint(int x) +/* Saves ugly inline code */ +{ + return ((unsigned long)x * (unsigned long)x); +} + +static Bubble * +get_closest_bubble(struct state *st, Bubble *bb) +/* Find the closest bubble touching the this bubble, NULL if none are + touching. */ +{ + Bubble *rv = (Bubble *)NULL; + Bubble *tmp; + unsigned long separation2, touchdist2; + int dx, dy; + unsigned long closest2 = ULONG_MAX; + int i; + +#ifdef DEBUG + if (null_bubble(bb)) { + fprintf(stderr, "NULL pointer 0x%x passed to get_closest_bubble()!", + (int)bb); + exit(1); + } +#endif /* DEBUG */ + + for (i = 0; i < 9; i++) { + /* There is a bug here where bb->cell_index is negaitve.. */ +#ifdef DEBUG + if ((bb->cell_index < 0) || (bb->cell_index >= st->mesh_cells)) { + fprintf(stderr, "bb->cell_index = %d\n", bb->cell_index); + exit(1); + } +#endif /* DEBUG */ +/* printf("%d,", bb->cell_index); */ + if (st->adjacent_list[bb->cell_index][i] != -1) { + tmp = st->mesh[st->adjacent_list[bb->cell_index][i]]; + while (! null_bubble(tmp)) { + if (tmp != bb) { + dx = tmp->x - bb->x; + dy = tmp->y - bb->y; + separation2 = ulongsqrint(dx) + ulongsqrint(dy); + /* Add extra leeway so circles _never_ overlap */ + touchdist2 = ulongsqrint(tmp->radius + bb->radius + 2); + if ((separation2 <= touchdist2) && (separation2 < + closest2)) { + rv = tmp; + closest2 = separation2; + } + } + tmp = tmp->next; + } + } + } + + return rv; +} + +#ifdef DEBUG +static void +ldr_barf (struct state *st) +{ +} +#endif /* DEBUG */ + +static long +long_div_round(long num, long dem) +{ + long divvie, moddo; + +#ifdef DEBUG + if ((num < 0) || (dem < 0)) { + fprintf(stderr, "long_div_round: %ld, %ld\n", num, dem); + ldr_barf(); + exit(1); + } +#endif /* DEBUG */ + + divvie = num / dem; + moddo = num % dem; + if (moddo > (dem / 2)) + ++divvie; + +#ifdef DEBUG + if ((divvie < 0) || (moddo < 0)) { + fprintf(stderr, "long_div_round: %ld, %ld\n", divvie, moddo); + ldr_barf(); + exit(1); + } +#endif /* DEBUG */ + + return divvie; +} + +static int +weighted_mean(int n1, int n2, long w1, long w2) +/* Mean of n1 and n2 respectively weighted by weights w1 and w2. */ +{ +#ifdef DEBUG + if ((w1 <= 0) || (w2 <= 0)) { + fprintf(stderr, + "Bad weights passed to weighted_mean() - (%d, %d, %ld, %ld)!\n", + n1, n2, w1, w2); + exit(1); + } +#endif /* DEBUG */ + return ((int)long_div_round((long)n1 * w1 + (long)n2 * w2, + w1 + w2)); +} + +static int +bubble_eat(struct state *st, Bubble *diner, Bubble *food) +/* The diner eats the food. Returns true (1) if the diner still exists */ +{ + int i; + int newmi; + +#ifdef DEBUG + if ((null_bubble(diner)) || (null_bubble(food))) { + fprintf(stderr, "Bad bubbles passed to bubble_eat()!\n"); + exit(1); + } +#endif /* DEBUG */ + + /* We hide the diner even in the case that it doesn't grow so that + if the food overlaps its boundary it is replaced. This could + probably be solved by letting bubbles eat others which are close + but not quite touching. It's probably worth it, too, since we + would then not have to redraw bubbles which don't change in + size. */ + + hide_bubble(st, diner); + hide_bubble(st, food); + diner->x = weighted_mean(diner->x, food->x, diner->area, food->area); + diner->y = weighted_mean(diner->y, food->y, diner->area, food->area); + newmi = pixel_to_mesh(st, diner->x, diner->y); + diner->area += food->area; + delete_bubble_in_mesh(st, food, DELETE_BUBBLE); + + if (st->drop) { + if ((st->simple) && (diner->area > st->bubble_areas[st->bubble_max_radius])) { + diner->area = st->bubble_areas[st->bubble_max_radius]; + } +#ifdef FANCY_BUBBLES + if ((! st->simple) && (diner->area > st->step_pixmaps[st->num_bubble_pixmaps]->area)) { + diner->area = st->step_pixmaps[st->num_bubble_pixmaps]->area; + } +#endif /* FANCY_BUBBLES */ + } + else { + if ((st->simple) && (diner->area > st->bubble_areas[st->bubble_max_radius])) { + delete_bubble_in_mesh(st, diner, DELETE_BUBBLE); + return 0; + } +#ifdef FANCY_BUBBLES + if ((! st->simple) && (diner->area > + st->step_pixmaps[st->num_bubble_pixmaps]->area)) { + delete_bubble_in_mesh(st, diner, DELETE_BUBBLE); + return 0; + } +#endif /* FANCY_BUBBLES */ + } + + if (st->simple) { + if (diner->area > st->bubble_areas[diner->radius + 1]) { + /* Move the bubble to a new radius */ + i = diner->radius; + while ((i < st->bubble_max_radius - 1) && (diner->area > st->bubble_areas[i+1])) + ++i; + diner->radius = i; + } + show_bubble(st, diner); +#ifdef FANCY_BUBBLES + } else { + if (diner->area > st->step_pixmaps[diner->step+1]->area) { + i = diner->step; + while ((i < st->num_bubble_pixmaps - 1) && (diner->area > st->step_pixmaps[i+1]->area)) + ++i; + diner->step = i; + diner->radius = st->step_pixmaps[diner->step]->radius; + } + show_bubble(st, diner); +#endif /* FANCY_BUBBLES */ + } + + /* Now adjust locations and cells if need be */ + if (newmi != diner->cell_index) { + delete_bubble_in_mesh(st, diner, KEEP_BUBBLE); + diner->cell_index = newmi; + add_to_mesh(st, diner); + } + + return 1; +} + +static int +merge_bubbles(struct state *st, Bubble *b1, Bubble *b2) +/* These two bubbles merge into one. If the first one wins out return +1 else return 2. If there is no winner (it explodes) then return 0 */ +{ + int b1size, b2size; + + b1size = b1->area; + b2size = b2->area; + +#ifdef DEBUG + if ((null_bubble(b1) || null_bubble(b2))) { + fprintf(stderr, "NULL bubble passed to merge_bubbles()!\n"); + exit(1); + } +#endif /* DEBUG */ + + if (b1 == b2) { + hide_bubble(st, b1); + delete_bubble_in_mesh(st, b1, DELETE_BUBBLE); + return 0; + } + + if (b1size > b2size) { + switch (bubble_eat(st, b1, b2)) { + case 0: + return 0; + break; + case 1: + return 1; + break; + default: + break; + } + } else if (b1size < b2size) { + switch (bubble_eat(st, b2, b1)) { + case 0: + return 0; + break; + case 1: + return 2; + break; + default: + break; + } + } else { + if ((random() % 2) == 0) { + switch (bubble_eat(st, b1, b2)) { + case 0: + return 0; + break; + case 1: + return 1; + break; + default: + break; + } + } else { + switch (bubble_eat(st, b2, b1)) { + case 0: + return 0; + break; + case 1: + return 2; + break; + default: + break; + } + } + } + fprintf(stderr, "An error occurred in merge_bubbles()\n"); + exit(1); +} + +static void +insert_new_bubble(struct state *st, Bubble *tmp) +/* Calculates which bubbles are eaten when a new bubble tmp is + inserted. This is called recursively in case when a bubble grows + it eats others. Careful to pick out disappearing bubbles. */ +{ + Bubble *nextbub; + Bubble *touch; + +#ifdef DEBUG + if (null_bubble(tmp)) { + fprintf(stderr, "Bad bubble passed to insert_new_bubble()!\n"); + exit(1); + } +#endif /* DEBUG */ + + nextbub = tmp; + touch = get_closest_bubble(st, nextbub); + if (null_bubble(touch)) + return; + + while (1) { + + /* Merge all touching bubbles */ + while (! null_bubble(touch)) { + switch (merge_bubbles(st, nextbub, touch)) { + case 2: + /* touch ate nextbub and survived */ + nextbub = touch; + break; + case 1: + /* nextbub ate touch and survived */ + break; + case 0: + /* somebody ate someone else but they exploded */ + nextbub = (Bubble *)NULL; + break; + default: + /* something went wrong */ + fprintf(stderr, "Error occurred in insert_new_bubble()\n"); + exit(1); + } + + /* Check to see if any bubble survived. */ + if (null_bubble(nextbub)) + break; + + /* Check to see if there are any other bubbles still in the area + and if we need to do this all over again for them. */ + touch = get_closest_bubble(st, nextbub); + } + + if (null_bubble(nextbub)) + break; + + /* Shift bubble down. Break if we run off the screen. */ + if (st->drop) { + if (drop_bubble( st, nextbub ) == -1) + break; + } + + /* Check to see if there are any other bubbles still in the area + and if we need to do this all over again for them. */ + touch = get_closest_bubble(st, nextbub); + if (null_bubble(touch)) { + /* We also continue every so often if we're dropping and the bubble is at max size */ + if (st->drop) { + if (st->simple) { + if ((nextbub->area >= st->bubble_areas[st->bubble_max_radius - 1]) && (random() % 2 == 0)) + continue; + } +#ifdef FANCY_BUBBLES + else { + if ((nextbub->step >= st->num_bubble_pixmaps - 1) && (random() % 2 == 0)) + continue; + } +#endif /* FANCY_BUBBLES */ + } + break; + } + + } +} + + +static void +leave_trail(struct state *st, Bubble *bb ) +{ + Bubble *tmp; + + tmp = new_bubble(st); + tmp->x = bb->x; + tmp->y = bb->y - ((bb->radius + 10) * st->drop_dir); + tmp->cell_index = pixel_to_mesh(st, tmp->x, tmp->y); + add_to_mesh(st, tmp); + insert_new_bubble(st, tmp); + show_bubble( st, tmp ); +} + + +static int +drop_bubble( struct state *st, Bubble *bb ) +{ + int newmi; + + hide_bubble( st, bb ); + + if (st->simple) + (bb->y) += (st->bubble_droppages[bb->radius] * st->drop_dir); +#ifdef FANCY_BUBBLES + else + (bb->y) += (st->step_pixmaps[bb->step]->droppage * st->drop_dir); +#endif /* FANCY_BUBBLES */ + if ((bb->y < 0) || (bb->y > st->screen_height)) { + delete_bubble_in_mesh( st, bb, DELETE_BUBBLE ); + return -1; + } + + show_bubble( st, bb ); + + /* Now adjust locations and cells if need be */ + newmi = pixel_to_mesh(st, bb->x, bb->y); + if (newmi != bb->cell_index) { + delete_bubble_in_mesh(st, bb, KEEP_BUBBLE); + bb->cell_index = newmi; + add_to_mesh(st, bb); + } + + if (st->trails) { + if (st->simple) { + if ((bb->area >= st->bubble_areas[st->bubble_max_radius - 1]) && (random() % 2 == 0)) + leave_trail( st, bb ); + } +#ifdef FANCY_BUBBLES + else { + if ((bb->step >= st->num_bubble_pixmaps - 1) && (random() % 2 == 0)) + leave_trail( st, bb ); + } +#endif /* FANCY_BUBBLES */ + } + + return 0; +} + + +#ifdef DEBUG +static int +get_length_of_bubble_list(Bubble *bb) +{ + Bubble *tmp = bb; + int rv = 0; + + while (! null_bubble(tmp)) { + rv++; + tmp = tmp->next; + } + + return rv; +} +#endif /* DEBUG */ + +/* + * Pixmap stuff used regardless of whether file I/O is available. Must + * still check for XPM, though! + */ + +#ifdef FANCY_BUBBLES + +/* + * Pixmaps without file I/O (but do have XPM) + */ + +static void +pixmap_sort(Bubble_Step **head, int numelems) +/* Couldn't get qsort to work right with this so I wrote my own. This puts +the numelems length array with first element at head into order of radius. +*/ +{ + Bubble_Step tmp; + Bubble_Step *least = 0; + int minradius = INT_MAX; + int i; + + for (i = 0; i < numelems; i++) { + if (head[i]->radius < minradius) { + least = head[i]; + minradius = head[i]->radius; + } + } + if (*head != least) { + memcpy(&tmp, least, sizeof(Bubble_Step)); + memcpy(least, *head, sizeof(Bubble_Step)); + memcpy(*head, &tmp, sizeof(Bubble_Step)); + } + + if (numelems > 2) + pixmap_sort(&head[1], numelems-1); +} + +static int +extrapolate(int i1, int i2) +{ + return (i2 + (i2 - i1)); +} + +static void +make_pixmap_array(struct state *st, Bubble_Step *list) +/* From a linked list of bubbles construct the array step_pixmaps */ +{ + Bubble_Step *tmp = list; + int ind; +#ifdef DEBUG + int prevrad = -1; +#endif + + if (list == (Bubble_Step *)NULL) { + fprintf(stderr, "NULL list passed to make_pixmap_array\n"); + exit(1); + } + + st->num_bubble_pixmaps = 1; + while(tmp->next != (Bubble_Step *)NULL) { + tmp = tmp->next; + ++st->num_bubble_pixmaps; + } + + if (st->num_bubble_pixmaps < 2) { + fprintf(stderr, "Must be at least two bubbles in file\n"); + exit(1); + } + + st->step_pixmaps = (Bubble_Step **)xmalloc((st->num_bubble_pixmaps + 1) * + sizeof(Bubble_Step *)); + + /* Copy them blindly into the array for sorting. */ + ind = 0; + tmp = list; + do { + st->step_pixmaps[ind++] = tmp; + tmp = tmp->next; + } while(tmp != (Bubble_Step *)NULL); + + /* We make another bubble beyond the ones with pixmaps so that the final + bubble hangs around and doesn't pop immediately. It's radius and area + are found by extrapolating from the largest two bubbles with pixmaps. */ + + st->step_pixmaps[st->num_bubble_pixmaps] = + (Bubble_Step *)xmalloc(sizeof(Bubble_Step)); + st->step_pixmaps[st->num_bubble_pixmaps]->radius = INT_MAX; + + pixmap_sort(st->step_pixmaps, (st->num_bubble_pixmaps + 1)); + +#ifdef DEBUG + if (st->step_pixmaps[st->num_bubble_pixmaps]->radius != INT_MAX) { + fprintf(stderr, "pixmap_sort() screwed up make_pixmap_array\n"); + } +#endif /* DEBUG */ + + st->step_pixmaps[st->num_bubble_pixmaps]->radius = + extrapolate(st->step_pixmaps[st->num_bubble_pixmaps-2]->radius, + st->step_pixmaps[st->num_bubble_pixmaps-1]->radius); + st->step_pixmaps[st->num_bubble_pixmaps]->area = + calc_bubble_area(st, st->step_pixmaps[st->num_bubble_pixmaps]->radius); + + +#ifdef DEBUG + /* Now check for correct order */ + for (ind = 0; ind < st->num_bubble_pixmaps; ind++) { + if (prevrad > 0) { + if (st->step_pixmaps[ind]->radius < prevrad) { + fprintf(stderr, "Pixmaps not in ascending order of radius\n"); + exit(1); + } + } + prevrad = st->step_pixmaps[ind]->radius; + } +#endif /* DEBUG */ + + /* Now populate the droppage values */ + for (ind = 0; ind < st->num_bubble_pixmaps; ind++) + st->step_pixmaps[ind]->droppage = MAX_DROPPAGE * ind / st->num_bubble_pixmaps; +} + +static void +make_pixmap_from_default(struct state *st, + const unsigned char *png_data, + unsigned long data_size, + Bubble_Step *bl) +/* Read pixmap data which has been compiled into the program and a pointer + to which has been passed. + + This is virtually copied verbatim from make_pixmap_from_file() above and +changes made to either should be propagated onwards! */ +{ + XGCValues gcv; + +#ifdef DEBUG + if (pixmap_data == (char **)0) { + fprintf(stderr, "make_pixmap_from_default(): NULL passed\n"); + exit(1); + } +#endif + + if (bl == (Bubble_Step *)NULL) { + fprintf(stderr, "NULL pointer passed to make_pixmap()\n"); + exit(1); + } + +#ifdef FANCY_BUBBLES + { + int w, h; + bl->ball = image_data_to_pixmap (st->dpy, st->window, png_data, data_size, + &w, &h, &bl->shape_mask); + bl->radius = MAX(w, h) / 2; + bl->area = calc_bubble_area(st, bl->radius); + } +#endif /* FANCY_BUBBLES */ + + gcv.foreground = st->default_fg_pixel; + gcv.function = GXcopy; + bl->draw_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + XSetClipMask(st->dpy, bl->draw_gc, bl->shape_mask); + + gcv.foreground = st->default_bg_pixel; + gcv.function = GXcopy; + bl->erase_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + XSetClipMask(st->dpy, bl->erase_gc, bl->shape_mask); +} + +static void +default_to_pixmaps (struct state *st) +/* Make pixmaps out of default ball data stored in bubbles_default.c */ +{ + int i; + Bubble_Step *pixmap_list = (Bubble_Step *)NULL; + Bubble_Step *newpix, *tmppix; + + init_default_bubbles(); + + for (i = 0; i < num_default_bubbles; i++) { + newpix = (Bubble_Step *)xmalloc(sizeof(Bubble_Step)); + make_pixmap_from_default(st, + default_bubbles[i].png, + default_bubbles[i].size, + newpix); + /* Now add to list */ + if (pixmap_list == (Bubble_Step *)NULL) { + pixmap_list = newpix; + } else { + tmppix = pixmap_list; + while (tmppix->next != (Bubble_Step *)NULL) + tmppix = tmppix->next; + tmppix->next = newpix; + } + newpix->next = (Bubble_Step *)NULL; + } + + /* Finally construct step_pixmaps[] */ + make_pixmap_array(st, pixmap_list); +} + +#endif /* FANCY_BUBBLES */ + + +/* + * Main stuff + */ + + +static void +get_resources(struct state *st) +/* Get the appropriate X resources and warn about any inconsistencies. */ +{ + Bool rise; + XWindowAttributes xgwa; + Colormap cmap; + char *s; + XGetWindowAttributes (st->dpy, st->window, &xgwa); + cmap = xgwa.colormap; + + st->threed = get_boolean_resource(st->dpy, "3D", "Boolean"); + st->quiet = get_boolean_resource(st->dpy, "quiet", "Boolean"); + st->simple = get_boolean_resource(st->dpy, "simple", "Boolean"); + /* Forbid rendered bubbles on monochrome displays */ + if ((mono_p) && (! st->simple)) { + if (! st->quiet) + fprintf(stderr, + "Rendered bubbles not supported on monochrome displays\n"); + st->simple = True; + } + st->delay = get_integer_resource(st->dpy, "delay", "Integer"); + + s = get_string_resource (st->dpy, "mode", "Mode"); + rise = False; + if (!s || !*s || !strcasecmp (s, "float")) + ; + else if (!strcasecmp (s, "rise")) + rise = True; + else if (!strcasecmp (s, "drop")) + st->drop = True; + else + fprintf (stderr, "%s: bogus mode: \"%s\"\n", progname, s); + + st->trails = get_boolean_resource(st->dpy, "trails", "Boolean"); + st->drop_dir = (st->drop ? 1 : -1); + if (st->drop || rise) + st->drop = 1; + + st->default_fg_pixel = get_pixel_resource (st->dpy, + cmap, "foreground", "Foreground"); + st->default_bg_pixel = get_pixel_resource (st->dpy, + cmap, "background", "Background"); + + if (st->simple) { + /* This is easy */ + st->broken = get_boolean_resource(st->dpy, "broken", "Boolean"); + if (st->broken) + if (! st->quiet) + fprintf(stderr, "-broken not available in simple mode\n"); + } else { +#ifndef FANCY_BUBBLES + st->simple = 1; +#else /* FANCY_BUBBLES */ + st->broken = get_boolean_resource(st->dpy, "broken", "Boolean"); +#endif /* FANCY_BUBBLES */ + } +} + +static void * +bubbles_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + XWindowAttributes xgwa; + int i; + + st->dpy = dpy; + st->window = window; + + get_resources(st); + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + +#ifdef DEBUG + printf("sizof(int) on this platform is %d\n", sizeof(int)); + printf("sizof(long) on this platform is %d\n", sizeof(long)); +#endif /* DEBUG */ + + st->screen_width = xgwa.width; + st->screen_height = xgwa.height; + st->screen_depth = xgwa.depth; + + if (st->simple) { + /* These are pretty much plucked out of the air */ + st->bubble_min_radius = (int)(0.006*(double)(MIN(st->screen_width, + st->screen_height))); + st->bubble_max_radius = (int)(0.045*(double)(MIN(st->screen_width, + st->screen_height))); + /* Some trivial values */ + if (st->bubble_min_radius < 1) + st->bubble_min_radius = 1; + if (st->bubble_max_radius <= st->bubble_min_radius) + st->bubble_max_radius = st->bubble_min_radius + 1; + + st->mesh_length = (2 * st->bubble_max_radius) + 3; + + /* store area of each bubble of certain radius as number of 1/10s of + a pixel area. PI is defined in */ + st->bubble_areas = (long *)xmalloc((st->bubble_max_radius + 2) * sizeof(int)); + for (i = 0; i < st->bubble_min_radius; i++) + st->bubble_areas[i] = 0; + for (i = st->bubble_min_radius; i <= (st->bubble_max_radius+1); i++) + st->bubble_areas[i] = calc_bubble_area(st, i); + + /* Now populate the droppage values */ + st->bubble_droppages = (int *)xmalloc((st->bubble_max_radius + 2) * sizeof(int)); + for (i = 0; i < st->bubble_min_radius; i++) + st->bubble_droppages[i] = 0; + for (i = st->bubble_min_radius; i <= (st->bubble_max_radius+1); i++) + st->bubble_droppages[i] = MAX_DROPPAGE * (i - st->bubble_min_radius) / (st->bubble_max_radius - st->bubble_min_radius); + + st->mesh_length = (2 * st->bubble_max_radius) + 3; + } else { +#ifndef FANCY_BUBBLES + fprintf(stderr, + "Bug: simple mode code not set but FANCY_BUBBLES not defined\n"); + exit(1); +#else /* FANCY_BUBBLES */ + /* Make sure all #ifdef sort of things have been taken care of in + get_resources(). */ + default_to_pixmaps(st); + + /* Set mesh length */ + st->mesh_length = (2 * st->step_pixmaps[st->num_bubble_pixmaps-1]->radius) + 3; +#endif /* FANCY_BUBBLES */ + + /* Am I missing something in here??? */ + } + + st->mesh_width = (st->screen_width / st->mesh_length) + 1; + st->mesh_height = (st->screen_height / st->mesh_length) + 1; + st->mesh_cells = st->mesh_width * st->mesh_height; + init_mesh(st); + + calculate_adjacent_list(st); + + adjust_areas(st); + + /* Graphics contexts for simple mode */ + if (st->simple) { + gcv.foreground = st->default_fg_pixel; + st->draw_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + gcv.foreground = st->default_bg_pixel; + st->erase_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + } + + XClearWindow (st->dpy, st->window); + +# ifndef FANCY_BUBBLES + st->simple = True; +# endif + + return st; +} + +static unsigned long +bubbles_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int i; + for (i = 0; i < 5; i++) + { + Bubble *tmp = new_bubble(st); + add_to_mesh(st, tmp); + insert_new_bubble(st, tmp); + } + return st->delay; +} + + +static void +bubbles_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +static Bool +bubbles_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +bubbles_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + +XSCREENSAVER_MODULE ("Bubbles", bubbles) diff --git a/hacks/bubbles.h b/hacks/bubbles.h new file mode 100644 index 0000000..24872e3 --- /dev/null +++ b/hacks/bubbles.h @@ -0,0 +1,208 @@ +/* bubbles.h - definitions for bubbles screensaver */ + +/* $Id: bubbles.h,v 1.6 2006/02/25 20:11:57 jwz Exp $ */ + +#ifndef _BUBBLES_H_ +#define _BUBBLES_H_ + +#ifdef HAVE_JWXYZ +# include "jwxyz.h" +#else +# include +#endif + +/*************************************************************************** + * Options you might like to change to affect the program's behaviour * + ***************************************************************************/ + +/* + * Uncommenting the following will enable support for reading bubbles from + * files (using the -file and -directory options to bubbles). This is + * disabled by default since such operations are inherently non-portable + * and we want the program to compile on as many systems as possible. + * + * If you uncomment this and you figure out how to get it working, please + * let me (J.Macnicol@student.anu.edu.au) know. Diffs against the standard + * distribution would be appreciated. Possible sources of problems are + * dirent and possibly the use of tmpnam(). + */ + +/* #define BUBBLES_IO */ + +/* + * The following only makes sense if BUBBLES_IO above is defined. + * + * Uncomment the following if you always want to use the -file or + * -directory options on the command line and never to use a default bubble + * compiled into the program. This way you would save memory and disk space + * since if you do use -file or -directory only one bubble will be loaded + * into memory at any one time (and remember the default bubble is really + * uncompressed, unlike bubbles in files which can be compressed). This + * is disabled by default only so people running the program for the first + * time with no knowldege of the command line options don't get error + * messages ;) + * + * NOTE: You will still need to have a bubbles_default.c file, else the + * build sequence will fail. Well constructed bubbles_default.c files + * have #ifdef's which simply exclude everything else in the file at + * compile time. The bubblestodefault script does this. + */ + +/* #define NO_DEFAULT_BUBBLE */ + +/* + * This turns on any debugging messages and sanity checks. Hopefully you + * won't need this :) It slows things down a bit, too. + * + * NOTE: If you uncomment this you will get some messages about unused + * functions when you compile. You can ignore these - they refer to + * convenient checking routines which simply aren't called but are left + * in case someone wants to use them. + */ + +/* #define DEBUG */ + +/*************************************************************************** + * Things you might need to change to get things working right * + ***************************************************************************/ + +/* + * Name of the gzip binary. You shouldn't need to change this unless it's + * not in your PATH when the program is run, in which case you will need to + * substitute the full path here. Keep the double quotes else things won't + * compile! + */ + +#define GZIP "gzip" + +/* + * Likewise for the Bourne shell. + */ + +#define BOURNESH "sh" + +/* + * The name of the directory entry structure is different under Linux + * (under which this code is being developed) than other systems. The case + * alternate form here is that given in Kernighan & Ritchie's C book (which + * must be authoratitive, no?) + * + * 04/07/96 : People will have to hack this to get it working on some + * systems. I believe it doesn't work on SGI, for example. + */ + +#ifdef _POSIX_SOURCE +#define STRUCT_DIRENT struct dirent +#else +#define STRUCT_DIRENT Dirent +#endif + +/* + * The naming of fields in struct dirent also seems to differ from system to + * system. This may have to be extended to make things truly portable. + * What we want here is the name field from a dirent struct pointed to + * by "dp". + * + * 04/07/96 : See above. This may need to be changed too. + */ + +#ifdef _POSIX_SOURCE +#define DIRENT_NAME dp->d_name +#else +#define DIRENT_NAME dp->name +#endif + +/* I don't know why this isn't defined. */ +#ifdef linux +/* apparently it is defined in recent linuxes. who knows. */ +/*extern char *tempnam(char *, char *);*/ +#endif + +/**************************************************************************** + * Buffer lengths and things you probably won't need to touch * + ****************************************************************************/ + +/* Maximum length of a full path name we can deal with */ +#define PATH_BUF_SIZE 1024 + +/* Size of string passed to shell as command */ +#define COMMAND_BUF_SIZE 2500 + +/* Size increments for read_line() buffers */ +#define READ_LINE_BUF_SIZE 24 + +/* Maximum amount to drop a bubble */ +#define MAX_DROPPAGE 20 + +/**************************************************************************** + * End of options * + ****************************************************************************/ + +/* Some machines define M_PI and not PI. If they don't define either, use +own own. Really, the accuracy of this is _not_ very important. */ +#ifndef PI +# define PI M_PI +# ifndef M_PI +# define M_PI 3.1415926535 +# endif +#endif + +/* for delete_bubble_in_mesh() */ +#define DELETE_BUBBLE 0 +#define KEEP_BUBBLE 1 + +/* Status codes for read_line */ +#define LINE_READ 0 +#define EOF_REACHED 1 +#define IO_ERROR 2 + +/* + * Magic number for Bubble struct, in case it's trashed when debugging code + * (which happened to me often.... :( + */ + +#define BUBBLE_MAGIC 5674 + +/* Useful macros */ +#define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) + +/* How we represent bubbles */ +struct bub { + int radius; + int step; /* for rendered bubbles */ + long area; + int x; + int y; + int magic; + int cell_index; + int visible; + struct bub *next; + struct bub *prev; +}; + +typedef struct bub Bubble; + +/* + * How we represent pixmaps of rendered bubbles. Because the range of radii + * available may not be continuous, we call each a step (for the lack of a + * better name...) + */ + +struct bub_step { + int radius; + long area; + int droppage; + Pixmap ball, shape_mask; + GC draw_gc, erase_gc; + struct bub_step *next; +}; + +typedef struct bub_step Bubble_Step; + +extern void init_default_bubbles(void); +extern int num_default_bubbles; +typedef struct { const unsigned char *png; unsigned long size; } bubble_png; +extern bubble_png default_bubbles[]; + +#endif /* _BUBBLES_H_ */ diff --git a/hacks/bubbles.man b/hacks/bubbles.man new file mode 100644 index 0000000..f9b892e --- /dev/null +++ b/hacks/bubbles.man @@ -0,0 +1,140 @@ +.de EX \"Begin example +.ne 5 +.if n .sp 1 +.if t .sp .5 +.nf +.in +.5i +.. +.de EE +.fi +.in -.5i +.if n .sp 1 +.if t .sp .5 +.. +.TH XScreenSaver 1 "14-Dec-95" "X Version 11" +.SH NAME +bubbles - frying pan / soft drink simulation +.SH SYNOPSIS +.B bubbles +[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install] [\-visual \fIvisual\fP] [\-simple] [\-broken] [\-3D] [\-rise|\-drop] [-trails] +[\-fps] +.SH DESCRIPTION +\fIBubbles\fP sprays lots of little random bubbles all over the window which +then grow until they reach their maximum size and go pop. The inspiration +for this was watching little globules of oil on the bottom of a frying pan +and it also looks a little like bubbles in fizzy soft drink. The default +mode uses fancy ray-traced bubbles but there is also a mode which just draws +circles in case the default mode is too taxing on your hardware. +.SH OPTIONS +Depending on how your +.I bubbles +was compiled, it accepts the following options: +.TP 8 +.B \-foreground +Colour of circles if \fI\-simple\fP mode is selected. +.TP 8 +.B \-background +Colour of window background. +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-mono +If on a color display, pretend we're on a monochrome display. +.TP 8 +.B \-install +Install a private colormap for the window. +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-delay microseconds +How much of a delay should be introduced between steps of the animation. +Default 800, or about 800 microsecond. Actually, this is the delay between each +group of 15 new bubbles since such a delay between each step results in a +very slow animation rate. +.TP 8 +.B \-nodelay +Same as \fI\-delay 0\fP. +.TP 8 +.B \-simple +Don't use the default fancy pixmap bubbles. Just draw circles instead. +This may give more bearable performance if your hardware wasn't made for +this sort of thing. +.TP 8 +.B \-broken +Don't hide bubbles when they pop. This was a bug during development +but the results were actually quite attractive. +.TP 8 +.B \-3D +Normally, the simulation is done completely in two dimensions. When a +bubble swallows up another bubble, the areas of each are added to get +the area of the resulting bubble. This option changes the algorithm +to instead add volume (imagining each to be a sphere in 3D space). The +whole thing looks more realistic but I find it attracts attention to +the flickering of each bubble as they are move and are redrawn. Your +mileage may vary. +.TP 8 +.B \-quiet +Don't print messages explaining why one or several command line options +were ignored. This is disabled by default. +.TP 8 +.B \-rise | \-drop +.TP 8 +.B \-trails +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH NOTES +If you find the pace of things too slow, remember that there is a delay +even though you specify no \fI\-delay\fP option. Try using \fI\-nodelay\fP +although beware of the effects of irritation of other users if you're on a +shared system as you bleed their CPU time away. + +Some tools to assist in creation of new bubbles are included in the source +distribution. These can either be loaded with the \fI\-file\fP or +\fI\-directory\fP options (if available) or they can be used in place +of the distributed default bubble (bubble_default.c). +You might like to copy these scripts to a permanent location and +use them. Read bubbles.README. + +Rendered bubbles are not supported on monochrome displays. I'm not +convinced that small bubbles, even dithered properly are going to look +like anything more than a jumble of random dots. +.SH BUGS +There is a delay before something appears on the screen when using +rendered bubbles. The XPM library seems to take a \fBlong\fP time to make +pixmaps out of raw data. This can be irritating on slower systems. + +The movement of the bubbles looks jerky if an incomplete set of bubbles +is used. + +The hide/display algorithm could do with some work to avoid flickering +when \fI\-nodelay\fP is set. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1) +.SH DISTRIBUTION POLICY +This work is Copyright \(co 1995, 1996 by James Macnicol. Permission +to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. No representations are made about the suitability of +this software for any purpose. It is provided "as is" without express +or implied warranty. +.SH AUTHOR +James Macnicol diff --git a/hacks/bumps.c b/hacks/bumps.c new file mode 100644 index 0000000..fa728e6 --- /dev/null +++ b/hacks/bumps.c @@ -0,0 +1,700 @@ +/* -*- mode: C; tab-width: 4 -*- + * Bumps, Copyright (c) 2002, 2006 Shane Smit + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * Module: "bumps.c" + * Tab Size: 4 + * + * Description: + * This is typical bump-mapping. The actual bump map is generated by a screen + * grab. The light source is represented by a spotlight of random color. This + * spotlight randomly traverses the bump map in a sinus pattern. + * + * Essentially, it 3D-izes your desktop, based on color intensity. + * + * Modification History: + * [10/01/1999] - Shane Smit: Creation + * [10/08/1999] - Shane Smit: Port to C. (Ick) + * [03/08/2002] - Shane Smit: New movement code. + * [09/12/2002] - Shane Smit: MIT-SHM XImages. + * Thanks to Kennett Galbraith + * for code optimization. + * [10/09/2016] - Dave Odell: Updated for new xshm.c. + * Y2K compliance. + */ + + +#include +#include +#include +#include "screenhack.h" +#include "xshm.h" + + +/* Defines: */ +/* #define VERBOSE */ +#define RANDOM() ((int) (random() & 0X7FFFFFFFL)) + +typedef unsigned char BOOL; + + +/* Globals: */ + +static const char *bumps_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*color: random", + "*colorcount: 64", + "*delay: 30000", + "*duration: 120", + "*soften: 1", + "*invert: FALSE", +#ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */ + "*visualID: Best", +#endif +#ifdef HAVE_XSHM_EXTENSION + "*useSHM: True", +#endif /* HAVE_XSHM_EXTENSION */ +#ifdef HAVE_MOBILE + "*ignoreRotation: True", + "*rotateImages: True", +#endif + 0 +}; + +static XrmOptionDescRec bumps_options [] = { + { "-color", ".color", XrmoptionSepArg, 0 }, + { "-colorcount", ".colorcount", XrmoptionSepArg, 0 }, + { "-duration", ".duration", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-soften", ".soften", XrmoptionSepArg, 0 }, + { "-invert", ".invert", XrmoptionNoArg, "TRUE" }, +#ifdef HAVE_XSHM_EXTENSION + { "-shm", ".useSHM", XrmoptionNoArg, "True" }, + { "-no-shm", ".useSHM", XrmoptionNoArg, "False" }, +#endif /* HAVE_XSHM_EXTENSION */ + + { 0, 0, 0, 0 } +}; + + +/* This structure handles everything to do with the spotlight, and is designed to be + * a member of TBumps. */ +typedef struct +{ + uint8_t *aLightMap; + uint16_t nFalloffDiameter, nFalloffRadius; + uint16_t nLightDiameter, nLightRadius; + float nAccelX, nAccelY; + float nAccelMax; + float nVelocityX, nVelocityY; + float nVelocityMax; + float nXPos, nYPos; +} SSpotLight; + + +/* The entire program's operation is contained within this structure. */ +typedef struct +{ + /* XWindows specific variables. */ + Display *dpy; + Window Win; + Screen *screen; + Pixmap source; + GC GraphicsContext; + XColor *xColors; + unsigned long *aColors; + XImage *pXImage; + XShmSegmentInfo XShmInfo; + + uint8_t nColorCount; /* Number of colors used. */ + uint8_t bytesPerPixel; + uint16_t iWinWidth, iWinHeight; + uint16_t *aBumpMap; /* The actual bump map. */ + SSpotLight SpotLight; + + int delay; + int duration; + time_t start_time; + + async_load_state *img_loader; +} SBumps; + + +static void SetPalette(Display *, SBumps *, XWindowAttributes * ); +static void InitBumpMap(Display *, SBumps *, XWindowAttributes * ); +static void InitBumpMap_2(Display *, SBumps *); +static void SoftenBumpMap( SBumps * ); + + + + +/* This function pointer will point to the appropriate PutPixel*() function below. */ +static void (*MyPutPixel)( int8_t *, uint32_t ); + +static void PutPixel32( int8_t *pData, uint32_t pixel ) +{ + *(uint32_t *)pData = pixel; +} + +static void PutPixel24( int8_t *pData, uint32_t pixel ) +{ + pData[ 2 ] = ( pixel & 0x00FF0000 ) >> 16; + pData[ 1 ] = ( pixel & 0x0000FF00 ) >> 8; + pData[ 0 ] = ( pixel & 0x000000FF ); +} + +static void PutPixel16( int8_t *pData, uint32_t pixel ) +{ + *(uint16_t *)pData = (uint16_t)pixel; +} + +static void PutPixel8( int8_t *pData, uint32_t pixel ) +{ + *(uint8_t *)pData = (uint8_t)pixel; +} + +/* Creates the light map, which is a circular image... going from black around the edges + * to white in the center. */ +static void CreateSpotLight( SSpotLight *pSpotLight, uint16_t iDiameter, uint16_t nColorCount ) +{ + double nDist; + int16_t iDistX, iDistY; + uint8_t *pLOffset; + + pSpotLight->nFalloffDiameter = iDiameter; + pSpotLight->nFalloffRadius = pSpotLight->nFalloffDiameter / 2; + pSpotLight->nLightDiameter = iDiameter / 2; + pSpotLight->nLightRadius = pSpotLight->nLightDiameter / 2; +#ifdef VERBOSE + printf( "%s: Falloff Diameter: %d\n", progclass, pSpotLight->nFalloffDiameter ); + printf( "%s: Spot Light Diameter: %d\n", progclass, pSpotLight->nLightDiameter ); +#endif + + pSpotLight->aLightMap = malloc( pSpotLight->nLightDiameter * pSpotLight->nLightDiameter * sizeof(uint8_t) ); + + pLOffset = pSpotLight->aLightMap; + for( iDistY=-pSpotLight->nLightRadius; iDistYnLightRadius; ++iDistY ) + { + for( iDistX=-pSpotLight->nLightRadius; iDistXnLightRadius; ++iDistX ) + { + nDist = sqrt( pow( iDistX+0.5F, 2 ) + pow( iDistY+0.5F, 2 ) ); + if( nDist / pSpotLight->nLightRadius <= 1.0f ) + *pLOffset = (uint8_t)(nColorCount - ( ( nDist / pSpotLight->nLightRadius ) * ( nColorCount - 1 ) )); + else + *pLOffset = 0; + + ++pLOffset; + } + } + + /* Initialize movement variables. */ + pSpotLight->nAccelX = 0; + pSpotLight->nAccelY = 0; + pSpotLight->nVelocityX = ( RANDOM() % 2 ) ? pSpotLight->nVelocityMax : -pSpotLight->nVelocityMax; + pSpotLight->nVelocityY = ( RANDOM() % 2 ) ? pSpotLight->nVelocityMax : -pSpotLight->nVelocityMax; +} + + +/* Calculates the position of the spot light on the screen. */ +static void CalcLightPos( SBumps *pBumps ) +{ + SSpotLight *pSpotLight = &pBumps->SpotLight; + float nGravity; + + /* X */ + if( pSpotLight->nXPos < pSpotLight->nFalloffRadius ) nGravity = 1.0f; + else if( pSpotLight->nXPos > pBumps->iWinWidth - pSpotLight->nFalloffRadius ) nGravity = -1.0f; + else nGravity = ( ( RANDOM() % 201 ) / 100.0f ) - 1.0f; + + pSpotLight->nAccelX += nGravity * ( pSpotLight->nAccelMax / 5.0f ); + if( pSpotLight->nAccelX < -pSpotLight->nAccelMax ) pSpotLight->nAccelX = -pSpotLight->nAccelMax; + else if( pSpotLight->nAccelX > pSpotLight->nAccelMax ) pSpotLight->nAccelX = pSpotLight->nAccelMax; + + pSpotLight->nVelocityX += pSpotLight->nAccelX; + if( pSpotLight->nVelocityX < -pSpotLight->nVelocityMax ) pSpotLight->nVelocityX = -pSpotLight->nVelocityMax; + else if( pSpotLight->nVelocityX > pSpotLight->nVelocityMax ) pSpotLight->nVelocityX = pSpotLight->nVelocityMax; + + pSpotLight->nXPos += pSpotLight->nVelocityX; + + /* Y */ + if( pSpotLight->nYPos < pSpotLight->nFalloffRadius ) nGravity = 1.0f; + else if( pSpotLight->nYPos > pBumps->iWinHeight - pSpotLight->nFalloffRadius ) nGravity = -1.0f; + else nGravity = ( ( RANDOM() % 201 ) / 100.0f ) - 1.0f; + + pSpotLight->nAccelY += nGravity * ( pSpotLight->nAccelMax / 5.0f ); + if( pSpotLight->nAccelY < -pSpotLight->nAccelMax ) pSpotLight->nAccelY = -pSpotLight->nAccelMax; + else if( pSpotLight->nAccelY > pSpotLight->nAccelMax ) pSpotLight->nAccelY = pSpotLight->nAccelMax; + + pSpotLight->nVelocityY += pSpotLight->nAccelY; + if( pSpotLight->nVelocityY < -pSpotLight->nVelocityMax ) pSpotLight->nVelocityY = -pSpotLight->nVelocityMax; + else if( pSpotLight->nVelocityY > pSpotLight->nVelocityMax ) pSpotLight->nVelocityY = pSpotLight->nVelocityMax; + + pSpotLight->nYPos += pSpotLight->nVelocityY; +} + + +/* Main initialization function. */ +static void CreateBumps( SBumps *pBumps, Display *dpy, Window NewWin ) +{ + XWindowAttributes XWinAttribs; + XGCValues GCValues; + int32_t nGCFlags; + uint16_t iDiameter; + + /* Make size and velocity a function of window size, so it appears the same at 100x60 as it does in 3200x1200. */ + XGetWindowAttributes( dpy, NewWin, &XWinAttribs ); + pBumps->iWinWidth = XWinAttribs.width; + pBumps->iWinHeight = XWinAttribs.height; + pBumps->SpotLight.nXPos = XWinAttribs.width / 2.0f; + pBumps->SpotLight.nYPos = XWinAttribs.height / 2.0f; + pBumps->SpotLight.nVelocityMax = ( ( XWinAttribs.width < XWinAttribs.height ) ? XWinAttribs.width : XWinAttribs.height ) / 140.0f; + pBumps->SpotLight.nAccelMax = pBumps->SpotLight.nVelocityMax / 10.0f; + pBumps->dpy = dpy; + pBumps->Win = NewWin; + pBumps->screen = XWinAttribs.screen; + + iDiameter = ( ( pBumps->iWinWidth < pBumps->iWinHeight ) ? pBumps->iWinWidth : pBumps->iWinHeight ) / 2; + + /* jwz: sometimes we get tearing if this lands on the wrong bounaary; + constraining it to be a multiple of 8 seems to fix it. */ + iDiameter = ((iDiameter+7)/8)*8; + + pBumps->pXImage = create_xshm_image( pBumps->dpy, XWinAttribs.visual, XWinAttribs.depth, + ZPixmap, &pBumps->XShmInfo, iDiameter, iDiameter ); + + /* For speed, access the XImage data directly using my own PutPixel routine. */ + switch( pBumps->pXImage->bits_per_pixel ) + { + case 32: + pBumps->bytesPerPixel = 4; + MyPutPixel = PutPixel32; + break; + + case 24: + pBumps->bytesPerPixel = 3; + MyPutPixel = PutPixel24; + break; + + case 16: + pBumps->bytesPerPixel = 2; + MyPutPixel = PutPixel16; + break; + + case 8: + pBumps->bytesPerPixel = 1; + MyPutPixel = PutPixel8; + break; + + default: + fprintf( stderr, "%s: Unknown XImage depth.", progname ); + destroy_xshm_image( pBumps->dpy, pBumps->pXImage, &pBumps->XShmInfo ); + exit( 1 ); + } + + GCValues.function = GXcopy; + GCValues.subwindow_mode = IncludeInferiors; + nGCFlags = GCFunction; + if( use_subwindow_mode_p( XWinAttribs.screen, pBumps->Win ) ) /* See grabscreen.c */ + nGCFlags |= GCSubwindowMode; + pBumps->GraphicsContext = XCreateGC( pBumps->dpy, pBumps->Win, nGCFlags, &GCValues ); + + SetPalette(dpy, pBumps, &XWinAttribs ); + CreateSpotLight( &pBumps->SpotLight, iDiameter, pBumps->nColorCount ); + InitBumpMap(dpy, pBumps, &XWinAttribs ); +} + + +/* Creates a specialized phong shade palette. */ +static void SetPalette(Display *dpy, SBumps *pBumps, XWindowAttributes *pXWinAttribs ) +{ + XColor BaseColor; + XColor Color; + char *sColor; /* Spotlight Color */ + int16_t iColor; + + sColor = get_string_resource(dpy, "color", "Color" ); + + BaseColor.red = RANDOM() % 0xFFFF; + BaseColor.green = RANDOM() % 0xFFFF; + BaseColor.blue = RANDOM() % 0xFFFF; + + /* Make one color full intesity to avoid dark spotlights. */ + switch( RANDOM() % 3 ) + { + case 0: BaseColor.red = 0xFFFF; break; + case 1: BaseColor.green = 0xFFFF; break; + case 2: BaseColor.blue = 0xFFFF; break; + } + + if( strcasecmp( sColor, "random" ) && !XParseColor( pBumps->dpy, pXWinAttribs->colormap, sColor, &BaseColor ) ) + fprintf( stderr, "%s: color %s not found in database. Choosing random...\n", progname, sColor ); + +#ifdef VERBOSE + printf( "%s: Spotlight color is <%d,%d,%d> RGB.\n", progclass, BaseColor.red, BaseColor.green, BaseColor.blue ); +#endif /* VERBOSE */ + + pBumps->nColorCount = get_integer_resource(dpy, "colorcount", "Integer" ); + if( pBumps->nColorCount < 2 ) pBumps->nColorCount = 2; + if( pBumps->nColorCount > 128 ) pBumps->nColorCount = 128; + + pBumps->aColors = malloc( pBumps->nColorCount * sizeof(unsigned long) ); + + /* Creates a phong shade: / BaseColor \ Index/ColorCount + * PhongShade = | ------------ | Index + ( 65535 - BaseColor )^ + * \ ColorCount / */ + pBumps->nColorCount--; + for( iColor=0; iColor<=pBumps->nColorCount; iColor++ ) + { + Color.red = (uint16_t)( ( ( BaseColor.red / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - BaseColor.red, iColor/(double)pBumps->nColorCount ) ); + Color.green = (uint16_t)( ( ( BaseColor.green / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - BaseColor.green, iColor/(double)pBumps->nColorCount ) ); + Color.blue = (uint16_t)( ( ( BaseColor.blue / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - BaseColor.blue, iColor/(double)pBumps->nColorCount ) ); + + if( !XAllocColor( pBumps->dpy, pXWinAttribs->colormap, &Color ) ) + { + XFreeColors( pBumps->dpy, pXWinAttribs->colormap, pBumps->aColors, iColor, 0 ); + free( pBumps->aColors ); + pBumps->aColors = malloc( pBumps->nColorCount * sizeof(unsigned long) ); + pBumps->nColorCount--; + iColor = -1; + } + else + pBumps->aColors[ iColor ] = Color.pixel; + } + pBumps->nColorCount++; + +#ifdef VERBOSE + printf( "%s: Allocated %d colors.\n", progclass, pBumps->nColorCount ); +#endif /* VERBOSE */ + + XSetWindowBackground( pBumps->dpy, pBumps->Win, pBumps->aColors[ 0 ] ); +} + + +/* Grabs the current contents of the window to use an intensity-based bump map. */ +static void InitBumpMap(Display *dpy, SBumps *pBumps, XWindowAttributes *pXWinAttribs ) +{ + pBumps->xColors = (XColor*)malloc( pBumps->iWinWidth * sizeof(XColor) ); + + if (pBumps->source) abort(); + pBumps->source = XCreatePixmap(pBumps->dpy, pBumps->Win, + pXWinAttribs->width, pXWinAttribs->height, + pXWinAttribs->depth); + pBumps->img_loader = load_image_async_simple (0, pXWinAttribs->screen, + pBumps->Win, pBumps->source, 0, 0); +} + +static void InitBumpMap_2(Display *dpy, SBumps *pBumps) +{ + XImage *pScreenImage; + XColor *pColor; + uint8_t nSoften; + uint16_t iWidth, iHeight; + uint32_t nAverager; + uint16_t *pBump; + uint16_t maxHeight; + double softenMultiplier = 1.0f; + BOOL bInvert = (BOOL)get_boolean_resource(dpy, "invert", "Boolean" ); + XWindowAttributes XWinAttribs; + XGetWindowAttributes( pBumps->dpy, pBumps->Win, &XWinAttribs ); + + pBumps->start_time = time ((time_t *) 0); + + pScreenImage = XGetImage( pBumps->dpy, pBumps->source, 0, 0, + pBumps->iWinWidth, pBumps->iWinHeight, + ~0L, ZPixmap ); +/* XFreePixmap (pBumps->dpy, pBumps->source); + pBumps->source = 0;*/ + + XSetWindowBackground( pBumps->dpy, pBumps->Win, pBumps->aColors[ 0 ] ); + XClearWindow (pBumps->dpy, pBumps->Win); + XSync (pBumps->dpy, 0); + + pBumps->aBumpMap = malloc( pBumps->iWinWidth * pBumps->iWinHeight * sizeof(uint16_t) ); + + nSoften = get_integer_resource(dpy, "soften", "Integer" ); + while( nSoften-- ) + softenMultiplier *= 1.0f + ( 1.0f / 3.0f ); /* Softening takes the max height down, so scale up to compensate. */ + maxHeight = pBumps->SpotLight.nLightRadius * softenMultiplier; + nAverager = maxHeight ? ( 3 * 0xFFFF ) / maxHeight : 0; + + pBump = pBumps->aBumpMap; + if( bInvert ) /* Funny, it's actually the 'else' that inverts the bump map... */ + { + for( iHeight=0; iHeightiWinHeight; iHeight++ ) + { + pColor = pBumps->xColors; + for( iWidth=0; iWidthiWinWidth; iWidth++ ) + (pColor++)->pixel = XGetPixel( pScreenImage, iWidth, iHeight ); + + XQueryColors( pBumps->dpy, XWinAttribs.colormap, pBumps->xColors, pBumps->iWinWidth ); + + pColor = pBumps->xColors; + for( iWidth=pBumps->iWinWidth; iWidth; --iWidth, ++pColor, ++pBump ) + *pBump = ( nAverager ? ( pColor->red + pColor->green + pColor->blue ) / nAverager : 0 ); + } + } + else + { + for( iHeight=0; iHeightiWinHeight; iHeight++ ) + { + pColor = pBumps->xColors; + for( iWidth=0; iWidthiWinWidth; iWidth++ ) + (pColor++)->pixel = XGetPixel( pScreenImage, iWidth, iHeight ); + + XQueryColors( pBumps->dpy, XWinAttribs.colormap, pBumps->xColors, pBumps->iWinWidth ); + + pColor = pBumps->xColors; + for( iWidth=pBumps->iWinWidth; iWidth; --iWidth, ++pColor, ++pBump ) + *pBump = ( maxHeight - ( nAverager ? ( pColor->red + pColor->green + pColor->blue ) / nAverager : 0 ) ); + } + } + + XDestroyImage( pScreenImage ); + + nSoften = get_integer_resource(dpy, "soften", "Integer" ); +#ifdef VERBOSE + if( nSoften ) printf( "%s: Softening Bump Map %d time(s)...\n", progclass, nSoften ); +#endif + while( nSoften-- ) + SoftenBumpMap( pBumps ); + +/* free( pBumps->xColors ); + pBumps->xColors = 0;*/ +} + +/* Soften the bump map. This is to avoid pixelated-looking ridges. + * |-----|-----|-----| + * | 0% |12.5%| 0% | The adjacent pixels are averaged together + * |-----|-----|-----| first. Then than value is averaged with + * |12.5%| 50% |12.5%| the pixel is question. This essentially weights + * |-----|-----|-----| each pixel as shown on the left. + * | 0% |12.5%| 0% | + * |-----|-----|-----| + */ +static void SoftenBumpMap( SBumps *pBumps ) +{ + uint16_t *pOffset, *pTOffset; + uint32_t nHeight; + uint32_t iWidth, iHeight; + uint16_t *aTempBuffer = malloc( pBumps->iWinWidth * pBumps->iWinHeight * sizeof(uint16_t) ); + + pOffset = pBumps->aBumpMap; + pTOffset = aTempBuffer; + for( iHeight=pBumps->iWinHeight; iHeight; --iHeight ) + { + for( iWidth=pBumps->iWinWidth; iWidth; --iWidth, ++pOffset, ++pTOffset ) + { + if( iHeight==pBumps->iWinHeight || iHeight==1 || + iWidth==pBumps->iWinWidth || iWidth==1 ) + { + *pTOffset = 0; + continue; + } + + nHeight = pOffset[ -pBumps->iWinWidth ]; + nHeight += pOffset[ 1 ]; + nHeight += pOffset[ pBumps->iWinWidth ]; + nHeight += pOffset[ -1 ]; + nHeight >>= 2; + nHeight += pOffset[ 0 ]; + nHeight >>= 1; + *pTOffset = nHeight; + } + } + + memcpy( pBumps->aBumpMap, aTempBuffer, pBumps->iWinWidth * pBumps->iWinHeight * sizeof(uint16_t) ); + free( aTempBuffer ); +} + + +/* This is where we slap down some pixels... */ +static void Execute( SBumps *pBumps ) +{ + int32_t nLightXPos, nLightYPos; + int32_t iScreenX, iScreenY; + int32_t iLightX, iLightY; + uint16_t *pBOffset; + int8_t *pDOffset; + int32_t nX, nY; + uint16_t nColor; + int32_t nLightOffsetFar = pBumps->SpotLight.nFalloffDiameter - pBumps->SpotLight.nLightRadius; + + CalcLightPos( pBumps ); + + /* Offset to upper left hand corner. */ + nLightXPos = pBumps->SpotLight.nXPos - pBumps->SpotLight.nFalloffRadius; + nLightYPos = pBumps->SpotLight.nYPos - pBumps->SpotLight.nFalloffRadius; + + for( iScreenY=nLightYPos, iLightY=-pBumps->SpotLight.nLightRadius; iLightY= pBumps->iWinHeight ) break; + + /* warning: pointer targets in assignment differ in signedness + Should pDOffset be a int8? I can't tell. -jwz, 22-Jul-2003 */ + pDOffset = (int8_t *) &pBumps->pXImage->data[ (iLightY+pBumps->SpotLight.nLightRadius) * pBumps->pXImage->bytes_per_line ]; + pBOffset = pBumps->aBumpMap + ( iScreenY * pBumps->iWinWidth ) + nLightXPos; + for( iScreenX=nLightXPos, iLightX=-pBumps->SpotLight.nLightRadius; iLightXbytesPerPixel ) + { + if( iScreenX < 0 ) continue; + else if( iScreenX >= pBumps->iWinWidth ) break; + else if( iScreenY == 0 || iScreenY >= pBumps->iWinHeight-2 || + iScreenX == 0 || iScreenX >= pBumps->iWinWidth-2 ) + { + MyPutPixel( pDOffset, pBumps->aColors[ 0 ] ); + continue; + } + + /* That's right folks, all the magic of bump mapping occurs in these two lines. (kinda disappointing, isn't it?) */ + nX = ( pBOffset[ 1 ] - pBOffset[ 0 ] ) + iLightX; + nY = ( pBOffset[ pBumps->iWinWidth ] - pBOffset[ 0 ] ) + iLightY; + + if( nX<0 || nX>=pBumps->SpotLight.nLightDiameter + || nY<0 || nY>=pBumps->SpotLight.nLightDiameter ) + { + MyPutPixel( pDOffset, pBumps->aColors[ 0 ] ); + continue; + } + + nColor = pBumps->SpotLight.aLightMap[ ( nY * pBumps->SpotLight.nLightDiameter ) + nX ]; + MyPutPixel( pDOffset, pBumps->aColors[ nColor ] ); + } + } + + /* Allow the spotlight to go *slightly* off the screen by clipping the XImage. */ + iLightX = iLightY = 0; /* Use these for XImages X and Y now. */ + nX = nY = pBumps->SpotLight.nFalloffDiameter; /* Use these for XImage width and height now. */ + if( nLightXPos < 0 ) + { + iLightX = -nLightXPos; + nX -= iLightX; + nLightXPos = 0; + } + else if( nLightXPos + nX >= pBumps->iWinWidth ) + { + nX -= ( nLightXPos + nX ) - pBumps->iWinWidth; + } + + if( nLightYPos < 0 ) + { + iLightY = -nLightYPos; + nY -= iLightY; + nLightYPos = 0; + } + else if( nLightYPos + nY >= pBumps->iWinHeight ) + { + nY -= ( nLightYPos + nY ) - pBumps->iWinHeight; + } + + put_xshm_image( pBumps->dpy, pBumps->Win, pBumps->GraphicsContext, pBumps->pXImage, iLightX, iLightY, nLightXPos, nLightYPos, + nX, nY, &pBumps->XShmInfo); +} + + +static void DestroySpotLight( SSpotLight *pSpotLight ) { free( pSpotLight->aLightMap ); } + +/* Clean up */ +static void DestroyBumps( SBumps *pBumps ) +{ + DestroySpotLight( &pBumps->SpotLight ); + free( pBumps->aColors ); + free( pBumps->aBumpMap ); + destroy_xshm_image( pBumps->dpy, pBumps->pXImage, &pBumps->XShmInfo ); +} + + +/* All messages to the screensaver are processed here. */ +static void * +bumps_init (Display *dpy, Window Win) +{ + SBumps *Bumps = (SBumps *) calloc (1, sizeof(SBumps)); + +#ifdef VERBOSE + time_t Time = time( NULL ); + uint16_t iFrame = 0; +#endif /* VERBOSE */ + + CreateBumps( Bumps, dpy, Win ); + Bumps->delay = get_integer_resource(dpy, "delay", "Integer" ); + Bumps->duration = get_integer_resource (dpy, "duration", "Seconds"); + if (Bumps->delay < 0) Bumps->delay = 0; + if (Bumps->duration < 1) Bumps->duration = 1; + Bumps->start_time = time ((time_t *) 0); + return Bumps; +} + +static unsigned long +bumps_draw (Display *dpy, Window window, void *closure) +{ + SBumps *Bumps = (SBumps *) closure; + + if (Bumps->img_loader) /* still loading */ + { + Bumps->img_loader = load_image_async_simple (Bumps->img_loader, 0, 0, 0, 0, 0); + if (! Bumps->img_loader) /* just finished */ + InitBumpMap_2(dpy, Bumps); + return Bumps->delay; + } + + if (!Bumps->img_loader && + Bumps->start_time + Bumps->duration < time ((time_t *) 0)) { + Bumps->img_loader = load_image_async_simple (0, Bumps->screen, + Bumps->Win, Bumps->source, + 0, 0); + } + + Execute( Bumps ); + +#ifdef VERBOSE + iFrame++; + if( Time - time( NULL ) ) + { + printf( "FPS: %d\n", iFrame ); + Time = time( NULL ); + iFrame = 0; + } +#endif /* VERBOSE */ + + return Bumps->delay; +} + +static void +bumps_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +static Bool +bumps_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + SBumps *Bumps = (SBumps *) closure; + if (screenhack_event_helper (dpy, window, event)) + { + Bumps->start_time = 0; + return True; + } + + return False; +} + +static void +bumps_free (Display *dpy, Window window, void *closure) +{ + SBumps *Bumps = (SBumps *) closure; + DestroyBumps( Bumps ); +} + + +XSCREENSAVER_MODULE ("Bumps", bumps) + +/* vim: ts=4 + */ diff --git a/hacks/bumps.man b/hacks/bumps.man new file mode 100644 index 0000000..8e47184 --- /dev/null +++ b/hacks/bumps.man @@ -0,0 +1,80 @@ +.TH XScreenSaver 1 "05-Apr-1999" "X Version 11" +.SH NAME +bumps - move distorting spotlight around desktop +.SH SYNOPSIS +.B bumps +[\-display \fIhost:display.screen\fP] +[\-foreground \fIcolor\fP] +[\-background \fIcolor\fP] +[\-window] +[\-root] +[\-mono] +[\-install] +[\-visual \fIvisual\fP] +[\-delay \fIusecs\fP] +[\-duration \fIsecs\fP] +[\-fps] +.SH DESCRIPTION +The \fIbumps\fP program takes an image and exposes small, distorted +sections of it as if through an odd wandering spotlight beam. + +The image that it manipulates will be grabbed from the portion of +the screen underlying the window, or from the system's video input, +or from a random file on disk, as indicated by +the \fIgrabDesktopImages\fP, \fIgrabVideoFrames\fP, +and \fIchooseRandomImages\fP options in the \fI~/.xscreensaver\fP +file; see +.BR xscreensaver-demo (1) +for more details. +.SH OPTIONS +.I bumps +accepts the following options: +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-mono +If on a color display, pretend we're on a monochrome display. +.TP 8 +.B \-install +Install a private colormap for the window. +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-delay \fImicroseconds\fP +Slow it down. +.TP 8 +.B \-duration \fIseconds\fP +How long to run before loading a new image. Default 120 seconds. +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1), +.BR xscreensaver\-demo (1), +.BR xscreensaver\-getimage (1) +.SH COPYRIGHT +Copyright \(co 1999 by Shane Smit. Permission to use, copy, modify, +distribute, and sell this software and its documentation for any purpose is +hereby granted without fee, provided that the above copyright notice appear +in all copies and that both that copyright notice and this permission notice +appear in supporting documentation. No representations are made about the +suitability of this software for any purpose. It is provided "as is" without +express or implied warranty. +.SH CREDITS +Shane Smit , 8-Oct-1999. diff --git a/hacks/ccurve.c b/hacks/ccurve.c new file mode 100644 index 0000000..23b53e8 --- /dev/null +++ b/hacks/ccurve.c @@ -0,0 +1,866 @@ +/* ccurve, Copyright (c) 1998, 1999 + * Rick Campbell + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + */ + +/* Draw self-similar linear fractals including the classic ``C Curve'' + * + * 16 Aug 1999 Rick Campbell + * Eliminated sub-windows-with-backing-store-double-buffering crap in + * favor of drawing the new image in a pixmap and then splatting that on + * the window. + * + * 19 Dec 1998 Rick Campbell + * Original version. + */ + +#include +#include +#include +#include +#include + +#include "screenhack.h" +#include "colors.h" +#include "erase.h" + +#define SQRT3 (1.73205080756887729353) +#define MAXIMUM_COLOR_COUNT (256) +#define EPSILON (1e-5) + +typedef struct Position_struct +{ + double x; + double y; +} +Position; + +typedef struct Segment_struct +{ + double angle; + double length; +} +Segment; + +struct state { + Display *dpy; + Window window; + + int color_count; + int color_index; + Colormap color_map; + XColor colors [MAXIMUM_COLOR_COUNT]; + int line_count; + int maximum_lines; + double plot_maximum_x; + double plot_maximum_y; + double plot_minimum_x; + double plot_minimum_y; + int total_lines; + + unsigned long int background; + GC context; + Pixmap pixmap; + int width; + int height; + float delay; + float delay2; + + int draw_index; + + int draw_iterations; + double draw_maximum_x; + double draw_maximum_y; + double draw_minimum_x; + double draw_minimum_y; + int draw_segment_count; + Segment* draw_segments; + double draw_x1; + double draw_y1; + double draw_x2; + double draw_y2; +}; + + + + +/* normalize alters the sequence to go from (0,0) to (1,0) */ +static void +normalized_plot (int segment_count, + Segment* segments, + Position* points) +{ + double angle = 0.0; + double cosine = 0.0; + int index = 0; + double length = 0.0; + double sine = 0.0; + double x = 0.0; + double y = 0.0; + + for (index = 0; index < segment_count; ++index) + { + Segment* segment = segments + index; + double length = segment->length; + double angle = segment->angle; + + x += length * cos (angle); + y += length * sin (angle); + points [index].x = x; + points [index].y = y; + } + angle = -(atan2 (y, x)); + cosine = cos (angle); + sine = sin (angle); + length = sqrt ((x * x) + (y * y)); + /* rotate and scale */ + for (index = 0; index < segment_count; ++index) + { + double temp_x = points [index].x; + double temp_y = points [index].y; + points [index].x = ((temp_x * cosine) + (temp_y * (-sine))) / length; + points [index].y = ((temp_x * sine) + (temp_y * cosine)) / length; + } +} + +static void +copy_points (int segment_count, + Position* source, + Position* target) +{ + int index = 0; + + for (index = 0; index < segment_count; ++index) + { + target [index] = source [index]; + } +} + +static void +realign (double x1, + double y1, + double x2, + double y2, + int segment_count, + Position* points) +{ + double angle = 0.0; + double cosine = 0.0; + double delta_x = 0.0; + double delta_y = 0.0; + int index = 0; + double length = 0.0; + double sine = 0.0; + + delta_x = x2 - x1; + delta_y = y2 - y1; + angle = atan2 (delta_y, delta_x); + cosine = cos (angle); + sine = sin (angle); + length = sqrt ((delta_x * delta_x) + (delta_y * delta_y)); + /* rotate, scale, then shift */ + for (index = 0; index < segment_count; ++index) + { + double temp_x = points [index].x; + double temp_y = points [index].y; + points [index].x + = (length * ((temp_x * cosine) + (temp_y * (-sine)))) + x1; + points [index].y + = (length * ((temp_x * sine) + (temp_y * cosine))) + y1; + } +} + +static Bool +self_similar_normalized (struct state *st, + int iterations, + double x1, + double y1, + double x2, + double y2, + double maximum_x, + double maximum_y, + double minimum_x, + double minimum_y, + int segment_count, + Position* points) +{ + if (iterations == 0) + { + double delta_x = maximum_x - minimum_x; + double delta_y = maximum_y - minimum_y; + st->color_index = (int)(((double)(st->line_count * st->color_count)) + / ((double)st->total_lines)); + ++st->line_count; + XSetForeground (st->dpy, st->context, st->colors [st->color_index].pixel); + if (st->plot_maximum_x < x1) st->plot_maximum_x = x1; + if (st->plot_maximum_x < x2) st->plot_maximum_x = x2; + if (st->plot_maximum_y < y1) st->plot_maximum_y = y1; + if (st->plot_maximum_y < y2) st->plot_maximum_y = y2; + if (st->plot_minimum_x > x1) st->plot_minimum_x = x1; + if (st->plot_minimum_x > x2) st->plot_minimum_x = x2; + if (st->plot_minimum_y > y1) st->plot_minimum_y = y1; + if (st->plot_minimum_y > y2) st->plot_minimum_y = y2; + XDrawLine (st->dpy, st->pixmap, st->context, + (int)(((x1 - minimum_x) / delta_x) * st->width), + (int)(((maximum_y - y1) / delta_y) * st->height), + (int)(((x2 - minimum_x) / delta_x) * st->width), + (int)(((maximum_y - y2) / delta_y) * st->height)); + } + else + { + int index = 0; + double next_x = 0.0; + double next_y = 0.0; + Position* replacement = (Position*)NULL; + double x = 0.0; + double y = 0.0; + + replacement = (Position*)(malloc (segment_count * sizeof (Segment))); + copy_points (segment_count, points, replacement); + assert (fabs ((replacement [segment_count - 1].x) - 1.0) < EPSILON); + assert (fabs (replacement [segment_count - 1].y) < EPSILON); + realign (x1, y1, x2, y2, segment_count, replacement); + /* jwz: I don't understand what these assertions are supposed to + be detecting, but let's just bail on the fractal instead of + crashing. */ +/* assert (fabs (x2 - (replacement [segment_count - 1].x)) < EPSILON); + assert (fabs (y2 - (replacement [segment_count - 1].y)) < EPSILON);*/ + if (fabs (x2 - (replacement [segment_count - 1].x)) >= EPSILON || + fabs (y2 - (replacement [segment_count - 1].y)) >= EPSILON) { + free (replacement); + return False; + } + x = x1; + y = y1; + for (index = 0; index < segment_count; ++index) + { + next_x = replacement [index].x; + next_y = replacement [index].y; + if (!self_similar_normalized (st, + iterations - 1, x, y, next_x, next_y, + maximum_x, maximum_y, + minimum_x, minimum_y, + segment_count, points)) { + free(replacement); + return False; + } + x = next_x; + y = next_y; + } + free(replacement); + } + return True; +} + +static void +self_similar (struct state *st, + Pixmap pixmap, + GC context, + int width, + int height, + int iterations, + double x1, + double y1, + double x2, + double y2, + double maximum_x, + double maximum_y, + double minimum_x, + double minimum_y, + int segment_count, + Segment* segments) +{ + Position* points = (Position*)NULL; + + points = (Position*)(malloc (segment_count * sizeof (Position))); + normalized_plot (segment_count, segments, points); + assert (fabs ((points [segment_count - 1].x) - 1.0) < EPSILON); + assert (fabs (points [segment_count - 1].y) < EPSILON); + self_similar_normalized (st, iterations, + x1, y1, x2, y2, + maximum_x, maximum_y, + minimum_x, minimum_y, + segment_count, points); + free((void*)points); +} + +static +double +random_double (double base, + double limit, + double epsilon) +{ + double range = 0.0; + unsigned int steps = 0; + + assert (base < limit); + assert (epsilon > 0.0); + range = limit - base; + steps = (unsigned int)(floor (range / epsilon)); + return base + ((random () % steps) * epsilon); +} + +static void +select_2_pattern (Segment* segments) +{ + if ((random () % 2) == 0) + { + if ((random () % 2) == 0) + { + segments [0].angle = -M_PI_4; + segments [0].length = M_SQRT2; + segments [1].angle = M_PI_4; + segments [1].length = M_SQRT2; + } + else + { + segments [0].angle = M_PI_4; + segments [0].length = M_SQRT2; + segments [1].angle = -M_PI_4; + segments [1].length = M_SQRT2; + } + } + else + { + segments [0].angle + = random_double (M_PI / 6.0, M_PI / 3.0, M_PI / 180.0); + segments [0].length = random_double (0.25, 0.67, 0.001); + if ((random () % 2) == 0) + { + segments [1].angle = -(segments [0].angle); + segments [1].length = segments [0].length; + } + else + { + segments [1].angle = random_double ((-M_PI) / 3.0, + (-M_PI) / 6.0, + M_PI / 180.0); + segments [1].length = random_double (0.25, 0.67, 0.001); + } + } +} + +static void +select_3_pattern (Segment* segments) +{ + switch (random () % 5) + { + case 0: + if ((random () % 2) == 0) + { + segments [0].angle = M_PI_4; + segments [0].length = M_SQRT2 / 4.0; + segments [1].angle = -M_PI_4; + segments [1].length = M_SQRT2 / 2.0; + segments [2].angle = M_PI_4; + segments [2].length = M_SQRT2 / 4.0; + } + else + { + segments [0].angle = -M_PI_4; + segments [0].length = M_SQRT2 / 4.0; + segments [1].angle = M_PI_4; + segments [1].length = M_SQRT2 / 2.0; + segments [2].angle = -M_PI_4; + segments [2].length = M_SQRT2 / 4.0; + } + break; + case 1: + if ((random () % 2) == 0) + { + segments [0].angle = M_PI / 6.0; + segments [0].length = 1.0; + segments [1].angle = -M_PI_2; + segments [1].length = 1.0; + segments [2].angle = M_PI / 6.0; + segments [2].length = 1.0; + } + else + { + segments [0].angle = -M_PI / 6.0; + segments [0].length = 1.0; + segments [1].angle = M_PI_2; + segments [1].length = 1.0; + segments [2].angle = -M_PI / 6.0; + segments [2].length = 1.0; + } + break; + case 2: + case 3: + case 4: + segments [0].angle + = random_double (M_PI / 6.0, M_PI / 3.0, M_PI / 180.0); + segments [0].length = random_double (0.25, 0.67, 0.001); + segments [1].angle + = random_double (-M_PI / 3.0, -M_PI / 6.0, M_PI / 180.0); + segments [1].length = random_double (0.25, 0.67, 0.001); + if ((random () % 3) == 0) + { + if ((random () % 2) == 0) + { + segments [2].angle = segments [0].angle; + } + else + { + segments [2].angle = -(segments [0].angle); + } + segments [2].length = segments [0].length; + } + else + { + segments [2].angle + = random_double (-M_PI / 3.0, -M_PI / 6.0, M_PI / 180.0); + segments [2].length = random_double (0.25, 0.67, 0.001); + } + break; + } +} + +static void +select_4_pattern (Segment* segments) +{ + switch (random () % 9) + { + case 0: + if ((random () % 2) == 0) + { + double length = random_double (0.25, 0.50, 0.001); + + segments [0].angle = 0.0; + segments [0].length = 0.5; + segments [1].angle = M_PI_2; + segments [1].length = length; + segments [2].angle = -M_PI_2; + segments [2].length = length; + segments [3].angle = 0.0; + segments [3].length = 0.5; + } + else + { + double length = random_double (0.25, 0.50, 0.001); + + segments [0].angle = 0.0; + segments [0].length = 0.5; + segments [1].angle = -M_PI_2; + segments [1].length = length; + segments [2].angle = M_PI_2; + segments [2].length = length; + segments [3].angle = 0.0; + segments [3].length = 0.5; + } + break; + case 1: + if ((random () % 2) == 0) + { + segments [0].angle = 0.0; + segments [0].length = 0.5; + segments [1].angle = M_PI_2; + segments [1].length = 0.45; + segments [2].angle = -M_PI_2; + segments [2].length = 0.45; + segments [3].angle = 0.0; + segments [3].length = 0.5; + } + else + { + segments [0].angle = 0.0; + segments [0].length = 0.5; + segments [1].angle = -M_PI_2; + segments [1].length = 0.45; + segments [2].angle = M_PI_2; + segments [2].length = 0.45; + segments [3].angle = 0.0; + segments [3].length = 0.5; + } + break; + case 2: + if ((random () % 2) == 0) + { + segments [0].angle = 0.0; + segments [0].length = 1.0; + segments [1].angle = (5.0 * M_PI) / 12.0; + segments [1].length = 1.2; + segments [2].angle = (-5.0 * M_PI) / 12.0; + segments [2].length = 1.2; + segments [3].angle = 0.0; + segments [3].length = 1.0; + } + else + { + segments [0].angle = 0.0; + segments [0].length = 1.0; + segments [1].angle = (-5.0 * M_PI) / 12.0; + segments [1].length = 1.2; + segments [2].angle = (5.0 * M_PI) / 12.0; + segments [2].length = 1.2; + segments [3].angle = 0.0; + segments [3].length = 1.0; + } + break; + case 3: + if ((random () % 2) == 0) + { + double angle + = random_double (M_PI / 4.0, + M_PI_2, + M_PI / 180.0); + + segments [0].angle = 0.0; + segments [0].length = 1.0; + segments [1].angle = angle; + segments [1].length = 1.2; + segments [2].angle = (-angle); + segments [2].length = 1.2; + segments [3].angle = 0.0; + segments [3].length = 1.0; + } + else + { + double angle + = random_double (M_PI / 4.0, + M_PI_2, + M_PI / 180.0); + + segments [0].angle = 0.0; + segments [0].length = 1.0; + segments [1].angle = (-angle); + segments [1].length = 1.2; + segments [2].angle = angle; + segments [2].length = 1.2; + segments [3].angle = 0.0; + segments [3].length = 1.0; + } + break; + case 4: + if ((random () % 2) == 0) + { + double angle + = random_double (M_PI / 4.0, + M_PI_2, + M_PI / 180.0); + + segments [0].angle = 0.0; + segments [0].length = 1.0; + segments [1].angle = angle; + segments [1].length = 1.2; + segments [2].angle = (-angle); + segments [2].length = 1.2; + segments [3].angle = 0.0; + segments [3].length = 1.0; + } + else + { + double angle + = random_double (M_PI / 4.0, + M_PI_2, + M_PI / 180.0); + + segments [0].angle = 0.0; + segments [0].length = 1.0; + segments [1].angle = (-angle); + segments [1].length = 1.2; + segments [2].angle = angle; + segments [2].length = 1.2; + segments [3].angle = 0.0; + segments [3].length = 1.0; + } + break; + case 5: + if ((random () % 2) == 0) + { + double angle + = random_double (M_PI / 4.0, + M_PI_2, + M_PI / 180.0); + double length = random_double (0.25, 0.50, 0.001); + + segments [0].angle = 0.0; + segments [0].length = 1.0; + segments [1].angle = angle; + segments [1].length = length; + segments [2].angle = (-angle); + segments [2].length = length; + segments [3].angle = 0.0; + segments [3].length = 1.0; + } + else + { + double angle + = random_double (M_PI / 4.0, + M_PI_2, + M_PI / 180.0); + double length = random_double (0.25, 0.50, 0.001); + + segments [0].angle = 0.0; + segments [0].length = 1.0; + segments [1].angle = (-angle); + segments [1].length = length; + segments [2].angle = angle; + segments [2].length = length; + segments [3].angle = 0.0; + segments [3].length = 1.0; + } + break; + case 6: + case 7: + case 8: + segments [0].angle + = random_double (M_PI / 12.0, (11.0 * M_PI) / 12.0, 0.001); + segments [0].length = random_double (0.25, 0.50, 0.001); + segments [1].angle + = random_double (M_PI / 12.0, (11.0 * M_PI) / 12.0, 0.001); + segments [1].length = random_double (0.25, 0.50, 0.001); + if ((random () % 3) == 0) + { + segments [2].angle + = random_double (M_PI / 12.0, (11.0 * M_PI) / 12.0, 0.001); + segments [2].length = random_double (0.25, 0.50, 0.001); + segments [3].angle + = random_double (M_PI / 12.0, (11.0 * M_PI) / 12.0, 0.001); + segments [3].length = random_double (0.25, 0.50, 0.001); + } + else + { + if ((random () % 2) == 0) + { + segments [2].angle = -(segments [1].angle); + segments [2].length = segments [1].length; + segments [3].angle = -(segments [0].angle); + segments [3].length = segments [0].length; + } + else + { + segments [2].angle = segments [1].angle; + segments [2].length = segments [1].length; + segments [3].angle = segments [0].angle; + segments [3].length = segments [0].length; + } + } + break; + } +} + +static void +select_pattern (int segment_count, + Segment* segments) +{ + switch (segment_count) + { + case 2: + select_2_pattern (segments); + break; + case 3: + select_3_pattern (segments); + break; + case 4: + select_4_pattern (segments); + break; + default: + fprintf (stderr, "\nBad segment count, must be 2, 3, or 4.\n"); + exit (1); + } +} + +#define Y_START (0.5) + +static void * +ccurve_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + unsigned long int black = 0; + int depth = 0; + XWindowAttributes hack_attributes; + XGCValues values; + unsigned long int white = 0; + + st->dpy = dpy; + st->window = window; + + st->delay = get_float_resource (st->dpy, "delay", "Integer"); + st->delay2 = get_float_resource (st->dpy, "pause", "Integer"); + st->maximum_lines = get_integer_resource (st->dpy, "limit", "Integer"); + black = BlackPixel (st->dpy, DefaultScreen (st->dpy)); + white = WhitePixel (st->dpy, DefaultScreen (st->dpy)); + st->background = black; + XGetWindowAttributes (st->dpy, st->window, &hack_attributes); + st->width = hack_attributes.width; + st->height = hack_attributes.height; + depth = hack_attributes.depth; + st->color_map = hack_attributes.colormap; + st->pixmap = XCreatePixmap (st->dpy, st->window, st->width, st->height, depth); + values.foreground = white; + values.background = black; + st->context = XCreateGC (st->dpy, st->window, GCForeground | GCBackground, + &values); + st->color_count = MAXIMUM_COLOR_COUNT; + make_color_loop (hack_attributes.screen, hack_attributes.visual, + st->color_map, + 0, 1, 1, + 120, 1, 1, + 240, 1, 1, + st->colors, &st->color_count, True, False); + if (st->color_count <= 0) + { + st->color_count = 1; + st->colors [0].red = st->colors [0].green = st->colors [0].blue = 0xFFFF; + XAllocColor (st->dpy, st->color_map, &st->colors [0]); + } + + st->draw_maximum_x = 1.20; + st->draw_maximum_y = 0.525; + st->draw_minimum_x = -0.20; + st->draw_minimum_y = -0.525; + st->draw_x2 = 1.0; + + return st; +} + +static unsigned long +ccurve_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + static const int lengths [] = { 4, 4, 4, 4, 4, 3, 3, 3, 2 }; + + if (st->draw_index == 0) + { + st->draw_segment_count + = lengths [random () % (sizeof (lengths) / sizeof (int))]; + st->draw_segments + = (Segment*)(malloc ((st->draw_segment_count) * sizeof (Segment))); + select_pattern (st->draw_segment_count, st->draw_segments); + st->draw_iterations = floor (log (st->maximum_lines) + / log (((double)(st->draw_segment_count)))); + if ((random () % 3) != 0) + { + double factor = 0.45; + st->draw_x1 += random_double (-factor, factor, 0.001); + st->draw_y1 += random_double (-factor, factor, 0.001); + st->draw_x2 += random_double (-factor, factor, 0.001); + st->draw_y2 += random_double (-factor, factor, 0.001); + } +/* background = (random () % 2) ? black : white; */ + + } + + /* for (st->draw_index = 0; st->draw_index < st->draw_iterations; ++st->draw_index) */ + { + double delta_x = 0.0; + double delta_y = 0.0; + + XSetForeground (st->dpy, st->context, st->background); + XFillRectangle (st->dpy, st->pixmap, st->context, 0, 0, st->width, st->height); + st->line_count = 0; + st->total_lines = (int)(pow ((double)(st->draw_segment_count), + (double)st->draw_index)); + st->plot_maximum_x = -1000.00; + st->plot_maximum_y = -1000.00; + st->plot_minimum_x = 1000.00; + st->plot_minimum_y = 1000.00; + self_similar (st, st->pixmap, st->context, st->width, st->height, st->draw_index, + st->draw_x1, st->draw_y1, st->draw_x2, st->draw_y2, + st->draw_maximum_x, + st->draw_maximum_y, + st->draw_minimum_x, + st->draw_minimum_y, + st->draw_segment_count, st->draw_segments); + delta_x = st->plot_maximum_x - st->plot_minimum_x; + delta_y = st->plot_maximum_y - st->plot_minimum_y; + st->draw_maximum_x = st->plot_maximum_x + (delta_x * 0.2); + st->draw_maximum_y = st->plot_maximum_y + (delta_y * 0.2); + st->draw_minimum_x = st->plot_minimum_x - (delta_x * 0.2); + st->draw_minimum_y = st->plot_minimum_y - (delta_y * 0.2); + delta_x = st->draw_maximum_x - st->draw_minimum_x; + delta_y = st->draw_maximum_y - st->draw_minimum_y; + if ((delta_y / delta_x) > (((double)st->height) / ((double)st->width))) + { + double new_delta_x + = (delta_y * ((double)st->width)) / ((double)st->height); + st->draw_minimum_x -= (new_delta_x - delta_x) / 2.0; + st->draw_maximum_x += (new_delta_x - delta_x) / 2.0; + } + else + { + double new_delta_y + = (delta_x * ((double)st->height)) / ((double)st->width); + st->draw_minimum_y -= (new_delta_y - delta_y) / 2.0; + st->draw_maximum_y += (new_delta_y - delta_y) / 2.0; + } + XCopyArea (st->dpy, st->pixmap, st->window, st->context, 0, 0, st->width, st->height, + 0, 0); + } + st->draw_index++; + /* #### mi->recursion_depth = st->draw_index; */ + + if (st->draw_index >= st->draw_iterations) + { + st->draw_index = 0; + free((void*)st->draw_segments); + st->draw_segments = 0; + return (int) (1000000 * st->delay); + } + else + return (int) (1000000 * st->delay2); +} + +static void +ccurve_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + XWindowAttributes xgwa; + st->width = w; + st->height = h; + XGetWindowAttributes (st->dpy, st->window, &xgwa); + XFreePixmap (dpy, st->pixmap); + st->pixmap = XCreatePixmap (st->dpy, st->window, st->width, st->height, + xgwa.depth); +} + +static Bool +ccurve_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + struct state *st = (struct state *) closure; + if (screenhack_event_helper (dpy, window, event)) + { + st->draw_index = 0; + return True; + } + return False; +} + +static void +ccurve_free (Display *dpy, Window window, void *closure) +{ +} + + +static const char *ccurve_defaults [] = +{ + ".background: black", + ".foreground: white", + ".delay: 3", + ".pause: 0.4", + ".limit: 200000", +#ifdef HAVE_MOBILE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec ccurve_options [] = +{ + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-pause", ".pause", XrmoptionSepArg, 0 }, + { "-limit", ".limit", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("CCurve", ccurve) diff --git a/hacks/ccurve.man b/hacks/ccurve.man new file mode 100644 index 0000000..93b81fc --- /dev/null +++ b/hacks/ccurve.man @@ -0,0 +1,60 @@ +.TH XScreenSaver 1 "" "X Version 11" +.SH NAME +ccurve - self-similar linear fractals. +.SH SYNOPSIS +.B ccurve +[\-display \fIhost:display.screen\fP] +[\-visual \fIvisual\fP] +[\-window] +[\-root] +[\-delay \fInumber\fP] +[\-pause \fInumber\fP] +[\-limit \fInumber\fP] +[\-fps] +.SH DESCRIPTION +Generates self-similar linear fractals, including the classic ``C Curve.'' +.SH OPTIONS +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-delay \fInumber\fP +Delay. 0 - 60. Default: 1. +.TP 8 +.B \-pause \fInumber\fP +Duration. 1 - 60. Default: 3. +.TP 8 +.B \-limit \fInumber\fP +Density. 3 - 300000. Default: 200000. +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1) +.SH COPYRIGHT +Copyright \(co 2002 by Rick Campbell. Permission to use, copy, modify, +distribute, and sell this software and its documentation for any purpose is +hereby granted without fee, provided that the above copyright notice appear +in all copies and that both that copyright notice and this permission notice +appear in supporting documentation. No representations are made about the +suitability of this software for any purpose. It is provided "as is" without +express or implied warranty. +.SH AUTHOR +Rick Campbell. diff --git a/hacks/celtic.c b/hacks/celtic.c new file mode 100644 index 0000000..890b398 --- /dev/null +++ b/hacks/celtic.c @@ -0,0 +1,1131 @@ +/* celtic, Copyright (c) 2006 Max Froumentin + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * A celtic pattern programme inspired by "Les Entrelacs Celtes", by + * Christian Mercat, Dossier Pour La Science, no. 47, april/june 2005. + * See + */ + +#include +#include "screenhack.h" +#include "erase.h" + +#define SQRT_3 1.73205080756887729352 +#undef assert +#define assert(EXP) do { if (!((EXP))) abort(); } while(0) + +/*-----------------------------------------*/ + +struct params { + unsigned long curve_width, shadow_width; + double shape1, shape2; + unsigned long margin; + + enum graph_type { polar, tgrid, kennicott, triangle } type; + unsigned long edge_size; + unsigned long cluster_size; /* only used if type is kennicott */ + unsigned long delay; /* controls curve drawing speed (step delay + * in microsecs) */ + unsigned long nsteps; /* only if triangle: number of subdivisions along the side */ + unsigned long nb_orbits; /* only used if type is polar */ + unsigned long nb_nodes_per_orbit; /* only used if type is polar */ + + double angle; /* angle of rotation of the graph around the centre */ +}; + +/*-----------------------------------------*/ +typedef enum direction { + CLOCKWISE=0, ANTICLOCKWISE=1 +} Direction; + + +/*-----------------------------------------*/ +typedef struct array { + int nb_elements; + int nb_allocated_elements; + int increment; + void **elements; +} *Array; + +typedef struct graph { + Array nodes; + Array edges; +} *Graph; + +typedef struct edge_couple { + int **array; + int size; +} *EdgeCouple; + +typedef struct pattern { + double shape1, shape2; + EdgeCouple ec; + Graph graph; + Array splines; + int ncolors; +} *Pattern; + +struct state { + Display *dpy; + Window window; + eraser_state *eraser; + + int ncolors; + XColor *colors; + GC gc,shadow_gc,gc_graph; + + Bool showGraph; + Pattern pattern; + Graph graph; + XWindowAttributes xgwa; + int delay2; + int reset, force_reset; + double t; + + struct params params; +}; + + + + +static Array array_new(int increment) +{ + Array new; + assert(new=(Array)calloc(1,sizeof(struct array))); + new->nb_elements=0; + new->nb_allocated_elements=0; + new->increment=increment; + return new; +} + +static void array_del(Array a, void (*free_element)(void*)) +{ + int i; + if (free_element) + for (i=0;inb_elements;i++) + free_element(a->elements[i]); + free(a->elements); + free(a); +} + +static void array_add_element(Array a, void *element) +{ + if (a->nb_elements == a->nb_allocated_elements) { + /* we must allocate more */ + a->nb_allocated_elements+=a->increment; + a->elements=realloc(a->elements,a->nb_allocated_elements*sizeof(void *)); + } + a->elements[a->nb_elements++]=element; +} +/*-----------------------------------------*/ + +typedef struct node { + double x,y; + Array edges; +} *Node; + +typedef struct edge { + Node node1, node2; + double angle1, angle2; +} *Edge; + +/*-----------------------------------------*/ +/* Node functions */ + +static Node node_new(double x, double y) +{ + Node new; + assert(new = (Node)calloc(1,sizeof(struct node))); + new->x=x; + new->y=y; + new->edges = array_new(10); + return new; +} + +static void node_del(void *n) +{ /* not Node * because the function is passed to array_del */ + array_del(((Node)n)->edges,NULL); + free(n); +} + +#if 0 +static void node_to_s(Node n, FILE *f) +{ + fprintf(f,"Node: %g %g\n",n->x,n->y); +} +#endif + +static void node_draw(struct state *st, Node n) +{ + XDrawArc(st->dpy,st->window,st->gc_graph,(int)rint(n->x)-5,(int)rint(n->y)-5,10,10,0,360*64); +} + +static void node_add_edge(Node n, Edge e) +{ + array_add_element(n->edges,e); +} + + +/*-----------------------------------------*/ +/* Edge functions */ + +static Edge edge_new(Node n1, Node n2) +{ + Edge new; + assert(new = (Edge)calloc(1,sizeof(struct edge))); + new->node1=n1; + new->node2=n2; + new->angle1=atan2(new->node2->y - new->node1->y, new->node2->x - new->node1->x); + if (new->angle1 < 0) new->angle1+=6.28; + + new->angle2=atan2(new->node1->y - new->node2->y, new->node1->x - new->node2->x); + if (new->angle2 < 0) new->angle2+=6.28; + return new; +} + +static void edge_del(void *e) /* not Edge * because the function is passed to array_del */ +{ + free(e); +} + +#if 0 +static void edge_to_s(Edge e, FILE *f) +{ + fprintf(f,"Edge: (%g, %g), (%g, %g) angles: %g, %g\n", + e->node1->x, e->node1->y, e->node2->x, e->node2->y, + e->angle1, e->angle2); +} +#endif + +static void edge_draw(struct state *st, Edge e) +{ + XDrawLine(st->dpy,st->window,st->gc_graph, e->node1->x, e->node1->y, e->node2->x, e->node2->y); +} + +static double edge_angle(Edge e, Node n) +{ + /* returns the angle of the edge at Node n */ + assert(n==e->node1 || n==e->node2); + if (n==e->node1) return e->angle1; else return e->angle2; +} + +static Node edge_other_node(Edge e, Node n) +{ + assert(n==e->node1 || n==e->node2); + if (n==e->node1) return e->node2; else return e->node1; +} + +static double edge_angle_to(Edge e, Edge e2, Node node, Direction direction) +{ + /* returns the absolute angle from this edge to "edge2" around + "node" following "direction" */ + double a; + + if (direction==CLOCKWISE) + a=edge_angle(e,node) - edge_angle(e2,node); + else + a=edge_angle(e2,node) - edge_angle(e,node); + + if (a<0) return a+2*M_PI; else return a; +} + +/*-----------------------------------------*/ + +static Graph graph_new(struct state *st) +{ + Graph new; + assert(new = (Graph)calloc(1,sizeof(struct graph))); + new->nodes = array_new(100); + new->edges = array_new(100); + return new; +} + +static void graph_del(Graph g) +{ + array_del(g->nodes, &node_del); + array_del(g->edges, &edge_del); + free(g); +} + + +static void graph_add_node(Graph g, Node n) +{ + array_add_element(g->nodes, n); +} + +static void graph_add_edge(Graph g, Edge e) +{ + array_add_element(g->edges, e); + + /* for each node n of e, add n to pointer e */ + node_add_edge(e->node1, e); + node_add_edge(e->node2, e); +} + +static Edge graph_next_edge_around(Graph g, Node n, Edge e, Direction direction) +{ + /* return the next edge after e around node n clockwise */ + double angle, minangle=20; + Edge next_edge = e, edge; + int i; + + for (i=0;iedges->nb_elements;i++) { + edge=n->edges->elements[i]; + if (edge != e) { + angle = edge_angle_to(e,edge,n,direction); + if (angle < minangle) { + next_edge=edge; + minangle=angle; + } + } + } + return next_edge; +} + +#if 0 +static void graph_to_s(Graph g, FILE *f) +{ + int i; + for (i=0;inodes->nb_elements;i++) + node_to_s(g->nodes->elements[i],f); + for (i=0;iedges->nb_elements;i++) + edge_to_s(g->edges->elements[i],f); +} +#endif + +static void graph_draw(struct state *st, Graph g) +{ + int i; + + for (i=0;inodes->nb_elements;i++) + node_draw(st, g->nodes->elements[i]); + for (i=0;iedges->nb_elements;i++) + edge_draw(st, g->edges->elements[i]); +} + +static void graph_rotate(Graph g, double angle, int cx, int cy) +{ + /* rotate all the nodes of the graph around the centre */ + int i; + float c=cos(angle),s=sin(angle),x,y; + Node n; + for (i=0;inodes->nb_elements;i++) { + n=g->nodes->elements[i]; + x=n->x; y=n->y; + n->x = (x-cx)*c-(y-cy)*s + cx; + n->y = (x-cx)*s+(y-cy)*c + cy; + } +} + + +/*---------------------------*/ + +static Graph make_polar_graph(struct state *st, + int xmin, int ymin, int width, int height, + int nbp, /* number of points on each orbit */ + int nbo /* number of orbits */) + /* make a simple grid graph, with edges present or absent randomly */ +{ + int cx = width/2+xmin, cy=height/2+ymin; /* centre */ + int os = (widthsegments=array_new(30); + new->color=color; + return new; +} + +static void spline_del(void *s) +{ + array_del(((Spline)s)->segments,&free); + free(s); +} + +static void spline_add_segment(Spline s, + double x1, double y1, double x2, double y2, + double x3, double y3, double x4, double y4) +{ + SplineSegment ss=(SplineSegment)calloc(1,sizeof(struct spline_segment)); + ss->x1=x1; ss->x2=x2; ss->x3=x3; ss->x4=x4; + ss->y1=y1; ss->y2=y2; ss->y3=y3; ss->y4=y4; + array_add_element(s->segments,ss); +} + +#if 0 +static void spline_to_s(Spline s, FILE *f) +{ + int i; + SplineSegment ss; + fprintf(f,"Spline: \n"); + for (i=0;isegments->nb_elements;i++) { + ss=s->segments->elements[i]; + fprintf(f," - segment %d: (%g, %g),(%g, %g),(%g, %g),(%g, %g)\n", + i,ss->x1,ss->y1,ss->x2,ss->y2,ss->x3,ss->y3,ss->x4,ss->y4); + } +} +#endif + +static void spline_value_at(Spline s, double *x, double *y, double t, int *segment) +{ + int si; + double tt; + SplineSegment ss; + si = floor(t*s->segments->nb_elements); + tt = t*s->segments->nb_elements - si; + assert(tt>=0 && tt<1); + ss=s->segments->elements[si]; + + *x = ss->x1*(1-tt)*(1-tt)*(1-tt)+3*ss->x2*tt*(1-tt)*(1-tt)+3*ss->x3*tt*tt*(1-tt)+ss->x4*tt*tt*tt; + *y = ss->y1*(1-tt)*(1-tt)*(1-tt)+3*ss->y2*tt*(1-tt)*(1-tt)+3*ss->y3*tt*tt*(1-tt)+ss->y4*tt*tt*tt; + + *segment=si; +} + +/*---------------------------*/ + +static EdgeCouple edge_couple_new(int nb_edges) { + int i; + EdgeCouple new = (EdgeCouple)calloc(1,sizeof(struct edge_couple)); + new->array = (int **)calloc(nb_edges, sizeof(int*)); + new->size = nb_edges; + + for (i=0;iarray[i]=(int *)calloc(2,sizeof(int)); + new->array[i][CLOCKWISE]=0; + new->array[i][ANTICLOCKWISE]=0; + } + return new; +} + +static void edge_couple_del(EdgeCouple e) +{ + int i; + for (i=0;isize;i++) free(e->array[i]); + free(e->array); + free(e); +} + +/*---------------------------*/ + +static Pattern pattern_new(struct state *st, Graph g, double shape1, double shape2) +{ + Pattern new; + assert(new=(Pattern)calloc(1,sizeof(struct pattern))); + new->shape1=shape1; + new->shape2=shape2; + new->graph=g; + new->ec=edge_couple_new(g->edges->nb_elements); + new->splines=array_new(10); + new->ncolors=st->ncolors; + return new; +} + +static void pattern_del(Pattern p) +{ + edge_couple_del(p->ec); + array_del(p->splines,&spline_del); + free(p); +} + +static void pattern_edge_couple_set(Pattern p, Edge e, Direction d, int value) +{ + int i; + for (i=0;igraph->edges->nb_elements;i++) + if (p->graph->edges->elements[i]==e) { + p->ec->array[i][d]=value; + return; + } +} + +static void pattern_draw_spline_direction(Pattern p, Spline s, + Node node, Edge edge1, Edge edge2, + Direction direction) +{ + double x1=(edge1->node1->x+edge1->node2->x)/2.0; + double y1=(edge1->node1->y+edge1->node2->y)/2.0; + + /* P2 (x2,y2) is the middle point of edge1 */ + double x4=(edge2->node1->x+edge2->node2->x)/2.0; + double y4=(edge2->node1->y+edge2->node2->y)/2.0; + + double alpha=edge_angle_to(edge1,edge2,node,direction)*p->shape1; + double beta=p->shape2; + + double i1x,i1y,i2x,i2y,x2,y2,x3,y3; + + if (direction == ANTICLOCKWISE) { + /* I1 must stick out to the left of NP1 and I2 to the right of NP4 */ + i1x = alpha*(node->y-y1)+x1; + i1y = -alpha*(node->x-x1)+y1; + i2x = -alpha*(node->y-y4)+x4; + i2y = alpha*(node->x-x4)+y4; + x2 = beta*(y1-i1y) + i1x; + y2 = -beta*(x1-i1x) + i1y; + x3 = -beta*(y4-i2y) + i2x; + y3 = beta*(x4-i2x) + i2y; + } + else { + /* I1 must stick out to the left of NP1 and I2 to the right of NP4 */ + i1x = -alpha*(node->y-y1)+x1; + i1y = alpha*(node->x-x1)+y1; + i2x = alpha*(node->y-y4)+x4; + i2y = -alpha*(node->x-x4)+y4; + x2 = -beta*(y1-i1y) + i1x; + y2 = beta*(x1-i1x) + i1y; + x3 = beta*(y4-i2y) + i2x; + y3 = -beta*(x4-i2x) + i2y; + } + + spline_add_segment(s,x1,y1,x2,y2,x3,y3,x4,y4); +} + +static int pattern_next_unfilled_couple(Pattern p, Edge *e, Direction *d) +{ + int i; + for (i=0;iec->size;i++) { + if (p->ec->array[i][CLOCKWISE]==0) { + *e=p->graph->edges->elements[i]; + *d=CLOCKWISE; + return 1; + } + else if (p->ec->array[i][ANTICLOCKWISE]==0) { + *e=p->graph->edges->elements[i]; + *d=ANTICLOCKWISE; + return 1; + } + } + return 0; +} + +static void pattern_make_curves(Pattern p) +{ + Edge current_edge, first_edge, next_edge; + Node current_node, first_node; + Direction current_direction, first_direction; + Spline s; + + while (pattern_next_unfilled_couple(p, &first_edge, &first_direction)) { + /* start a new loop */ + s=spline_new(random()%(p->ncolors-2)+2); + array_add_element(p->splines, s); + + current_edge=first_edge; + current_node=first_node=current_edge->node1; + current_direction=first_direction; + + do { + pattern_edge_couple_set(p, current_edge, current_direction, 1); + next_edge = graph_next_edge_around(p->graph,current_node,current_edge,current_direction); + + /* add the spline segment to the spline */ + pattern_draw_spline_direction(p,s,current_node, + current_edge,next_edge,current_direction); + + /* cross the edge */ + current_edge = next_edge; + current_node = edge_other_node(next_edge, current_node); + current_direction=1-current_direction; + + } while (current_node!=first_node || current_edge!=first_edge || current_direction!=first_direction); + + if (s->segments->nb_elements==2) /* spline is just one point: remove it */ + p->splines->elements[p->splines->nb_elements-1]=NULL; + + } +} + +static void pattern_animate(struct state *st) +{ + Pattern p = st->pattern; + double t = st->t; + double t2; + double x,y,x2,y2,x3,y3,x4,y4; + int i,segment,unused; + int ticks; + double step=0.0001; /* TODO: set the step (or the delay) as a + * function of the spline length, so that + * drawing speed is constant + */ + Spline s; + + XSetLineAttributes(st->dpy,st->gc,st->params.curve_width,LineSolid,CapRound,JoinRound); + XSetLineAttributes(st->dpy,st->shadow_gc,st->params.shadow_width,LineSolid,CapRound,JoinRound); + + for (ticks=0;ticks<100 && t<1;ticks++) { + for (i=0;isplines->nb_elements;i++) + if ((s=p->splines->elements[i])) { /* skip if one-point spline */ + spline_value_at(s, &x, &y, fmod(t,1.0),&segment); + spline_value_at(s, &x2, &y2, fmod(t+step,1.0),&unused); + + /* look ahead for the shadow segment */ + t2=t+step; + if (t2<=1.0) { + spline_value_at(s, &x3, &y3, fmod(t2,1.0),&unused); + while (t2+step<1.0 && (x3-x2)*(x3-x2)+(y3-y2)*(y3-y2) < st->params.shadow_width*st->params.shadow_width) { + t2+=step; + spline_value_at(s, &x3, &y3, fmod(t2,1.0),&unused); + } + + spline_value_at(s, &x4, &y4, fmod(t2+step,1.0),&unused); + + /* draw shadow line */ + XDrawLine(st->dpy,st->window,st->shadow_gc, + (int)rint(x3),(int)rint(y3), + (int)rint(x4),(int)rint(y4)); + } + /* draw line segment */ + if (p->splines->nb_elements==1) + XSetForeground(st->dpy, st->gc, st->colors[segment%(p->ncolors-3)+2].pixel); + else + XSetForeground(st->dpy, st->gc, st->colors[s->color].pixel); + XDrawLine(st->dpy,st->window,st->gc, + (int)rint(x),(int)rint(y), + (int)rint(x2),(int)rint(y2)); + } + t+=step; + } + st->t=t; + + if (t>=1) { + st->reset=1; + + /* at the end we redraw back to remove shadow spillage */ + for (i=0;isplines->nb_elements;i++) { + if ((s=p->splines->elements[i])) { + double offset=step; + XSetForeground(st->dpy, st->gc, st->colors[s->color].pixel); + spline_value_at(s, &x, &y, fmod(t,1.0),&unused); + + spline_value_at(s, &x2, &y2, fmod(t-offset,1.0),&unused); + + while ((x2-x)*(x2-x)+(y2-y)*(y2-y) < st->params.shadow_width*st->params.shadow_width) { + offset+=step; + spline_value_at(s, &x2, &y2, fmod(t-offset,1.0),&unused); + } + + XDrawLine(st->dpy,st->window,st->gc, (int)rint(x),(int)rint(y), (int)rint(x2),(int)rint(y2)); + } + } + } +} + +/*======================================================================*/ + +static const char *celtic_defaults[] = { + ".background: black", + ".foreground: #333333", + "*fpsSolid: true", + "*ncolors: 20", + "*delay: 10000", + "*delay2: 5", + "*showGraph: False", +#ifdef HAVE_MOBILE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec celtic_options[] = { + {"-background", ".background", XrmoptionSepArg, 0}, + {"-foreground", ".foreground", XrmoptionSepArg, 0}, + {"-ncolors", ".ncolors", XrmoptionSepArg, 0}, + {"-delay", ".delay", XrmoptionSepArg, 0}, + {"-delay2", ".delay2", XrmoptionSepArg, 0}, + {"-graph", ".showGraph", XrmoptionNoArg, "True"}, + {0, 0, 0, 0} +}; + +#if 0 +static void params_to_s(FILE *f) +{ + switch (st->params.type) { + case polar: fprintf(f,"type: polar\n"); + fprintf(f,"nb_orbits: %ld\n",st->params.nb_orbits); + fprintf(f,"nb_nodes_per_orbit: %ld\n",st->params.nb_nodes_per_orbit); + break; + case tgrid: fprintf(f,"type: grid\n"); + fprintf(f,"edge_size: %ld\n",st->params.edge_size); + break; + case triangle: fprintf(f,"type: triangle\n"); + fprintf(f,"edge_size: %ld\n",st->params.edge_size); + break; + case kennicott: + fprintf(f,"type: kennicott\n"); + fprintf(f,"edge_size: %ld\n",st->params.edge_size); + fprintf(f,"cluster_size: %ld\n",st->params.cluster_size); + break; + } + + fprintf(f,"curve width: %ld\n",st->params.curve_width); + fprintf(f,"shadow width: %ld\n",st->params.shadow_width); + fprintf(f,"shape1: %g\n",st->params.shape1); + fprintf(f,"shape2: %g\n",st->params.shape2); + fprintf(f,"margin: %ld\n",st->params.margin); + fprintf(f,"angle: %g\n",st->params.angle); + fprintf(f,"delay: %ld\n",st->params.delay); +} +#endif + +#if 0 +static void colormap_to_s(int ncolors, XColor *colors) +{ + int i; + printf("-- colormap (%d colors):\n",st->ncolors); + for (i=0;incolors;i++) + printf("%d: %d %d %d\n", i, st->colors[i].red, st->colors[i].green, st->colors[i].blue); + printf("----\n"); +} +#endif + + +static void * +celtic_init (Display *d_arg, Window w_arg) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + + st->dpy=d_arg; st->window=w_arg; + st->showGraph=get_boolean_resource (st->dpy, "showGraph", "Boolean"); + + st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer"); + + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + assert(st->colors = (XColor *) calloc (st->ncolors,sizeof(XColor))); + + if (get_boolean_resource(st->dpy, "mono", "Boolean")) + { + MONO: + st->ncolors = 1; + st->colors[0].pixel = get_pixel_resource(st->dpy, st->xgwa.colormap, + "foreground", "Foreground"); + } + else + { +#if 0 + make_random_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + st->colors, &st->ncolors, True, True, 0, True); +#else + make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + st->colors, &st->ncolors, True, 0, True); +#endif + if (st->ncolors < 2) + goto MONO; + else { + st->colors[0].pixel = get_pixel_resource(st->dpy, st->xgwa.colormap, + "foreground", "Foreground"); + st->colors[1].pixel = get_pixel_resource(st->dpy, st->xgwa.colormap, + "background", "Background"); + } + } + + + /* graphic context for curves */ + gcv.foreground = st->colors[0].pixel; + gcv.background = st->colors[1].pixel; + gcv.line_width = st->params.curve_width; + gcv.cap_style=CapRound; + st->gc = XCreateGC (st->dpy, st->window, GCForeground|GCBackground|GCLineWidth|GCCapStyle, &gcv); + + /* graphic context for graphs */ + gcv.foreground = st->colors[0].pixel; + gcv.background = st->colors[1].pixel; + st->gc_graph = XCreateGC (st->dpy, st->window, GCForeground|GCBackground, &gcv); + + /* graphic context for shadows */ + gcv.foreground = st->colors[1].pixel; + gcv.line_width = st->params.shadow_width; + gcv.cap_style=CapRound; + st->shadow_gc = XCreateGC(st->dpy, st->window, GCForeground|GCLineWidth|GCCapStyle, &gcv); + + st->delay2 = 1000000 * get_integer_resource(st->dpy, "delay2", "Delay2"); + + return st; +} + +static unsigned long +celtic_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + if (st->eraser) { + st->eraser = erase_window (st->dpy, st->window, st->eraser); + return 10000; + } + + if (st->reset || st->force_reset) { + int delay = (st->force_reset ? 0 : st->delay2); + st->reset = 0; + st->force_reset = 0; + st->t = 1; + + if (st->pattern != NULL) { + pattern_del(st->pattern); + } + st->pattern = NULL; + graph_del(st->graph); + + /* recolor each time */ + st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer"); + if (st->ncolors > 2) + make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, + st->colors, &st->ncolors, True, 0, True); + + st->eraser = erase_window (st->dpy, st->window, st->eraser); + return (delay); + } + + if (st->pattern == NULL) { + st->params.curve_width=random()%5+4; + st->params.shadow_width=st->params.curve_width+4; + st->params.shape1=(15+random()%15)/10.0 -1.0; + st->params.shape2=(15+random()%15)/10.0 -1.0; + st->params.edge_size=10*(random()%5)+20; + st->params.delay=get_integer_resource(st->dpy, "delay", "Delay"); + st->params.angle=random()%360*2*M_PI/360; + st->params.margin=(random()%8)*100-600; + + switch (random()%4) { + case 0: + st->params.type=tgrid; + st->params.shape1=(random()%1*2-1.0)*(random()%10+3)/10.0; + st->params.shape2=(random()%1*2-1.0)*(random()%10+3)/10.0; + st->params.edge_size=10*(random()%5)+50; + break; + case 1: + st->params.type=kennicott; + st->params.shape1=(random()%20)/10.0 -1.0; + st->params.shape2=(random()%20)/10.0 -1.0; + st->params.edge_size=10*(random()%3)+70; + st->params.cluster_size=st->params.edge_size/(3.0+random()%10)-1; + break; + case 2: + st->params.type=triangle; + st->params.edge_size=10*(random()%5)+60; + st->params.margin=(random()%10)*100-900; + break; + case 3: + st->params.type=polar; + st->params.nb_orbits=2+random()%10; + st->params.nb_nodes_per_orbit=4+random()%10; + break; + } + + +/* st->params.type= polar; */ +/* st->params.nb_orbits= 5; */ +/* st->params.nb_nodes_per_orbit= 19; */ +/* st->params.curve_width= 4; */ +/* st->params.shadow_width= 8; */ +/* st->params.shape1= 0.5; */ +/* st->params.shape2= 1.3; */ +/* st->params.margin= 30; */ +/* st->params.angle= 5.21853; */ +/* st->params.delay= 10000; */ + + +/* params_to_s(stdout); */ + + /*=======================================================*/ + + + switch (st->params.type) { + case tgrid: + st->graph=make_grid_graph(st, st->params.margin,st->params.margin, + st->xgwa.width-2*st->params.margin, + st->xgwa.height-2*st->params.margin, + st->params.edge_size); + break; + case kennicott: + st->graph=make_kennicott_graph(st, st->params.margin,st->params.margin, + st->xgwa.width-2*st->params.margin, + st->xgwa.height-2*st->params.margin, + st->params.edge_size, + st->params.cluster_size); + break; + case triangle: + st->graph=make_triangle_graph(st, st->params.margin,st->params.margin, + st->xgwa.width-2*st->params.margin, + st->xgwa.height-2*st->params.margin, + st->params.edge_size); + break; + case polar: + st->graph=make_polar_graph(st, st->params.margin,st->params.margin, + st->xgwa.width-2*st->params.margin, + st->xgwa.height-2*st->params.margin, + st->params.nb_nodes_per_orbit, + st->params.nb_orbits); + break; + default: + st->graph=make_grid_graph(st, st->params.margin,st->params.margin, + st->xgwa.width-2*st->params.margin, + st->xgwa.height-2*st->params.margin, + st->params.edge_size); + break; + } + + graph_rotate(st->graph,st->params.angle,st->xgwa.width/2,st->xgwa.height/2); + + if (st->showGraph) + graph_draw(st, st->graph); + + st->pattern=pattern_new(st, st->graph, st->params.shape1, st->params.shape2); + pattern_make_curves(st->pattern); + st->t = 0.0; + } + + pattern_animate(st); + + return st->params.delay; +} + + +static void +celtic_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); +} + +static Bool +celtic_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + struct state *st = (struct state *) closure; + if (screenhack_event_helper (dpy, window, event)) + { + st->force_reset = 1; + return True; + } + return False; +} + +static void +celtic_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +XSCREENSAVER_MODULE ("Celtic", celtic) diff --git a/hacks/celtic.man b/hacks/celtic.man new file mode 100644 index 0000000..9747cd5 --- /dev/null +++ b/hacks/celtic.man @@ -0,0 +1,64 @@ +.TH XScreenSaver 1 "" "X Version 11" +.SH NAME +celtic - draws celtic cross-stich patterns +.SH SYNOPSIS +.B ifs +[\-display \fIhost:display.screen\fP] +[\-visual \fIvisual\fP] +[\-window] +[\-root] +[\-delay \fInumber\fP] +[\-delay2 \fInumber\fP] +[\-ncolors \fInumber\fP] +[\-graph \fImode\fP] +[\-fps] +.SH DESCRIPTION +The \fIceltic\fP program repeatedly draws random cross-stitch patterns. +.SH OPTIONS +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-delay \fInumber\fP +Per-frame delay, in microseconds. Default: 10000. +.TP 8 +.B \-delay2 \fInumber\fP +Delay between patterns, in seconds. Default: 5. +.TP 8 +.B \-ncolors \fInumber\fP +Number of colours to use. Default: 20. +.TP 8 +.B \-graph +Whether to render the underlying graph. Default: no. +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1) +.SH COPYRIGHT +Copyright \(co 2005 by Max Froumentin. Permission to use, copy, modify, +distribute, and sell this software and its documentation for any purpose is +hereby granted without fee, provided that the above copyright notice appear +in all copies and that both that copyright notice and this permission notice +appear in supporting documentation. No representations are made about the +suitability of this software for any purpose. It is provided "as is" without +express or implied warranty. +.SH AUTHOR +Max Froumentin diff --git a/hacks/check-configs.pl b/hacks/check-configs.pl new file mode 100755 index 0000000..7a7d0bb --- /dev/null +++ b/hacks/check-configs.pl @@ -0,0 +1,1243 @@ +#!/usr/bin/perl -w +# Copyright © 2008-2017 Jamie Zawinski +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation. No representations are made about the suitability of this +# software for any purpose. It is provided "as is" without express or +# implied warranty. +# +# This parses the .c and .xml files and makes sure they are in sync: that +# options are spelled the same, and that all the numbers are in sync. +# +# It also converts the hacks/config/ XML files into the Android XML files. +# +# Created: 1-Aug-2008. + +require 5; +use diagnostics; +use strict; + +my $progname = $0; $progname =~ s@.*/@@g; +my ($version) = ('$Revision: 1.26 $' =~ m/\s(\d[.\d]+)\s/s); + +my $verbose = 0; +my $debug_p = 0; + + +my $text_default_opts = ''; +foreach (qw(text-mode text-literal text-file text-url text-program)) { + my $s = $_; $s =~ s/-(.)/\U$1/g; $s =~ s/url/URL/si; + $text_default_opts .= "{\"-$_\", \".$s\", XrmoptionSepArg, 0},\n"; +} +my $image_default_opts = ''; +foreach (qw(choose-random-images grab-desktop-images)) { + my $s = $_; $s =~ s/-(.)/\U$1/g; + $image_default_opts .= "{\"-$_\", \".$s\", XrmoptionSepArg, 0},\n"; +} +my $xlockmore_default_opts = ''; +foreach (qw(count cycles delay ncolors size font)) { + $xlockmore_default_opts .= "{\"-$_\", \".$_\", XrmoptionSepArg, 0},\n"; +} +$xlockmore_default_opts .= + "{\"-wireframe\", \".wireframe\", XrmoptionNoArg, \"true\"},\n" . + "{\"-3d\", \".use3d\", XrmoptionNoArg, \"true\"},\n" . + "{\"-no-3d\", \".use3d\", XrmoptionNoArg, \"false\"},\n"; + +my $thread_default_opts = + "{\"-threads\", \".useThreads\", XrmoptionNoArg, \"True\"},\n" . + "{\"-no-threads\", \".useThreads\", XrmoptionNoArg, \"False\"},\n"; + +my $analogtv_default_opts = ''; +foreach (qw(color tint brightness contrast)) { + $analogtv_default_opts .= "{\"-tv-$_\", \".TV$_\", XrmoptionSepArg, 0},\n"; +} + +$analogtv_default_opts .= $thread_default_opts; + + + +# Returns two tables: +# - A table of the default resource values. +# - A table of "-switch" => "resource: value", or "-switch" => "resource: %" +# +sub parse_src($) { + my ($saver) = @_; + my $file = lc($saver) . ".c"; + + # kludge... + $file = 'apple2-main.c' if ($file eq 'apple2.c'); + $file = 'sproingiewrap.c' if ($file eq 'sproingies.c'); + $file = 'b_lockglue.c' if ($file eq 'bubble3d.c'); + $file = 'polyhedra-gl.c' if ($file eq 'polyhedra.c'); + $file = 'companion.c' if ($file eq 'companioncube.c'); + $file = 'rd-bomb.c' if ($file eq 'rdbomb.c'); + + my $ofile = $file; + $file = "glx/$ofile" unless (-f $file); + $file = "../hacks/$ofile" unless (-f $file); + $file = "../hacks/glx/$ofile" unless (-f $file); + my $body = ''; + open (my $in, '<', $file) || error ("$ofile: $!"); + while (<$in>) { $body .= $_; } + close $in; + $file =~ s@^.*/@@; + + my $xlockmore_p = 0; + my $thread_p = ($body =~ m/THREAD_DEFAULTS/); + my $analogtv_p = ($body =~ m/ANALOGTV_DEFAULTS/); + my $text_p = ($body =~ m/"textclient\.h"/); + my $grab_p = ($body =~ m/load_image_async/); + + $body =~ s@/\*.*?\*/@@gs; + $body =~ s@^#\s*(if|ifdef|ifndef|elif|else|endif).*$@@gm; + $body =~ s/(THREAD|ANALOGTV)_(DEFAULTS|OPTIONS)(_XLOCK)?//gs; + $body =~ s/__extension__//gs; + + print STDERR "$progname: $file: defaults:\n" if ($verbose > 2); + my %res_to_val; + if ($body =~ m/_defaults\s*\[\]\s*=\s*{(.*?)}\s*;/s) { + foreach (split (/,\s*\n/, $1)) { + s/^\s*//s; + s/\s*$//s; + next if m/^0?$/s; + my ($key, $val) = m@^\"([^:\s]+)\s*:\s*(.*?)\s*\"$@; + print STDERR "$progname: $file: unparsable: $_\n" unless $key; + $key =~ s/^[.*]//s; + $res_to_val{$key} = $val; + print STDERR "$progname: $file: $key = $val\n" if ($verbose > 2); + } + } elsif ($body =~ m/\#\s*define\s*DEFAULTS\s*\\?\s*(.*?)\n[\n#]/s) { + $xlockmore_p = 1; + my $str = $1; + $str =~ s/\"\s*\\\n\s*\"//gs; + $str =~ m/^\s*\"(.*?)\"\s*\\?\s*$/ || + error ("$file: unparsable defaults: $str"); + $str = $1; + $str =~ s/\s*\\n\s*/\n/gs; + foreach (split (/\n/, $str)) { + my ($key, $val) = m@^([^:\s]+)\s*:\s*(.*?)\s*$@; + print STDERR "$progname: $file: unparsable: $_\n" unless $key; + $key =~ s/^[.*]//s; + $val =~ s/"\s*"\s*$//s; + $res_to_val{$key} = $val; + print STDERR "$progname: $file: $key = $val\n" if ($verbose > 2); + } + + while ($body =~ s/^#\s*define\s+(DEF_([A-Z\d_]+))\s+\"([^\"]+)\"//m) { + my ($key1, $key2, $val) = ($1, lc($2), $3); + $key2 =~ s/_(.)/\U$1/gs; # "foo_bar" -> "fooBar" + $key2 =~ s/Rpm/RPM/; # kludge + $res_to_val{$key2} = $val; + print STDERR "$progname: $file: $key1 ($key2) = $val\n" + if ($verbose > 2); + } + + } else { + error ("$file: no defaults"); + } + + $body =~ m/XSCREENSAVER_MODULE(_2)?\s*\(\s*\"([^\"]+)\"/ || + error ("$file: no module name"); + $res_to_val{progclass} = $2; + $res_to_val{doFPS} = 'false'; + $res_to_val{textMode} = 'date'; + $res_to_val{textLiteral} = ''; + $res_to_val{textURL} = + 'https://en.wikipedia.org/w/index.php?title=Special:NewPages&feed=rss'; + $res_to_val{grabDesktopImages} = 'true'; + $res_to_val{chooseRandomImages} = 'true'; + + print STDERR "$progname: $file: progclass = $2\n" if ($verbose > 2); + + print STDERR "$progname: $file: switches to resources:\n" + if ($verbose > 2); + my %switch_to_res; + $switch_to_res{'-fps'} = 'doFPS: true'; + $switch_to_res{'-fg'} = 'foreground: %'; + $switch_to_res{'-bg'} = 'background: %'; + $switch_to_res{'-no-grab-desktop-images'} = 'grabDesktopImages: false'; + $switch_to_res{'-no-choose-random-images'} = 'chooseRandomImages: false'; + + my ($ign, $opts) = ($body =~ m/(_options|\bopts)\s*\[\]\s*=\s*{(.*?)}\s*;/s); + if ($xlockmore_p || $thread_p || $analogtv_p || $opts) { + $opts = '' unless $opts; + $opts .= ",\n$text_default_opts" if ($text_p); + $opts .= ",\n$image_default_opts" if ($grab_p); + $opts .= ",\n$xlockmore_default_opts" if ($xlockmore_p); + $opts .= ",\n$thread_default_opts" if ($thread_p); + $opts .= ",\n$analogtv_default_opts" if ($analogtv_p); + + foreach (split (/,\s*\n/, $opts)) { + s/^\s*//s; + s/\s*$//s; + next if m/^$/s; + next if m/^\{\s*0\s*,/s; + my ($switch, $res, $type, $v0, $v1, $v2) = + m@^ \s* { \s * \"([^\"]+)\" \s* , + \s * \"([^\"]+)\" \s* , + \s * ([^\s]+) \s* , + \s * (\"([^\"]*)\"|([a-zA-Z\d_]+)) \s* }@xi; + print STDERR "$progname: $file: unparsable: $_\n" unless $switch; + my $val = defined($v1) ? $v1 : $v2; + $val = '%' if ($type eq 'XrmoptionSepArg'); + $res =~ s/^[.*]//s; + $res =~ s/^[a-z\d]+\.//si; + $switch =~ s/^\+/-no-/s; + + $val = "$res: $val"; + if (defined ($switch_to_res{$switch})) { + print STDERR "$progname: $file: DUP! $switch = \"$val\"\n" + if ($verbose > 2); + } else { + $switch_to_res{$switch} = $val; + print STDERR "$progname: $file: $switch = \"$val\"\n" + if ($verbose > 2); + } + } + } else { + error ("$file: no options"); + } + + return (\%res_to_val, \%switch_to_res); +} + +my %video_dups; + +# Returns a list of: +# "resource = default value" +# or "resource != non-default value" +# +# Also a hash of the simplified XML contents. +# +sub parse_xml($$$) { + my ($saver, $switch_to_res, $src_opts) = @_; + + my $saver_title = undef; + my $gl_p = 0; + my $file = "config/" . lc($saver) . ".xml"; + my $ofile = $file; + $file = "../hacks/$ofile" unless (-f $file); + my $body = ''; + open (my $in, '<', $file) || error ("$ofile: $!"); + while (<$in>) { $body .= $_; } + close $in; + $file =~ s@^.*/@@; + + my @result = (); + + $body =~ s@@ + + + + @gs; + + $body =~ s@@ + + + @gs; + + $body =~ s// /gsi; + + $body =~ s@(<(_description)>.*?)@{ $_ = $1; s/\n/\002/gs; $_; }@gsexi; + + $body =~ s/\s+/ /gs; + $body =~ s/ 2); + foreach (split (m/\001/, $body)) { + next if (m/^\s*$/s); + my ($type, $args) = m@^<([?/]?[-_a-z]+)\b\s*(.*)$@si; + error ("$progname: $file: unparsable: $_") unless $type; + next if ($type =~ m@^/@); + + my $ctrl = { type => $type }; + + if ($type =~ m/^( [hv]group | + \?xml | + command | + file | + xscreensaver-image | + xscreensaver-updater + )/sx) { + $ctrl = undef; + + } elsif ($type eq '_description') { + $args =~ s/\002/\n/gs; + $args =~ s@^>\s*@@s; + $args =~ s/^\n*|\s*$//gs; + $ctrl->{text} = $args; + + } elsif ($type eq 'screensaver') { + ($saver_title) = ($args =~ m/\b_label\s*=\s*\"([^\"]+)\"/s); + ($gl_p) = ($args =~ m/\bgl="?yes/s); + my $s = $saver_title; + $s =~ s/\s+//gs; + my $val = "progclass = $s"; + push @result, $val; + print STDERR "$progname: $file: name: $saver_title\n" + if ($verbose > 2); + $ctrl = undef; + + } elsif ($type eq 'video') { + error ("$file: multiple videos") if $video; + ($video) = ($args =~ m/\bhref="(.*?)"/); + error ("$file: unparsable video") unless $video; + error ("$file: unparsable video URL") + unless ($video =~ m@^https?://www\.youtube\.com/watch\?v=[^?&]+$@s); + $ctrl = undef; + + } elsif ($type eq 'select') { + $args =~ s/\s*$@@s; + while ($opt =~ s/^\s*([^\s]+)\s*=\s*"(.*?)"\s*(.*)/$3/s) { + my ($k, $v) = ($1, $2); + $item{$k} = $v; + } + + error ("unparsable XML option line: $_ [$opt]") if ($opt); + push @menu, \%item; + + my ($set) = $item{'arg-set'}; + if ($set) { + my ($set2, $val) = ($set =~ m/^(.*?) (.*)$/s); + $set = $set2 if ($set2); + my ($res) = $switch_to_res->{$set}; + error ("$file: no resource for select switch \"$set\"") unless $res; + + my ($res2, $val2) = ($res =~ m/^(.*?): (.*)$/s); + error ("$file: unparsable select resource: $res") unless $res2; + $res = $res2; + $val = $val2 unless ($val2 eq '%'); + $item{value} = $val; + + error ("$file: mismatched resources: $res vs $this_res") + if (defined($this_res) && $this_res ne $res); + $this_res = $res; + + $val = "$res != $val"; + push @result, $val; + print STDERR "$progname: $file: select: $val\n" if ($verbose > 2); + + } else { + error ("$file: multiple default options: $set") if ($unset_p); + $unset_p++; + } + } + $ctrl->{resource} = $this_res; + $ctrl->{default} = $src_opts->{$this_res}; + $ctrl->{menu} = \@menu; + + } else { + + my $rest = $args; + $rest =~ s@[/?]*>\s*$@@s; + while ($rest =~ s/^\s*([^\s]+)\s*=\s*"(.*?)"\s*(.*)/$3/s) { + my ($k, $v) = ($1, $2); + $ctrl->{$k} = $v; + } + error ("unparsable XML line: $args [$rest]") if ($rest); + + if ($type eq 'number') { + my ($arg) = $ctrl->{arg}; + my ($val) = $ctrl->{default}; + $val = '' unless defined($val); + + my $switch = $arg; + $switch =~ s/\s+.*$//; + my ($res) = $switch_to_res->{$switch}; + error ("$file: no resource for $type switch \"$arg\"") unless $res; + + $res =~ s/: \%$//; + error ("$file: unparsable value: $res") if ($res =~ m/:/); + $ctrl->{resource} = $res; + + $val = "$res = $val"; + push @result, $val; + print STDERR "$progname: $file: number: $val\n" if ($verbose > 2); + + } elsif ($type eq 'boolean') { + my ($set) = $ctrl->{'arg-set'}; + my ($unset) = $ctrl->{'arg-unset'}; + my ($arg) = $set || $unset || error ("$file: unparsable: $args"); + my ($res) = $switch_to_res->{$arg}; + error ("$file: no resource for boolean switch \"$arg\"") unless $res; + + my ($res2, $val) = ($res =~ m/^(.*?): (.*)$/s); + error ("$file: unparsable boolean resource: $res") unless $res2; + $res = $res2; + + $ctrl->{resource} = $res; + $ctrl->{convert} = 'invert' if ($val =~ m/off|false|no/i); + $ctrl->{default} = ($ctrl->{convert} ? 'true' : 'false'); + +# $val = ($set ? "$res != $val" : "$res = $val"); + $val = "$res != $val"; + push @result, $val; + print STDERR "$progname: $file: boolean: $val\n" if ($verbose > 2); + + } elsif ($type eq 'string') { + my ($arg) = $ctrl->{arg}; + + my $switch = $arg; + $switch =~ s/\s+.*$//; + my ($res) = $switch_to_res->{$switch}; + error ("$file: no resource for $type switch \"$arg\"") unless $res; + + $res =~ s/: \%$//; + error ("$file: unparsable value: $res") if ($res =~ m/:/); + $ctrl->{resource} = $res; + $ctrl->{default} = $src_opts->{$res}; + my $val = "$res = %"; + push @result, $val; + print STDERR "$progname: $file: string: $val\n" if ($verbose > 2); + + } else { + error ("$file: unknown type \"$type\" for no arg"); + } + } + + push @widgets, $ctrl if $ctrl; + } + +# error ("$file: no video") unless $video; + print STDERR "\n$file: WARNING: no video\n\n" unless $video; + + if ($video && $video_dups{$video} && + $video_dups{$video} ne $saver_title) { + print STDERR "\n$file: WARNING: $saver_title: dup video with " . + $video_dups{$video} . "\n"; + } + $video_dups{$video} = $saver_title if ($video); + + return ($saver_title, $gl_p, \@result, \@widgets); +} + + +sub check_config($) { + my ($saver) = @_; + + # kludge + return 0 if ($saver =~ m/(-helper)$/); + + my ($src_opts, $switchmap) = parse_src ($saver); + my ($saver_title, $gl_p, $xml_opts, $widgets) = + parse_xml ($saver, $switchmap, $src_opts); + + my $failures = 0; + foreach my $claim (@$xml_opts) { + my ($res, $compare, $xval) = ($claim =~ m/^(.*) (=|!=) (.*)$/s); + error ("$saver: unparsable xml claim: $claim") unless $compare; + + my $sval = $src_opts->{$res}; + if ($res =~ m/^TV|^text-mode/) { + print STDERR "$progname: $saver: OK: skipping \"$res\"\n" + if ($verbose > 1); + } elsif (!defined($sval)) { + print STDERR "$progname: $saver: $res: not in source\n"; + } elsif ($claim !~ m/ = %$/s && + ($compare eq '!=' + ? $sval eq $xval + : $sval ne $xval)) { + print STDERR "$progname: $saver: " . + "src has \"$res = $sval\", xml has \"$claim\"\n"; + $failures++; + } elsif ($verbose > 1) { + print STDERR "$progname: $saver: OK: \"$res = $sval\" vs \"$claim\"\n"; + } + } + + # Now make sure the progclass in the source and XML also matches + # the XCode target name. + # + my $obd = "../OSX/build/Debug"; + if (-d $obd) { + my $progclass = $src_opts->{progclass}; + $progclass = 'DNAlogo' if ($progclass eq 'DNALogo'); + my $f = (glob("$obd/$progclass.saver*"))[0]; + if (!$f && $progclass ne 'Flurry') { + print STDERR "$progname: $progclass.saver does not exist\n"; + $failures++; + } + } + + print STDERR "$progname: $saver: OK\n" + if ($verbose == 1 && $failures == 0); + + return $failures; +} + + +# Returns true if the two files differ (by running "cmp") +# +sub cmp_files($$) { + my ($file1, $file2) = @_; + + my @cmd = ("cmp", "-s", "$file1", "$file2"); + print STDERR "$progname: executing \"" . join(" ", @cmd) . "\"\n" + if ($verbose > 3); + + system (@cmd); + my $exit_value = $? >> 8; + my $signal_num = $? & 127; + my $dumped_core = $? & 128; + + error ("$cmd[0]: core dumped!") if ($dumped_core); + error ("$cmd[0]: signal $signal_num!") if ($signal_num); + return $exit_value; +} + + +sub diff_files($$) { + my ($file1, $file2) = @_; + + my @cmd = ("diff", + "-U1", +# "-w", + "--unidirectional-new-file", "$file1", "$file2"); + print STDERR "$progname: executing \"" . join(" ", @cmd) . "\"\n" + if ($verbose > 3); + + system (@cmd); + my $exit_value = $? >> 8; + my $signal_num = $? & 127; + my $dumped_core = $? & 128; + + error ("$cmd[0]: core dumped!") if ($dumped_core); + error ("$cmd[0]: signal $signal_num!") if ($signal_num); + return $exit_value; +} + + +# If the two files differ: +# mv file2 file1 +# else +# rm file2 +# +sub rename_or_delete($$;$) { + my ($file, $file_tmp, $suffix_msg) = @_; + + my $changed_p = cmp_files ($file, $file_tmp); + + if ($changed_p && $debug_p) { + print STDOUT "\n" . ('#' x 79) . "\n"; + diff_files ("$file", "$file_tmp"); + $changed_p = 0; + } + + if ($changed_p) { + + if (!rename ("$file_tmp", "$file")) { + unlink "$file_tmp"; + error ("mv $file_tmp $file: $!"); + } + print STDERR "$progname: wrote $file" . + ($suffix_msg ? " $suffix_msg" : "") . "\n"; + + } else { + unlink "$file_tmp" || error ("rm $file_tmp: $!\n"); + print STDERR "$file unchanged" . + ($suffix_msg ? " $suffix_msg" : "") . "\n" + if ($verbose); + print STDERR "$progname: rm $file_tmp\n" if ($verbose > 2); + } +} + + +# Write the given body to the file, but don't alter the file's +# date if the new content is the same as the existing content. +# +sub write_file_if_changed($$;$) { + my ($outfile, $body, $suffix_msg) = @_; + + my $file_tmp = "$outfile.tmp"; + open (my $out, '>', $file_tmp) || error ("$file_tmp: $!"); + (print $out $body) || error ("$file_tmp: $!"); + close $out || error ("$file_tmp: $!"); + rename_or_delete ($outfile, $file_tmp, $suffix_msg); +} + + +# Read the template file and splice in the @KEYWORDS@ in the hash. +# +sub read_template($$) { + my ($file, $subs) = @_; + my $body = ''; + open (my $in, '<', $file) || error ("$file: $!"); + while (<$in>) { $body .= $_; } + close $in; + + $body =~ s@/\*.*?\*/@@gs; # omit comments + $body =~ s@//.*$@@gm; + + foreach my $key (keys %$subs) { + my $val = $subs->{$key}; + $body =~ s/@\Q$key\E@/$val/gs; + } + + if ($body =~ m/(@[-_A-Z\d]+@)/s) { + error ("$file: unmatched: $1 [$body]"); + } + + $body =~ s/[ \t]+$//gm; + $body =~ s/(\n\n)\n+/$1/gs; + return $body; +} + + +# This is duplicated in OSX/update-info-plist.pl +# +sub munge_blurb($$$$) { + my ($filename, $name, $vers, $desc) = @_; + + $desc =~ s/^([ \t]*\n)+//s; + $desc =~ s/\s*$//s; + + # in case it's done already... + $desc =~ s@@@gs; + $desc =~ s/^.* version \d[^\n]*\n//s; + $desc =~ s/^From the XScreenSaver.*\n//m; + $desc =~ s@^https://www\.jwz\.org/xscreensaver.*\n@@m; + $desc =~ + s/\nCopyright [^ \r\n\t]+ (\d{4})(-\d{4})? (.*)\.$/\nWritten $3; $1./s; + $desc =~ s/^\n+//s; + + error ("$filename: description contains markup: $1") + if ($desc =~ m/([<>&][^<>&\s]*)/s); + error ("$filename: description contains ctl chars: $1") + if ($desc =~ m/([\000-\010\013-\037])/s); + + error ("$filename: can't extract authors") + unless ($desc =~ m@^(.*)\nWritten by[ \t]+(.+)$@s); + $desc = $1; + my $authors = $2; + $desc =~ s/\s*$//s; + + my $year = undef; + if ($authors =~ m@^(.*?)\s*[,;]\s+(\d\d\d\d)([-\s,;]+\d\d\d\d)*[.]?$@s) { + $authors = $1; + $year = $2; + } + + error ("$filename: can't extract year") unless $year; + my $cyear = 1900 + ((localtime())[5]); + $year = "$cyear" unless $year; + if ($year && ! ($year =~ m/$cyear/)) { + $year = "$year-$cyear"; + } + + $authors =~ s/[.,;\s]+$//s; + + # List me as a co-author on all of them, since I'm the one who + # did the OSX port, packaged it up, and built the executables. + # + my $curator = "Jamie Zawinski"; + if (! ($authors =~ m/$curator/si)) { + if ($authors =~ m@^(.*?),? and (.*)$@s) { + $authors = "$1, $2, and $curator"; + } else { + $authors .= " and $curator"; + } + } + + my $desc1 = ("$name, version $vers.\n\n" . # savername.xml + $desc . "\n" . + "\n" . + "From the XScreenSaver collection: " . + "https://www.jwz.org/xscreensaver/\n" . + "Copyright \302\251 $year by $authors.\n"); + + my $desc2 = ("$name $vers,\n" . # Info.plist + "\302\251 $year $authors.\n" . + #"From the XScreenSaver collection:\n" . + #"https://www.jwz.org/xscreensaver/\n" . + "\n" . + $desc . + "\n"); + + # unwrap lines, but only when it's obviously ok: leave blank lines, + # and don't unwrap if that would compress leading whitespace on a line. + # + $desc2 =~ s/^(From |https?:)/\n$1/gm; + 1 while ($desc2 =~ s/([^\s])[ \t]*\n([^\s])/$1 $2/gs); + $desc2 =~ s/\n\n(From |https?:)/\n$1/gs; + + return ($desc1, $desc2); +} + + +sub build_android(@) { + my (@savers) = @_; + + my $package = "org.jwz.xscreensaver"; + my $project_dir = "xscreensaver"; + my $xml_dir = "$project_dir/res/xml"; + my $values_dir = "$project_dir/res/values"; + my $java_dir = "$project_dir/src/org/jwz/xscreensaver/gen"; + my $gen_dir = "gen"; + + my $xml_header = "\n"; + + my $manifest = ''; + my $daydream_java = ''; + my $settings_java = ''; + my $wallpaper_java = ''; + my $fntable_h2 = ''; + my $fntable_h3 = ''; + my $arrays = ''; + my $strings = ''; + my %write_files; + my %string_dups; + + my $vers; + { + my $file = "../utils/version.h"; + my $body = ''; + open (my $in, '<', $file) || error ("$file: $!"); + while (<$in>) { $body .= $_; } + close $in; + ($vers) = ($body =~ m@ (\d+\.[0-9a-z]+) @s); + error ("$file: no version number") unless $vers; + } + + + foreach my $saver (@savers) { + next if ($saver =~ m/(-helper)$/); + $saver = 'rdbomb' if ($saver eq 'rd-bomb'); + + my ($src_opts, $switchmap) = parse_src ($saver); + my ($saver_title, $gl_p, $xml_opts, $widgets) = + parse_xml ($saver, $switchmap, $src_opts); + + my $saver_class = "${saver_title}"; + $saver_class =~ s/\s+//gs; + $saver_class =~ s/^([a-z])/\U$1/gs; # upcase first letter + + $saver_title =~ s/(.[a-z])([A-Z\d])/$1 $2/gs; # Spaces in InterCaps + $saver_title =~ s/^(GL|RD)[- ]?(.)/$1 \U$2/gs; # Space after "GL" + $saver_title =~ s/^Apple ?2$/Apple ][/gs; # "Apple ][" + $saver_title =~ s/(m)oe(bius)/$1ö$2/gsi; # ö + $saver_title =~ s/(moir)e/$1é/gsi; # é + $saver_title =~ s/^([a-z])/\U$1/s; # "M6502" for sorting + + my $settings = ''; + + my $localize0 = sub($$) { + my ($key, $string) = @_; + $string =~ s@([\\\"\'])@\\$1@gs; # backslashify + $string =~ s@\n@\\n@gs; # quote newlines + $key =~ s@[^a-z\d_]+@_@gsi; # illegal characters + + my $old = $string_dups{$key}; + error ("dup string: $key: \"$old\" != \"$string\"") + if (defined($old) && $old ne $string); + $string_dups{$key} = $string; + + my $fmt = ($string =~ m/%/ ? ' formatted="false"' : ''); + $strings .= "$string\n" + unless defined($old); + return "\@string/$key"; + }; + + $localize0->('app_name', 'XScreenSaver'); + + $settings .= ("('reset_to_defaults', 'Reset to defaults') . + "\"\n" . + " />\n"); + + my $daydream_desc = ''; + foreach my $widget (@$widgets) { + my $type = $widget->{type}; + my $rsrc = $widget->{resource}; + my $label = $widget->{_label}; + my $def = $widget->{default}; + my $invert_p = (($widget->{convert} || '') eq 'invert'); + + my $key = "${saver}_$rsrc" if $rsrc; + + #### The menus don't actually have titles on X11 or Cocoa... + $label = $widget->{resource} unless $label; + + my $localize = sub($;$) { + my ($string, $suf) = @_; + $suf = 'title' unless $suf; + return $localize0->("${saver}_${rsrc}_${suf}", $string); + }; + + if ($type eq 'slider' || $type eq 'spinbutton') { + + my $low = $widget->{low}; + my $high = $widget->{high}; + my $float_p = $low =~ m/[.]/; + my $low_label = $widget->{'_low-label'}; + my $high_label = $widget->{'_high-label'}; + + $low_label = $low unless defined($low_label); + $high_label = $high unless defined($high_label); + + ($low, $high) = ($high, $low) + if (($widget->{convert} || '') eq 'invert'); + + $settings .= + ("<$package.SliderPreference\n" . + " android:layout=\"\@layout/slider_preference\"\n" . + " android:key=\"${key}\"\n" . + " android:title=\"" . $localize->($label) . "\"\n" . + " android:defaultValue=\"$def\"\n" . + " low=\"$low\"\n" . + " high=\"$high\"\n" . + " lowLabel=\"" . $localize->($low_label, 'low_label') . "\"\n" . + " highLabel=\"" . $localize->($high_label, 'high_label') . "\"\n" . + " integral=\"" .($float_p ? 'false' : 'true'). "\" />\n"); + + } elsif ($type eq 'boolean') { + + my $def = ($invert_p ? 'true' : 'false'); + $settings .= + ("($label) . "\"\n" . + " android:defaultValue=\"$def\" />\n"); + + } elsif ($type eq 'select') { + + $label =~ s/^(.)/\U$1/s; # upcase first letter of menu title + $label =~ s/[-_]/ /gs; + $label =~ s/([a-z])([A-Z])/$1 $2/gs; + $def = '' unless defined ($def); + $settings .= + ("($label, 'menu') . "\"\n" . + " android:entries=\"\@array/${key}_entries\"\n" . + " android:defaultValue=\"$def\"\n" . + " android:entryValues=\"\@array/${key}_values\" />\n"); + + my $a1 = ''; + foreach my $item (@{$widget->{menu}}) { + my $val = $item->{value}; + if (! defined($val)) { + $val = $src_opts->{$widget->{resource}}; + error ("$saver: no default resource in option menu " . + $item->{_label}) + unless defined($val); + } + $val =~ s@([\\\"\'])@\\$1@gs; # backslashify + $a1 .= " $val\n"; + } + + my $a2 = ''; + foreach my $item (@{$widget->{menu}}) { + my $val = $item->{value}; + $val = $src_opts->{$widget->{resource}} unless defined($val); + $a2 .= (" " . $localize->($item->{_label}, $val) . + "\n"); + } + + my $fmt1 = ($a1 =~ m/%/ ? ' formatted="false"' : ''); + my $fmt2 = ($a2 =~ m/%/ ? ' formatted="false"' : ''); + $arrays .= ("\n" . + $a1 . + "\n" . + "\n" . + $a2 . + "\n"); + + } elsif ($type eq 'string') { + + $def =~ s/&/&/gs; + $settings .= + ("($label) . "\"\n" . + " android:defaultValue=\"$def\" />\n"); + + } elsif ($type eq 'file') { + + } elsif ($type eq '_description') { + + $type = 'description'; + $rsrc = $type; + my $desc = $widget->{text}; + (undef, $desc) = munge_blurb ($saver, $saver_title, $vers, $desc); + + # Lose the Wikipedia URLs. + $desc =~ s@https?:.*?\b(wikipedia|mathworld)\b[^\s]+[ \t]*\n?@@gm; + $desc =~ s/(\n\n)\n+/$1/s; + $desc =~ s/\s*$/\n\n\n/s; + + $daydream_desc = $desc; + + my ($year) = ($daydream_desc =~ m/\b((19|20)\d\d)\b/s); + error ("$saver: no year") unless $year; + $daydream_desc =~ s/^.*?\n\n//gs; + $daydream_desc =~ s/\n.*$//gs; + $daydream_desc = "$year: $daydream_desc"; + $daydream_desc =~ s/^(.{72}).+$/$1.../s; + + $settings .= + ("($desc) . "\">\n" . + " \n" . + "\n"); + + } else { + error ("unhandled type: $type"); + } + } + + my $heading = "XScreenSaver: $saver_title"; + + $settings =~ s/^/ /gm; + $settings = ($xml_header . + "("${saver}_settings_title", $heading) . "\">\n" . + $settings . + "\n"); + + my $saver_underscore = $saver; + $saver_underscore =~ s/-/_/g; + $write_files{"$xml_dir/${saver_underscore}_settings.xml"} = $settings; + + $manifest .= ("("${saver_underscore}_saver_title", + $saver_title) . + "\"\n" . + " android:summary=\"" . + $localize0->("${saver_underscore}_saver_desc", + $daydream_desc) . "\"\n" . + " android:name=\".gen.Daydream\$$saver_class\"\n" . + " android:permission=\"android.permission" . + ".BIND_DREAM_SERVICE\"\n" . + " android:exported=\"true\"\n" . + " android:icon=\"\@drawable/${saver_underscore}\">\n" . + " \n" . + " \n" . + " \n" . + " \n" . + " \n" . + "\n" . + "("${saver_underscore}_saver_title", + $saver_title) . + "\"\n" . + " android:summary=\"" . + $localize0->("${saver_underscore}_saver_desc", + $daydream_desc) . "\"\n" . + " android:name=\".gen.Wallpaper\$$saver_class\"\n" . + " android:permission=\"android.permission" . + ".BIND_WALLPAPER\">\n" . + " \n" . + " \n" . + " \n" . # TODO: Is the DEFAULT category needed? + " \n" . + " \n" . + "\n" . + "("${saver}_settings_title", $heading) . "\"\n" . + " android:name=\"$package.gen.Settings\$$saver_class\"\n" . + " android:exported=\"true\">\n" . + "\n" + ); + + my $dream = ("\n"); + $write_files{"$xml_dir/${saver_underscore}_dream.xml"} = $dream; + + my $wallpaper = ("\n"); + $write_files{"$xml_dir/${saver_underscore}_wallpaper.xml"} = $wallpaper; + + $daydream_java .= + (" public static class $saver_class extends org.jwz.xscreensaver.Daydream {\n" . + " }\n" . + "\n"); + + $wallpaper_java .= + (" public static class $saver_class extends org.jwz.xscreensaver.Wallpaper {\n" . + " }\n" . + "\n"); + + $settings_java .= + (" public static class $saver_class extends org.jwz.xscreensaver.Settings\n" . + " implements SharedPreferences.OnSharedPreferenceChangeListener {\n" . + " }\n" . + "\n"); + + $fntable_h2 .= ",\n " if $fntable_h2 ne ''; + $fntable_h3 .= ",\n " if $fntable_h3 ne ''; + + $fntable_h2 .= "${saver}_xscreensaver_function_table"; + $fntable_h3 .= "{\"${saver}\", &${saver}_xscreensaver_function_table}"; + } + + $arrays =~ s/^/ /gm; + $arrays = ($xml_header . + "\n" . + $arrays . + "\n"); + + $strings =~ s/^/ /gm; + $strings = ($xml_header . + "\n" . + $strings . + "\n"); + + $manifest .= "\n"; + + $manifest .= ("\n" . + " \n" . + " \n" . + " \n" . + " \n" . + " \n" . + " \n" . + " \n" . + " \n" . + " \n" . + "\n"); + + + $manifest .= ("\n" . + " \n" . + " \n" . + " \n" . + " \n" . + " \n" . + " \n" . + " \n" . + " \n" . + " \n" . + "\n"); + + + + + # Android wants this to be an int + my $versb = $vers; + $versb =~ s/^(\d+)\.(\d+).*$/{ $1 * 10000 + $2 * 100 }/sex; + $versb++ if ($versb == 53500); # Herp derp + + $manifest =~ s/^/ /gm; + $manifest = ($xml_header . + "\n" . + + " \n" . + + " \n" . + + " \n" . + + " \n" . + + " \n" . + " \n" . + + " \n" . + $manifest . + " \n" . + "\n"); + + $daydream_java = ("package org.jwz.xscreensaver.gen;\n" . + "\n" . + "import org.jwz.xscreensaver.jwxyz;\n" . + "\n" . + "public class Daydream {\n" . + $daydream_java . + "}\n"); + + $wallpaper_java = ("package org.jwz.xscreensaver.gen;\n" . + "\n" . + "import org.jwz.xscreensaver.jwxyz;\n" . + "\n" . + "public class Wallpaper {\n" . + $wallpaper_java . + "}\n"); + + $settings_java = ("package org.jwz.xscreensaver.gen;\n" . + "\n" . + "import android.content.SharedPreferences;\n" . + "\n" . + "public class Settings {\n" . + $settings_java . + "}\n"); + + $write_files{"$project_dir/AndroidManifest.xml"} = $manifest; + $write_files{"$values_dir/settings.xml"} = $arrays; + $write_files{"$values_dir/strings.xml"} = $strings; + $write_files{"$java_dir/Daydream.java"} = $daydream_java; + $write_files{"$java_dir/Wallpaper.java"} = $wallpaper_java; + $write_files{"$java_dir/Settings.java"} = $settings_java; + + my $fntable_h = ("extern struct xscreensaver_function_table\n" . + " " . $fntable_h2 . ";\n" . + "\n" . + "static const struct function_table_entry" . + " function_table[] = {\n" . + " " . $fntable_h3 . "\n" . + "};\n"); + $write_files{"$gen_dir/function-table.h"} = $fntable_h; + + + $write_files{"$values_dir/attrs.xml"} = + # This file doesn't actually have any substitutions in it, so it could + # just be static, somewhere... + # SliderPreference.java refers to this via "R.styleable.SliderPreference". + ("\n" . + "\n" . + " \n" . + " \n" . + " \n" . + "\n"); + + + foreach my $file (sort keys %write_files) { + my ($dir) = ($file =~ m@^(.*)/[^/]*$@s); + system ("mkdir", "-p", $dir) if (! -d $dir && !$debug_p); + my $body = $write_files{$file}; + $body = "// Generated by $progname\n$body" + if ($file =~ m/\.(java|[chm])$/s); + write_file_if_changed ($file, $body); + } + + # Unlink any .xml files from a previous run that shouldn't be there: + # if a hack is removed from $ANDROID_HACKS in android/Makefile but + # the old XML files remain behind, the build blows up. + # + foreach my $dd ($xml_dir, $gen_dir, $java_dir) { + opendir (my $dirp, $dd) || error ("$dd: $!"); + my @files = readdir ($dirp); + closedir $dirp; + foreach my $f (sort @files) { + next if ($f eq '.' || $f eq '..'); + $f = "$dd/$f"; + next if (defined ($write_files{$f})); + if ($f =~ m/_(settings|wallpaper|dream)\.xml$/s || + $f =~ m/(Settings|Daydream)\.java$/s) { + print STDERR "$progname: rm $f\n"; + unlink ($f) unless ($debug_p); + } else { + print STDERR "$progname: warning: unrecognised file: $f\n"; + } + } + } +} + + +sub error($) { + my ($err) = @_; + print STDERR "$progname: $err\n"; + exit 1; +} + +sub usage() { + print STDERR "usage: $progname [--verbose] [--debug]" . + " [--build-android] files ...\n"; + exit 1; +} + +sub main() { + my $android_p = 0; + my @files = (); + while ($#ARGV >= 0) { + $_ = shift @ARGV; + if (m/^--?verbose$/) { $verbose++; } + elsif (m/^-v+$/) { $verbose += length($_)-1; } + elsif (m/^--?debug$/s) { $debug_p++; } + elsif (m/^--?build-android$/s) { $android_p++; } + elsif (m/^-./) { usage; } + else { push @files, $_; } +# else { usage; } + } + + usage unless ($#files >= 0); + my $failures = 0; + foreach my $file (@files) { + $failures += check_config ($file); + } + + build_android (@files) if ($android_p); + + exit ($failures); +} + +main(); diff --git a/hacks/cloudlife.c b/hacks/cloudlife.c new file mode 100644 index 0000000..4b65f9e --- /dev/null +++ b/hacks/cloudlife.c @@ -0,0 +1,428 @@ +/* cloudlife by Don Marti + * + * Based on Conway's Life, but with one rule change to make it a better + * screensaver: cells have a max age. + * + * When a cell exceeds the max age, it counts as 3 for populating the next + * generation. This makes long-lived formations explode instead of just + * sitting there burning a hole in your screen. + * + * Cloudlife only draws one pixel of each cell per tick, whether the cell is + * alive or dead. So gliders look like little comets. + + * 20 May 2003 -- now includes color cycling and a man page. + + * Based on several examples from the hacks directory of: + + * xscreensaver, Copyright (c) 1997, 1998, 2002 Jamie Zawinski + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +#include "screenhack.h" + +#ifndef MAX_WIDTH +#include +#define MAX_WIDTH SHRT_MAX +#endif + +#ifdef TIME_ME +#include +#endif + +/* this program goes faster if some functions are inline. The following is + * borrowed from ifs.c */ +#if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus) +#undef inline +#define inline /* */ +#endif + +struct field { + unsigned int height; + unsigned int width; + unsigned int max_age; + unsigned int cell_size; + unsigned char *cells; + unsigned char *new_cells; +}; + +struct state { + Display *dpy; + Window window; + +#ifdef TIME_ME + time_t start_time; +#endif + + unsigned int cycles; + unsigned int colorindex; /* which color in the colormap are we on */ + unsigned int colortimer; /* when this reaches 0, cycle to next color */ + + int cycle_delay; + int cycle_colors; + int ncolors; + int density; + + GC fgc, bgc; + XGCValues gcv; + XWindowAttributes xgwa; + XColor *colors; + + struct field *field; + + XPoint fg_points[MAX_WIDTH]; + XPoint bg_points[MAX_WIDTH]; +}; + + +static void +*xrealloc(void *p, size_t size) +{ + void *ret; + if ((ret = realloc(p, size)) == NULL) { + fprintf(stderr, "%s: out of memory\n", progname); + exit(1); + } + return ret; +} + +static struct field * +init_field(struct state *st) +{ + struct field *f = xrealloc(NULL, sizeof(struct field)); + f->height = 0; + f->width = 0; + f->cell_size = get_integer_resource(st->dpy, "cellSize", "Integer"); + f->max_age = get_integer_resource(st->dpy, "maxAge", "Integer"); + + if (f->max_age > 255) { + fprintf (stderr, "%s: max-age must be < 256 (not %d)\n", progname, + f->max_age); + exit (1); + } + + f->cells = NULL; + f->new_cells = NULL; + return f; +} + +static void +resize_field(struct field * f, unsigned int w, unsigned int h) +{ + int s = w * h * sizeof(unsigned char); + f->width = w; + f->height = h; + + f->cells = xrealloc(f->cells, s); + f->new_cells = xrealloc(f->new_cells, s); + memset(f->cells, 0, s); + memset(f->new_cells, 0, s); +} + +static inline unsigned char +*cell_at(struct field * f, unsigned int x, unsigned int y) +{ + return (f->cells + x * sizeof(unsigned char) + + y * f->width * sizeof(unsigned char)); +} + +static inline unsigned char +*new_cell_at(struct field * f, unsigned int x, unsigned int y) +{ + return (f->new_cells + x * sizeof(unsigned char) + + y * f->width * sizeof(unsigned char)); +} + +static void +draw_field(struct state *st, struct field * f) +{ + unsigned int x, y; + unsigned int rx, ry = 0; /* random amount to offset the dot */ + unsigned int size = 1 << f->cell_size; + unsigned int mask = size - 1; + unsigned int fg_count, bg_count; + + /* columns 0 and width-1 are off screen and not drawn. */ + for (y = 1; y < f->height - 1; y++) { + fg_count = 0; + bg_count = 0; + + /* rows 0 and height-1 are off screen and not drawn. */ + for (x = 1; x < f->width - 1; x++) { + rx = random(); + ry = rx >> f->cell_size; + rx &= mask; + ry &= mask; + + if (*cell_at(f, x, y)) { + st->fg_points[fg_count].x = (short) x *size - rx - 1; + st->fg_points[fg_count].y = (short) y *size - ry - 1; + fg_count++; + } else { + st->bg_points[bg_count].x = (short) x *size - rx - 1; + st->bg_points[bg_count].y = (short) y *size - ry - 1; + bg_count++; + } + } + XDrawPoints(st->dpy, st->window, st->fgc, st->fg_points, fg_count, + CoordModeOrigin); + XDrawPoints(st->dpy, st->window, st->bgc, st->bg_points, bg_count, + CoordModeOrigin); + } +} + +static inline unsigned int +cell_value(unsigned char c, unsigned int age) +{ + if (!c) { + return 0; + } else if (c > age) { + return (3); + } else { + return (1); + } +} + +static inline unsigned int +is_alive(struct field * f, unsigned int x, unsigned int y) +{ + unsigned int count; + unsigned int i, j; + unsigned char *p; + + count = 0; + + for (i = x - 1; i <= x + 1; i++) { + for (j = y - 1; j <= y + 1; j++) { + if (y != j || x != i) { + count += cell_value(*cell_at(f, i, j), f->max_age); + } + } + } + + p = cell_at(f, x, y); + if (*p) { + if (count == 2 || count == 3) { + return ((*p) + 1); + } else { + return (0); + } + } else { + if (count == 3) { + return (1); + } else { + return (0); + } + } +} + +static unsigned int +do_tick(struct field * f) +{ + unsigned int x, y; + unsigned int count = 0; + for (x = 1; x < f->width - 1; x++) { + for (y = 1; y < f->height - 1; y++) { + count += *new_cell_at(f, x, y) = is_alive(f, x, y); + } + } + memcpy(f->cells, f->new_cells, f->width * f->height * + sizeof(unsigned char)); + return count; +} + + +static unsigned int +random_cell(unsigned int p) +{ + int r = random() & 0xff; + + if (r < p) { + return (1); + } else { + return (0); + } +} + +static void +populate_field(struct field * f, unsigned int p) +{ + unsigned int x, y; + + for (x = 0; x < f->width; x++) { + for (y = 0; y < f->height; y++) { + *cell_at(f, x, y) = random_cell(p); + } + } +} + +static void +populate_edges(struct field * f, unsigned int p) +{ + unsigned int i; + + for (i = f->width; i--;) { + *cell_at(f, i, 0) = random_cell(p); + *cell_at(f, i, f->height - 1) = random_cell(p); + } + + for (i = f->height; i--;) { + *cell_at(f, f->width - 1, i) = random_cell(p); + *cell_at(f, 0, i) = random_cell(p); + } +} + +static void * +cloudlife_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + Bool tmp = True; + + st->dpy = dpy; + st->window = window; + st->field = init_field(st); + +#ifdef TIME_ME + st->start_time = time(NULL); +#endif + + st->cycle_delay = get_integer_resource(st->dpy, "cycleDelay", "Integer"); + st->cycle_colors = get_integer_resource(st->dpy, "cycleColors", "Integer"); + st->ncolors = get_integer_resource(st->dpy, "ncolors", "Integer"); + st->density = (get_integer_resource(st->dpy, "initialDensity", "Integer") + % 100 * 256)/100; + + XGetWindowAttributes(st->dpy, st->window, &st->xgwa); + + if (st->cycle_colors) { + st->colors = (XColor *) xrealloc(st->colors, sizeof(XColor) * (st->ncolors+1)); + make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, + st->xgwa.colormap, st->colors, &st->ncolors, + True, &tmp, True); + } + + st->gcv.foreground = get_pixel_resource(st->dpy, st->xgwa.colormap, + "foreground", "Foreground"); + st->fgc = XCreateGC(st->dpy, st->window, GCForeground, &st->gcv); + + st->gcv.foreground = get_pixel_resource(st->dpy, st->xgwa.colormap, + "background", "Background"); + st->bgc = XCreateGC(st->dpy, st->window, GCForeground, &st->gcv); + + return st; +} + +static unsigned long +cloudlife_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + + if (st->cycle_colors) { + if (st->colortimer == 0) { + st->colortimer = st->cycle_colors; + if( st->colorindex == 0 ) + st->colorindex = st->ncolors; + st->colorindex--; + XSetForeground(st->dpy, st->fgc, st->colors[st->colorindex].pixel); + } + st->colortimer--; + } + + XGetWindowAttributes(st->dpy, st->window, &st->xgwa); + if (st->field->height != st->xgwa.height / (1 << st->field->cell_size) + 2 || + st->field->width != st->xgwa.width / (1 << st->field->cell_size) + 2) { + + resize_field(st->field, st->xgwa.width / (1 << st->field->cell_size) + 2, + st->xgwa.height / (1 << st->field->cell_size) + 2); + populate_field(st->field, st->density); + } + + draw_field(st, st->field); + + if (do_tick(st->field) < (st->field->height + st->field->width) / 4) { + populate_field(st->field, st->density); + } + + if (st->cycles % (st->field->max_age /2) == 0) { + populate_edges(st->field, st->density); + do_tick(st->field); + populate_edges(st->field, 0); + } + + st->cycles++; + +#ifdef TIME_ME + if (st->cycles % st->field->max_age == 0) { + printf("%g s.\n", + ((time(NULL) - st->start_time) * 1000.0) / st->cycles); + } +#endif + + return (st->cycle_delay); +} + + +static void +cloudlife_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +static Bool +cloudlife_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + struct state *st = (struct state *) closure; + if (screenhack_event_helper (dpy, window, event)) + { + XClearWindow (dpy, window); + st->cycles = 0; + st->field = init_field(st); + return True; + } + return False; +} + +static void +cloudlife_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + + +static const char *cloudlife_defaults[] = { + ".background: black", + ".foreground: blue", + "*fpsSolid: true", + "*cycleDelay: 25000", + "*cycleColors: 2", + "*ncolors: 64", + "*maxAge: 64", + "*initialDensity: 30", + "*cellSize: 3", +#ifdef HAVE_MOBILE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec cloudlife_options[] = { + {"-background", ".background", XrmoptionSepArg, 0}, + {"-foreground", ".foreground", XrmoptionSepArg, 0}, + {"-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0}, + {"-cycle-colors", ".cycleColors", XrmoptionSepArg, 0}, + {"-ncolors", ".ncolors", XrmoptionSepArg, 0}, + {"-cell-size", ".cellSize", XrmoptionSepArg, 0}, + {"-initial-density", ".initialDensity", XrmoptionSepArg, 0}, + {"-max-age", ".maxAge", XrmoptionSepArg, 0}, + {0, 0, 0, 0} +}; + + +XSCREENSAVER_MODULE ("CloudLife", cloudlife) diff --git a/hacks/cloudlife.man b/hacks/cloudlife.man new file mode 100644 index 0000000..35eae12 --- /dev/null +++ b/hacks/cloudlife.man @@ -0,0 +1,87 @@ +.TH XScreenSaver 6 "20-May-2003" "X Version 11" +.SH NAME +cloudlife - a cellular automaton based on Conway's Life +.SH SYNOPSIS +.B cloudlife +[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install] [\-visual \fIvisual\fP] [\-ncolors \fIinteger\fP] [\-cycle-delay \fImicroseconds\fP] [\-cycle-colors \fIinteger\fP][\-cell-size \fIinteger\fP] [\-initial-density \fIinteger\fP] [\-max-age \fIinteger\fP] + +[\-fps] +.SH DESCRIPTION +The \fIcloudlife\fP program draws a cellular +automaton based on Conway's Life, except that +cells have a maximum age, and only one pixel per +cell is drawn every tick. +.SH OPTIONS +.I cloudlife +accepts the following options: +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-mono +If on a color display, pretend we're on a monochrome display. +.TP 8 +.B \-install +Install a private colormap for the window. +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-cycle-delay \fIinteger\fP +Time in microseconds to sleep between ticks. Default 25000. +.TP 8 +.B \-cycle-colors \fIinteger\fP +How many ticks should elapse between cycling colors. 0 to disable +color cycling. Default 2. +.TP 8 +.B \-ncolors \fIinteger\fP +How many colors should be used (if possible). Default 64. +The colors are chosen randomly. +.TP 8 +.B \-cell-size \fIinteger\fP +Size of each cell, in powers of 2. Default 3 (8-pixel cells). +.TP 8 +.B \-initial-density \fIinteger\fP +Percentage of cells that are alive at start and when the +field is repopulated. Default 30. +.TP 8 +.B \-max-age \fIinteger\fP +Maximum age for a cell. Default 64. +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1), +.BR xlock (1) +.SH COPYRIGHT + +Copyright \(co 2003 by Don Marti. Based on +examples from the hacks directory of xscreensaver, +Copyright (c) 1997, 1998, 2002 Jamie Zawinski + + +This man page based on the man page of sierpinski, +Copyright \(co 1996 by Desmond Daignault. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. +.SH AUTHOR +Don Marti 20 May 2003. + diff --git a/hacks/compass.c b/hacks/compass.c new file mode 100644 index 0000000..1dc1d3e --- /dev/null +++ b/hacks/compass.c @@ -0,0 +1,986 @@ +/* xscreensaver, Copyright (c) 1999-2018 Jamie Zawinski + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +#include +#include "screenhack.h" + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION +# include "xdbe.h" +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + +#define countof(x) (sizeof(x)/sizeof(*(x))) +#define ABS(x) ((x)<0?-(x):(x)) +#define MAX(x,y) ((x)<(y)?(y):(x)) +#define MIN(x,y) ((x)>(y)?(y):(x)) +#define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n)))) +#define RANDSIGN() ((random() & 1) ? 1 : -1) + +struct state { + Display *dpy; + Window window; + + int delay; + Bool dbuf; + struct disc *discs[4]; + int x, y, size, size2; + GC ptr_gc; + GC erase_gc; + XWindowAttributes xgwa; + Pixmap b, ba, bb; /* double-buffer to reduce flicker */ +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + XdbeBackBuffer backb; +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ +}; + + + +struct disc { + int theta; /* 0 - 360*64 */ + int velocity; + int acceleration; + int limit; + GC gc; + void (*draw) (struct state *, Drawable, struct disc *, + int x, int y, int radius); +}; + + +static void +draw_letters (struct state *st, Drawable d, struct disc *disc, + int x, int y, int radius) +{ + XPoint points[50]; + double th2 = 2 * M_PI * (disc->theta / ((double) 360*64)); + double th; + + /* W */ + + th = th2; + + points[0].x = x + radius * 0.8 * cos(th - 0.07); + points[0].y = y + radius * 0.8 * sin(th - 0.07); + + points[1].x = x + radius * 0.7 * cos(th - 0.05); + points[1].y = y + radius * 0.7 * sin(th - 0.05); + + points[2].x = x + radius * 0.78 * cos(th); + points[2].y = y + radius * 0.78 * sin(th); + + points[3].x = x + radius * 0.7 * cos(th + 0.05); + points[3].y = y + radius * 0.7 * sin(th + 0.05); + + points[4].x = x + radius * 0.8 * cos(th + 0.07); + points[4].y = y + radius * 0.8 * sin(th + 0.07); + + XDrawLines (st->dpy, d, disc->gc, points, 5, CoordModeOrigin); + + /* 30 (1) */ + + th = th2 + (2 * M_PI * 0.08333); + + points[0].x = x + radius * 0.78 * cos(th - 0.13); + points[0].y = y + radius * 0.78 * sin(th - 0.13); + + points[1].x = x + radius * 0.8 * cos(th - 0.08); + points[1].y = y + radius * 0.8 * sin(th - 0.08); + + points[2].x = x + radius * 0.78 * cos(th - 0.03); + points[2].y = y + radius * 0.78 * sin(th - 0.03); + + points[3].x = x + radius * 0.76 * cos(th - 0.03); + points[3].y = y + radius * 0.76 * sin(th - 0.03); + + points[4].x = x + radius * 0.75 * cos(th - 0.08); + points[4].y = y + radius * 0.75 * sin(th - 0.08); + + points[5].x = x + radius * 0.74 * cos(th - 0.03); + points[5].y = y + radius * 0.74 * sin(th - 0.03); + + points[6].x = x + radius * 0.72 * cos(th - 0.03); + points[6].y = y + radius * 0.72 * sin(th - 0.03); + + points[7].x = x + radius * 0.7 * cos(th - 0.08); + points[7].y = y + radius * 0.7 * sin(th - 0.08); + + points[8].x = x + radius * 0.72 * cos(th - 0.13); + points[8].y = y + radius * 0.72 * sin(th - 0.13); + + XDrawLines (st->dpy, d, disc->gc, points, 9, CoordModeOrigin); + + /* 30 (2) */ + + points[0].x = x + radius * 0.78 * cos(th + 0.03); + points[0].y = y + radius * 0.78 * sin(th + 0.03); + + points[1].x = x + radius * 0.8 * cos(th + 0.08); + points[1].y = y + radius * 0.8 * sin(th + 0.08); + + points[2].x = x + radius * 0.78 * cos(th + 0.13); + points[2].y = y + radius * 0.78 * sin(th + 0.13); + + points[3].x = x + radius * 0.72 * cos(th + 0.13); + points[3].y = y + radius * 0.72 * sin(th + 0.13); + + points[4].x = x + radius * 0.7 * cos(th + 0.08); + points[4].y = y + radius * 0.7 * sin(th + 0.08); + + points[5].x = x + radius * 0.72 * cos(th + 0.03); + points[5].y = y + radius * 0.72 * sin(th + 0.03); + + points[6] = points[0]; + + XDrawLines (st->dpy, d, disc->gc, points, 7, CoordModeOrigin); + + /* 33 (1) */ + + th = th2 + (2 * M_PI * 0.16666); + + points[0].x = x + radius * 0.78 * cos(th - 0.13); + points[0].y = y + radius * 0.78 * sin(th - 0.13); + + points[1].x = x + radius * 0.8 * cos(th - 0.08); + points[1].y = y + radius * 0.8 * sin(th - 0.08); + + points[2].x = x + radius * 0.78 * cos(th - 0.03); + points[2].y = y + radius * 0.78 * sin(th - 0.03); + + points[3].x = x + radius * 0.76 * cos(th - 0.03); + points[3].y = y + radius * 0.76 * sin(th - 0.03); + + points[4].x = x + radius * 0.75 * cos(th - 0.08); + points[4].y = y + radius * 0.75 * sin(th - 0.08); + + points[5].x = x + radius * 0.74 * cos(th - 0.03); + points[5].y = y + radius * 0.74 * sin(th - 0.03); + + points[6].x = x + radius * 0.72 * cos(th - 0.03); + points[6].y = y + radius * 0.72 * sin(th - 0.03); + + points[7].x = x + radius * 0.7 * cos(th - 0.08); + points[7].y = y + radius * 0.7 * sin(th - 0.08); + + points[8].x = x + radius * 0.72 * cos(th - 0.13); + points[8].y = y + radius * 0.72 * sin(th - 0.13); + + XDrawLines (st->dpy, d, disc->gc, points, 9, CoordModeOrigin); + + /* 33 (2) */ + + points[0].x = x + radius * 0.78 * cos(th + 0.03); + points[0].y = y + radius * 0.78 * sin(th + 0.03); + + points[1].x = x + radius * 0.8 * cos(th + 0.08); + points[1].y = y + radius * 0.8 * sin(th + 0.08); + + points[2].x = x + radius * 0.78 * cos(th + 0.13); + points[2].y = y + radius * 0.78 * sin(th + 0.13); + + points[3].x = x + radius * 0.76 * cos(th + 0.13); + points[3].y = y + radius * 0.76 * sin(th + 0.13); + + points[4].x = x + radius * 0.75 * cos(th + 0.08); + points[4].y = y + radius * 0.75 * sin(th + 0.08); + + points[5].x = x + radius * 0.74 * cos(th + 0.13); + points[5].y = y + radius * 0.74 * sin(th + 0.13); + + points[6].x = x + radius * 0.72 * cos(th + 0.13); + points[6].y = y + radius * 0.72 * sin(th + 0.13); + + points[7].x = x + radius * 0.7 * cos(th + 0.08); + points[7].y = y + radius * 0.7 * sin(th + 0.08); + + points[8].x = x + radius * 0.72 * cos(th + 0.03); + points[8].y = y + radius * 0.72 * sin(th + 0.03); + + XDrawLines (st->dpy, d, disc->gc, points, 9, CoordModeOrigin); + + /* N */ + + th = th2 + (2 * M_PI * 0.25); + + points[0].x = x + radius * 0.7 * cos(th - 0.05); + points[0].y = y + radius * 0.7 * sin(th - 0.05); + + points[1].x = x + radius * 0.8 * cos(th - 0.05); + points[1].y = y + radius * 0.8 * sin(th - 0.05); + + points[2].x = x + radius * 0.7 * cos(th + 0.05); + points[2].y = y + radius * 0.7 * sin(th + 0.05); + + points[3].x = x + radius * 0.8 * cos(th + 0.05); + points[3].y = y + radius * 0.8 * sin(th + 0.05); + + XDrawLines (st->dpy, d, disc->gc, points, 4, CoordModeOrigin); + + /* 3 */ + + th = th2 + (2 * M_PI * 0.33333); + + points[0].x = x + radius * 0.78 * cos(th - 0.05); + points[0].y = y + radius * 0.78 * sin(th - 0.05); + + points[1].x = x + radius * 0.8 * cos(th); + points[1].y = y + radius * 0.8 * sin(th); + + points[2].x = x + radius * 0.78 * cos(th + 0.05); + points[2].y = y + radius * 0.78 * sin(th + 0.05); + + points[3].x = x + radius * 0.76 * cos(th + 0.05); + points[3].y = y + radius * 0.76 * sin(th + 0.05); + + points[4].x = x + radius * 0.75 * cos(th); + points[4].y = y + radius * 0.75 * sin(th); + + points[5].x = x + radius * 0.74 * cos(th + 0.05); + points[5].y = y + radius * 0.74 * sin(th + 0.05); + + points[6].x = x + radius * 0.72 * cos(th + 0.05); + points[6].y = y + radius * 0.72 * sin(th + 0.05); + + points[7].x = x + radius * 0.7 * cos(th); + points[7].y = y + radius * 0.7 * sin(th); + + points[8].x = x + radius * 0.72 * cos(th - 0.05); + points[8].y = y + radius * 0.72 * sin(th - 0.05); + + XDrawLines (st->dpy, d, disc->gc, points, 9, CoordModeOrigin); + + /* 6 */ + + th = th2 + (2 * M_PI * 0.41666); + + points[0].x = x + radius * 0.78 * cos(th + 0.05); + points[0].y = y + radius * 0.78 * sin(th + 0.05); + + points[1].x = x + radius * 0.8 * cos(th); + points[1].y = y + radius * 0.8 * sin(th); + + points[2].x = x + radius * 0.78 * cos(th - 0.05); + points[2].y = y + radius * 0.78 * sin(th - 0.05); + + points[3].x = x + radius * 0.72 * cos(th - 0.05); + points[3].y = y + radius * 0.72 * sin(th - 0.05); + + points[4].x = x + radius * 0.7 * cos(th); + points[4].y = y + radius * 0.7 * sin(th); + + points[5].x = x + radius * 0.72 * cos(th + 0.05); + points[5].y = y + radius * 0.72 * sin(th + 0.05); + + points[6].x = x + radius * 0.74 * cos(th + 0.05); + points[6].y = y + radius * 0.74 * sin(th + 0.05); + + points[7].x = x + radius * 0.76 * cos(th); + points[7].y = y + radius * 0.76 * sin(th); + + points[8].x = x + radius * 0.74 * cos(th - 0.05); + points[8].y = y + radius * 0.74 * sin(th - 0.05); + + XDrawLines (st->dpy, d, disc->gc, points, 9, CoordModeOrigin); + + + /* E */ + + th = th2 + (2 * M_PI * 0.5); + + points[0].x = x + radius * 0.8 * cos(th + 0.05); + points[0].y = y + radius * 0.8 * sin(th + 0.05); + + points[1].x = x + radius * 0.8 * cos(th - 0.05); + points[1].y = y + radius * 0.8 * sin(th - 0.05); + + points[2].x = x + radius * 0.75 * cos(th - 0.05); + points[2].y = y + radius * 0.75 * sin(th - 0.05); + + points[3].x = x + radius * 0.75 * cos(th + 0.025); + points[3].y = y + radius * 0.75 * sin(th + 0.025); + + points[4].x = x + radius * 0.75 * cos(th - 0.05); + points[4].y = y + radius * 0.75 * sin(th - 0.05); + + points[5].x = x + radius * 0.7 * cos(th - 0.05); + points[5].y = y + radius * 0.7 * sin(th - 0.05); + + points[6].x = x + radius * 0.7 * cos(th + 0.05); + points[6].y = y + radius * 0.7 * sin(th + 0.05); + + XDrawLines (st->dpy, d, disc->gc, points, 7, CoordModeOrigin); + + /* 12 (1) */ + + th = th2 + (2 * M_PI * 0.58333); + + points[0].x = x + radius * 0.77 * cos(th - 0.06); + points[0].y = y + radius * 0.77 * sin(th - 0.06); + + points[1].x = x + radius * 0.8 * cos(th - 0.03); + points[1].y = y + radius * 0.8 * sin(th - 0.03); + + points[2].x = x + radius * 0.7 * cos(th - 0.03); + points[2].y = y + radius * 0.7 * sin(th - 0.03); + + XDrawLines (st->dpy, d, disc->gc, points, 3, CoordModeOrigin); + + /* 12 (2) */ + + points[0].x = x + radius * 0.78 * cos(th + 0.02); + points[0].y = y + radius * 0.78 * sin(th + 0.02); + + points[1].x = x + radius * 0.8 * cos(th + 0.07); + points[1].y = y + radius * 0.8 * sin(th + 0.07); + + points[2].x = x + radius * 0.78 * cos(th + 0.11); + points[2].y = y + radius * 0.78 * sin(th + 0.11); + + points[3].x = x + radius * 0.76 * cos(th + 0.11); + points[3].y = y + radius * 0.76 * sin(th + 0.11); + + points[4].x = x + radius * 0.74 * cos(th + 0.02); + points[4].y = y + radius * 0.74 * sin(th + 0.02); + + points[5].x = x + radius * 0.71 * cos(th + 0.03); + points[5].y = y + radius * 0.71 * sin(th + 0.03); + + points[6].x = x + radius * 0.7 * cos(th + 0.03); + points[6].y = y + radius * 0.7 * sin(th + 0.03); + + points[7].x = x + radius * 0.7 * cos(th + 0.13); + points[7].y = y + radius * 0.7 * sin(th + 0.13); + + XDrawLines (st->dpy, d, disc->gc, points, 8, CoordModeOrigin); + + /* 15 (1) */ + + th = th2 + (2 * M_PI * 0.66666); + + points[0].x = x + radius * 0.77 * cos(th - 0.06); + points[0].y = y + radius * 0.77 * sin(th - 0.06); + + points[1].x = x + radius * 0.8 * cos(th - 0.03); + points[1].y = y + radius * 0.8 * sin(th - 0.03); + + points[2].x = x + radius * 0.7 * cos(th - 0.03); + points[2].y = y + radius * 0.7 * sin(th - 0.03); + + XDrawLines (st->dpy, d, disc->gc, points, 3, CoordModeOrigin); + + /* 15 (2) */ + + points[0].x = x + radius * 0.8 * cos(th + 0.11); + points[0].y = y + radius * 0.8 * sin(th + 0.11); + + points[1].x = x + radius * 0.8 * cos(th + 0.02); + points[1].y = y + radius * 0.8 * sin(th + 0.02); + + points[2].x = x + radius * 0.76 * cos(th + 0.02); + points[2].y = y + radius * 0.76 * sin(th + 0.02); + + points[3].x = x + radius * 0.77 * cos(th + 0.06); + points[3].y = y + radius * 0.77 * sin(th + 0.06); + + points[4].x = x + radius * 0.76 * cos(th + 0.10); + points[4].y = y + radius * 0.76 * sin(th + 0.10); + + points[5].x = x + radius * 0.73 * cos(th + 0.11); + points[5].y = y + radius * 0.73 * sin(th + 0.11); + + points[6].x = x + radius * 0.72 * cos(th + 0.10); + points[6].y = y + radius * 0.72 * sin(th + 0.10); + + points[7].x = x + radius * 0.7 * cos(th + 0.06); + points[7].y = y + radius * 0.7 * sin(th + 0.06); + + points[8].x = x + radius * 0.72 * cos(th + 0.02); + points[8].y = y + radius * 0.72 * sin(th + 0.02); + + XDrawLines (st->dpy, d, disc->gc, points, 9, CoordModeOrigin); + + /* S */ + + th = th2 + (2 * M_PI * 0.75); + + points[0].x = x + radius * 0.78 * cos(th + 0.05); + points[0].y = y + radius * 0.78 * sin(th + 0.05); + + points[1].x = x + radius * 0.8 * cos(th); + points[1].y = y + radius * 0.8 * sin(th); + + points[2].x = x + radius * 0.78 * cos(th - 0.05); + points[2].y = y + radius * 0.78 * sin(th - 0.05); + + points[3].x = x + radius * 0.76 * cos(th - 0.05); + points[3].y = y + radius * 0.76 * sin(th - 0.05); + + points[4].x = x + radius * 0.74 * cos(th + 0.05); + points[4].y = y + radius * 0.74 * sin(th + 0.05); + + points[5].x = x + radius * 0.72 * cos(th + 0.05); + points[5].y = y + radius * 0.72 * sin(th + 0.05); + + points[6].x = x + radius * 0.7 * cos(th); + points[6].y = y + radius * 0.7 * sin(th); + + points[7].x = x + radius * 0.72 * cos(th - 0.05); + points[7].y = y + radius * 0.72 * sin(th - 0.05); + + XDrawLines (st->dpy, d, disc->gc, points, 8, CoordModeOrigin); + + /* 21 (1) */ + + th = th2 + (2 * M_PI * 0.83333); + + points[0].x = x + radius * 0.78 * cos(th - 0.13); + points[0].y = y + radius * 0.78 * sin(th - 0.13); + + points[1].x = x + radius * 0.8 * cos(th - 0.08); + points[1].y = y + radius * 0.8 * sin(th - 0.08); + + points[2].x = x + radius * 0.78 * cos(th - 0.03); + points[2].y = y + radius * 0.78 * sin(th - 0.03); + + points[3].x = x + radius * 0.76 * cos(th - 0.03); + points[3].y = y + radius * 0.76 * sin(th - 0.03); + + points[4].x = x + radius * 0.74 * cos(th - 0.12); + points[4].y = y + radius * 0.74 * sin(th - 0.12); + + points[5].x = x + radius * 0.71 * cos(th - 0.13); + points[5].y = y + radius * 0.71 * sin(th - 0.13); + + points[6].x = x + radius * 0.7 * cos(th - 0.13); + points[6].y = y + radius * 0.7 * sin(th - 0.13); + + points[7].x = x + radius * 0.7 * cos(th - 0.02); + points[7].y = y + radius * 0.7 * sin(th - 0.02); + + XDrawLines (st->dpy, d, disc->gc, points, 8, CoordModeOrigin); + + /* 21 (2) */ + + points[0].x = x + radius * 0.77 * cos(th + 0.03); + points[0].y = y + radius * 0.77 * sin(th + 0.03); + + points[1].x = x + radius * 0.8 * cos(th + 0.06); + points[1].y = y + radius * 0.8 * sin(th + 0.06); + + points[2].x = x + radius * 0.7 * cos(th + 0.06); + points[2].y = y + radius * 0.7 * sin(th + 0.06); + + XDrawLines (st->dpy, d, disc->gc, points, 3, CoordModeOrigin); + + /* 24 (1) */ + + th = th2 + (2 * M_PI * 0.91666); + + points[0].x = x + radius * 0.78 * cos(th - 0.13); + points[0].y = y + radius * 0.78 * sin(th - 0.13); + + points[1].x = x + radius * 0.8 * cos(th - 0.08); + points[1].y = y + radius * 0.8 * sin(th - 0.08); + + points[2].x = x + radius * 0.78 * cos(th - 0.03); + points[2].y = y + radius * 0.78 * sin(th - 0.03); + + points[3].x = x + radius * 0.76 * cos(th - 0.03); + points[3].y = y + radius * 0.76 * sin(th - 0.03); + + points[4].x = x + radius * 0.74 * cos(th - 0.12); + points[4].y = y + radius * 0.74 * sin(th - 0.12); + + points[5].x = x + radius * 0.71 * cos(th - 0.13); + points[5].y = y + radius * 0.71 * sin(th - 0.13); + + points[6].x = x + radius * 0.7 * cos(th - 0.13); + points[6].y = y + radius * 0.7 * sin(th - 0.13); + + points[7].x = x + radius * 0.7 * cos(th - 0.02); + points[7].y = y + radius * 0.7 * sin(th - 0.02); + + XDrawLines (st->dpy, d, disc->gc, points, 8, CoordModeOrigin); + + /* 24 (2) */ + + points[0].x = x + radius * 0.69 * cos(th + 0.09); + points[0].y = y + radius * 0.69 * sin(th + 0.09); + + points[1].x = x + radius * 0.8 * cos(th + 0.09); + points[1].y = y + radius * 0.8 * sin(th + 0.09); + + points[2].x = x + radius * 0.72 * cos(th + 0.01); + points[2].y = y + radius * 0.72 * sin(th + 0.01); + + points[3].x = x + radius * 0.72 * cos(th + 0.13); + points[3].y = y + radius * 0.72 * sin(th + 0.13); + + XDrawLines (st->dpy, d, disc->gc, points, 4, CoordModeOrigin); +} + + +static void +draw_ticks (struct state *st, Drawable d, struct disc *disc, + int x, int y, int radius) +{ + XSegment segs[72]; + int i; + double tick = (M_PI * 2) / 72; + + for (i = 0; i < 72; i++) + { + int radius2 = radius; + double th = (i * tick) + (2 * M_PI * (disc->theta / ((double) 360*64))); + + if (i % 6) + radius2 -= radius / 16; + else + radius2 -= radius / 8; + + segs[i].x1 = x + radius * cos(th); + segs[i].y1 = y + radius * sin(th); + segs[i].x2 = x + radius2 * cos(th); + segs[i].y2 = y + radius2 * sin(th); + } + XDrawSegments (st->dpy, d, disc->gc, segs, countof(segs)); + + draw_letters (st, d, disc, x, y, radius); +} + + +static void +draw_thin_arrow (struct state *st, Drawable d, struct disc *disc, + int x, int y, int radius) +{ + XPoint points[3]; + double th; + int radius2; + double tick = ((M_PI * 2) / 72) * 2; + + radius *= 0.9; + radius2 = radius - (radius / 8) * 3; + + th = 2 * M_PI * (disc->theta / ((double) 360*64)); + + points[0].x = x + radius * cos(th); /* tip */ + points[0].y = y + radius * sin(th); + + points[1].x = x + radius2 * cos(th - tick); /* tip left */ + points[1].y = y + radius2 * sin(th - tick); + + points[2].x = x + radius2 * cos(th + tick); /* tip right */ + points[2].y = y + radius2 * sin(th + tick); + + XDrawLine (st->dpy, d, disc->gc, + (int) (x + radius2 * cos(th)), + (int) (y + radius2 * sin(th)), + (int) (x + -radius * cos(th)), + (int) (y + -radius * sin(th))); + + XFillPolygon (st->dpy, d, disc->gc, points, 3, Convex, CoordModeOrigin); +} + + +static void +draw_thick_arrow (struct state *st, Drawable d, struct disc *disc, + int x, int y, int radius) +{ + XPoint points[10]; + double th; + int radius2, radius3; + double tick = ((M_PI * 2) / 72) * 2; + + radius *= 0.9; + radius2 = radius - (radius / 8) * 3; + radius3 = radius - (radius / 8) * 2; + th = 2 * M_PI * (disc->theta / ((double) 360*64)); + + points[0].x = x + radius * cos(th); /* tip */ + points[0].y = y + radius * sin(th); + + points[1].x = x + radius2 * cos(th - tick); /* tip left */ + points[1].y = y + radius2 * sin(th - tick); + + points[2].x = x + radius2 * cos(th + tick); /* tip right */ + points[2].y = y + radius2 * sin(th + tick); + + points[3] = points[0]; + + XDrawLines (st->dpy, d, disc->gc, points, 4, CoordModeOrigin); + + points[0].x = x + radius2 * cos(th - tick/2); /* top left */ + points[0].y = y + radius2 * sin(th - tick/2); + + points[1].x = x + -radius2 * cos(th + tick/2); /* bottom left */ + points[1].y = y + -radius2 * sin(th + tick/2); + + points[2].x = x + -radius3 * cos(th); /* bottom */ + points[2].y = y + -radius3 * sin(th); + + points[3].x = x + -radius * cos(th); /* bottom spike */ + points[3].y = y + -radius * sin(th); + + points[4] = points[2]; /* return */ + + points[5].x = x + -radius2 * cos(th - tick/2); /* bottom right */ + points[5].y = y + -radius2 * sin(th - tick/2); + + points[6].x = x + radius2 * cos(th + tick/2); /* top right */ + points[6].y = y + radius2 * sin(th + tick/2); + + XDrawLines (st->dpy, d, disc->gc, points, 7, CoordModeOrigin); +} + + + +static void +roll_disc (struct disc *disc) +{ + double th = disc->theta; + if (th < 0) + th = -(th + disc->velocity); + else + th = (th + disc->velocity); + + if (th > (360*64)) + th -= (360*64); + else if (th < 0) + th += (360*64); + + disc->theta = (disc->theta > 0 ? th : -th); + + disc->velocity += disc->acceleration; + + if (disc->velocity > disc->limit || + disc->velocity < -disc->limit) + disc->acceleration = -disc->acceleration; + + /* Alter direction of rotational acceleration randomly. */ + if (! (random() % 120)) + disc->acceleration = -disc->acceleration; + + /* Change acceleration very occasionally. */ + if (! (random() % 200)) + { + if (random() & 1) + disc->acceleration *= 1.2; + else + disc->acceleration *= 0.8; + } +} + + +static void +init_spin (struct disc *disc) +{ + disc->limit = 5*64; + disc->theta = RAND(360*64); + disc->velocity = RAND(16) * RANDSIGN(); + disc->acceleration = RAND(16) * RANDSIGN(); +} + + +static void +draw_compass (struct state *st) +{ + int i = 0; + while (st->discs[i]) + { + st->discs[i]->draw (st, st->b, st->discs[i], st->x, st->y, st->size); + roll_disc (st->discs[i]); + i++; + } +} + +static void +draw_pointer (struct state *st) +{ + int radius = st->size; + GC dot_gc = st->discs[0]->gc; + XPoint points[3]; + int size = radius * 0.1; + + /* top */ + + points[0].x = st->x - size; + points[0].y = st->y - radius - size; + + points[1].x = st->x + size; + points[1].y = st->y - radius - size; + + points[2].x = st->x; + points[2].y = st->y - radius; + + XFillPolygon (st->dpy, st->b, st->ptr_gc, points, 3, Convex, CoordModeOrigin); + + /* top right */ + + points[0].x = st->x - (radius * 0.85); + points[0].y = st->y - (radius * 0.8); + + points[1].x = st->x - (radius * 1.1); + points[1].y = st->y - (radius * 0.55); + + points[2].x = st->x - (radius * 0.6); + points[2].y = st->y - (radius * 0.65); + + XFillPolygon (st->dpy, st->b, st->ptr_gc, points, 3, Convex, CoordModeOrigin); + + /* left */ + + points[0].x = st->x - (radius * 1.05); + points[0].y = st->y; + + points[1].x = st->x - (radius * 1.1); + points[1].y = st->y - (radius * 0.025); + + points[2].x = st->x - (radius * 1.1); + points[2].y = st->y + (radius * 0.025); + + XFillPolygon (st->dpy, st->b, dot_gc, points, 3, Convex, CoordModeOrigin); + + /* right */ + + points[0].x = st->x + (radius * 1.05); + points[0].y = st->y; + + points[1].x = st->x + (radius * 1.1); + points[1].y = st->y - (radius * 0.025); + + points[2].x = st->x + (radius * 1.1); + points[2].y = st->y + (radius * 0.025); + + XFillPolygon (st->dpy, st->b, dot_gc, points, 3, Convex, CoordModeOrigin); + + /* bottom */ + + points[0].x = st->x; + points[0].y = st->y + (radius * 1.05); + + points[1].x = st->x - (radius * 0.025); + points[1].y = st->y + (radius * 1.1); + + points[2].x = st->x + (radius * 0.025); + points[2].y = st->y + (radius * 1.1); + + XFillPolygon (st->dpy, st->b, dot_gc, points, 3, Convex, CoordModeOrigin); + + /* bottom left */ + + points[0].x = st->x + (radius * 0.74); + points[0].y = st->y + (radius * 0.74); + + points[1].x = st->x + (radius * 0.78); + points[1].y = st->y + (radius * 0.75); + + points[2].x = st->x + (radius * 0.75); + points[2].y = st->y + (radius * 0.78); + + XFillPolygon (st->dpy, st->b, dot_gc, points, 3, Convex, CoordModeOrigin); + + /* top left */ + + points[0].x = st->x + (radius * 0.74); + points[0].y = st->y - (radius * 0.74); + + points[1].x = st->x + (radius * 0.78); + points[1].y = st->y - (radius * 0.75); + + points[2].x = st->x + (radius * 0.75); + points[2].y = st->y - (radius * 0.78); + + XFillPolygon (st->dpy, st->b, dot_gc, points, 3, Convex, CoordModeOrigin); + + /* bottom right */ + + points[0].x = st->x - (radius * 0.74); + points[0].y = st->y + (radius * 0.74); + + points[1].x = st->x - (radius * 0.78); + points[1].y = st->y + (radius * 0.75); + + points[2].x = st->x - (radius * 0.75); + points[2].y = st->y + (radius * 0.78); + + XFillPolygon (st->dpy, st->b, dot_gc, points, 3, Convex, CoordModeOrigin); +} + + +static void * +compass_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + XGCValues gcv; + st->dpy = dpy; + st->window = window; + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->dbuf = get_boolean_resource (st->dpy, "doubleBuffer", "Boolean"); + +# ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */ + st->dbuf = False; +# endif + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + st->size2 = MIN(st->xgwa.width, st->xgwa.height); + + if (st->xgwa.width > st->xgwa.height * 5 || /* goofy aspect ratio */ + st->xgwa.height > st->xgwa.width * 5) + st->size2 = MAX(st->xgwa.width, st->xgwa.height); + + { + int max = 600; + if (st->xgwa.width > 2560) max *= 2; /* Retina displays */ + if (st->size2 > max) st->size2 = max; + } + + st->size = (st->size2 / 2) * 0.8; + + st->x = st->xgwa.width/2; + st->y = st->xgwa.height/2; + + if (st->dbuf) + { +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + st->b = st->backb = xdbe_get_backbuffer (st->dpy, st->window, XdbeUndefined); +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + + if (!st->b) + { + st->x = st->size2/2; + st->y = st->size2/2; + st->ba = XCreatePixmap (st->dpy, st->window, st->size2, st->size2, st->xgwa.depth); + st->bb = XCreatePixmap (st->dpy, st->window, st->size2, st->size2, st->xgwa.depth); + st->b = st->ba; + } + } + else + { + st->b = st->window; + } + + st->discs[0] = (struct disc *) calloc (1, sizeof (struct disc)); + st->discs[1] = (struct disc *) calloc (1, sizeof (struct disc)); + st->discs[2] = (struct disc *) calloc (1, sizeof (struct disc)); + st->discs[3] = 0; + + gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap, + "foreground", "Foreground"); + gcv.line_width = MAX(2, (st->size/60)); + gcv.join_style = JoinBevel; + st->discs[0]->draw = draw_ticks; + st->discs[0]->gc = XCreateGC (st->dpy, st->b, GCForeground|GCLineWidth|GCJoinStyle, + &gcv); + init_spin (st->discs[0]); + + gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap, + "arrow2Foreground", "Foreground"); + gcv.line_width = MAX(4, (st->size / 30)); + st->discs[1]->draw = draw_thick_arrow; + st->discs[1]->gc = XCreateGC (st->dpy, st->b, GCForeground|GCLineWidth, &gcv); + init_spin (st->discs[1]); + + gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap, + "arrow1Foreground", "Foreground"); + gcv.line_width = MAX(4, (st->size / 30)); + st->discs[2]->draw = draw_thin_arrow; + st->discs[2]->gc = XCreateGC (st->dpy, st->b, GCForeground|GCLineWidth, &gcv); + init_spin (st->discs[2]); + + gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap, + "pointerForeground", "Foreground"); + st->ptr_gc = XCreateGC (st->dpy, st->b, GCForeground|GCLineWidth, &gcv); + + gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap, + "background", "Background"); + st->erase_gc = XCreateGC (st->dpy, st->b, GCForeground, &gcv); + + if (st->ba) XFillRectangle (st->dpy, st->ba, st->erase_gc, 0, 0, st->size2, st->size2); + if (st->bb) XFillRectangle (st->dpy, st->bb, st->erase_gc, 0, 0, st->size2, st->size2); + + return st; +} + +static unsigned long +compass_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + XFillRectangle (st->dpy, st->b, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height); + + draw_compass (st); + draw_pointer (st); + +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + if (st->backb) + { + XdbeSwapInfo info[1]; + info[0].swap_window = st->window; + info[0].swap_action = XdbeUndefined; + XdbeSwapBuffers (st->dpy, info, 1); + } + else +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + if (st->dbuf) + { + XCopyArea (st->dpy, st->b, st->window, st->erase_gc, 0, 0, + st->size2, st->size2, + st->xgwa.width/2 - st->x, + st->xgwa.height/2 - st->y); + st->b = (st->b == st->ba ? st->bb : st->ba); + } + + return st->delay; +} + +static void +compass_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + st->size2 = MIN(st->xgwa.width, st->xgwa.height); + st->x = st->xgwa.width/2; + st->y = st->xgwa.height/2; +} + +static Bool +compass_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +compass_free (Display *dpy, Window window, void *closure) +{ +} + + + +static const char *compass_defaults [] = { + ".background: #000000", + ".foreground: #DDFFFF", + "*arrow1Foreground: #FFF66A", + "*arrow2Foreground: #F7D64A", + "*pointerForeground: #FF0000", + "*delay: 20000", + "*doubleBuffer: True", +#ifdef HAVE_DOUBLE_BUFFER_EXTENSION + "*useDBE: True", +#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ + 0 +}; + +static XrmOptionDescRec compass_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-db", ".doubleBuffer", XrmoptionNoArg, "True" }, + { "-no-db", ".doubleBuffer", XrmoptionNoArg, "False" }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("Compass", compass) diff --git a/hacks/compass.man b/hacks/compass.man new file mode 100644 index 0000000..8d7cc7e --- /dev/null +++ b/hacks/compass.man @@ -0,0 +1,57 @@ +.TH XScreenSaver 1 "" "X Version 11" +.SH NAME +compass - draws a spinning compass. +.SH SYNOPSIS +.B compass +[\-display \fIhost:display.screen\fP] +[\-visual \fIvisual\fP] +[\-window] +[\-root] +[\-delay \fInumber\fP] +[\-no-db] +[\-fps] +.SH DESCRIPTION +This draws a compass, with all elements spinning about randomly, for that +``lost and nauseous'' feeling. +.SH OPTIONS +.TP 8 +.B \-visual \fIvisual\fP +Specify which visual to use. Legal values are the name of a visual class, +or the id number (decimal or hex) of a specific visual. +.TP 8 +.B \-window +Draw on a newly-created window. This is the default. +.TP 8 +.B \-root +Draw on the root window. +.TP 8 +.B \-delay \fInumber\fP +Per-frame delay, in microseconds. Default: 20000 (0.02 seconds.). +.TP 8 +.B \-db | \-no-db +Double Buffer. Boolean. +.TP 8 +.B \-fps +Display the current frame rate and CPU load. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH SEE ALSO +.BR X (1), +.BR xscreensaver (1) +.SH COPYRIGHT +Copyright \(co 2002 by Jamie Zawinski. Permission to use, copy, modify, +distribute, and sell this software and its documentation for any purpose is +hereby granted without fee, provided that the above copyright notice appear +in all copies and that both that copyright notice and this permission notice +appear in supporting documentation. No representations are made about the +suitability of this software for any purpose. It is provided "as is" without +express or implied warranty. +.SH AUTHOR +Jamie Zawinski. diff --git a/hacks/compile_axp.com b/hacks/compile_axp.com new file mode 100644 index 0000000..c50e0f9 --- /dev/null +++ b/hacks/compile_axp.com @@ -0,0 +1,156 @@ +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ABSTRACTILE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ANALOGTV.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ANEMONE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ANEMOTAXIS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ANT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) APOLLONIAN.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) APPLE2.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) APPLE2-MAIN.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ASM6502.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ATTRACTION.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BARCODE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BINARYRING.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BLASTER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BLITSPIN.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BOUBOULE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BOXFIT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BRAID.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BSOD.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BUBBLES.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BUBBLES-DEFAULT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BUMPS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CCURVE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CELTIC.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CLOUDLIFE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) COMPASS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CORAL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CRITICAL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CRYSTAL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CWAVES.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CYNOSURE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DECAYSCREEN.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DECO.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DELAUNAY.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DELUXE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DEMON.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DISCRETE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DISTORT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DRIFT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) EPICYCLE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ERUPTION.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) EULER2D.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FADEPLOT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FIBERLAMP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FILMLEADER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FIREWORKX.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FLAG.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FLAME.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FLOW.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FLUIDBALLS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FONTGLIDE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FOREST.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FPS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FUZZYFLAKES.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) GALAXY.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) GLITCHPEG.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) GOOP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) GRAV.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) GREYNETIC.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) HALFTONE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) HALO.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) HELIX.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) HEXADROP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) HOPALONG.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) HYPERBALL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) HYPERCUBE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) IFS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) IMSMAP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) INTERAGGREGATE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) INTERFERENCE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) INTERMOMENTARY.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) JUGGLE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) JULIA.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) KALEIDESCOPE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) KUMPPA.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) LASER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) LCDSCRUB.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) LIGHTNING.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) LISA.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) LISSIE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) LMORPH.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) LOOP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) M6502.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) MAZE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) MEMSCROLLER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) METABALLS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) MOIRE2.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) MOIRE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) MOUNTAIN.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) MUNCH.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) NERVEROT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) NOSEGUY.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PACMAN_AI.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PACMAN.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PACMAN_LEVEL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PEDAL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PENETRATE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PENROSE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PETRI.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PHOSPHOR.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PIECEWISE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) POLYOMINOES.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PONG.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) POPSQUARES.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PYRO.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) QIX.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) RD-BOMB.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) RECANIM.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) RIPPLES.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ROCKS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) RORSCHACH.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ROTOR.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ROTZOOMER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SCREENHACK.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SHADEBOBS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SIERPINSKI.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SLIDESCREEN.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SLIP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SPEEDMINE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SPHERE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SPIRAL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SPOTLIGHT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SQUIRAL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) STARFISH.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) STRANGE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SUBSTRATE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SWIRL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) T3D.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) TESSELLIMAGE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) TESTX11.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) THORNBIRD.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) TRIANGLE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) TRUCHET.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) TWANG.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) VERMICULATE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) VFEEDBACK.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) VINES.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WANDER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WEBCOLLAGE-COCOA.M +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WEBCOLLAGE-HELPER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WEBCOLLAGE-HELPER-COCOA.M +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WHIRLWINDWARP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WHIRLYGIG.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WORM.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WORMHOLE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XANALOGTV.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XFLAME.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XIMAGE-LOADER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XJACK.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XLOCKMORE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XLYAP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XMATRIX.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XRAYSWARM.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XSCREENSAVER-SGIGL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XSPIROGRAPH.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XSUBLIM.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ZOOM.C diff --git a/hacks/compile_decc.com b/hacks/compile_decc.com new file mode 100644 index 0000000..c50e0f9 --- /dev/null +++ b/hacks/compile_decc.com @@ -0,0 +1,156 @@ +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ABSTRACTILE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ANALOGTV.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ANEMONE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ANEMOTAXIS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ANT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) APOLLONIAN.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) APPLE2.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) APPLE2-MAIN.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ASM6502.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ATTRACTION.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BARCODE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BINARYRING.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BLASTER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BLITSPIN.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BOUBOULE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BOXFIT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BRAID.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BSOD.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BUBBLES.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BUBBLES-DEFAULT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BUMPS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CCURVE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CELTIC.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CLOUDLIFE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) COMPASS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CORAL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CRITICAL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CRYSTAL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CWAVES.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CYNOSURE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DECAYSCREEN.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DECO.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DELAUNAY.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DELUXE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DEMON.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DISCRETE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DISTORT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) DRIFT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) EPICYCLE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ERUPTION.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) EULER2D.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FADEPLOT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FIBERLAMP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FILMLEADER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FIREWORKX.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FLAG.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FLAME.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FLOW.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FLUIDBALLS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FONTGLIDE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FOREST.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FPS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) FUZZYFLAKES.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) GALAXY.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) GLITCHPEG.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) GOOP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) GRAV.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) GREYNETIC.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) HALFTONE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) HALO.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) HELIX.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) HEXADROP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) HOPALONG.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) HYPERBALL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) HYPERCUBE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) IFS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) IMSMAP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) INTERAGGREGATE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) INTERFERENCE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) INTERMOMENTARY.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) JUGGLE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) JULIA.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) KALEIDESCOPE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) KUMPPA.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) LASER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) LCDSCRUB.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) LIGHTNING.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) LISA.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) LISSIE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) LMORPH.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) LOOP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) M6502.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) MAZE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) MEMSCROLLER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) METABALLS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) MOIRE2.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) MOIRE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) MOUNTAIN.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) MUNCH.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) NERVEROT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) NOSEGUY.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PACMAN_AI.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PACMAN.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PACMAN_LEVEL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PEDAL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PENETRATE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PENROSE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PETRI.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PHOSPHOR.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PIECEWISE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) POLYOMINOES.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PONG.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) POPSQUARES.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) PYRO.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) QIX.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) RD-BOMB.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) RECANIM.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) RIPPLES.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ROCKS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) RORSCHACH.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ROTOR.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ROTZOOMER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SCREENHACK.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SHADEBOBS.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SIERPINSKI.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SLIDESCREEN.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SLIP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SPEEDMINE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SPHERE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SPIRAL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SPOTLIGHT.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SQUIRAL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) STARFISH.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) STRANGE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SUBSTRATE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) SWIRL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) T3D.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) TESSELLIMAGE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) TESTX11.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) THORNBIRD.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) TRIANGLE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) TRUCHET.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) TWANG.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) VERMICULATE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) VFEEDBACK.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) VINES.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WANDER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WEBCOLLAGE-COCOA.M +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WEBCOLLAGE-HELPER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WEBCOLLAGE-HELPER-COCOA.M +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WHIRLWINDWARP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WHIRLYGIG.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WORM.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) WORMHOLE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XANALOGTV.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XFLAME.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XIMAGE-LOADER.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XJACK.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XLOCKMORE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XLYAP.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XMATRIX.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XRAYSWARM.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XSCREENSAVER-SGIGL.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XSPIROGRAPH.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) XSUBLIM.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) ZOOM.C diff --git a/hacks/config/README b/hacks/config/README new file mode 100644 index 0000000..9771a89 --- /dev/null +++ b/hacks/config/README @@ -0,0 +1,262 @@ + + XScreenSaver + + a screen saver and locker for the X window system + by Jamie Zawinski + + version 5.40 + 12-Aug-2018 + + https://www.jwz.org/xscreensaver/ + +----------------------------------------------------------------------- + +This directory contains XML files that describe each of the screenhacks; +the per-hack user interface is constructed based on the things in these +files. The files are loaded at run-time by xscreensaver-demo (also +known as "the Control Center screensaver properties capplet".) + +The tags and parameters used here are: + +----------------------------------------------------------------------- + + + ... + + + This encloses the whole file: all of the tags described below + are inside this one. + +----------------------------------------------------------------------- + + + + specifies that "-SWITCH" always appears on the command line. + You'll most often see this with "-root". + +----------------------------------------------------------------------- + + + + This creates a checkbox. + + "id" is currently unused, but may eventually be used for + letting other widgets refer to this one. + + "_label" is the string printed next to the checkbox. + + "arg-set" is what to insert into the command line if the + box is checked. + + "arg-unset" is what to insert into the command line if the + box is unchecked. + + You will probably never specify both "arg-set" and "arg-unset", + because the setting that is the default should insert nothing + into the command line (that's what makes it the default.) + For example: + + + + or if "foo" is the default, and must be explicity turned off, + + + +----------------------------------------------------------------------- + + + + This creates a slider. + + The _label is printed above the slider. The _low-label and + _high-label are printed to the left and right, respectively. + + If any of the numbers you type has a decimal point, then + the range is assumed to be a floating-point value; otherwise, + only integral values will be used. So be careful about "1" + versus "1.0". + + If convert="invert" is specified, then the value that the + user tweaks goes the other way from the value the command + line expects: e.g., if the slider goes from 10-20 and the + user picks 13, the converted value goes from 20-10 (and + would be 17.) This is useful for converting between the + concepts of "delay" and "speed". + + In the "arg" string, the first occurence of "%" is replaced + with the numeric value, when creating the command line. + +----------------------------------------------------------------------- + + + + This creates a spinbox (a text field with a number in it, + and up/down arrows next to it.) + + Arguments are exactly like type="slider", except that + _low-label and _high-label are not used. Also, _label + appears to the left of the box, instead of above it. + +----------------------------------------------------------------------- + + + + This creates a selection popup menu. + + Options should have arg-set (arg-unset is not used here.) + + One of the menu items (the default) should have no arg-set. + + Each arg-set should begin with the same switch: that is, + all the args in a given menu should look like: + + -mode one + -mode two + -mode three + + and not + + -this + -that + -the other + +----------------------------------------------------------------------- + + + + This creates a text entry field. + +----------------------------------------------------------------------- + + + + This creates a file entry field (a text field with a "Browse" + button next to it.) + +----------------------------------------------------------------------- + + + + This indicates that this screen saver displays text via the + "xscreensaver-text" program. + + In the X11 version, this tag does nothing: the text-related + preferences are in the main Screen Saver Preferences window, + not in the per-display-mode preferences. + + In the MacOS version, the text-related preferences appear + in this pane, and this tag emits those several controls. + +----------------------------------------------------------------------- + + + + This indicates that this screen saver displays images via the + "xscreensaver-getimage" program. + + In the X11 version, this tag does nothing: the image-loading + and screen-grabbing-related preferences are in the main + Screen Saver Preferences window, not in the per-display-mode + preferences. + + In the MacOS version, the image-related preferences appear + in this pane, and this tag emits those several controls. + +----------------------------------------------------------------------- + + + + Where to position the "Check for Updates" options. + This is used on MacOS and ignored on X11. + +----------------------------------------------------------------------- + +